一、前言:
最近接了一些学生的毕业设计, 大多数都是要求前后端分离。后台大多数都是java+springboot, 业务也都是对表的增删改查, 最多也就是连表查询, 代码也都千篇一律的CRUD, 我都快成为CV选手了。懒人总是想办法偷懒, 于是考虑自动生成代码, 以前用过mybatis-generator这个逆向工程, 能生成实体,dao层和xml文件, 用起来也比较简单, maven安装一个依赖+一个配置文件就搞定, 但是业务层和控制层并不能通用, 再后来就发现了EasyCode这个idea的插件, 用起来还是比较顺手的。以下是这个插件的优点和缺点
优点:
- 可以生成所有层的代码, 控制, 业务, dao, xml等等
- 可以自定义配置生成的模板, 根据公司和个人需要定制
- 可以自定义字段类型和实体属性的映射
- 支持全局变量
缺点:
- 没有模板的情况下生成的代码不是特别好用…
- 不常用的类型都需要自己映射, 不是特别方便
二、准备工作
每个人开发习惯不同, 可以根据我的进行修改
接口文档我是用的swagger, 控制层统一通过一个类进行返回, 这个类我会在下面分享
通过自动生成的代码中主要包含了对库表的增删改查, 查询全部, 分页查询, 根据实体查询,查询总数等等
首先是公共门户Response类
import com.rambler.core.bean.Const;
/**
* 对外统一的出口进行封装
*
* @author rambler
* @since 2019-09-13 23:23
*/
public class Response<T> {
/* 状态码 */
private Integer code;
/* 提示消息 */
private String message;
/* 具体返回的数据 */
private T data;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
private Response(Integer code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}
private Response(Integer code, String msg) {
this.code = code;
this.message = msg;
}
/**
* 返回成功Response对象
*
* @param successMessage 成功提示信息
* @param data 需要返回的数据
* @return 成功信息
*/
public static <T> Response<T> createSuccessResponse(String successMessage, T data) {
return new Response<>(Const.SUCCESS, successMessage, data);
}
/**
* 只返回成功消息, 默认成功状态码
*
* @param successMessage 成功消息
* @return Response对象
*/
public static <T> Response<T> createSuccessResponse(String successMessage) {
return new Response<>(Const.SUCCESS, successMessage);
}
/**
* 只返回成功消息, 默认成功状态码
*
* @param data 返回的数据
* @return Response对象
*/
public static <T> Response<T> createSuccessResponse(T data) {
return new Response<>(Const.SUCCESS, "成功", data);
}
/**
* 返回错误Response对象
*
* @param errorMessage 错误信息
* @return 错误信息
*/
public static <T> Response<T> createErrorResponse(String errorMessage) {
return new Response<>(Const.ERROR, errorMessage);
}
/**
* 返回未登录状态码
* @param message 提示信息
* @return Response
*/
public static <T> Response<T> createUnLoginResponse(String message){
return new Response<>(Const.UN_LOGIN,message);
}
}
Const实体类
这个类中定义了一些常量, 个人习惯用HTTP的200状态码标识请求成功状态码, 用201标识失败, 用100标识未登录或者session过期, 可以根据个人习惯更改
package com.rambler.core.bean;
/**
* 常用常量
*
* @author rambler
* @since 2019-09-13 23:30
*/
public class Const {
/* 成功状态码 */
public static final Integer SUCCESS = 200;
/* 失败状态码 */
public static final Integer ERROR = 201;
/* 未登录验证码 */
public static final Integer UN_LOGIN = 100;
/* 用户部分 */
public static final String CURRENT_USER = "user";
/* 日志操作类型常量定义 */
public static final String DELETE = "删除";
public static final String LOGIC_DELETE = "逻辑删除";
public static final String UPDATE = "更新";
public static final String ADD = "新增";
public static final String UPLOAD = "上传文件";
public static final String RECYCLE = "还原";
}
三、正式上模版
1. controller层模版
支持功能: 数据的增删改查, 分页查询, 查询全部等功能
其中有个Page类, 可以自己封装, 我这里直接用的Mybatis-plus中提供的Page类
##定义初始变量
#set($tableName = $tool.append($tableInfo.name, "Controller"))
##设置回调
$!callback.setFileName($tool.append($tableName, ".java"))
$!callback.setSavePath($tool.append($tableInfo.savePath, "/controller"))
##拿到主键
#if(!$tableInfo.pkColumn.isEmpty())
#set($pk = $tableInfo.pkColumn.get(0))
#end
#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}controller;
import $!{tableInfo.savePackageName}.entity.$!{tableInfo.name};
import $!{tableInfo.savePackageName}.service.$!{tableInfo.name}Service;
import org.springframework.web.bind.annotation.*;
import io.swagger.annotations.*;
import com.baomidou.mybatisplus.plugins.Page;
import com.rambler.core.door.Response;
import java.util.List;
import javax.annotation.Resource;
/**
* @author $!author
* @since $!time.currTime()
*/
@Api(tags = "$!{tableInfo.comment}($!{tableInfo.name})控制层")
@RestController
@RequestMapping("/$!tool.firstLowerCase($tableInfo.name)")
public class $!{tableName} {
/**
* 服务对象
*/
@Resource
private $!{tableInfo.name}Service $!tool.firstLowerCase($tableInfo.name)Service;
@ApiOperation(value = "通过主键查询单条数据")
@ApiImplicitParam(name = "id", value = "实体id", required = true, paramType = "query")
@RequestMapping(value = "selectOne", method = RequestMethod.GET)
public Response<$tableInfo.name> selectOne($!pk.shortType $!pk.name) {
if (id == null) {
return Response.createErrorResponse("参数错误");
}
$tableInfo.name result = $!{tool.firstLowerCase($tableInfo.name)}Service.selectById($!pk.name);
if(result != null){
return Response.createSuccessResponse("查询成功", result);
}
return Response.createErrorResponse("查询失败");
}
@ApiOperation(value = "发布新增实体类")
@RequestMapping(value = "insert", method = RequestMethod.POST)
public Response<$tableInfo.name> insert(@RequestBody @ApiParam(name = "文章对象", value = "json格式", required = true) $tableInfo.name $!tool.firstLowerCase($tableInfo.name)) {
int result = $!{tool.firstLowerCase($tableInfo.name)}Service.insert($!tool.firstLowerCase($tableInfo.name));
if (result > 0) {
return Response.createSuccessResponse("新增成功", $!tool.firstLowerCase($tableInfo.name));
}
return Response.createErrorResponse("新增失败");
}
@ApiOperation(value = "更新实体")
@RequestMapping(value = "update", method = RequestMethod.PUT)
public Response<$tableInfo.name> update(@RequestBody @ApiParam(name = "文章对象", value = "json格式", required = true) $tableInfo.name $!tool.firstLowerCase($tableInfo.name)) {
int result = $!{tool.firstLowerCase($tableInfo.name)}Service.update($!tool.firstLowerCase($tableInfo.name));
if (result != -1) {
return Response.createSuccessResponse("修改成功", null);
}
return Response.createErrorResponse("修改失败");
}
@ApiOperation(value = "通过id删除")
@ApiImplicitParam(name = "id", value = "实体id", required = true, paramType = "query")
@RequestMapping(value = "delete", method = RequestMethod.DELETE)
public Response<$tableInfo.name> delete($!pk.shortType $!pk.name) {
if (id == null) {
return Response.createErrorResponse("参数错误");
}
int result = $!{tool.firstLowerCase($tableInfo.name)}Service.deleteById($!pk.name);
if (result > 0) {
return Response.createSuccessResponse("删除成功", null);
}
return Response.createErrorResponse("删除失败");
}
@ApiOperation(value = "查询所有", notes = "不需要参数")
@RequestMapping(value = "selectAll", method = RequestMethod.GET)
public Response<List<$tableInfo.name>> selectAll() {
List<$tableInfo.name> $!tool.firstLowerCase($tableInfo.name)List = $!{tool.firstLowerCase($tableInfo.name)}Service.selectAll();
if ($!tool.firstLowerCase($tableInfo.name)List != null) {
return Response.createSuccessResponse("查询成功", $!tool.firstLowerCase($tableInfo.name)List);
}
return Response.createErrorResponse("查询失败");
}
@ApiOperation(value = "分页查询")
@ApiImplicitParams({
@ApiImplicitParam(name = "start", value = "开始位置,正整数", required = true, paramType = "query"),
@ApiImplicitParam(name = "limit", value = "页面大小,正整数", required = true, paramType = "query")
})
@RequestMapping(value = "selectPage", method = RequestMethod.GET)
public Response<Page<$tableInfo.name>> selectPage(Integer start, Integer limit) {
if(start < 0 || limit <= 0){
return Response.createErrorResponse("分页参数错误");
}
List<$tableInfo.name> $!tool.firstLowerCase($tableInfo.name)List = $!{tool.firstLowerCase($tableInfo.name)}Service.selectPage(start, limit);
Page<$tableInfo.name> page = new Page<>((start/limit)+1,limit);
page.setRecords($!tool.firstLowerCase($tableInfo.name)List);
page.setTotal($!{tool.firstLowerCase($tableInfo.name)}Service.count());
if ($!tool.firstLowerCase($tableInfo.name)List != null) {
return Response.createSuccessResponse("查询成功", page);
}
return Response.createErrorResponse("查询失败");
}
}
2. 业务层(Service)
业务层主要是和控制层对应, 功能也都类似
##定义初始变量
#set($tableName = $tool.append($tableInfo.name, "Service"))
##设置回调
$!callback.setFileName($tool.append($tableName, ".java"))
$!callback.setSavePath($tool.append($tableInfo.savePath, "/service"))
##拿到主键
#if(!$tableInfo.pkColumn.isEmpty())
#set($pk = $tableInfo.pkColumn.get(0))
#end
#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}service;
import $!{tableInfo.savePackageName}.entity.$!{tableInfo.name};
import java.util.List;
import java.util.Map;
/**
* $!{tableInfo.comment}($!{tableInfo.name})表服务接口
*
* @author $!author
* @since $!time.currTime()
*/
public interface $!{tableName} {
/**
* 通过ID查询单条数据
*/
$!{tableInfo.name} selectById($!pk.shortType $!pk.name);
/**
* 分页查询
*/
List<$!{tableInfo.name}> selectPage(int start, int limit);
/**
* 查询全部
*/
List<$!{tableInfo.name}> selectAll();
/**
* 通过实体作为筛选条件查询
*/
List<$!{tableInfo.name}> selectList($!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name}));
/**
* 新增数据
*/
int insert($!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name}));
/**
* 批量新增
*/
int batchInsert(List<$!{tableInfo.name}> $!tool.firstLowerCase($!{tableInfo.name})s);
/**
* 修改数据
*/
int update($!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name}));
/**
* 通过主键删除数据
*/
int deleteById($!pk.shortType $!pk.name);
/**
* 查询总数据数
*/
int count();
}
3. 业务实现类(ServiceImpl)
针对业务层进行具体实现, 就是调dao层
##定义初始变量
#set($tableName = $tool.append($tableInfo.name, "ServiceImpl"))
##设置回调
$!callback.setFileName($tool.append($tableName, ".java"))
$!callback.setSavePath($tool.append($tableInfo.savePath, "/service/impl"))
##拿到主键
#if(!$tableInfo.pkColumn.isEmpty())
#set($pk = $tableInfo.pkColumn.get(0))
#end
#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}service.impl;
import $!{tableInfo.savePackageName}.entity.$!{tableInfo.name};
import $!{tableInfo.savePackageName}.dao.$!{tableInfo.name}Dao;
import $!{tableInfo.savePackageName}.service.$!{tableInfo.name}Service;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
* $!{tableInfo.comment}($!{tableInfo.name})表服务实现类
*
* @author $!author
* @since $!time.currTime()
*/
@Service("$!tool.firstLowerCase($!{tableInfo.name})Service")
public class $!{tableName} implements $!{tableInfo.name}Service {
@Resource
private $!{tableInfo.name}Dao $!tool.firstLowerCase($!{tableInfo.name})Dao;
/**
* 通过ID查询单条数据
*
* @param $!pk.name 主键
* @return 实例对象
*/
@Override
public $!{tableInfo.name} selectById($!pk.shortType $!pk.name) {
return this.$!{tool.firstLowerCase($!{tableInfo.name})}Dao.selectById($!pk.name);
}
/**
* 分页查询
*
* @param start 查询起始位置
* @param limit 查询条数
* @return 对象列表
*/
@Override
public List<$!{tableInfo.name}> selectPage(int start, int limit) {
return this.$!{tool.firstLowerCase($!{tableInfo.name})}Dao.selectPage(start, limit);
}
/**
* 查询全部
*
* @return 对象列表
*/
@Override
public List<$!{tableInfo.name}> selectAll() {
return this.$!{tool.firstLowerCase($!{tableInfo.name})}Dao.selectAll();
}
/**
* 根据实体类进行筛选
* @param $!tool.firstLowerCase($!{tableInfo.name}) 实例对象
* @return 对象列表
*/
@Override
public List<$!{tableInfo.name}> selectList($!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name})) {
return this.$!{tool.firstLowerCase($!{tableInfo.name})}Dao.selectList($!tool.firstLowerCase($!{tableInfo.name}));
}
/**
* 新增数据
*
* @param $!tool.firstLowerCase($!{tableInfo.name}) 实例对象
* @return 生效条数
*/
@Override
public int insert($!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name})) {
return this.$!{tool.firstLowerCase($!{tableInfo.name})}Dao.insert($!tool.firstLowerCase($!{tableInfo.name}));
}
/**
* 批量新增
*
* @param $!tool.firstLowerCase($!{tableInfo.name})List 实例对象
* @return 生效条数
*/
@Override
public int batchInsert(List<$!{tableInfo.name}> $!tool.firstLowerCase($!{tableInfo.name})List) {
return this.$!{tool.firstLowerCase($!{tableInfo.name})}Dao.batchInsert($!tool.firstLowerCase($!{tableInfo.name})List);
}
/**
* 修改数据
*
* @param $!tool.firstLowerCase($!{tableInfo.name}) 实例对象
* @return 实例对象
*/
@Override
public int update($!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name})) {
return this.$!{tool.firstLowerCase($!{tableInfo.name})}Dao.update($!tool.firstLowerCase($!{tableInfo.name}));
}
/**
* 通过主键删除数据
*
* @param $!pk.name 主键
* @return 是否成功
*/
@Override
public int deleteById($!pk.shortType $!pk.name) {
return this.$!{tool.firstLowerCase($!{tableInfo.name})}Dao.deleteById($!pk.name);
}
/**
* 查询总数据数
*
* @return 数据总数
*/
@Override
public int count() {
return this.$!{tool.firstLowerCase($!{tableInfo.name})}Dao.count();
}
}
4. Dao层(数据库操作层)
支持的功能: 数据库的增删改查,批量新增, 查询全部, 分页查询, 查询总数等功能
##定义初始变量
#set($tableName = $tool.append($tableInfo.name, "Dao"))
##设置回调
$!callback.setFileName($tool.append($tableName, ".java"))
$!callback.setSavePath($tool.append($tableInfo.savePath, "/dao"))
##拿到主键
#if(!$tableInfo.pkColumn.isEmpty())
#set($pk = $tableInfo.pkColumn.get(0))
#end
#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}dao;
import $!{tableInfo.savePackageName}.entity.$!{tableInfo.name};
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
* $!{tableInfo.comment}($!{tableInfo.name})表数据库访问层
*
* @author $!author
* @since $!time.currTime()
*/
public interface $!{tableName} {
/**
* 通过ID查询单条数据
*
* @param $!pk.name 主键
* @return 实例对象
*/
$!{tableInfo.name} selectById($!pk.shortType $!pk.name);
/**
* 分页查询
*
* @param start 查询起始位置
* @param limit 查询条数
* @return 对象列表
*/
List<$!{tableInfo.name}> selectPage(@Param("start") int start, @Param("limit") int limit);
/**
* 查询全部
*
* @return 对象列表
*/
List<$!{tableInfo.name}> selectAll();
/**
* 通过实体作为筛选条件查询
*
* @param $!tool.firstLowerCase($!{tableInfo.name}) 实例对象
* @return 对象列表
*/
List<$!{tableInfo.name}> selectList($!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name}));
/**
* 新增数据
*
* @param $!tool.firstLowerCase($!{tableInfo.name}) 实例对象
* @return 影响行数
*/
int insert($!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name}));
/**
* 批量新增
*
* @param $!tool.firstLowerCase($!{tableInfo.name})List 实例对象的集合
* @return 影响行数
*/
int batchInsert(List<$!{tableInfo.name}> $!tool.firstLowerCase($!{tableInfo.name})List);
/**
* 修改数据
*
* @param $!tool.firstLowerCase($!{tableInfo.name}) 实例对象
* @return 影响行数
*/
int update($!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name}));
/**
* 通过主键删除数据
*
* @param $!pk.name 主键
* @return 影响行数
*/
int deleteById($!pk.shortType $!pk.name);
/**
* 查询总数据数
*
* @return 数据总数
*/
int count();
}
5. 实体类
##引入宏定义
$!define
##使用宏定义设置回调(保存位置与文件后缀)
#save("/entity", ".java")
##使用宏定义设置包后缀
#setPackageSuffix("entity")
##使用全局变量实现默认包导入
$!autoImport
import java.io.Serializable;
##使用宏定义实现类注释信息
#tableComment("实体类")
public class $!{tableInfo.name} implements Serializable {
private static final long serialVersionUID = $!tool.serial();
#foreach($column in $tableInfo.fullColumn)
#if(${column.comment})/**
* ${column.comment}
*/#end
private $!{tool.getClsNameByFullName($column.type)} $!{column.name};
#end
#foreach($column in $tableInfo.fullColumn)
##使用宏定义实现get,set方法
#getSetMethod($column)
#end
}
6. xml生成
xml就是dao的具体实现, 排版可能有些问题
##引入mybatis支持
$!mybatisSupport
##设置保存名称与保存位置
$!callback.setFileName($tool.append($!{tableInfo.name}, "Mapper.xml"))
$!callback.setSavePath($tool.append($modulePath, "/src/main/resources/mappings"))
##拿到主键
#if(!$tableInfo.pkColumn.isEmpty())
#set($pk = $tableInfo.pkColumn.get(0))
#end
<?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="$!{tableInfo.savePackageName}.dao.$!{tableInfo.name}Dao">
<!-- 结果集 -->
<resultMap type="$!{tableInfo.savePackageName}.entity.$!{tableInfo.name}" id="$!{tableInfo.name}Map">
#foreach($column in $tableInfo.fullColumn)
<result property="$!column.name" column="$!column.obj.name" jdbcType="$!column.ext.jdbcType"/>
#end
</resultMap>
<!-- 基本字段 -->
<sql id="Base_Column_List">
#allSqlColumn()
</sql>
<!-- 查询单个 -->
<select id="selectById" resultMap="$!{tableInfo.name}Map">
select
<include refid="Base_Column_List" />
from $!tableInfo.obj.name
where $!pk.obj.name = #{$!pk.name}
</select>
<!-- 分页查询 -->
<select id="selectPage" resultMap="$!{tableInfo.name}Map">
select
<include refid="Base_Column_List" />
from $!tableInfo.obj.name
limit #{start},#{limit}
</select>
<!-- 查询全部 -->
<select id="selectAll" resultMap="$!{tableInfo.name}Map">
select
<include refid="Base_Column_List" />
from $!tableInfo.obj.name
</select>
<!--通过实体作为筛选条件查询-->
<select id="selectList" resultMap="$!{tableInfo.name}Map">
select
<include refid="Base_Column_List" />
from $!tableInfo.obj.name
<where>
#foreach($column in $tableInfo.fullColumn)
<if test="$!column.name != null#if($column.type.equals("java.lang.String")) and $!column.name != ''#end">
and $!column.obj.name = #{$!column.name}
</if>
#end
</where>
</select>
<!-- 新增所有列 -->
<insert id="insert" keyProperty="$!pk.name" useGeneratedKeys="true">
insert into $!{tableInfo.obj.name}(#foreach($column in $tableInfo.fullColumn)$!column.obj.name#if($velocityHasNext), #end#end)
values ( #foreach($column in $tableInfo.fullColumn)#{$!{column.name}}#if($velocityHasNext), #end#end)
</insert>
<!-- 批量新增 -->
<insert id="batchInsert">
insert into $!{tableInfo.obj.name}(#foreach($column in $tableInfo.fullColumn)$!column.obj.name#if($velocityHasNext), #end#end)
values
<foreach collection="$!tool.firstLowerCase($!{tableInfo.name})s" item="item" index="index" separator=",">
(
#foreach($column in $tableInfo.fullColumn)
#{item.$!{column.name}}#if($velocityHasNext), #end
#end
)
</foreach>
</insert>
<!-- 通过主键修改数据 -->
<update id="update">
update $!{tableInfo.obj.parent.name}.$!{tableInfo.obj.name}
<set>
#foreach($column in $tableInfo.otherColumn)
<if test="$!column.name != null#if($column.type.equals("java.lang.String")) and $!column.name != ''#end">
$!column.obj.name = #{$!column.name},
</if>
#end
</set>
where $!pk.obj.name = #{$!pk.name}
</update>
<!--通过主键删除-->
<delete id="deleteById">
delete from $!{tableInfo.obj.name} where $!pk.obj.name = #{$!pk.name}
</delete>
<!-- 总数 -->
<select id="count" resultType="int">
select count(*) from $!{tableInfo.obj.name}
</select>
</mapper>
最后欢迎大家提出意见