需求 对于增删改查类的代码,每次都要写很多重复的代码,所以考虑使用自动生成代码来减少重复工作。
自动生成代码的现状 目前有多种方式可以自动生成代码:
将模板引擎集成到项目中,通过代码的形式自动生成代码,此种方法和项目耦合度较高,对项目由侵入性
在线网站自动生成代码,使用互联网,安全性较低
IDEA+groovy方法,目前了解到生成的代码比较简单,定制化程度不高
IDEA插件生成,一般插件也都是以模板引擎为基础,进行代码的生成
最后选择了第四种,IDEA插件的方式,插件使用的是EasyCode, 基于velocity模板引擎。 > https://gitee.com/makejava/EasyCode
Velocity(速度)语法 比较精简的一种语言,关键字不多,和代码混合使用。教程:https://www.cnblogs.com/hduwbf/p/6201731.html
EasyCode 我的模板(具有个人风格,可以进行修改使用) Controller 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 ##导入宏定义 $!{init.vm} $!{define.vm} ##保存文件(宏定义) #save("/controller/$!{workPath}", "Controller.java") ##包路径(宏定义) #setPackageSuffix("controller$!{workPackage}") $!{autoImport.vm} import io.swagger.annotations.ApiOperation; import $!{tableInfo.savePackageName}.service$!{workPackage}.$!{serviceType}; import $!{tableInfo.savePackageName}.dto$!{workPackage}.$!{dtoType}; import $!{tableInfo.savePackageName}.vo$!{workPackage}.$!{voType}; import org.springframework.web.bind.annotation.*; import io.swagger.annotations.Api; import org.apache.commons.lang3.StringUtils; import javax.annotation.Resource; import java.util.List; ##表注释(宏定义) #classNotes("表控制层") @Api(tags = "$!{tableInfo.comment}") @RestController @RequestMapping("$!entityName") public class $!apiType { @Resource private $!serviceType $!serviceName; /** * 分页查询所有数据 * * @param query 查询实体 * @return 所有数据 */ @PostMapping("/queryPage") @ApiOperation("按字段条件分页查询$!{tableInfo.comment}") public BaseResult<PageVo<$!voType>> query$!{entityType}ByPage(@RequestBody $!{queryType} query) { return $!{serviceName}.queryByPage(query); } /** * 通过主键查询多条数据 * * @param query 查询实体 * @return 多条数据 */ @PostMapping("/query") @ApiOperation("根据Id查询$!{tableInfo.comment}") public BaseResult<List<$!voType>> query(@RequestBody $!{queryType} query) { return $!{serviceName}.queryByCondition(query); } /** * 新增数据 * * @param dto 实体对象 * @return 新增结果 */ @PostMapping("/save") @ApiOperation("新增$!{tableInfo.comment}数据") public BaseResult<Object> save(@RequestBody $!{dtoType} dto) { //数据校验 if (StringUtils.isBlank(dto.getName())) { return new BaseResult<>(ResponseEnum.NO_ARGS.getCode(), ResponseEnum.NO_ARGS.getMessage()); } if ($!{serviceName}.isExist(dto)) { return new BaseResult<>(ResponseEnum.REPEAT.getCode(), ResponseEnum.REPEAT.getMessage()); } return $!{serviceName}.save(dto); } /** * 修改数据 * * @param dto 实体对象 * @return 修改结果 */ @PostMapping("/update") @ApiOperation("更新$!{tableInfo.comment}") public BaseResult<Object> update($!{dtoType} dto) { //数据校验 if (StringUtils.isBlank(dto.getName())) { return new BaseResult<>(ResponseEnum.NO_ARGS.getCode(), ResponseEnum.NO_ARGS.getMessage()); } return $!{serviceName}.update(dto); } /** * 删除多条数据 * * @param ids 主键ids * @return 删除结果 */ @PostMapping("/delete") @ApiOperation("根据Id软删除$!{tableInfo.comment}数据") public BaseResult<List<SingleResult>> deleteByRowIds(List<Long> ids) { List<SingleResult> result = new ArrayList<>(); ids.forEach(x -> { // 数据校验 if (!$!{serviceName}.isExistById(x)) { result.add(SingleResult.successBuild(x.toString())); } else { result.add($!{serviceName}.deleteById(x)); } }); return BaseResult.success(result); } } Entity 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 $!{init.vm} $!{define.vm} ##保存文件(宏定义) #save("/entity$!{workPath}", ".java") ##包路径(宏定义) #setPackageSuffix("entity$!{workPackage}") import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import javax.persistence.*; import java.io.Serializable; import java.util.Date; ##表注释(宏定义) #classNotes("") @Data ##@ApiModel(value="$tableInfo.savePackageName.replace(".","-")-entity$!{workCommon}-$!{entityType}") @ApiModel(value="$!{tableInfo.comment}") @Table(name = "$!{tableInfo.obj.name}") public class $!entityType implements Serializable { private static final long serialVersionUID = 1L; ## 主键列 #foreach($column in $tableInfo.pkColumn) /** * $!column.comment */ @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name = "$!{column.obj.name}") @ApiModelProperty(value = "$!column.comment") private $!tool.getClsNameByFullName($column.type) $!column.name; #end ## 其他列 #foreach($column in $tableInfo.otherColumn) /** * $!{column.comment} */ @Column(name = "$!{column.obj.name}") @ApiModelProperty(value = "$!column.comment") private $!tool.getClsNameByFullName($!column.type) $!column.name; #end } Service 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 ##导入宏定义 $!{init.vm} $!{define.vm} ##保存文件(宏定义) #save("/service$!{workPath}", "Service.java") ##包路径(宏定义) #setPackageSuffix("service$!{workPackage}") $!{autoimpot.vm} ##表注释(宏定义) #classNotes("表服务接口") public interface $!serviceType { BaseResult<PageVo<$!{voType}>> queryByPage($!{queryType} query); BaseResult<List<$!{voType}>> queryByCondition($!{queryType} query); BaseResult<Object> save($!{dtoType} dto); BaseResult<List<SingleResult>> saveBatch(List<$!{dtoType}> dtos); BaseResult<Object> update($!{dtoType} dto); BaseResult<List<SingleResult>> updateBatch(List<$!{dtoType}> dtos); SingleResult deleteById(Long id); boolean isExist($!{dtoType} dto); boolean isExistById(Long id); } ServiceImpl 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 ##导入宏定义 $!{init.vm} $!{define.vm} ##保存文件(宏定义) #save("/service/impl/$!{workPath}", "ServiceImpl.java") ##包路径(宏定义) #setPackageSuffix("service.impl$!{workPackage}") $!{autoimport.vm} import org.apache.commons.lang3.StringUtils; import javax.transaction.Transactional; import $!{tableInfo.savePackageName}.entity$!{workPackage}.$!{entityType}; import javax.persistence.criteria.Predicate; #classNotes("表服务实现类") @Service public class $!{serviceImplType} implements $!{serviceType} { @Resource private $!{repositoryType} $!{repositoryName}; /** * 查询多条数据 * * @param query 查询参数 * @return 实例对象 */ @Override public BaseResult<List<$!{voType}>> queryByCondition($!{queryType} query) { List<$!{tableInfo.name}> items = $!{repositoryName}.findAll(getWhereClause(query)); return BaseResult.success(BaseConverter.convertAll(items, $!{voType}.class)); } /** * 分页查询 * * @param query 筛选条件 * @return 查询结果 */ @Override public BaseResult<PageVo<$!voType>> queryByPage($!{queryType} query) { try { Sort sort = Sort.by("desc".equals(query.getSortOrder()) ? Sort.Direction.DESC : Sort.Direction.ASC, query.getSortField()); Pageable pageable = PageRequest.of(query.getPageNo() - 1, (query.getPageSize()), sort); Page<$!{tableInfo.name}> page = $!{repositoryName}.findAll(getWhereClause(query), pageable); return BaseResult.success(BaseConverter.convertPage(page, $!{voType}.class)); } catch (Exception e) { return new BaseResult<>("-1", "查询分页失败"); } } /** * 新增数据 * * @param dto dto对象 * @return vo $!voName */ @Override public BaseResult<Object> save($!dtoType dto) { try { $!{tableInfo.name} entity = BaseConverter.convert(dto, $!{tableInfo.name}.class); $!{repositoryName}.save(entity); } catch (Exception e) { return new BaseResult<>("-1", "保存失败"); } return new BaseResult<>(); } /** * 批量新增数据 * * @param dtos dto对象 * @return BaseResult */ @Override public BaseResult<List<SingleResult>> saveBatch(List<$!dtoType> dtos) { try { List<$!{tableInfo.name}> entitys = BaseConverter.convertAll(dtos, $!{tableInfo.name}.class); $!{repositoryName}.saveAll(entitys); } catch (Exception e) { return new BaseResult<>("-1", "保存失败"); } return new BaseResult<>(); } /** * 修改数据 * * @param dto dto对象 * @return BaseResult */ @Override @Transactional public BaseResult<Object> update($!dtoType dto) { try { $!{tableInfo.name} entity = BaseConverter.convert(dto, $!{tableInfo.name}.class); $!{repositoryName}.save(entity); } catch (Exception e) { return new BaseResult<>("-1", "更新失败"); } return new BaseResult<>(); } /** * 批量修改数据 * * @param dtos dto对象 * @return 实例对象 */ @Override @Transactional public BaseResult<List<SingleResult>> updateBatch(List<$!dtoType> dtos) { try { List<$!{tableInfo.name}> entitys = BaseConverter.convertAll(dtos, $!{tableInfo.name}.class); $!{repositoryName}.saveAll(entitys); } catch (Exception e) { return new BaseResult<>("-1", "批量更新失败"); } return new BaseResult<>(); } /** * 通过主键删除数据 * * @param id 主键 * @return 是否成功 */ @Override @Transactional public SingleResult deleteById(Long id) { try { $!{repositoryName}.updateDeletedById(id); } catch (Exception e) { return SingleResult.build(id.toString(), "false", "删除异常"); } return SingleResult.successBuild(id.toString()); } @Override public boolean isExist($!{dtoType} dto) { Integer exist = $!{repositoryName}.isExist(dto.getName()); return null != exist; } @Override public boolean isExistById(Long id) { Integer exist = $!{repositoryName}.isExistById(id); return null != exist; } private Specification<$!{tableInfo.name}> getWhereClause($!{queryType} query) { return (Specification<$!{tableInfo.name}>) (root, criteriaQuery, criteriaBuilder) -> { List<Predicate> predicates = new ArrayList<>(); if (StringUtils.isNotBlank(query.getName())) { predicates.add(criteriaBuilder.like(root.get("name"), "%" + query.getName() + "%")); } if (ObjectUtils.isNotEmpty(query.getCreatedTime())) { //大于等于开始时间 predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("createTime"), DateUtil.parse(query.getCreatedTime()))); } if (ObjectUtils.isNotEmpty(query.getCreatedTime())) { //小于等于结束时间 predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("createTime"), DateUtil.parse(query.getCreatedTime()))); } return criteriaBuilder.and(predicates.toArray(new Predicate[0])); }; } } VO 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 $!{init.vm} $!{define.vm} ##保存文件 #save("/vo$!{workPath}", "VO.java") ##包路径(宏定义) #setPackageSuffix("vo$!{workPackage}") ##自动导入包(全局变量) $!{autoImport.vm} import java.util.Date; ##表注释(宏定义) #classNotes("") @Data @ApiModel(value="$tableInfo.savePackageName.replace(".","-")-dto$!{workCommon}-$!{voType}") public class $!voType implements Serializable { private static final long serialVersionUID = 1L; ## 主键列 #foreach($column in $tableInfo.pkColumn) /** * $!column.comment */ @ApiModelProperty(value = "$!column.comment") private $!tool.getClsNameByFullName($column.type) $!column.name; #end ## 其他列 #foreach($column in $tableInfo.otherColumn) /** * $!{column.comment} */ @ApiModelProperty(value = "$!column.comment") private $!tool.getClsNameByFullName($!column.type) $!column.name; #end } DTO 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 $!{init.vm} $!{define.vm} ##保存文件 #save("/dto$!{workPath}", "DTO.java") ##包路径(宏定义) #setPackageSuffix("dto$!{workPackage}") ##自动导入包(全局变量) $!{autoImport.vm} import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import java.io.Serializable; import lombok.Data; import java.util.Date; ##表注释(宏定义) #classNotes("") @Data @ApiModel(value="$tableInfo.savePackageName.replace(".","-")-dto$!{workCommon}-$!{dtoType}") public class $!dtoType implements Serializable { private static final long serialVersionUID = 1L; ## 主键列 #foreach($column in $tableInfo.pkColumn) /** * $!column.comment */ @ApiModelProperty(value = "$!column.comment") private $!tool.getClsNameByFullName($column.type) $!column.name; #end ## 其他列 #foreach($column in $tableInfo.otherColumn) /** * $!{column.comment} */ @ApiModelProperty(value = "$!column.comment") private $!tool.getClsNameByFullName($!column.type) $!column.name; #end } Repository JPA 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 ##导入宏定义 $!{init.vm} $!{define.vm} ##保存文件(宏定义) #save("/repository/$!{workPath}", "Repository.java") ##包路径(宏定义) #setPackageSuffix("repository$!{workPackage}") import com.javahik.hiklife.easycode.entity.$!{tableInfo.name}; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; ##表注释(宏定义) #classNotes("表数据库访问层") @Repository public interface $!{repositoryType} extends JpaRepository<$!{tableInfo.name}, String>, JpaSpecificationExecutor<$!{tableInfo.name}> { @Modifying @Query(nativeQuery = true, value = "update $!{tableInfo.name} set deleted = '1' where id = ?1") void updateDeletedById(Long id); @Query(nativeQuery = true, value = "select 1 from $!{tableInfo.name} where name = ?1 limit 1") Integer isExist(String name); @Query(nativeQuery = true, value = "select 1 from $!{tableInfo.name} where id = ?1 limit 1") Integer isExistById(Long id); } QueryDTO 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 $!{init.vm} $!{define.vm} ##保存文件 #save("/dto$!{workPath}", "Query.java") ##包路径(宏定义) #setPackageSuffix("dto$!{workPackage}") ##自动导入包(全局变量) $!{autoImport.vm} import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import java.io.Serializable; import lombok.Data; import java.util.Date; ##表注释(宏定义) #classNotes("查询类") @Data public class $!{queryType} implements Serializable { private static final long serialVersionUID = 1L; private Integer pageNo = 1; private Integer pageSize = 20; private String sortField = "createDate"; private String sortOrder = "desc"; private String createdTime; private String name; } Define 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 ##(Velocity宏定义) ##定义设置表名后缀的宏定义,调用方式:#setTableSuffix("Test") #macro(setTableSuffix $suffix) #set($tableName = $!tool.append($tableInfo.name, $suffix)) #end ##定义设置包名后缀的宏定义,调用方式:#setPackageSuffix("Test") #macro(setPackageSuffix $suffix) #if($suffix!="")package #end#if($tableInfo.savePackageName!="")$!{tableInfo.savePackageName}.#{end}$!suffix; #end ##定义直接保存路径与文件名简化的宏定义,调用方式:#save("/entity", ".java") #macro(save $path $fileName) $!callback.setSavePath($tool.append($tableInfo.savePath, $path)) $!callback.setFileName($tool.append($tableInfo.name, $fileName)) #end ## 自定义entity、Mapper、Service、Api、DTO、VO的名字减少拼接,增加重用性 #set($entityType = $!tool.firstUpperCase($!tableInfo.name)) #set($entityName = $!tool.firstLowerCase($!tableInfo.name)) #set($mapperType = $!tool.append($!tool.firstUpperCase($!tableInfo.name), "Mapper")) #set($mapperName = $!tool.append($!tool.firstLowerCase($!tableInfo.name), "Mapper")) #set($repositoryType = $!tool.append($!tool.firstUpperCase($!tableInfo.name), "Repository")) #set($repositoryName = $!tool.append($!tool.firstLowerCase($!tableInfo.name), "Repository")) #set($serviceType = $!tool.append($!tool.firstUpperCase($!tableInfo.name), "Service")) #set($serviceName = $!tool.append($!tool.firstLowerCase($!tableInfo.name), "Service")) #set($serviceImplType = $!tool.append($!tool.firstUpperCase($!tableInfo.name), "ServiceImpl")) #set($serviceImplName = $!tool.append($!tool.firstLowerCase($!tableInfo.name), "ServiceImpl")) #set($apiType = $!tool.append($!tool.firstUpperCase($!tableInfo.name), "Controller")) #set($apiName = $!tool.append($!tool.firstLowerCase($!tableInfo.name), "Controller")) #set($dtoType = $!tool.append($!tool.firstUpperCase($!tableInfo.name), "DTO")) #set($dtoName = $!tool.append($!tool.firstLowerCase($!tableInfo.name), "DTO")) #set($queryType = $!tool.append($!tool.firstUpperCase($!tableInfo.name), "Query")) #set($queryName = "query") #set($voType = $!tool.append($!tool.firstUpperCase($!tableInfo.name), "VO")) #set($voName = $!tool.append($!tool.firstLowerCase($!tableInfo.name), "VO")) ## 自定义类注解 #macro(classNotes $notes) /** * @Description $!tableInfo.obj.name $notes * @Author $!author * @Date $!time.currTime() */ #end Init 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 ##初始化区域 ##去掉表的t_前缀 $!tableInfo.setName($tool.getClassName($tableInfo.obj.name.replaceFirst("tb_",""))) ## 设置业务模块名 #set($index = 0) #foreach ($element in $tableInfo.obj.name.split("_")) #set($index = $index +1) #if($index == 3) #set($work = $element) #end #end #if($!{work}) ## 包.模块名 #set($workPackage = $!tool.append(".",$!{work})) ## 路径/模块名 #set($workPath = $!tool.append("/",$!{work})) ## Common-模块名 #set($workCommon = $!tool.append("-",$!{work})) #end ##参考阿里巴巴开发手册,POJO 类中布尔类型的变量,都不要加 is 前缀,否则部分框架解析会引起序列化错误 #foreach($column in $tableInfo.fullColumn) #if($column.name.startsWith("is") && $column.type.equals("java.lang.Boolean")) $!column.setName($tool.firstLowerCase($column.name.substring(2))) #end #end ##实现动态排除列 #set($temp = $tool.newHashSet("testCreateTime", "otherColumn")) #foreach($item in $temp) #set($newList = $tool.newArrayList()) #foreach($column in $tableInfo.fullColumn) #if($column.name!=$item) ##带有反回值的方法调用时使用$tool.call来消除返回值 $tool.call($newList.add($column)) #end #end ##重新保存 $tableInfo.setFullColumn($newList) #end ##对importList进行篡改 #set($temp = $tool.newHashSet()) #foreach($column in $tableInfo.fullColumn) #if(!$column.type.startsWith("java.lang.")) ##带有反回值的方法调用时使用$tool.call来消除返回值 $tool.call($temp.add($column.type)) #end #end ##覆盖 #set($importList = $temp) autoimport 1 2 3 4 ##自动导入包(仅导入实体属性需要的包,通常用于实体类) #foreach($import in $importList) import $!import; #end