SpringBoot代碼生成器,讓你釋放雙手,從此不用手擼代碼
前言
通常在開始開發項目的時候,首先會建立好數據庫相關表,然后根據表結構生成 Controller、Service、DAO、Model以及一些前端頁面。
如果開發前沒有強制的約束,而每個程序員都有自己的編碼習慣,最終會導致一個項目呈現出多種編碼風格。再有就是一些CRUD的列表功能,基本是沒啥挑戰性的,純粹苦力活,浪費時間。
所以,根據公司現有框架,開發一款統一風格的代碼生成器還是很有必要的。
技術選型
開發框架:SpringBoot+JPA,考慮到會生成各種前后端代碼文件,這里我們選用freemarker模板引擎來制作相應的模板。
實現思路
獲取表結構信息
首先我們定義一個實體類,為了使用方便,把表和字段信息放到了一個類中:
- /**
- * 表以及相關字段信息
- */
- @Data
- public class AppGen extends PageBean implements Serializable {
- /**
- * 表名
- */
- private String tableName;
- /**
- * 實體類名
- */
- private String entityName;
- /**
- * 實體類名 首字母小寫
- */
- private String lowerEntityName;
- /**
- * 表備注
- */
- private String tableComment;
- /**
- * 表前綴
- */
- private String prefix;
- /**
- * 功能描述
- */
- private String function;
- /**
- * 列名
- */
- private String columnName;
- /**
- * 實體列名
- */
- private String entityColumnName;
- /**
- * 列描述
- */
- private String columnComment;
- /**
- * 類型
- */
- private String dataType;
- /**
- * 自增
- */
- private Object columnExtra;
- /**
- * 長度
- */
- private Object columnLength;
- private List<AppGen> list;
- }
獲取表列表:
- @Override
- @Transactional(readOnly = true)
- public Result list(AppGen gen){
- String countSql = "SELECT COUNT(*) FROM information_schema.tables ";
- countSql +="WHERE table_schema='tools'";
- Long totalCount = dynamicQuery.nativeQueryCount(countSql);
- PageBean<AppGen> data = new PageBean<>();
- if(totalCount>0){
- String nativeSql = "SELECT table_name as tableName,table_comment as tableComment ";
- nativeSql+="FROM information_schema.tables WHERE table_schema='tools'";
- Pageable pageable = PageRequest.of(gen.getPageNo(),gen.getPageSize());
- List<AppGen> list = dynamicQuery.nativeQueryPagingListModel(AppGen.class,pageable, nativeSql);
- data = new PageBean<>(list, totalCount);
- }
- return Result.ok(data);
- }

