文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

你还在手写crud吗,看完这篇文章,绝对赚了

2024-12-03 16:51

关注

本文转载自微信公众号「Java极客技术」,作者鸭血粉丝 。转载本文请联系Java极客技术公众号。  

一、介绍

我记得最早刚步入互联网行业的时候,当时按照 MVC 的思想和模型,每次开发新功能,会依次编写 dao、service、controller相关服务类,包括对应的 dto、entity、vo 等等实体类,如果有多张单表,也会重复的编写相似的代码,现在回想起来,感觉当时自己好像处于石器时代!

实际上,当仔细的总结一下,对于任何一张单表的操作,基本都是围绕增(Create )、删(Delete )、改(Update )、查(Retrieve )四个方向进行数据操作,简称 CRUD!

他们除了表名和存储空间不一样,基本的 CRUD 思路基本都是一样的。

为了解决这些重复劳动的痛点,业界逐渐开源了一批代码生成器,目的也很简单,就是为了减少手工操作的繁琐,集中精力在业务开发上,提升开发效率。

而今天,我们所要介绍的也是代码生成器,很多初学者可能觉得代码生成器很高深。代码生成器其实是一个很简单的东西,一点都不高深。

当你看完本文的时候,你会完全掌握代码生成器的逻辑,甚至可以根据自己的项目情况,进行深度定制。

二、实现思路

下面我们就以SpringBoot项目为例,数据持久化操作采用Mybatis,数据库采用Mysql,编写一个自动生成增、删、改、查等基础功能的代码生成器,内容包括controller、service、dao、entity、dto、vo等信息。

实现思路如下:

获取表字段名称、类型、表注释等信息

基于 freemarker 模板引擎,编写相应的模板

根据对应的模板,生成相应的 java 代码

2.1、获取表结构

