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
│      └─mapperSignInDao.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 的组合。

@PostMapping

  • @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);
    }

}

注解说明:

@EnablePaiResourceServer

  • 意味着服务(就OAuth 2.0而言 – 资源服务器)需要访问令牌才能进行请求
  • 在调用资源服务器之前,应通过OAuth 2.0客户端从授权服务器获取访问令牌
  • 如果注释掉此注解,会走原生SpringSecurity,从而需要登陆,就算登陆成功,在调用资 源服务器也可能面临被拒绝访问

@EnablePaiFeignClients

  • 启用feign客户端
  • 将远端服务映射成为本地方法进行调用
  • 扫描和注册feign客户端bean定义

@SpringCloudApplication

  • 启动类,用于启动容器

@EnableAspectJAutoProxy

  • 启用AOP动态代理
文档更新时间: 2024-03-25 11:23   作者:朱灿奕