制作模板
模板太多了,這里只以Controller模板為例,貼一下實現代碼,更多模板見源碼:
- package com.tools.module.${prefix}.web;
- import com.tools.common.config.AbstractController;
- import com.tools.common.model.Result;
- import com.tools.module.${prefix}.entity.${entityName};
- import com.tools.module.${prefix}.service.${entityName}Service;
- 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;
- @RestController
- @RequestMapping("/${prefix}/${function}")
- public class ${entityName}Controller extends AbstractController {
- @Autowired
- private ${entityName}Service ${function}Service;
- /**
- * 列表
- */
- @PostMapping("/list")
- public Result list(${entityName} ${function}){
- return ${function}Service.list(${function});
- }
- /**
- * 查詢
- */
- @PostMapping("/get")
- public Result get(Long id){
- return ${function}Service.get(id);
- }
- /**
- * 保存
- */
- @PostMapping("/save")
- public Result save(@RequestBody ${entityName} ${function}){
- return ${function}Service.save(${function});
- }
- /**
- * 刪除
- */
- @PostMapping("/delete")
- public Result delete(Long id){
- return ${function}Service.delete(id);
- }
- }
說白了其實就是傳遞參數,把一些可變的代碼片段使用${name}形式編寫。
代碼生成
有點長,慢慢看,其實就是渲染各種前后端模板:
- /**
- * 生成代碼
- * @param gen
- * @return
- * @throws IOException
- * @throws TemplateException
- */
- @PostMapping("/create")
- public Result create(@RequestBody AppGen gen) throws IOException, TemplateException {
- /**
- * 獲取表字段以及注釋
- */
- List<AppGen> list = genService.getByTable(gen);
- String name = gen.getTableName();
- String[] table = StringUtils.split(name,"_");
- gen.setPrefix(table[0]);
- gen.setFunction(table[1]);
- gen.setEntityName(GenUtils.allInitialCapital(gen.getTableName()));
- list.stream().forEach(column-> {
- column.setEntityColumnName(GenUtils.secInitialCapital(column.getColumnName()));
- });
- gen.setList(list);
- String baseFile = filePath+ SystemConstant.SF_FILE_SEPARATOR+"com"+
- SystemConstant.SF_FILE_SEPARATOR+ "tools"+
- SystemConstant.SF_FILE_SEPARATOR+ "module"+
- SystemConstant.SF_FILE_SEPARATOR+ gen.getPrefix()+SystemConstant.SF_FILE_SEPARATOR;
- /**
- * 后端代碼
- */
- File entityFile = FileUtil.touch(baseFile+"entity"+
- SystemConstant.SF_FILE_SEPARATOR+gen.getEntityName()+".java");
- File repositoryFile = FileUtil.touch(baseFile+"repository"+
- SystemConstant.SF_FILE_SEPARATOR+gen.getEntityName()+"Repository.java");
- File serviceFile = FileUtil.touch(baseFile+"service"+
- SystemConstant.SF_FILE_SEPARATOR+gen.getEntityName()+"Service.java");
- File serviceImplFile = FileUtil.touch(baseFile+"service"+
- SystemConstant.SF_FILE_SEPARATOR+"impl"+SystemConstant.SF_FILE_SEPARATOR+
- gen.getEntityName()+"ServiceImpl.java");
- File controllerFile = FileUtil.touch(baseFile+"web"+
- SystemConstant.SF_FILE_SEPARATOR + gen.getEntityName() + "Controller.java");
- /**
- * 前端代碼
- */
- String htmlPath = filePath+
- SystemConstant.SF_FILE_SEPARATOR + "templates"+
- SystemConstant.SF_FILE_SEPARATOR + gen.getPrefix()+
- SystemConstant.SF_FILE_SEPARATOR + gen.getFunction()+SystemConstant.SF_FILE_SEPARATOR;
- File listFile = FileUtil.touch(htmlPath + "list.html");
- File formFile = FileUtil.touch(htmlPath + "form.html");
- /**
- * 生成靜態頁面
- */
- Template template = configuration.getTemplate("html/list.ftl");
- String text = FreeMarkerTemplateUtils.processTemplateIntoString(
- template, gen);
- FileUtil.writeString(text,listFile,"UTF-8");
- template = configuration.getTemplate("html/form.ftl");
- text = FreeMarkerTemplateUtils.processTemplateIntoString(
- template, gen);
- FileUtil.writeString(text,formFile,"UTF-8");
- /**
- * 生成后端代碼 repository
- */
- template = configuration.getTemplate("java/repository.ftl");
- text = FreeMarkerTemplateUtils.processTemplateIntoString(
- template, gen);
- FileUtil.writeString(text,repositoryFile,"UTF-8");
- /**
- * 生成后端代碼 entity
- */
- template = configuration.getTemplate("java/entity.ftl");
- text = FreeMarkerTemplateUtils.processTemplateIntoString(
- template, gen);
- FileUtil.writeString(text,entityFile,"UTF-8");
- /**
- * 生成后端代碼 service
- */
- template = configuration.getTemplate("java/service.ftl");
- text = FreeMarkerTemplateUtils.processTemplateIntoString(
- template, gen);
- FileUtil.writeString(text,serviceFile,"UTF-8");
- /**
- * 生成后端代碼 service 實現
- */
- template = configuration.getTemplate("java/serviceImpl.ftl");
- text = FreeMarkerTemplateUtils.processTemplateIntoString(
- template, gen);
- FileUtil.writeString(text,serviceImplFile,"UTF-8");
- /**
- * 生成后端代碼 controller 實現
- */
- template = configuration.getTemplate("java/controller.ftl");
- text = FreeMarkerTemplateUtils.processTemplateIntoString(
- template, gen);
- FileUtil.writeString(text,controllerFile,"UTF-8");
- return Result.ok();
- }
生成邏輯還是很傻瓜的,后期會慢慢優化,比如根據字段類型生成不同的表單形式,可以自定義字段是否顯示等的。
小結
總的來說,還是比較容易上手的,相對于一些簡單的列表功能分分鐘擼出效果,開發一分鐘,喝茶一整天。當然對于一些復雜的效果,還是自己一一去實現,但這并不影響生成器的實用性。
源碼
https://gitee.com/52itstyle/SPTools