📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗
🌻 CSDN入驻不久,希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数,欢迎多多交流。👍
写在前面的话
本系列博文已连载到第九篇,看过前面几篇系列文章,应该发现了,博主在创建完教师信息表后,若干前后端核心代码基本都使用代码生成器生成,手敲代码却是甚少,本篇文章就介绍一下,如何在日常工作借助代码生成器快速开发。
关联文章:
《程序猿入职必会(1) · 搭建拥有数据交互的 SpringBoot 》
《程序猿入职必会(2) · 搭建具备前端展示效果的 Vue》
《程序猿入职必会(3) · SpringBoot 各层功能完善 》
《程序猿入职必会(4) · Vue 完成 CURD 案例 》
《程序猿入职必会(5) · CURD 页面细节规范 》
《程序猿入职必会(6) · 返回结果统一封装》
《程序猿入职必会(7) · 前端请求工具封装》
《程序猿入职必会(8) · 整合 Knife4j 接口文档》
代码生成器简介
代码生成器是一种开发工具,可以帮助开发者快速生成重复性高的代码,从而极大地提高开发效率,尤其是在需要重复生成相似代码的场景中。
日常开发过程中,重复性工作最大的,无非是各个业务表对应的各层业务代码,都有各自的基础增删改查业务,这其中涉及的前后端代码,基本代码都相似,也就是程序猿日常的拧螺丝
工作。
通常在软件公司中,针对前后端开发,都有封装相关核心框架,相应的,各层业务代码也都有相应规约,比如后端 Spring 开发常见的 Controller、Service、Mapper、Entity、SqlXml,前端 Vue 开发常见的 Page.vue、Api.js。因此,一款优秀的代码生成器应该具备与框架结合的能力,即模板自定义功能。
常见代码生成器
先列举一些常见的代码生成器产品。
**1. MyBatis Generator **
简介:MyBatis Generator 是一个用于生成 MyBatis 和 MyBatis 相关代码的工具,这是 MyBatis 官方提供的代码生成器,主要用于生成 MyBatis 的 Mapper 接口和 XML 文件。它支持自定义模板,可以很好地与 Spring Boot 集成。
特点:
- 支持 XML 和注解配置。
- 可以生成实体类、Mapper 接口、XML 映射文件等。
- 可以通过自定义模板来适应公司的代码风格。
适用场景:适合使用 MyBatis 的项目,尤其是需要快速生成数据库操作代码的场景。
2. JHipster
简介:JHipster 是一个开发平台,用于生成、开发和部署 Spring Boot + Angular/React/Vue 的 Web 应用程序,一个全栈式代码生成器,可以生成完整的 Web 应用程序,包括前后端代码。
特点:
- 提供了丰富的生成选项,可以生成完整的应用程序架构。
- 支持自定义生成模板。
- 集成了多种前端框架和后端技术。
适用场景:适合需要快速搭建全栈应用的项目。
3. Spring Roo
简介:Spring Roo 是一个快速开发框架,能够通过命令行生成 Spring 应用程序的代码。提供了一个命令行界面,可以快速生成CRUD操作、数据库访问层等。
特点:
- 支持快速生成 Spring MVC、Spring Data JPA 等代码。
- 可以通过自定义模板来适应特定需求。
适用场景:适合使用 Spring 技术栈的项目。
4. Rapid-Generator(√)
简介:Rapid-Generator 是一个轻量级的代码生成器,支持多种模板引擎(如 FreeMarker、Velocity)。这是一个非常强大的代码生成器工具,可以根据数据库表结构自动生成 CRUD 代码、DTO、Mapper 等,它支持自定义模板,可以很好地与 Spring Boot、MyBatis 等框架集成,使用起来非常方便,是很多公司的首选。
特点:
- 提供了简单易用的命令行界面。
- 支持自定义模板,可以根据公司需求进行调整。
- 适合快速生成 CRUD 代码。
适用场景:适合需要快速生成代码的项目,尤其是 CRUD 操作。
- CodeSmith
简介:CodeSmith 是一个强大的代码生成器,支持多种编程语言和框架。这是一个强大的代码生成工具,支持多种编程语言和数据库。它提供了强大的模板功能,用户可以创建复杂的代码模板来生成代码。
特点:
- 提供了丰富的模板库,可以根据需要进行自定义。
- 支持与多种数据库和 ORM 框架集成。
适用场景:适合需要生成大量重复代码的项目。
6. Yeoman
简介:Yeoman 是一个前端工具,能够生成项目的骨架代码。一个基于 Node.js 的生成工具,可以用于生成各种类型的项目,包括前端和后端项目。
特点:
- 提供了丰富的生成器,可以快速生成前端项目结构。
- 支持自定义生成器。
适用场景:适合前端开发,尤其是需要快速搭建项目的场景。
自定义能力说明
大多数代码生成器允许你自定义模板。这通常是必要的,因为每个公司的框架和编码规范都有所不同。自定义模板可以确保生成的代码符合你的特定需求。模板通常使用模板引擎(如Freemarker或Velocity)来编写,它们允许你以编程方式创建代码结构,并根据数据库模型动态填充内容。
实战效果说明
Tips:上面介绍了若干代码生成器,都是优秀的产品,其实也没必要去纠结使用哪个,能解决自己的需要即可。
选择合适的代码生成器主要取决于你的项目需求、技术栈以及团队的开发习惯。无论选择哪个工具,通常都需要根据公司的代码规范和框架进行模板的自定义,以确保生成的代码符合团队的标准。
博主的项目采用 Rapid-Generator ,它是一个不错的选择,尤其是在需要快速生成 CRUD 代码的场景中。
【确定要生成的文件范围】
要生成的文件包含但不限于:controller、service、mapper、xml、entity、api.js、page.vue
【编辑模板思路】
要快速生成上面一系列的代码,核心就是模板制作。
先以控制层代码做一个示例说明,下方是模板示例。
- 先根据自身框架,手写实现一个业务表对应的增删改查逻辑,包括前后端,包装功能可用;
- 将对应代码贴到模板文件中,将动态部分用相关变量替换;
- 创建表后,测试生成效果;
<#assign className = table.className>
<#assign classNameLower = className?uncap_first>
<#assign table_chn = table.remarks>
<#assign pkColumn = table.pkColumn>
<#assign pkColumnName = table.pkColumn.columnName>
<#assign pkColumnNameLower = table.pkColumn.columnNameLower>
package ${basepackage}.web<#if nextPackageFileUrl != "">.${nextPackageFileUrl}</#if>;
import ${basepackage}.common.utils.IdUtils;
import ${basepackage}.common.web.anno.Required;
import ${basepackage}.common.base.BaseController;
import ${basepackage}.common.vo.PageInfo;
import ${basepackage}.entity<#if nextPackageFileUrl != "">.${nextPackageFileUrl}</#if>.${className};
import ${basepackage}.service<#if nextPackageFileUrl != "">.${nextPackageFileUrl}</#if>.${className}Service;
import com.lw.sbdemo2.common.web.anno.ResultController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.List;
/**
* <p>标题: ${table_chn}服务 - 请求控制层</p>
* <p>描述: </p>
* <p>版权: Copyright (c) ${now?string('yyyy')}</p>
* <p>公司: 山人行工作室</p>
*
* @version: 1.0
* @author: ${author}
* @date ${now?date}
*/
@ResultController
@Api(value = "${className}Controller", tags = {"${table_chn}服务"})
@RequestMapping(value = "/<#if nextPackageApiUrl != "">${nextPackageApiUrl}/</#if>${classNameLower}")
public class ${className}Controller extends BaseController {
/**
* ${table_chn}服务
*/
@Autowired
private ${className}Service ${classNameLower}Service;
@ApiOperation(value = "获取${table_chn}列表")
@GetMapping("")
public List<${className}> findList(${className} ${classNameLower}) {
return ${classNameLower}Service.findList(${classNameLower});
}
@ApiOperation(value = "获取${table_chn}列表(分页)", response = PageInfo.class)
@ApiImplicitParams({
@ApiImplicitParam(name = "query", value = "关键词", dataType = "string"),
@ApiImplicitParam(name = "pageNum", value = "当前页码", required = true, dataType = "int"),
})
@GetMapping(value = "/page")
public PageInfo<${className}> page(String query, @Required("pageNum") PageInfo pageInfo, ${className} ${classNameLower}) {
return ${classNameLower}Service.findListPage(query, pageInfo, ${classNameLower});
}
@ApiOperation(value = "获取${table_chn}详细信息", notes = "根据url的id来获取${table_chn}详细信息")
@ApiImplicitParam(name = "id", value = "${table_chn}ID", required = true, dataType = "String")
@GetMapping("/{id}")
public ${className} get(@PathVariable String id) {
return ${classNameLower}Service.getById(id);
}
@ApiOperation(value = "创建${table_chn}")
@PostMapping("/insert")
public void insert(${className} ${classNameLower}) {
<#list table.columns as column>
<#if column.sqlName == 'CREATED_TIME'>
${classNameLower}.setCreatedTime(new Date());
</#if>
</#list>
${classNameLower}.set${pkColumnName}(IdUtils.uuid());
${classNameLower}Service.insert(${classNameLower});
}
@ApiOperation(value = "更新${table_chn}详细信息")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "${table_chn}ID", required = true, paramType = "query", dataType = "String")
})
@PostMapping("/update")
public void update(${className} ${classNameLower}) {
<#list table.columns as column>
<#if column.sqlName == 'MODIFIED_TIME'>
${classNameLower}.setModifiedTime(new Date());
</#if>
</#list>
${classNameLower}Service.update(${classNameLower});
}
@ApiOperation(value = "删除${table_chn}", notes = "删除${table_chn}")
@ApiImplicitParam(name = "id", value = "${table_chn}ID", required = true, paramType = "query", dataType = "String")
@PostMapping("/delete")
public void delete${className}(${className} ${classNameLower}) {
${classNameLower}Service.delete(${classNameLower});
}
}
【修改配置文件】
调整 generator.xml 配置文件,配置代码生成器相关属性。
<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<!-- 包路径前缀com.zoe.optimus.service.模块名 -->
<entry key="basepackage">com.lw.sbdemo2</entry>
<!-- 项目模块名 已basepackage的模块名一致 -->
<entry key="m_eng"></entry>
<!-- 该表所在的包名称 用于文件路径-->
<entry key="nextPackageFileUrl"></entry>
<!-- 该表所在的包名称 用于api路径 -->
<entry key="nextPackageApiUrl"></entry>
<!-- 该表所在的包名称 用于bean别名 -->
<entry key="nextPackageBean"></entry>
<!-- 是否是字典 1;是,0:不是 -->
<entry key="is_dict">0</entry>
<!-- 显示在java文件里的中文名字 -->
<entry key="table_chn">床头卡信息表</entry>
<!-- 显示在java文件里的author -->
<entry key="author">ZhanShen</entry>
<entry key="namespace">WEB-INF/template</entry>
<entry key="outRoot">.\generator-output</entry>
<!-- 数据库类型映射 -->
<entry key="java_typemapping.java.sql.Timestamp">java.util.Date</entry>
<entry key="java_typemapping.java.sql.Date">java.util.Date</entry>
<entry key="java_typemapping.java.sql.Time">java.util.Date</entry>
<entry key="java_typemapping.java.lang.Byte">Integer</entry>
<entry key="java_typemapping.java.lang.Short">Integer</entry>
<entry key="java_typemapping.java.math.BigDecimal">Long</entry>
<entry key="java_typemapping.java.sql.Clob">String</entry>
<entry key="java_typemapping.java.sql.Blob">byte[]</entry>
<!-- Mysql -->
<entry key="jdbc_url"></entry>
<entry key="jdbc_driver"></entry>
<entry key="jdbc_username"></entry>
<entry key="jdbc_password"></entry>
</properties>
【生成演示】
进入主目录,输入cmd,打开命令窗口
输入相关的表,输入:gen 表名
,即可生成相应代码,拷贝到项目中即可。
理想成果是文件导入后,直接可用,不用调整任何代码。
总结陈词
此篇文章介绍了代码生成器
的基础运用,仅供学习参考。
选择合适的代码生成器需要据公司框架、业务需求和团队的技术水平进行综合考虑,建议根据实际情况选择合适的代码生成器,并进行必要的自定义和测试。
💗 后续会逐步分享企业实际开发中的实战经验,有需要交流的可以联系博主。