- pai 通过数据表生成CRUD 代码
- 操作示例
- 1. 首先切换到项目目录结构下,并输入 pai code -h。
- 2. 根据提示帮助,选择语句。
- 3. 到这里代码已经自动生成了。
- 代码结构解析
- model 领域模型层
- 编写 model 实体
- PO Model 规范
- VO Model 规范
- po对象 sign_in 签到表
- vo 对象 sign_in 签到表
- 基础设施层(dao,mapper)
- Mapper 接口类
- mapper.xml
- SignInMapper.java 代码
- SignInMapper.xml 代码
- 应用层(service)
- service介绍
- SignInService.java 代码
- service 实现类介绍
- API 展现层
- 编写 Controller
- Controller 类相关标签
- 其他说明
pai 通过数据表生成CRUD 代码
操作示例
1. 首先切换到项目目录结构下,并输入 pai code -h。
D:\home\pai-demo-attendance>pai code -h
Found D:\pai\pai-cli\.pai\wrapper\pai-wrapper.jar
根据表结构生成代码
语法:
pai code [参数]
参数:
-h,--help 使用帮助
-t,--table <arg> 表名
-n,--name <arg> 工程名称(默认当前目录名称)
-o,--output <arg> 文件保存绝对路径(默认当前路径)
示例:
pai code -t user
pai code -t user -n pai-demo
2. 根据提示帮助,选择语句。
D:\home\pai-demo-attendance>pai code -n pai-demo-attendance -t sign_in
Found D:\pai\pai-cli\.pai\wrapper\pai-wrapper.jar
signIn对象代码已生成
3. 到这里代码已经自动生成了。
我们使用idea打开该项目,打开src目录,相比刚创建的工程,部分增加的代码都是根据你的表结构所自动生成的。
以下是项目创建好后大致的src目录结构:
├─main
│ ├─java
│ │ └─cn
│ │ └─flyrise
│ │ └─pai
│ │ └─demoattendance
│ │ │ Application.java
│ │ ├─config
│ │ ├─controller
│ │ │ SignInController.java
│ │ ├─dao
│ │ │ SignInMapper.java
│ │ ├─exception
│ │ │ BusinessErrors.java
│ │ │ PaiBizException.java
│ │ ├─model
│ │ │ ├─po
│ │ │ │ SignInPO.java
│ │ │ └─vo
│ │ │ SignInVO.java
│ │ │
│ │ └─service
│ │ │ ISignInService.java
│ │ └─impl
│ │ SignInServiceImpl.java
│ │
│ └─resources
│ └─mapper
│ SignInDao.xml
代码结构解析
model 领域模型层
model 包分为po、vo 两个包,po 目录来对应数据库的表的对象,vo 目录是用于对外暴露的对象,例如请求的对象放vo而不要放po对象,返回值同样。
下面用一个简单的例子说明,例如一个请假表中有个审核字段 state
{0 发起 1同意 2拒绝},但是我们在写接口的时候并不会传递该值,因为发起的时候该状态就是0,而调用了同意的接口该状态才会变为1,拒绝依此类推。这就意味着我们写发起接口的时候不会有 state
该字段,所以我们用VO做为参数的时候可以吧 state
字段给去掉。
编写 model 实体
PO Model 规范
- 一个PO对应一张数据表
- 使用
@TableId('id')
注解标注主键 - 实体继承 BaseEntity,BaseEntity 包含(create_by:创建人,create_time:创建时间,update_by:更新人,update_time:更新时间)
- 使用
@Table (javax.persistence.Table)
映射表名 - 使用
@TableField (javax.persistence.TableField)
映射字段名 - 属性上写注释/** 注释 */
- 非数据库字段使用
@Transient
注解标注,如果页面用到的非数据库字段比较多,建议使用 DTO 封装数据。 - 所有属性均为private属性,每一个属性需要生成对应的 getter、setter 方法。
- 不使用基本类型,全部使用基本类型的包装类,如
Long
对应数据库中的INTEGER
,而不是使用long
。 - 数字类型主键统一采用
Long
。金额、数量 等精度严格浮点类型采用BigDecimal
(注意:BigDecimal 在计算、比较方面的特殊性)
VO Model 规范
- 使用 @ApiModel 注解说明实体含义,在 Swagger 文档上就可以看到实体说明。
- 实体字段使用 @ApiModelProperty 说明字段含义,在 Swagger 文档上可以看到字段说明。
- 所有属性均为private属性,每一个属性需要生成对应的 getter、setter 方法。
- 不使用基本类型,全部使用基本类型的包装类,如
Long
对应数据库中的INTEGER
,而不是使用long
。 - 数字类型主键统一采用
Long
。金额、数量 等精度严格浮点类型采用BigDecimal
(注意:BigDecimal 在计算、比较方面的特殊性)
po对象 sign_in 签到表
package cn.flyrise.pai.demoattendance.model.po;
import java.io.Serializable;
import java.util.Date;
import cn.flyrise.mybatis.base.BaseEntity;
import com.baomidou.mybatisplus.annotation.*;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
/**
* 签到表对象 sign_in
*
* @author pai
* @date 2021-04-22
*/
@TableName("sign_in")
public class SignInPO extends BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId("id")
private String id;
/**
* 用户id
*/
@TableField("us_id")
private String usId;
/**
* 经度
*/
@TableField("lat")
private String lat;
/**
* 用户名称
*/
@TableField("us_name")
private String usName;
/**
* 纬度
*/
@TableField("lng")
private String lng;
/**
* 打卡地址
*/
@TableField("address")
private String address;
/**
* 打卡时间
*/
@TableField("sign_time")
private Date signTime;
/**
* 租户ID
*/
@TableField("tenant_id")
private String tenantId;
/**
* 园区ID
*/
@TableField(value = "park_id", fill = FieldFill.INSERT)
private String parkId;
/**
* 是否已删除(0:否 1:是)
*/
@TableLogic
@TableField("is_deleted")
private Integer isDeleted;
/**
* 状态
*/
@TableField("status")
private Integer status;
// get set 忽略
}
vo 对象 sign_in 签到表
package cn.flyrise.pai.demoattendance.model.vo;
import java.io.Serializable;
import java.util.Date;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
/**
* 签到表对象 sign_in
*
* @author pai
* @date 2021-04-22
*/
@ApiModel("签到表")
public class SignInVO implements Serializable {
private static final long serialVersionUID=1L;
/** 主键 */
@ApiModelProperty("主键")
private String id;
/** 用户id */
@ApiModelProperty("用户id")
private String usId;
/** 经度 */
@NotBlank // 非空控制
@Length(max = 20) //长度限制
@ApiModelProperty("经度")
private String lat;
/** 用户名称 */
@ApiModelProperty("用户名称")
private String usName;
/** 纬度 */
@NotBlank
@Length(max = 20) //长度限制
@ApiModelProperty("纬度")
private String lng;
/** 打卡地址 */
@Length(max = 100) //长度限制
@ApiModelProperty("打卡地址")
private String address;
/** 打卡时间 */
@ApiModelProperty("打卡时间")
private Date signTime;
/** 租户ID */
@ApiModelProperty("租户ID")
private String tenantId;
/** 园区ID */
@ApiModelProperty("园区ID")
private String parkId;
/** 是否已删除(0:否 1:是) */
@ApiModelProperty("是否已删除(0:否 1:是)")
private Integer isDeleted;
/** 状态 */
@ApiModelProperty("状态")
private Integer status;
/** 创建人 */
@ApiModelProperty("创建人")
private String createBy;
/** 创建时间 */
@ApiModelProperty("创建时间")
private Date createTime;
/** 修改人 */
@ApiModelProperty("修改人")
private String updateBy;
/** 修改时间 */
@ApiModelProperty("修改时间")
private Date updateTime;
//get set 忽略
}
基础设施层(dao,mapper)
Mapper 接口类
- mapper 接口类即为传统意义上的 DAO,但与 interface 不同,mapper 本身就是对数据访问的具体实现,所以属于供应方的服务实现层。创建在 项目模块 的 xxx.dao 包下。
- 每一个 mapper 接口类封装了对数据库表的操作,每一个 mapper 对应一个 实体 类,命名为 实体 类名尾缀替换为 Mapper 。如:SignInMapper 对应实体为 SignIn 类。
- 基础的 CRUD 操作不需要再次实现,通过继承 BaseMapper< PO > 类实现。其中 PO 为 对应 实体 的泛型。
- 复杂的数据库操作需要定义具体的接口方法
mapper.xml
- Mapper的xml文件 是数据库的的具体映射,与 Mapper 接口同级,创建在 项目模块 resources 目录下的 mapper 目录下。
- Mapper的xml文件,与 Mapper 接口对应。所以命名与 Mapper 接口类相同。
- Mapper的xml文件非必须,由于继承BaseMapper类后基本的 CRUD 不需要进行配置,所以只有CRUD操作时不需要创建对应的 xml 文件。
- 对于自定义的数据库方法,需要创建对应的 mapper.xml 文件。
- Mapper的xml 中的操作 id 对应 Mapper 接口类的方法名。
SignInMapper.java 代码
package cn.flyrise.pai.demoattendance.dao;
import cn.flyrise.pai.demoattendance.model.po.SignInPO;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
/**
* 签到表数据库访问层
*
* @author pai
* @date 2021-04-22
*/
@Mapper
@Repository
public interface SignInMapper extends BaseMapper<SignInPO> {
}
SignInMapper.xml 代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.flyrise.pai.demoattendance.dao.SignInMapper">
<resultMap type="cn.flyrise.pai.demoattendance.model.po.SignInPO" id="SignInMap">
<result property="id" column="id"/>
<result property="usId" column="us_id"/>
<result property="lat" column="lat"/>
<result property="usName" column="us_name"/>
<result property="lng" column="lng"/>
<result property="address" column="address"/>
<result property="signTime" column="sign_time"/>
<result property="tenantId" column="tenant_id"/>
<result property="parkId" column="park_id"/>
<result property="isDeleted" column="is_deleted"/>
<result property="status" column="status"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/>
<result property="updateBy" column="update_by"/>
<result property="updateTime" column="update_time"/>
</resultMap>
</mapper>
应用层(service)
service介绍
service
调用领域对象或服务来解决问题,应用层Service主要有以下特性:
- 负责事务处理,所以事务的注解可以在这一层的service中使用。
- 只处理非业务逻辑,重点是调度业务处理流程。业务逻辑处理一定要放在领域层处理。
- 不做单元测试,只做验收测试。
SignInService.java 代码
package cn.flyrise.pai.demoattendance.service;
import cn.flyrise.pai.demoattendance.model.po.SignInPO;
import cn.flyrise.pai.demoattendance.model.vo.SignInVO;
import cn.flyrise.mybatis.base.IBaseService;
/**
* 签到表Service接口
*
* @author pai
* @date 2021-04-22
*/
public interface ISignInService extends IBaseService<SignInPO, SignInVO> {
/**
* 新增
* @param signInVO
* @return
*/
SignInVO add(SignInVO signInVO);
/**
* 保存
* @param signInVO
* @return
*/
SignInVO save(SignInVO signInVO);
/**
* 查询
* @param id
* @return
*/
SignInVO findById(String id);
/**
* 删除
* @param id
*/
void delete(String id);
}
service 实现类介绍
Service
实现类
- Service 接口的具体实现通过服务实现层提供,所以属于供应方的服务实现层。创建在项目模块的 xxx.service.impl 包下。
- 实现类,需要用 @Service 标注
package cn.flyrise.pai.demoattendance.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import cn.flyrise.common.core.utils.IdUtils;
import cn.flyrise.pai.demoattendance.service.ISignInService;
import cn.flyrise.pai.demoattendance.model.po.SignInPO;
import cn.flyrise.pai.demoattendance.model.vo.SignInVO;
import javax.annotation.Resource;
import cn.flyrise.common.core.exception.CommonException;
import cn.flyrise.pai.demoattendance.dao.SignInMapper;
import cn.flyrise.mybatis.base.BaseServiceImpl;
import cn.hutool.core.util.StrUtil;
import cn.flyrise.common.core.utils.ConvertUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* 签到表服务实现类
*
* @author pai
* @date 2021-04-22
*/
@Service("signIn")
@Transactional(rollbackFor = RuntimeException.class)
public class SignInServiceImpl extends BaseServiceImpl<SignInMapper, SignInPO,SignInVO> implements ISignInService {
@Override
public SignInVO add(SignInVO signInVO){
signInVO = insertVoReturnVO(signInVO);
return signInVO;
}
@Override
public SignInVO save(SignInVO signInVO){
String id = signInVO.getId();
if(getById(id)==null){
throw new CommonException("404","数据不存在");
}
signInVO = updateVoReturnVO(signInVO);
return signInVO;
}
@Override
public SignInVO findById(String id){
SignInVO signInVO = selectById(id);
if(signInVO==null){
throw new CommonException("404","数据不存在");
}
return signInVO;
}
@Override
public void delete(String id) {
SignInVO signInVO = selectById(id);
if(signInVO==null){
throw new CommonException("404","数据不存在");
}
deleteById(id);
}
}
API 展现层
编写 Controller
Controller
负责对Model
的处理,创建在项目模块的xxx.controller
包下。如xxx.attendance.controller
。需要通过
@Controller
指定该类为一个Controller
类。
Controller 类相关标签
@RestController
是一个组合注解,是 @ResponseBody
和 @Controller
的组合。
@ApiOperation
,显示在swagger ui上的接口注释,同时与该接口对应的权限表中的描述字段对应@GetMapping
,是@RequestMapping(mathod = RequestMethod.GET)
的缩写
@Api(tags = "打卡API")
,在类上对类进行说明,显示在 Swagger 文档上@ApiImplicitParams
,在方法上对方法参数进行说明,显示在 Swagger 文档上@ApiParam
,在方法参数上对参数进行说明,显示在 Swagger 文档上
package cn.flyrise.pai.demoattendance.controller;
import cn.flyrise.pai.demoattendance.model.vo.SignInVO;
import cn.flyrise.pai.demoattendance.service.ISignInService;
import cn.flyrise.common.core.domain.Reply;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
* 签到表 控制层
*
* @author pai
* @date 2021-04-22
*/
@Api(tags = "签到表 控制层")
@RestController
@RequestMapping("signIn")
public class SignInController {
/**
* 服务对象
*/
@Resource
private ISignInService signInService;
@ApiOperation("获取单条记录")
@GetMapping
public Reply<SignInVO> query(String id) {
return Reply.success(this.signInService.findById(id));
}
@ApiOperation("添加单条记录")
@PostMapping
public Reply<SignInVO> insert(@RequestBody SignInVO vo) {
return Reply.success(this.signInService.add(vo));
}
@ApiOperation("更新单条记录")
@PutMapping
public Reply<SignInVO> update(@RequestBody SignInVO vo) {
return Reply.success(this.signInService.save(vo));
}
@ApiOperation("删除单条记录")
@DeleteMapping
public Reply<?> delete(String id) {
this.signInService.delete(id);
return Reply.success();
}
@ApiOperation("分页查询")
@GetMapping(value = "page")
public Reply<Page<SignInVO>> page(Integer page, Integer size) {
return Reply.success(this.signInService.findByPage(page, size));
}
}
其他说明
以上就是代码生成的全部,生成代码还会根据主子表配置来生成对应的代码,这里就不展示了,如果觉得代码生成过于复杂可以提出你的宝贵意见或者自己实现。
其中Application就是我们工程的启动类
@EnablePaiResourceServer
@SpringCloudApplication
@EnablePaiFeignClients("cn.flyrise.*")
@EnableAspectJAutoProxy(exposeProxy = true)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
注解说明:
- 意味着服务(就OAuth 2.0而言 – 资源服务器)需要访问令牌才能进行请求
- 在调用资源服务器之前,应通过OAuth 2.0客户端从授权服务器获取访问令牌
- 如果注释掉此注解,会走原生SpringSecurity,从而需要登陆,就算登陆成功,在调用资 源服务器也可能面临被拒绝访问
- 启用feign客户端
- 将远端服务映射成为本地方法进行调用
- 扫描和注册feign客户端bean定义
- 启动类,用于启动容器
- 启用AOP动态代理