新聞中心
本文轉(zhuǎn)載自微信公眾號(hào)「Java極客技術(shù)」,作者鴨血粉絲 。轉(zhuǎn)載本文請(qǐng)聯(lián)系Java極客技術(shù)公眾號(hào)。

成都創(chuàng)新互聯(lián)服務(wù)項(xiàng)目包括南樂網(wǎng)站建設(shè)、南樂網(wǎng)站制作、南樂網(wǎng)頁制作以及南樂網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,南樂網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到南樂省份的部分城市,未來相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!
一、介紹
我記得最早剛步入互聯(lián)網(wǎng)行業(yè)的時(shí)候,當(dāng)時(shí)按照 MVC 的思想和模型,每次開發(fā)新功能,會(huì)依次編寫 dao、service、controller相關(guān)服務(wù)類,包括對(duì)應(yīng)的 dto、entity、vo 等等實(shí)體類,如果有多張單表,也會(huì)重復(fù)的編寫相似的代碼,現(xiàn)在回想起來,感覺當(dāng)時(shí)自己好像處于石器時(shí)代!
實(shí)際上,當(dāng)仔細(xì)的總結(jié)一下,對(duì)于任何一張單表的操作,基本都是圍繞增(Create )、刪(Delete )、改(Update )、查(Retrieve )四個(gè)方向進(jìn)行數(shù)據(jù)操作,簡稱 CRUD!
他們除了表名和存儲(chǔ)空間不一樣,基本的 CRUD 思路基本都是一樣的。
為了解決這些重復(fù)勞動(dòng)的痛點(diǎn),業(yè)界逐漸開源了一批代碼生成器,目的也很簡單,就是為了減少手工操作的繁瑣,集中精力在業(yè)務(wù)開發(fā)上,提升開發(fā)效率。
而今天,我們所要介紹的也是代碼生成器,很多初學(xué)者可能覺得代碼生成器很高深。代碼生成器其實(shí)是一個(gè)很簡單的東西,一點(diǎn)都不高深。
當(dāng)你看完本文的時(shí)候,你會(huì)完全掌握代碼生成器的邏輯,甚至可以根據(jù)自己的項(xiàng)目情況,進(jìn)行深度定制。
二、實(shí)現(xiàn)思路
下面我們就以SpringBoot項(xiàng)目為例,數(shù)據(jù)持久化操作采用Mybatis,數(shù)據(jù)庫采用Mysql,編寫一個(gè)自動(dòng)生成增、刪、改、查等基礎(chǔ)功能的代碼生成器,內(nèi)容包括controller、service、dao、entity、dto、vo等信息。
實(shí)現(xiàn)思路如下:
第一步:獲取表字段名稱、類型、表注釋等信息
第二步:基于 freemarker 模板引擎,編寫相應(yīng)的模板
第三步:根據(jù)對(duì)應(yīng)的模板,生成相應(yīng)的 java 代碼
2.1、獲取表結(jié)構(gòu)
首先我們創(chuàng)建一張test_db表,腳本如下:
- CREATE TABLE test_db (
- id bigint(20) unsigned NOT NULL COMMENT '主鍵ID',
- name varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '名稱',
- is_delete tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否刪除 1:已刪除;0:未刪除',
- create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時(shí)間',
- update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時(shí)間',
- PRIMARY KEY (id),
- KEY idx_create_time (create_time) USING BTREE
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='測試表';
表創(chuàng)建完成之后,基于test_db表,我們查詢對(duì)應(yīng)的表結(jié)果字段名稱、類型、備注信息,這些關(guān)鍵信息將用于后續(xù)進(jìn)行代碼生成器所使用!
- # 獲取對(duì)應(yīng)表結(jié)構(gòu)
- SELECT column_name, data_type, column_comment FROM information_schema.columns WHERE table_schema = 'yjgj_base' AND table_name = 'test_db'
同時(shí),獲取對(duì)應(yīng)表注釋,用于生成備注信息!
- # 獲取對(duì)應(yīng)表注釋
- SELECT TABLE_COMMENT FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = 'yjgj_base' AND table_name = 'test_db'
2.2、編寫模板
編寫mapper.ftl模板,涵蓋新增、修改、刪除、查詢等信息
- <#list columns as pro>
- <#if pro.proName == primaryId>
- <#else>
- #if>
- #list>
- <#list columns as pro>
- <#if pro_index == 0>${pro.fieldName}<#else>,${pro.fieldName}#if>
- #list>
- insert into ${tableName} (
- <#list columns as pro>
- <#if pro_index == 0>${pro.fieldName},<#elseif pro_index == 1>${pro.fieldName}<#else>,${pro.fieldName}#if>
- #list>
- )
- values
- <#list columns as pro>
- ${r"#{obj." + pro.proName + r"}"},
- #list>
- insert into ${tableName}
- <#list columns as pro>
- ${pro.fieldName},
- #list>
- <#list columns as pro>
- ${r"#{" + pro.proName + r",jdbcType=" + pro.fieldType +r"}"},
- #list>
- update ${tableName}
- <#list columns as pro>
- <#if pro.fieldName != primaryId && pro.fieldName != primaryId>
- ${pro.fieldName} = ${r"#{" + pro.proName + r",jdbcType=" + pro.fieldType +r"}"},
- #if>
- #list>
- where ${primaryId} = ${r"#{" + "${primaryId}" + r",jdbcType=BIGINT}"}
- update ${tableName}
- <#list columns as pro>
- <#if pro.fieldName != primaryId && pro.fieldName != primaryId>
- when id = ${r"#{" + "obj.id" + r"}"}
- then ${r"#{obj." + pro.proName + r",jdbcType=" + pro.fieldType +r"}"}
- #if>
- #list>
- where
- id = ${r"#{" + "obj.id" + r"}"}
- delete from ${tableName}
- where ${primaryId} = ${r"#{" + "${primaryId}" + r",jdbcType=BIGINT}"}
- select
- from ${tableName}
- where ${primaryId} = ${r"#{" + "${primaryId}" + r",jdbcType=BIGINT}"}
- select
- from ${tableName}
- select
- from ${tableName}
- and ${primaryId} in
- ${r"#{" + "item" + r"}"}
- select
- from ${tableName}
- select count(${primaryId})
- from ${tableName}
- select
- from ${tableName}
- limit ${r"#{" + "start,jdbcType=INTEGER" + r"}"},${r"#{" + "end,jdbcType=INTEGER" + r"}"}
編寫dao.ftl數(shù)據(jù)訪問模板
- package ${daoPackageName};
- import com.example.generator.core.BaseMapper;
- import java.util.List;
- import ${entityPackageName}.${entityName};
- import ${dtoPackageName}.${dtoName};
- /**
- *
- * @ClassName: ${daoName}
- * @Description: 數(shù)據(jù)訪問接口
- * @author ${authorName}
- * @date ${currentTime}
- *
- */
- public interface ${daoName} extends BaseMapper<${entityName}>{
- int countPage(${dtoName} ${dtoName?uncap_first});
- List<${entityName}> selectPage(${dtoName} ${dtoName?uncap_first});
- }
編寫service.ftl服務(wù)接口模板
- package ${servicePackageName};
- import com.example.generator.core.BaseService;
- import com.example.generator.common.Pager;
- import ${voPackageName}.${voName};
- import ${dtoPackageName}.${dtoName};
- import ${entityPackageName}.${entityName};
- /**
- *
- * @ClassName: ${serviceName}
- * @Description: ${entityName}業(yè)務(wù)訪問接口
- * @author ${authorName}
- * @date ${currentTime}
- *
- */
- public interface ${serviceName} extends BaseService<${entityName}> {
- /**
- * 分頁列表查詢
- * @param request
- */
- Pager<${voName}> getPage(${dtoName} request);
- }
編寫serviceImpl.ftl服務(wù)實(shí)現(xiàn)類模板
- package ${serviceImplPackageName};
- import com.example.generator.common.Pager;
- import com.example.generator.core.BaseServiceImpl;
- import com.example.generator.test.service.TestEntityService;
- import org.springframework.beans.BeanUtils;
- import org.springframework.stereotype.Service;
- import org.springframework.util.CollectionUtils;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import java.util.ArrayList;
- import java.util.List;
- import ${daoPackageName}.${daoName};
- import ${entityPackageName}.${entityName};
- import ${dtoPackageName}.${dtoName};
- import ${voPackageName}.${voName};
- @Service
- public class ${serviceImplName} extends BaseServiceImpl<${daoName}, ${entityName}> implements ${serviceName} {
- private static final Logger log = LoggerFactory.getLogger(${serviceImplName}.class);
- /**
- * 分頁列表查詢
- * @param request
- */
- public Pager<${voName}> getPage(${dtoName} request) {
- List<${voName}> resultList = new ArrayList();
- int count = super.baseMapper.countPage(request);
- List<${entityName}> dbList = count > 0 ? super.baseMapper.selectPage(request) : new ArrayList<>();
- if(!CollectionUtils.isEmpty(dbList)){
- dbList.forEach(source->{
- ${voName} target = new ${voName}();
- BeanUtils.copyProperties(source, target);
- resultList.add(target);
- });
- }
- return new Pager(request.getCurrPage(), request.getPageSize(), count, resultList);
- }
- }
編寫controller.ftl控制層模板
- package ${controllerPackageName};
- import com.example.generator.common.IdRequest;
- import com.example.generator.common.Pager;
- import org.springframework.beans.BeanUtils;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.PostMapping;
- import org.springframework.web.bind.annotation.RequestBody;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
- import java.util.Objects;
- import ${servicePackageName}.${serviceName};
- import ${entityPackageName}.${entityName};
- import ${dtoPackageName}.${dtoName};
- import ${voPackageName}.${voName};
- /**
- *
- * @ClassName: ${controllerName}
- * @Description: 外部訪問接口
- * @author ${authorName}
- * @date ${currentTime}
- *
- */
- @RestController
- @RequestMapping("/${entityName?uncap_first}")
- public class ${controllerName} {
- @Autowired
- private ${serviceName} ${serviceName?uncap_first};
- /**
- * 分頁列表查詢
- * @param request
- */
- @PostMapping(value = "/getPage")
- public Pager<${voName}> getPage(@RequestBody ${dtoName} request){
- return ${serviceName?uncap_first}.getPage(request);
- }
- /**
- * 查詢?cè)斍?/li>
- * @param request
- */
- @PostMapping(value = "/getDetail")
- public ${voName} getDetail(@RequestBody IdRequest request){
- ${entityName} source = ${serviceName?uncap_first}.selectById(request.getId());
- if(Objects.nonNull(source)){
- ${voName} result = new ${voName}();
- BeanUtils.copyProperties(source, result);
- return result;
- }
- return null;
- }
- /**
- * 新增操作
- * @param request
- */
- @PostMapping(value = "/save")
- public void save(${dtoName} request){
- ${entityName} entity = new ${entityName}();
- BeanUtils.copyProperties(request, entity);
- ${serviceName?uncap_first}.insert(entity);
- }
- /**
- * 編輯操作
- * @param request
- */
- @PostMapping(value = "/edit")
- public void edit(${dtoName} request){
- ${entityName} entity = new ${entityName}();
- BeanUtils.copyProperties(request, entity);
- ${serviceName?uncap_first}.updateById(entity);
- }
- /**
- * 刪除操作
- * @param request
- */
- @PostMapping(value = "/delete")
- public void delete(IdRequest request){
- ${serviceName?uncap_first}.deleteById(request.getId());
- }
- }
編寫entity.ftl實(shí)體類模板
- package ${entityPackageName};
- import java.io.Serializable;
- import java.math.BigDecimal;
- import java.util.Date;
- /**
- *
- * @ClassName: ${entityName}
- * @Description: ${tableDes!}實(shí)體類
- * @author ${authorName}
- * @date ${currentTime}
- *
- */
- public class ${entityName} implements Serializable {
- private static final long serialVersionUID = 1L;
- <#--屬性遍歷-->
- <#list columns as pro>
- <#--<#if pro.proName != primaryId
- && pro.proName != 'remarks'
- && pro.proName != 'createBy'
- && pro.proName != 'createDate'
- && pro.proName != 'updateBy'
- && pro.proName != 'updateDate'
- && pro.proName != 'delFlag'
- && pro.proName != 'currentUser'
- && pro.proName != 'page'
- && pro.proName != 'sqlMap'
- && pro.proName != 'isNewRecord'
- >#if>-->
- /**
- * ${pro.proDes!}
- */
- private ${pro.proType} ${pro.proName};
- #list>
- <#--屬性get||set方法-->
- <#list columns as pro>
- public ${pro.proType} get${pro.proName?cap_first}() {
- return this.${pro.proName};
- }
- public ${entityName} set${pro.proName?cap_first}(${pro.proType} ${pro.proName}) {
- this.${pro.proName} = ${pro.proName};
- return this;
- }
- #list>
- }
編寫dto.ftl實(shí)體類模板
- package ${dtoPackageName};
- import com.example.generator.core.BaseDTO;
- import java.io.Serializable;
- /**
- * @ClassName: ${dtoName}
- * @Description: 請(qǐng)求實(shí)體類
- * @author ${authorName}
- * @date ${currentTime}
- *
- */
- public class ${dtoName} extends BaseDTO {
- }
編寫vo.ftl視圖實(shí)體類模板
- package ${voPackageName};
- import java.io.Serializable;
- /**
- * @ClassName: ${voName}
- * @Description: 返回視圖實(shí)體類
- * @author ${authorName}
- * @date ${currentTime}
- *
- */
- public class ${voName} implements Serializable {
- private static final long serialVersionUID = 1L;
- }
可能細(xì)心的網(wǎng)友已經(jīng)看到了,在模板中我們用到了BaseMapper、BaseService、BaseServiceImpl等等服務(wù)類。
之所以有這三個(gè)類,是因?yàn)樵谀0逯?,我們有大量的相同的方法名包括邏輯也相似,除了所在?shí)體類不一樣以外,其他都一樣,因此我們可以借助泛型類來將這些服務(wù)抽成公共的部分。
BaseMapper,主要負(fù)責(zé)將dao層的公共方法抽出來
- package com.example.generator.core;
- import org.apache.ibatis.annotations.Param;
- import java.io.Serializable;
- import java.util.List;
- import java.util.Map;
- /**
- * @author pzblog
- * @Description
- * @since 2020-11-11
- */
- public interface BaseMapper
{ - /**
- * 批量插入
- * @param list
- * @return
- */
- int insertList(@Param("list") List
list); - /**
- * 按需插入一條記錄
- * @param entity
- * @return
- */
- int insertPrimaryKeySelective(T entity);
- /**
- * 按需修改一條記錄(通過主鍵ID)
- * @return
- */
- int updatePrimaryKeySelective(T entity);
- /**
- * 批量按需修改記錄(通過主鍵ID)
- * @param list
- * @return
- */
- int updateBatchByIds(@Param("list") List
list); - /**
- * 根據(jù)ID刪除
- * @param id 主鍵ID
- * @return
- */
- int deleteByPrimaryKey(Serializable id);
- /**
- * 根據(jù)ID查詢
- * @param id 主鍵ID
- * @return
- */
- T selectByPrimaryKey(Serializable id);
- /**
- * 按需查詢
- * @param entity
- * @return
- */
- List
selectByPrimaryKeySelective(T entity); - /**
- * 批量查詢
- * @param ids 主鍵ID集合
- * @return
- */
- List
selectByIds(@Param("ids") List extends Serializable> ids); - /**
- * 查詢(根據(jù) columnMap 條件)
- * @param columnMap 表字段 map 對(duì)象
- * @return
- */
- List
selectByMap(Map columnMap); - }
BaseService,主要負(fù)責(zé)將service層的公共方法抽出來
- package com.example.generator.core;
- import java.io.Serializable;
- import java.util.List;
- import java.util.Map;
- /**
- * @author pzblog
- * @Description 服務(wù)類
- * @since 2020-11-11
- */
- public interface BaseService
{ - /**
- * 新增
- * @param entity
- * @return boolean
- */
- boolean insert(T entity);
- /**
- * 批量新增
- * @param list
- * @return boolean
- */
- boolean insertList(List
list); - /**
- * 通過ID修改記錄(如果想全部更新,只需保證字段都不為NULL)
- * @param entity
- * @return boolean
- */
- boolean updateById(T entity);
- /**
- * 通過ID批量修改記錄(如果想全部更新,只需保證字段都不為NULL)
- * @param list
- * @return boolean
- */
- boolean updateBatchByIds(List
list); - /**
- * 根據(jù)ID刪除
- * @param id 主鍵ID
- * @return boolean
- */
- boolean deleteById(Serializable id);
- /**
- * 根據(jù)ID查詢
- * @param id 主鍵ID
- * @return
- */
- T selectById(Serializable id);
- /**
- * 按需查詢
- * @param entity
- * @return
- */
- List
selectByPrimaryKeySelective(T entity); - /**
- * 批量查詢
- * @param ids
- * @return
- */
- List
selectByIds(List extends Serializable> ids); - /**
- * 根據(jù)條件查詢
- * @param columnMap
- * @return
- */
- List
selectByMap(Map columnMap); - }
BaseServiceImpl,service層的公共方法具體實(shí)現(xiàn)類
- package com.example.generator.core;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.transaction.annotation.Transactional;
- import java.io.Serializable;
- import java.util.List;
- import java.util.Map;
- /**
- * @author pzblog
- * @Description 實(shí)現(xiàn)類( 泛型說明:M 是 mapper 對(duì)象,T 是實(shí)體)
- * @since 2020-11-11
- */
- public abstract class BaseServiceImpl
, T> implements BaseService { - @Autowired
- protected M baseMapper;
- /**
- * 新增
- * @param entity
- * @return boolean
- */
- @Override
- @Transactional(rollbackFor = {Exception.class})
- public boolean insert(T entity){ 當(dāng)前題目:你還在手寫crud嗎,看完這篇文章,絕對(duì)賺了
分享網(wǎng)址:http://www.fisionsoft.com.cn/article/djocoep.html


咨詢
建站咨詢