首先我们创建一张test_db表,脚本如下:

  1. CREATE TABLE test_db ( 
  2.   id bigint(20) unsigned NOT NULL COMMENT '主键ID'
  3.   name varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '名称'
  4.   is_delete tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否删除 1:已删除;0:未删除'
  5.   create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'
  6.   update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
  7.   PRIMARY KEY (id), 
  8.   KEY idx_create_time (create_time) USING BTREE 
  9. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='测试表'

表创建完成之后,基于test_db表,我们查询对应的表结果字段名称、类型、备注信息,这些关键信息将用于后续进行代码生成器所使用!

  1. # 获取对应表结构 
  2. SELECT column_name, data_type, column_comment FROM information_schema.columns WHERE table_schema = 'yjgj_base' AND table_name = 'test_db' 

 

同时,获取对应表注释,用于生成备注信息!

  1. # 获取对应表注释 
  2. SELECT TABLE_COMMENT FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = 'yjgj_base' AND table_name = 'test_db' 

 

2.2、编写模板

编写mapper.ftl模板,涵盖新增、修改、删除、查询等信息

  1. "1.0" encoding="UTF-8" ?> 
  2. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > 
  3. "${daoPackageName}.${daoName}"
  4.  
  5.  --BaseResultMap--> 
  6.  "BaseResultMap" type="${entityPackageName}.${entityName}"
  7.         <#list columns as pro> 
  8.             <#if pro.proName == primaryId> 
  9.     column="${primaryId}" property="${primaryId}" jdbcType="${pro.fieldType}"/> 
  10.             <#else
  11.     column="${pro.fieldName}" property="${pro.proName}" jdbcType="${pro.fieldType}"/> 
  12.              
  13.          
  14.   
  15.  
  16.  --Base_Column_List--> 
  17.  "Base_Column_List"
  18.         <#list columns as pro> 
  19.             <#if pro_index == 0>${pro.fieldName}<#else>,${pro.fieldName} 
  20.          
  21.   
  22.  
  23.  --批量插入--> 
  24.  <insert id="insertList" parameterType="java.util.List"
  25.   insert into ${tableName} ( 
  26.         <#list columns as pro> 
  27.             <#if pro_index == 0>${pro.fieldName},<#elseif pro_index == 1>${pro.fieldName}<#else>,${pro.fieldName} 
  28.          
  29.   ) 
  30.   values 
  31.   "list" item="obj" separator =","
  32.    " (" suffix=")" suffixOverrides=","
  33.                 <#list columns as pro> 
  34.                     ${r"#{obj." + pro.proName + r"}"}, 
  35.                  
  36.     
  37.    
  38.  insert
  39.  
  40.  --按需新增--> 
  41.  <insert id="insertPrimaryKeySelective" parameterType="${entityPackageName}.${entityName}"
  42.   insert into ${tableName} 
  43.   "(" suffix=")" suffixOverrides=","
  44.             <#list columns as pro> 
  45.     "${pro.proName} != null"
  46.                     ${pro.fieldName}, 
  47.      
  48.              
  49.    
  50.   "values (" suffix=")" suffixOverrides=","
  51.             <#list columns as pro> 
  52.     "${pro.proName} != null"
  53.                     ${r"#{" + pro.proName + r",jdbcType=" + pro.fieldType +r"}"}, 
  54.      
  55.              
  56.    
  57.  insert
  58.  
  59.  -- 按需修改--> 
  60.  <update id="updatePrimaryKeySelective" parameterType="${entityPackageName}.${entityName}"
  61.   update ${tableName} 
  62.   <set
  63.             <#list columns as pro> 
  64.                 <#if pro.fieldName != primaryId && pro.fieldName != primaryId> 
  65.      "${pro.proName} != null"
  66.                         ${pro.fieldName} = ${r"#{" + pro.proName + r",jdbcType=" + pro.fieldType +r"}"}, 
  67.       
  68.                  
  69.              
  70.   set
  71.   where ${primaryId} = ${r"#{" + "${primaryId}" + r",jdbcType=BIGINT}"
  72.  update
  73.  
  74.  -- 按需批量修改--> 
  75.  <update id="updateBatchByIds" parameterType="java.util.List"
  76.   update ${tableName} 
  77.   "set" suffixOverrides=","
  78.             <#list columns as pro> 
  79.                 <#if pro.fieldName != primaryId && pro.fieldName != primaryId> 
  80.      "${pro.fieldName}=case" suffix="end,"
  81.       "list" item="obj" index="index"
  82.        "obj.${pro.proName} != null"
  83.         when id = ${r"#{" + "obj.id" + r"}"
  84.         then  ${r"#{obj." + pro.proName + r",jdbcType=" + pro.fieldType +r"}"
  85.         
  86.        
  87.       
  88.                  
  89.              
  90.    
  91.   where 
  92.   "list" separator="or" item="obj" index="index" > 
  93.    id = ${r"#{" + "obj.id" + r"}"
  94.    
  95.  update
  96.  
  97.  -- 删除--> 
  98.  <delete id="deleteByPrimaryKey" parameterType="java.lang.Long"
  99.   delete from ${tableName} 
  100.   where ${primaryId} = ${r"#{" + "${primaryId}" + r",jdbcType=BIGINT}"
  101.  delete
  102.  
  103.  -- 查询详情 --> 
  104.  <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Long"
  105.   select 
  106.   "Base_Column_List"/> 
  107.   from ${tableName} 
  108.   where ${primaryId} = ${r"#{" + "${primaryId}" + r",jdbcType=BIGINT}"
  109.  select
  110.  
  111.  -- 按需查询 --> 
  112.  <select id="selectByPrimaryKeySelective" resultMap="BaseResultMap" parameterType="${entityPackageName}.${entityName}"
  113.   select 
  114.   "Base_Column_List"/> 
  115.   from ${tableName} 
  116.  select
  117.  
  118.  -- 批量查询--> 
  119.  <select id="selectByIds" resultMap="BaseResultMap" parameterType="java.util.List"
  120.   select 
  121.   "Base_Column_List"/> 
  122.   from ${tableName} 
  123.   <where
  124.    "ids != null"
  125.     and ${primaryId} in 
  126.     "item" index="index" collection="ids" open="(" separator="," close=")"
  127.                     ${r"#{" + "item" + r"}"
  128.      
  129.     
  130.   where
  131.  select
  132.  
  133.  -- 根据条件查询 --> 
  134.  <select id="selectByMap" resultMap="BaseResultMap" parameterType="java.util.Map"
  135.   select 
  136.   "Base_Column_List"/> 
  137.   from ${tableName} 
  138.  select
  139.  
  140.  -- 查询${entityName}总和 --> 
  141.  <select id="countPage" resultType="int" parameterType="${dtoPackageName}.${dtoName}"
  142.   select count(${primaryId}) 
  143.   from ${tableName} 
  144.  select
  145.  
  146.  -- 查询${entityName}列表 --> 
  147.  <select id="selectPage" resultMap="BaseResultMap" parameterType="${dtoPackageName}.${dtoName}"
  148.   select 
  149.   "Base_Column_List"/> 
  150.   from ${tableName} 
  151.   limit ${r"#{" + "start,jdbcType=INTEGER" + r"}"},${r"#{" + "end,jdbcType=INTEGER" + r"}"
  152.  select
  153.  
  154.  

编写dao.ftl数据访问模板

  1. package ${daoPackageName}; 
  2.  
  3. import com.example.generator.core.BaseMapper; 
  4. import java.util.List; 
  5. import ${entityPackageName}.${entityName}; 
  6. import ${dtoPackageName}.${dtoName}; 
  7.  
  8.  
  9. public interface ${daoName} extends BaseMapper<${entityName}>{ 
  10.  
  11.  int countPage(${dtoName} ${dtoName?uncap_first}); 
  12.  
  13.  List<${entityName}> selectPage(${dtoName} ${dtoName?uncap_first}); 

编写service.ftl服务接口模板

  1. package ${servicePackageName}; 
  2.  
  3. import com.example.generator.core.BaseService; 
  4. import com.example.generator.common.Pager; 
  5. import ${voPackageName}.${voName}; 
  6. import ${dtoPackageName}.${dtoName}; 
  7. import ${entityPackageName}.${entityName}; 
  8.  
  9.  
  10. public interface ${serviceName} extends BaseService<${entityName}> { 
  11.  
  12.   
  13.  Pager<${voName}> getPage(${dtoName} request); 

编写serviceImpl.ftl服务实现类模板

  1. package ${serviceImplPackageName}; 
  2.  
  3. import com.example.generator.common.Pager; 
  4. import com.example.generator.core.BaseServiceImpl; 
  5. import com.example.generator.test.service.TestEntityService; 
  6. import org.springframework.beans.BeanUtils; 
  7. import org.springframework.stereotype.Service; 
  8. import org.springframework.util.CollectionUtils; 
  9. import org.slf4j.Logger; 
  10. import org.slf4j.LoggerFactory; 
  11.  
  12. import java.util.ArrayList; 
  13. import java.util.List; 
  14.  
  15.  
  16. import ${daoPackageName}.${daoName}; 
  17. import ${entityPackageName}.${entityName}; 
  18. import ${dtoPackageName}.${dtoName}; 
  19. import ${voPackageName}.${voName}; 
  20.  
  21.  
  22. @Service 
  23. public class ${serviceImplName} extends BaseServiceImpl<${daoName}, ${entityName}> implements ${serviceName} { 
  24.  
  25.  private static final Logger log = LoggerFactory.getLogger(${serviceImplName}.class); 
  26.  
  27.   
  28.  public Pager<${voName}> getPage(${dtoName} request) { 
  29.   List<${voName}> resultList = new ArrayList(); 
  30.   int count = super.baseMapper.countPage(request); 
  31.   List<${entityName}> dbList = count > 0 ? super.baseMapper.selectPage(request) : new ArrayList<>(); 
  32.   if(!CollectionUtils.isEmpty(dbList)){ 
  33.    dbList.forEach(source->{ 
  34.     ${voName} target = new ${voName}(); 
  35.     BeanUtils.copyProperties(source, target); 
  36.     resultList.add(target); 
  37.    }); 
  38.   } 
  39.   return new Pager(request.getCurrPage(), request.getPageSize(), count, resultList); 
  40.  } 

编写controller.ftl控制层模板

  1. package ${controllerPackageName}; 
  2.  
  3. import com.example.generator.common.IdRequest; 
  4. import com.example.generator.common.Pager; 
  5. import org.springframework.beans.BeanUtils; 
  6. import org.springframework.beans.factory.annotation.Autowired; 
  7. import org.springframework.web.bind.annotation.PostMapping; 
  8. import org.springframework.web.bind.annotation.RequestBody; 
  9. import org.springframework.web.bind.annotation.RequestMapping; 
  10. import org.springframework.web.bind.annotation.RestController; 
  11. import java.util.Objects; 
  12.  
  13. import ${servicePackageName}.${serviceName}; 
  14. import ${entityPackageName}.${entityName}; 
  15. import ${dtoPackageName}.${dtoName}; 
  16. import ${voPackageName}.${voName}; 
  17.  
  18.  
  19. @RestController 
  20. @RequestMapping("/${entityName?uncap_first}"
  21. public class ${controllerName} { 
  22.  
  23.  @Autowired 
  24.  private ${serviceName} ${serviceName?uncap_first}; 
  25.  
  26.   
  27.  @PostMapping(value = "/getPage"
  28.  public Pager<${voName}> getPage(@RequestBody ${dtoName} request){ 
  29.   return ${serviceName?uncap_first}.getPage(request); 
  30.  } 
  31.  
  32.   
  33.  @PostMapping(value = "/getDetail"
  34.  public ${voName} getDetail(@RequestBody IdRequest request){ 
  35.   ${entityName} source = ${serviceName?uncap_first}.selectById(request.getId()); 
  36.   if(Objects.nonNull(source)){ 
  37.    ${voName} result = new ${voName}(); 
  38.    BeanUtils.copyProperties(source, result); 
  39.    return result; 
  40.   } 
  41.   return null
  42.  } 
  43.  
  44.   
  45.  @PostMapping(value = "/save"
  46.  public void save(${dtoName} request){ 
  47.   ${entityName} entity = new ${entityName}(); 
  48.   BeanUtils.copyProperties(request, entity); 
  49.   ${serviceName?uncap_first}.insert(entity); 
  50.  } 
  51.  
  52.   
  53.  @PostMapping(value = "/edit"
  54.  public void edit(${dtoName} request){ 
  55.   ${entityName} entity = new ${entityName}(); 
  56.   BeanUtils.copyProperties(request, entity); 
  57.   ${serviceName?uncap_first}.updateById(entity); 
  58.  } 
  59.  
  60.   
  61.  @PostMapping(value = "/delete"
  62.  public void delete(IdRequest request){ 
  63.   ${serviceName?uncap_first}.deleteById(request.getId()); 
  64.  } 

编写entity.ftl实体类模板

  1. package ${entityPackageName}; 
  2.  
  3. import java.io.Serializable
  4. import java.math.BigDecimal; 
  5. import java.util.Date
  6.  
  7.  
  8. public class ${entityName} implements Serializable { 
  9.  
  10.  private static final long serialVersionUID = 1L; 
  11.   
  12.  <#--属性遍历--> 
  13.  <#list columns as pro> 
  14.  <#--<#if pro.proName != primaryId 
  15.  && pro.proName != 'remarks' 
  16.  && pro.proName != 'createBy' 
  17.  && pro.proName != 'createDate' 
  18.  && pro.proName != 'updateBy' 
  19.  && pro.proName != 'updateDate' 
  20.  && pro.proName != 'delFlag' 
  21.  && pro.proName != 'currentUser' 
  22.  && pro.proName != 'page' 
  23.  && pro.proName != 'sqlMap' 
  24.  && pro.proName != 'isNewRecord' 
  25.  >--> 
  26.   
  27.  private ${pro.proType} ${pro.proName}; 
  28.   
  29.  
  30.  <#--属性get||set方法--> 
  31.  <#list columns as pro> 
  32.  public ${pro.proType} get${pro.proName?cap_first}() { 
  33.   return this.${pro.proName}; 
  34.  } 
  35.  
  36.  public ${entityName} set${pro.proName?cap_first}(${pro.proType} ${pro.proName}) { 
  37.   this.${pro.proName} = ${pro.proName}; 
  38.   return this; 
  39.  } 
  40.   

编写dto.ftl实体类模板

  1. package ${dtoPackageName}; 
  2.  
  3. import com.example.generator.core.BaseDTO; 
  4. import java.io.Serializable
  5.  
  6.  
  7. public class ${dtoName} extends BaseDTO { 
  8.  

编写vo.ftl视图实体类模板

  1. package ${voPackageName}; 
  2.  
  3. import java.io.Serializable
  4.  
  5.  
  6. public class ${voName} implements Serializable { 
  7.  
  8.  private static final long serialVersionUID = 1L; 

可能细心的网友已经看到了,在模板中我们用到了BaseMapper、BaseService、BaseServiceImpl等等服务类。

之所以有这三个类,是因为在模板中,我们有大量的相同的方法名包括逻辑也相似,除了所在实体类不一样以外,其他都一样,因此我们可以借助泛型类来将这些服务抽成公共的部分。

BaseMapper,主要负责将dao层的公共方法抽出来

  1. package com.example.generator.core; 
  2.  
  3. import org.apache.ibatis.annotations.Param; 
  4.  
  5. import java.io.Serializable
  6. import java.util.List; 
  7. import java.util.Map; 
  8.  
  9.  
  10. public interface BaseMapper { 
  11.  
  12.      
  13.     int insertList(@Param("list") List list); 
  14.  
  15.      
  16.     int insertPrimaryKeySelective(T entity); 
  17.  
  18.      
  19.     int updatePrimaryKeySelective(T entity); 
  20.  
  21.      
  22.     int updateBatchByIds(@Param("list") List list); 
  23.  
  24.      
  25.     int deleteByPrimaryKey(Serializable id); 
  26.  
  27.      
  28.     T selectByPrimaryKey(Serializable id); 
  29.  
  30.      
  31.     List selectByPrimaryKeySelective(T entity); 
  32.  
  33.      
  34.     List selectByIds(@Param("ids") ListSerializable> ids); 
  35.  
  36.      
  37.     List selectByMap(Map columnMap); 

BaseService,主要负责将service层的公共方法抽出来

  1. package com.example.generator.core; 
  2.  
  3. import java.io.Serializable
  4. import java.util.List; 
  5. import java.util.Map; 
  6.  
  7.  
  8. public interface BaseService { 
  9.  
  10.      
  11.     boolean insert(T entity); 
  12.  
  13.      
  14.     boolean insertList(List list); 
  15.  
  16.      
  17.     boolean updateById(T entity); 
  18.  
  19.      
  20.     boolean updateBatchByIds(List list); 
  21.  
  22.      
  23.     boolean deleteById(Serializable id); 
  24.  
  25.      
  26.     T selectById(Serializable id); 
  27.  
  28.      
  29.     List selectByPrimaryKeySelective(T entity); 
  30.  
  31.      
  32.     List selectByIds(ListSerializable> ids); 
  33.  
  34.      
  35.     List selectByMap(Map columnMap); 
  36.  

BaseServiceImpl,service层的公共方法具体实现类

  1. package com.example.generator.core; 
  2.  
  3. import org.springframework.beans.factory.annotation.Autowired; 
  4. import org.springframework.transaction.annotation.Transactional; 
  5.  
  6. import java.io.Serializable
  7. import java.util.List; 
  8. import java.util.Map; 
  9.  
  10.  
  11. public abstract class BaseServiceImpl, T> implements BaseService
  12.  
  13.     @Autowired 
  14.     protected M baseMapper; 
  15.  
  16.      
  17.     @Override 
  18.     @Transactional(rollbackFor = {Exception.class}) 
  19.     public boolean insert(T entity){ 
  20.         return returnBool(baseMapper.insertPrimaryKeySelective(entity)); 
  21.     } 
  22.  
  23.      
  24.     @Override 
  25.     @Transactional(rollbackFor = {Exception.class}) 
  26.     public boolean insertList(List list){ 
  27.         return returnBool(baseMapper.insertList(list)); 
  28.     } 
  29.  
  30.      
  31.     @Override 
  32.     @Transactional(rollbackFor = {Exception.class}) 
  33.     public boolean updateById(T entity){ 
  34.         return returnBool(baseMapper.updatePrimaryKeySelective(entity)); 
  35.     } 
  36.  
  37.      
  38.     @Override 
  39.     @Transactional(rollbackFor = {Exception.class}) 
  40.     public boolean updateBatchByIds(List list){ 
  41.         return returnBool(baseMapper.updateBatchByIds(list)); 
  42.     } 
  43.  
  44.      
  45.     @Override 
  46.     @Transactional(rollbackFor = {Exception.class}) 
  47.     public boolean deleteById(Serializable id){ 
  48.         return returnBool(baseMapper.deleteByPrimaryKey(id)); 
  49.     } 
  50.  
  51.      
  52.     @Override 
  53.     public T selectById(Serializable id){ 
  54.         return baseMapper.selectByPrimaryKey(id); 
  55.     } 
  56.  
  57.      
  58.     @Override 
  59.     public List selectByPrimaryKeySelective(T entity){ 
  60.         return baseMapper.selectByPrimaryKeySelective(entity); 
  61.     } 
  62.  
  63.      
  64.     @Override 
  65.     public List selectByIds(ListSerializable> ids){ 
  66.         return baseMapper.selectByIds(ids); 
  67.     } 
  68.  
  69.      
  70.     @Override 
  71.     public List selectByMap(Map columnMap){ 
  72.         return baseMapper.selectByMap(columnMap); 
  73.     } 
  74.  
  75.      
  76.     protected boolean returnBool(Integer result) { 
  77.         return null != result && result >= 1; 
  78.     } 
  79.  

在此,还封装来其他的类,例如 dto 公共类BaseDTO,分页类Pager,还有 id 请求类IdRequest。

BaseDTO公共类

  1. public class BaseDTO implements Serializable { 
  2.  
  3.      
  4.     private String token; 
  5.  
  6.      
  7.     private Integer currPage = 1; 
  8.  
  9.      
  10.     private Integer pageSize = 20; 
  11.  
  12.      
  13.     private Integer start; 
  14.  
  15.      
  16.     private Integer end
  17.  
  18.      
  19.     private String loginUserId; 
  20.  
  21.      
  22.     private String loginUserName; 
  23.  
  24.     public String getToken() { 
  25.         return token; 
  26.     } 
  27.  
  28.     public BaseDTO setToken(String token) { 
  29.         this.token = token; 
  30.         return this; 
  31.     } 
  32.  
  33.     public Integer getCurrPage() { 
  34.         return currPage; 
  35.     } 
  36.  
  37.     public BaseDTO setCurrPage(Integer currPage) { 
  38.         this.currPage = currPage; 
  39.         return this; 
  40.     } 
  41.  
  42.     public Integer getPageSize() { 
  43.         return pageSize; 
  44.     } 
  45.  
  46.     public BaseDTO setPageSize(Integer pageSize) { 
  47.         this.pageSize = pageSize; 
  48.         return this; 
  49.     } 
  50.  
  51.     public Integer getStart() { 
  52.         if (this.currPage != null && this.currPage > 0) { 
  53.             start = (currPage - 1) * getPageSize(); 
  54.             return start; 
  55.         } 
  56.         return start == null ? 0 : start; 
  57.     } 
  58.  
  59.     public BaseDTO setStart(Integer start) { 
  60.         this.start = start; 
  61.         return this; 
  62.     } 
  63.  
  64.     public Integer getEnd() { 
  65.         return getPageSize(); 
  66.     } 
  67.  
  68.     public BaseDTO setEnd(Integer end) { 
  69.         this.end = end
  70.         return this; 
  71.     } 
  72.  
  73.     public String getLoginUserId() { 
  74.         return loginUserId; 
  75.     } 
  76.  
  77.     public BaseDTO setLoginUserId(String loginUserId) { 
  78.         this.loginUserId = loginUserId; 
  79.         return this; 
  80.     } 
  81.  
  82.     public String getLoginUserName() { 
  83.         return loginUserName; 
  84.     } 
  85.  
  86.     public BaseDTO setLoginUserName(String loginUserName) { 
  87.         this.loginUserName = loginUserName; 
  88.         return this; 
  89.     } 
  90.  

Pager分页类

  1. public class PagerSerializable> implements Serializable { 
  2.  
  3.     private static final long serialVersionUID = -6557244954523041805L; 
  4.  
  5.      
  6.     private int currPage; 
  7.  
  8.      
  9.     private int pageSize; 
  10.  
  11.      
  12.     private int totalPage; 
  13.  
  14.      
  15.     private int totalCount; 
  16.  
  17.      
  18.     private List list; 
  19.  
  20.     public Pager(int currPage, int pageSize) { 
  21.         this.currPage = currPage; 
  22.         this.pageSize = pageSize; 
  23.     } 
  24.  
  25.     public Pager(int currPage, int pageSize, int totalCount, List list) { 
  26.         this.currPage = currPage; 
  27.         this.pageSize = pageSize; 
  28.         this.totalPage = (int) Math.ceil((double) totalCount / pageSize);; 
  29.         this.totalCount = totalCount; 
  30.         this.list = list; 
  31.     } 
  32.  
  33.     public int getCurrPage() { 
  34.         return currPage; 
  35.     } 
  36.  
  37.     public Pager setCurrPage(int currPage) { 
  38.         this.currPage = currPage; 
  39.         return this; 
  40.     } 
  41.  
  42.     public int getPageSize() { 
  43.         return pageSize; 
  44.     } 
  45.  
  46.     public Pager setPageSize(int pageSize) { 
  47.         this.pageSize = pageSize; 
  48.         return this; 
  49.     } 
  50.  
  51.     public int getTotalPage() { 
  52.         return totalPage; 
  53.     } 
  54.  
  55.     public Pager setTotalPage(int totalPage) { 
  56.         this.totalPage = totalPage; 
  57.         return this; 
  58.     } 
  59.  
  60.     public int getTotalCount() { 
  61.         return totalCount; 
  62.     } 
  63.  
  64.     public Pager setTotalCount(int totalCount) { 
  65.         this.totalCount = totalCount; 
  66.         return this; 
  67.     } 
  68.  
  69.     public List getList() { 
  70.         return list; 
  71.     } 
  72.  
  73.     public Pager setList(List list) { 
  74.         this.list = list; 
  75.         return this; 
  76.     } 

IdRequest公共请求类

  1. public class IdRequest extends BaseDTO { 
  2.  
  3.     private Long id; 
  4.  
  5.     public Long getId() { 
  6.         return id; 
  7.     } 
  8.  
  9.     public IdRequest setId(Long id) { 
  10.         this.id = id; 
  11.         return this; 
  12.     } 

2.3、编写代码生成器

前两部分主要介绍的是如何获取对应的表结构,以及代码器运行之前的准备工作。

其实代码生成器,很简单,其实就是一个main方法,没有想象中的那么复杂。

处理思路也很简单,过程如下:

定义基本变量,例如包名路径、模块名、表名、转换后的实体类、以及数据库连接配置,我们可以将其写入配置文件

读取配置文件,封装对应的模板中定义的变量

根据对应的模板文件和变量,生成对应的java文件

2.3.1、创建配置文件,定义变量

小编我用的是application.properties配置文件来定义变量,这个没啥规定,你也可以自定义文件名,内容如下:

  1. #包前缀 
  2. packageNamePre=com.example.generator 
  3. #模块名称 
  4. moduleName=test 
  5. #表 
  6. tableName=test_db 
  7. #实体类名称 
  8. entityName=TestEntity 
  9. #主键ID 
  10. primaryId=id 
  11. #作者 
  12. authorName=pzblog 
  13. #数据库名称 
  14. databaseName=yjgj_base 
  15.  
  16. #数据库服务器IP地址 
  17. ipName=127.0.0.1 
  18. #数据库服务器端口 
  19. portName=3306 
  20. #用户名 
  21. userName=root 
  22. #密码 
  23. passWord=123456 
  24.  
  25. #文件输出路径,支持自定义输出路径,如果为空,默认取当前工程的src/main/java路径 
  26. outUrl= 

2.3.2、根据模板生成对应的java代码

首先,读取配置文件变量

  1. public class SystemConstant { 
  2.  
  3.     private static Properties properties = new Properties(); 
  4.  
  5.     static { 
  6.         try { 
  7.             // 加载上传文件设置参数:配置文件 
  8.             properties.load(SystemConstant.class.getClassLoader().getResourceAsStream("application.properties")); 
  9.         } catch (IOException e) { 
  10.             e.printStackTrace(); 
  11.         } 
  12.     } 
  13.  
  14.     public static final String tableName = properties.getProperty("tableName"); 
  15.     public static final String entityName = properties.getProperty("entityName"); 
  16.     public static final String packageNamePre = properties.getProperty("packageNamePre"); 
  17.     public static final String outUrl = properties.getProperty("outUrl"); 
  18.     public static final String databaseName = properties.getProperty("databaseName"); 
  19.     public static final String ipName = properties.getProperty("ipName"); 
  20.     public static final String portName = properties.getProperty("portName"); 
  21.     public static final String userName = properties.getProperty("userName"); 
  22.     public static final String passWord = properties.getProperty("passWord"); 
  23.     public static final String authorName = properties.getProperty("authorName"); 
  24.  
  25.     public static final String primaryId = properties.getProperty("primaryId"); 
  26.  
  27.     public static final String moduleName = properties.getProperty("moduleName"); 

然后,封装对应的模板中定义的变量

  1. public class CodeService { 
  2.  
  3.     public void generate(Map templateData) { 
  4.         //包前缀 
  5.         String packagePreAndModuleName = getPackagePreAndModuleName(templateData); 
  6.  
  7.         //支持对应实体插入在前面,需要带上%s 
  8.         templateData.put("entityPackageName", String.format(packagePreAndModuleName + ".entity"
  9.                 templateData.get("entityName").toString().toLowerCase())); 
  10.  
  11.         templateData.put("dtoPackageName", String.format(packagePreAndModuleName + ".dto"
  12.                 templateData.get("entityName").toString().toLowerCase())); 
  13.  
  14.         templateData.put("voPackageName", String.format(packagePreAndModuleName + ".vo"
  15.                 templateData.get("entityName").toString().toLowerCase())); 
  16.  
  17.         templateData.put("daoPackageName", String.format(packagePreAndModuleName + ".dao"
  18.                 templateData.get("entityName").toString().toLowerCase())); 
  19.  
  20.         templateData.put("mapperPackageName", packagePreAndModuleName + ".mapper"); 
  21.  
  22.  
  23.         templateData.put("servicePackageName", String.format(packagePreAndModuleName + ".service"
  24.                 templateData.get("entityName").toString().toLowerCase())); 
  25.  
  26.         templateData.put("serviceImplPackageName", String.format(packagePreAndModuleName + ".service.impl"
  27.                 templateData.get("entityName").toString().toLowerCase())); 
  28.  
  29.         templateData.put("controllerPackageName", String.format(packagePreAndModuleName + ".web"
  30.                 templateData.get("entityName").toString().toLowerCase())); 
  31.  
  32.         templateData.put("apiTestPackageName", String.format(packagePreAndModuleName + ".junit"
  33.                 templateData.get("entityName").toString().toLowerCase())); 
  34.  
  35.  
  36.         templateData.put("currentTime", new SimpleDateFormat("yyyy-MM-dd").format(new Date())); 
  37.  
  38.         //======================生成文件配置====================== 
  39.         try { 
  40.             // 生成Entity 
  41.             String entityName = String.format("%s", templateData.get("entityName").toString()); 
  42.             generateFile("entity.ftl", templateData, templateData.get("entityPackageName").toString(), entityName+".java"); 
  43.  
  44.             // 生成dto 
  45.             String dtoName = String.format("%sDTO", templateData.get("entityName").toString()); 
  46.             templateData.put("dtoName", dtoName); 
  47.             generateFile("dto.ftl", templateData, templateData.get("dtoPackageName").toString(), 
  48.                     dtoName + ".java"); 
  49.  
  50.             // 生成VO 
  51.             String voName = String.format("%sVO", templateData.get("entityName").toString()); 
  52.             templateData.put("voName", voName); 
  53.             generateFile("vo.ftl", templateData, templateData.get("voPackageName").toString(), 
  54.                     voName + ".java"); 
  55.  
  56.             // 生成DAO 
  57.             String daoName = String.format("%sDao", templateData.get("entityName").toString()); 
  58.             templateData.put("daoName", daoName); 
  59.             generateFile("dao.ftl", templateData, templateData.get("daoPackageName").toString(), 
  60.                     daoName + ".java"); 
  61.  
  62.             // 生成Mapper 
  63.             String mapperName = String.format("%sMapper", templateData.get("entityName").toString()); 
  64.             generateFile("mapper.ftl", templateData, templateData.get("mapperPackageName").toString(), 
  65.                     mapperName+".xml"); 
  66.  
  67.  
  68.             // 生成Service 
  69.             String serviceName = String.format("%sService", templateData.get("entityName").toString()); 
  70.             templateData.put("serviceName", serviceName); 
  71.             generateFile("service.ftl", templateData, templateData.get("servicePackageName").toString(), 
  72.                     serviceName + ".java"); 
  73.  
  74.             // 生成ServiceImpl 
  75.    String serviceImplName = String.format("%sServiceImpl", templateData.get("entityName").toString()); 
  76.    templateData.put("serviceImplName", serviceImplName); 
  77.    generateFile("serviceImpl.ftl", templateData, templateData.get("serviceImplPackageName").toString(), 
  78.                     serviceImplName + ".java"); 
  79.  
  80.             // 生成Controller 
  81.    String controllerName = String.format("%sController", templateData.get("entityName").toString()); 
  82.    templateData.put("controllerName", controllerName); 
  83.    generateFile("controller.ftl", templateData, templateData.get("controllerPackageName").toString(), 
  84.                     controllerName + ".java"); 
  85.  
  86. //   // 生成junit测试类 
  87. //            String apiTestName = String.format("%sApiTest", templateData.get("entityName").toString()); 
  88. //            templateData.put("apiTestName", apiTestName); 
  89. //            generateFile("test.ftl", templateData, templateData.get("apiTestPackageName").toString(), 
  90. //                    apiTestName + ".java"); 
  91.  
  92.         } catch (Exception e) { 
  93.             e.printStackTrace(); 
  94.         } 
  95.     } 
  96.  
  97.      
  98.     public void generateFile(String templateName, Map templateData, String packageName, String fileName) { 
  99.         templateData.put("fileName", fileName); 
  100.  
  101.         DaseService dbService = new DaseService(templateData); 
  102.  
  103.         // 获取数据库参数 
  104.         if("entity.ftl".equals(templateName) || "mapper.ftl".equals(templateName)){ 
  105.             dbService.getAllColumns(templateData); 
  106.         } 
  107.         try { 
  108.             // 默认生成文件的路径 
  109.             FreeMakerUtil freeMakerUtil = new FreeMakerUtil(); 
  110.             freeMakerUtil.generateFile(templateName, templateData, packageName, fileName); 
  111.         } catch (Exception e) { 
  112.             e.printStackTrace(); 
  113.         } 
  114.     } 
  115.  
  116.      
  117.     private String getPackagePreAndModuleName(Map templateData){ 
  118.         String packageNamePre = templateData.get("packageNamePre").toString(); 
  119.         String moduleName = templateData.get("moduleName").toString(); 
  120.         if(StringUtils.isNotBlank(moduleName)){ 
  121.             return packageNamePre + "." + moduleName; 
  122.         } 
  123.         return packageNamePre; 
  124.     } 
  125.  

接着,获取模板文件,并生成相应的模板文件

  1. public class FreeMakerUtil { 
  2.  
  3.  
  4.      
  5.     public void generateFile(String templateName, Map root, String packageName, String fileName) throws Exception { 
  6.         FileOutputStream fos=null
  7.         Writer out =null
  8.         try { 
  9.             // 通过一个文件输出流,就可以写到相应的文件中,此处用的是绝对路径 
  10.             String entityName = (String) root.get("entityName"); 
  11.             String fileFullName = String.format(fileName, entityName); 
  12.             packageName = String.format(packageName, entityName.toLowerCase()); 
  13.  
  14.             String fileStylePackageName = packageName.replaceAll("\\.""/"); 
  15.             File file = new File(root.get("outUrl").toString() + "/" + fileStylePackageName + "/" + fileFullName); 
  16.             if (!file.getParentFile().exists()) { 
  17.                 file.getParentFile().mkdirs(); 
  18.             } 
  19.             file.createNewFile(); 
  20.  
  21.             Template template = getTemplate(templateName); 
  22.             fos = new FileOutputStream(file); 
  23.             out = new OutputStreamWriter(fos); 
  24.             template.process(root, out); 
  25.             out.flush(); 
  26.         } catch (Exception e) { 
  27.             e.printStackTrace(); 
  28.         } finally { 
  29.             try { 
  30.                 if (fos != null){ 
  31.                     fos.close(); 
  32.                 } 
  33.                 if(out != null){ 
  34.                     out.close(); 
  35.                 } 
  36.             } catch (IOException e) { 
  37.                 e.printStackTrace(); 
  38.             } 
  39.         } 
  40.     } 
  41.  
  42.      
  43.     public Template getTemplate(String name) { 
  44.         try { 
  45.             Configuration cfg = new Configuration(Configuration.VERSION_2_3_23); 
  46.             cfg.setClassForTemplateLoading(this.getClass(), "/ftl"); 
  47.             Template template = cfg.getTemplate(name); 
  48.             return template; 
  49.         } catch (IOException e) { 
  50.             e.printStackTrace(); 
  51.         } 
  52.         return null
  53.     } 

最后,我们编写一个main方法,看看运行之后的效果

  1. public class GeneratorMain { 
  2.  
  3.     public static void main(String[] args) { 
  4.         System.out.println("生成代码start......"); 
  5.  
  6.         //获取页面或者配置文件的参数 
  7.         Map templateData = new HashMap(); 
  8.         templateData.put("tableName", SystemConstant.tableName); 
  9.         System.out.println("表名=="+ SystemConstant.tableName); 
  10.  
  11.         templateData.put("entityName", SystemConstant.entityName); 
  12.         System.out.println("实体类名称=="+ SystemConstant.entityName); 
  13.  
  14.         templateData.put("packageNamePre", SystemConstant.packageNamePre); 
  15.         System.out.println("包名前缀=="+ SystemConstant.packageNamePre); 
  16.  
  17.         //支持自定义输出路径 
  18.         if(StringUtils.isNotBlank(SystemConstant.outUrl)){ 
  19.             templateData.put("outUrl", SystemConstant.outUrl); 
  20.         } else { 
  21.             String path = GeneratorMain.class.getClassLoader().getResource("").getPath() + "../../src/main/java"
  22.             templateData.put("outUrl", path); 
  23.         } 
  24.         System.out.println("生成文件路径为=="+ templateData.get("outUrl")); 
  25.  
  26.         templateData.put("authorName", SystemConstant.authorName); 
  27.         System.out.println("以后代码出问题找=="+ SystemConstant.authorName); 
  28.  
  29.  
  30.         templateData.put("databaseName", SystemConstant.databaseName); 
  31.         templateData.put("ipName", SystemConstant.ipName); 
  32.         templateData.put("portName", SystemConstant.portName); 
  33.         templateData.put("userName", SystemConstant.userName); 
  34.         templateData.put("passWord", SystemConstant.passWord); 
  35.  
  36.         //主键ID 
  37.         templateData.put("primaryId", SystemConstant.primaryId); 
  38.  
  39.         //模块名称 
  40.         templateData.put("moduleName", SystemConstant.moduleName); 
  41.         CodeService dataService = new CodeService(); 
  42.  
  43.         try { 
  44.             //生成代码文件 
  45.             dataService.generate(templateData); 
  46.         } catch (Exception e) { 
  47.             e.printStackTrace(); 
  48.         } 
  49.  
  50.         System.out.println("生成代码end......"); 
  51.     } 

结果如下:

 

生成的 Controller 层代码如下

  1.  
  2. @RestController 
  3. @RequestMapping("/testEntity"
  4. public class TestEntityController { 
  5.  
  6.  @Autowired 
  7.  private TestEntityService testEntityService; 
  8.  
  9.   
  10.  @PostMapping(value = "/getPage"
  11.  public Pager getPage(@RequestBody TestEntityDTO request){ 
  12.   return testEntityService.getPage(request); 
  13.  } 
  14.  
  15.   
  16.  @PostMapping(value = "/getDetail"
  17.  public TestEntityVO getDetail(@RequestBody IdRequest request){ 
  18.   TestEntity source = testEntityService.selectById(request.getId()); 
  19.   if(Objects.nonNull(source)){ 
  20.    TestEntityVO result = new TestEntityVO(); 
  21.    BeanUtils.copyProperties(source, result); 
  22.    return result; 
  23.   } 
  24.   return null
  25.  } 
  26.  
  27.   
  28.  @PostMapping(value = "/save"
  29.  public void save(TestEntityDTO request){ 
  30.   TestEntity entity = new TestEntity(); 
  31.   BeanUtils.copyProperties(request, entity); 
  32.   testEntityService.insert(entity); 
  33.  } 
  34.  
  35.   
  36.  @PostMapping(value = "/edit"
  37.  public void edit(TestEntityDTO request){ 
  38.   TestEntity entity = new TestEntity(); 
  39.   BeanUtils.copyProperties(request, entity); 
  40.   testEntityService.updateById(entity); 
  41.  } 
  42.  
  43.   
  44.  @PostMapping(value = "/delete"
  45.  public void delete(IdRequest request){ 
  46.   testEntityService.deleteById(request.getId()); 
  47.  } 

至此,一张单表的90%的基础工作量全部开发完毕!

三、总结

代码生成器,在实际的项目开发中应用非常的广,本文主要以freemaker模板引擎为基础,开发的一套全自动代码生成器,一张单表的CRUD,只需要5秒钟就可以完成!

最后多说一句,如果你是项目负责人,那么代码生成器会是一个比较好的提升项目开发效率的工具,希望能帮到各位!

 

来源:Java极客技术内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