数据库脚本
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mp_generator` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `mp_generator`;
CREATE TABLE `mp_user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
`username` varchar(50) DEFAULT NULL COMMENT '用户名',
`age` tinyint(10) DEFAULT NULL COMMENT '年龄',
`sex` tinyint(1) DEFAULT NULL COMMENT '性别 0 男 1 女',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `mp_user`(`id`, `username`, `age`, `sex`) VALUES (1, '张三', 14, 0);
INSERT INTO `mp_user`(`id`, `username`, `age`, `sex`) VALUES (2, '李四', 15, 1);
INSERT INTO `mp_user`(`id`, `username`, `age`, `sex`) VALUES (3, '张美美', 13, 1);
INSERT INTO `mp_user`(`id`, `username`, `age`, `sex`) VALUES (4, '鲁班七号', 16, 0);
INSERT INTO `mp_user`(`id`, `username`, `age`, `sex`) VALUES (5, '上官婉儿', 17, 1);
INSERT INTO `mp_user`(`id`, `username`, `age`, `sex`) VALUES (6, '甄姬', 18, 1);
INSERT INTO `mp_user`(`id`, `username`, `age`, `sex`) VALUES (7, NULL, NULL, NULL);
添加依赖
- 添加
Spring Boot Web
依赖<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
- 添加
Lombok
依赖<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> <scope>provided</scope> </dependency>
- 添加
MyBatis-Plus
依赖<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.0</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.4.0</version> </dependency> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> </dependency>
- 添加
数据库
依赖<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.49</version> </dependency>
- 添加
javaformat代码美化
插件<plugin> <groupId>io.spring.javaformat</groupId> <artifactId>spring-javaformat-maven-plugin</artifactId> <version>0.0.25</version> </plugin>
Spring Boot 配置
在 src/main/resources
目录下创建名为 application.yml
文件
spring:
application:
name: mybatis-plus-generator
main:
allow-bean-definition-overriding: true
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/mp_generator?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false
username: root
password: 123456
hikari:
minimum-idle: 5
idle-timeout: 600000
maximum-pool-size: 10
auto-commit: true
pool-name: MyHikariCP
max-lifetime: 1800000
connection-timeout: 30000
connection-test-query: SELECT 1
代码模版
ORM 映射文件
在 src/main/resources/templates
目录下创建名为 mapper.xml.ftl
文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="${package.Mapper}.${table.mapperName}">
<#if enableCache>
<cache type="org.mybatis.caches.ehcache.LoggingEhcache"/>
</#if>
<#if baseResultMap>
<resultMap id="BaseResultMap" type="${package.Entity}.${entity}">
<#list table.fields as field>
<#if field.keyFlag>
<#--生成主键排在第一位-->
<id column="${field.name}" property="${field.propertyName}" />
</#if>
</#list>
<#list table.commonFields as field>
<#--生成公共字段 -->
<result column="${field.name}" property="${field.propertyName}" />
</#list>
<#list table.fields as field>
<#if !field.keyFlag>
<#--生成普通字段 -->
<result column="${field.name}" property="${field.propertyName}" />
</#if>
</#list>
</resultMap>
</#if>
<#if baseColumnList>
<sql id="Base_Column_List">
<#list table.commonFields as field>
${field.name},
</#list>
${table.fieldNames}
</sql>
</#if>
</mapper>
数据访问接口
在 src/main/resources/templates
目录下创建名为 mapper.java.ftl
文件
package ${package.Mapper};
import ${package.Entity}.${entity};
import ${superMapperClassPackage};
/**
* <p>
* ${table.comment!} Mapper 接口
* </p>
*
* @author ${author}
* @since ${date}
*/
<#if kotlin>
interface ${table.mapperName} : ${superMapperClass}<${entity}>
<#else>
public interface ${table.mapperName} extends ${superMapperClass}<${entity}> {
}
</#if>
领域模型
在 src/main/resources/templates
目录下创建名为 entity.java.ftl
文件
package ${package.Entity};
<#list table.importPackages as pkg>
import ${pkg};
</#list>
<#if swagger2>
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
</#if>
<#if entityLombokModel>
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
</#if>
/**
* <p>
* ${table.comment!}
* </p>
*
* @author ${author}
* @since ${date}
*/
<#if entityLombokModel>
@Data
<#if superEntityClass??>
@EqualsAndHashCode(callSuper = true)
<#else>
@EqualsAndHashCode(callSuper = false)
</#if>
@Accessors(chain = true)
</#if>
<#if table.convert>
@TableName("${table.name}")
</#if>
<#if swagger2>
@ApiModel(value="${entity}对象", description="${table.comment!}")
</#if>
<#if superEntityClass??>
public class ${entity} extends ${superEntityClass}<#if activeRecord><${entity}></#if> {
<#elseif activeRecord>
public class ${entity} extends Model<${entity}> {
<#else>
public class ${entity} implements Serializable {
</#if>
<#if entitySerialVersionUID>
private static final long serialVersionUID = 1L;
</#if>
<#-- ---------- BEGIN 字段循环遍历 ---------->
<#list table.fields as field>
<#if field.keyFlag>
<#assign keyPropertyName="${field.propertyName}"/>
</#if>
<#if field.comment!?length gt 0>
<#if swagger2>
@ApiModelProperty(value = "${field.comment}")
<#else>
/**
* ${field.comment}
*/
</#if>
</#if>
<#if field.keyFlag>
<#-- 主键 -->
<#if field.keyIdentityFlag>
@TableId(value = "${field.name}", type = IdType.ASSIGN_ID)
<#elseif idType??>
@TableId(value = "${field.name}", type = IdType.${idType})
<#elseif field.convert>
@TableId("${field.name}")
</#if>
<#-- 普通字段 -->
<#elseif field.fill??>
<#-- ----- 存在字段填充设置 ----->
<#if field.convert>
@TableField(value = "${field.name}", fill = FieldFill.${field.fill})
<#else>
@TableField(fill = FieldFill.${field.fill})
</#if>
<#elseif field.convert>
@TableField("${field.name}")
</#if>
<#-- 乐观锁注解 -->
<#if (versionFieldName!"") == field.name>
@Version
</#if>
<#-- 逻辑删除注解 -->
<#if (logicDeleteFieldName!"") == field.name>
@TableLogic
</#if>
private ${field.propertyType} ${field.propertyName};
</#list>
<#------------ END 字段循环遍历 ---------->
<#if !entityLombokModel>
<#list table.fields as field>
<#if field.propertyType == "boolean">
<#assign getprefix="is"/>
<#else>
<#assign getprefix="get"/>
</#if>
public ${field.propertyType} ${getprefix}${field.capitalName}() {
return ${field.propertyName};
}
<#if entityBuilderModel>
public ${entity} set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
<#else>
public void set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
</#if>
this.${field.propertyName} = ${field.propertyName};
<#if entityBuilderModel>
return this;
</#if>
}
</#list>
</#if>
<#if entityColumnConstant>
<#list table.fields as field>
public static final String ${field.name?upper_case} = "${field.name}";
</#list>
</#if>
<#if activeRecord>
@Override
protected Serializable pkVal() {
<#if keyPropertyName??>
return this.${keyPropertyName};
<#else>
return null;
</#if>
}
</#if>
<#if !entityLombokModel>
@Override
public String toString() {
return "${entity}{" +
<#list table.fields as field>
<#if field_index==0>
"${field.propertyName}=" + ${field.propertyName} +
<#else>
", ${field.propertyName}=" + ${field.propertyName} +
</#if>
</#list>
"}";
}
</#if>
}
业务逻辑接口
在 src/main/resources/templates
目录下创建名为 service.java.ftl
文件
package ${package.Service};
import com.baomidou.mybatisplus.core.metadata.IPage;
import ${package.Entity}.${entity};
import ${superServiceClassPackage};
/**
* <p>
* ${table.comment!} 服务类
* </p>
*
* @author ${author}
* @since ${date}
*/
<#if kotlin>
interface ${table.serviceName} : ${superServiceClass}<${entity}>
<#else>
public interface ${table.serviceName} extends ${superServiceClass}<${entity}> {
/**
* 新增
* @param ${entity?uncap_first} {@link ${entity}}
* @return {@code boolean}
*/
boolean create(${entity} ${entity?uncap_first});
/**
* 删除
* @param id {@code Long}
* @return {@code boolean}
*/
boolean remove(Long id);
/**
* 编辑
* @param ${entity?uncap_first} {@link ${entity}}
* @return {@code boolean}
*/
boolean update(${entity} ${entity?uncap_first});
/**
* 获取
* @param id {@code Long}
* @return {@link ${entity}}
*/
${entity} get(Long id);
/**
* 分页
* @param current {@code int} 页码
* @param size {@code int} 笔数
* @param ${entity?uncap_first} {@link ${entity}}
* @return {@code IPage<${entity}>}
*/
IPage<${entity}> page(int current, int size, ${entity} ${entity?uncap_first});
}
</#if>
业务逻辑实现
在 src/main/resources/templates
目录下创建名为 serviceImpl.java.ftl
文件
package ${package.ServiceImpl};
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import ${package.Entity}.${entity};
import ${package.Mapper}.${table.mapperName};
import ${package.Service}.${table.serviceName};
import ${superServiceImplClassPackage};
import org.springframework.stereotype.Service;
/**
* <p>
* ${table.comment!} 服务实现类
* </p>
*
* @author ${author}
* @since ${date}
*/
@Service
<#if kotlin>
open class ${table.serviceImplName} : ${superServiceImplClass}<${table.mapperName}, ${entity}>(), ${table.serviceName} {
}
<#else>
public class ${table.serviceImplName} extends ${superServiceImplClass}<${table.mapperName}, ${entity}> implements ${table.serviceName} {
@Override
public boolean create(${entity} ${entity?uncap_first}) {
return super.save(${entity?uncap_first});
}
@Override
public boolean remove(Long id) {
return super.removeById(id);
}
@Override
public boolean update(${entity} ${entity?uncap_first}) {
return super.updateById(${entity?uncap_first});
}
@Override
public ${entity} get(Long id) {
return super.getById(id);
}
@Override
public IPage<${entity}> page(int current, int size, ${entity} ${entity?uncap_first}) {
Page<${entity}> page = new Page<>(current, size);
LambdaQueryWrapper<${entity}> wrapper = new LambdaQueryWrapper<>();
// TODO 查询
// TODO 排序
return super.page(page, wrapper);
}
}
</#if>
请求处理控制器
在 src/main/resources/templates
目录下创建名为 controller.java.ftl
文件
package ${package.Controller};
import org.springframework.web.bind.annotation.RequestMapping;
<#if restControllerStyle>
import org.springframework.web.bind.annotation.RestController;
<#else>
import org.springframework.stereotype.Controller;
</#if>
<#if superControllerClassPackage??>
import ${superControllerClassPackage};
</#if>
/**
* <p>
* ${table.comment!} 前端控制器
* </p>
*
* @author ${author}
* @since ${date}
*/
<#if restControllerStyle>
@RestController
<#else>
@Controller
</#if>
@RequestMapping("<#if package.ModuleName??>/${package.ModuleName}</#if>/<#if controllerMappingHyphenStyle??>${controllerMappingHyphen}<#else>${table.entityPath}</#if>")
<#if kotlin>
class ${table.controllerName}<#if superControllerClass??> : ${superControllerClass}()</#if>
<#else>
<#if superControllerClass??>
public class ${table.controllerName} extends ${superControllerClass} {
<#else>
public class ${table.controllerName} {
@Resource
private I${entity}Service ${entity?uncap_first}Service;
/**
* 新增
*
* @param ${entity?uncap_first} {@link ${entity}}
* @return {@link ResponseResult}
*/
@PostMapping("create")
public ResponseResult create(@RequestBody ${entity} ${entity?uncap_first}) {
// 业务逻辑
boolean created = ${entity?uncap_first}Service.create(${entity?uncap_first});
if (created) {
return ResponseResult.success("创建成功");
}
return null;
}
/**
* 删除
*
* @param ${entity?uncap_first}Id {@code Long}
* @return {@link ResponseResult}
*/
@DeleteMapping("remove/{${entity?uncap_first}Id}")
public ResponseResult remove(@PathVariable Long ${entity?uncap_first}Id) {
// 业务逻辑
boolean deleted = ${entity?uncap_first}Service.remove(${entity?uncap_first}Id);
if (deleted) {
return ResponseResult.success("删除成功");
}
return null;
}
/**
* 修改
*
* @param ${entity?uncap_first} {@link ${entity}}
* @return {@link ResponseResult}
*/
@PutMapping("update")
public ResponseResult update(@RequestBody ${entity} ${entity?uncap_first}) {
// 业务逻辑
boolean updated = ${entity?uncap_first}Service.update(${entity?uncap_first});
if (updated) {
return ResponseResult.success("编辑成功");
}
return null;
}
/**
* 获取
*
* @param ${entity?uncap_first}Id {@code Long}
* @return {@link ResponseResult}
*/
@GetMapping("get/{${entity?uncap_first}Id}")
public ResponseResult get(@PathVariable Long ${entity?uncap_first}Id) {
${entity} ${entity?uncap_first} = ${entity?uncap_first}Service.get(${entity?uncap_first}Id);
return ResponseResult.success(${entity?uncap_first});
}
/**
* 分页
*
* @param current {@code int} 页码
* @param size {@code int} 笔数
* @return {@link ResponseResult}
*/
@GetMapping("page")
public ResponseResult page(
@RequestParam int current, @RequestParam int size, @ModelAttribute ${entity} ${entity?uncap_first}) {
IPage<${entity}> page = ${entity?uncap_first}Service.page(current, size, ${entity?uncap_first});
return ResponseResult.success(page);
}
</#if>
}
</#if>
代码生成
创建名为 MyBatisPlusGenerator
类
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import java.util.ArrayList;
import java.util.List;
/**
* @ClassName: MyBatisPlusGenerate
* @Auther: Yuu
* @Date: 2020/9/7 15:21
* @Description: MyBatisPlus 代码生成器
*/
public class MyBatisPlusGenerate {
/**
* 作者
*/
private static final String AUTHOR = "Yuu";
/**
* 工作目录
*/
private static final String USER_DIR = System.getProperty("user.dir");
/**
* JDBC 连接地址
*/
private static final String JDBC_URL = "jdbc:mysql://localhost:3306/dict_demo?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false";
/**
* JDBC 驱动程序
*/
private static final String JDBC_DRIVER_NAME = "com.mysql.jdbc.Driver";
/**
* 数据库账号
*/
private static final String JDBC_USERNAME = "root";
/**
* 数据库密码
*/
private static final String JDBC_PASSWORD = "123456";
/**
* 包配置 - 父级目录
*/
private static final String PACKAGE_PARENT = "";
/**
* 包配置 - 模块目录 <br>
* 注意:如果表前缀与模块命相同,生成时会删除前缀,比如:core_admin 最终构建为 Admin, AdminController ...
*/
private static final String PACKAGE_MODULE_NAME = "";
/**
* 包配置 - 实体类目录
*/
private static final String PACKAGE_ENTITY = "domain";
/**
* 包配置 - 数据访问接口目录
*/
private static final String PACKAGE_MAPPER = "mapper";
/**
* 包配置 - 业务处理接口目录
*/
private static final String PACKAGE_SERVICE = "service";
/**
* 包配置 - 业务处理实现目录
*/
private static final String PACKAGE_SERVICE_IMPL = "service.impl";
/**
* 包配置 - 控制器目录
*/
private static final String PACKAGE_CONTROLLER = "controller";
/**
* 要生成的表,用 `,` 分割
*/
private static final String TABLES = "";
/**
* 全局配置
* @return {@link GlobalConfig}
*/
private static GlobalConfig globalConfig() {
GlobalConfig config = new GlobalConfig();
config.setOutputDir(USER_DIR + "/src/main/java");
config.setAuthor(AUTHOR);
config.setOpen(false);
return config;
}
/**
* 数据源配置
* @return {@link DataSourceConfig}
*/
private static DataSourceConfig dataSourceConfig() {
DataSourceConfig config = new DataSourceConfig();
config.setUrl(JDBC_URL);
config.setDriverName(JDBC_DRIVER_NAME);
config.setUsername(JDBC_USERNAME);
config.setPassword(JDBC_PASSWORD);
return config;
}
/**
* 包配置
* @return {@link PackageConfig}
*/
private static PackageConfig packageConfig() {
PackageConfig config = new PackageConfig();
// 你哪个父目录下创建包
config.setParent(PACKAGE_PARENT);
// 设置模块的名字,比如 core,生成效果为 com.qfdmy.core
config.setModuleName(PACKAGE_MODULE_NAME);
// 实体类创建在哪个包
config.setEntity(PACKAGE_ENTITY);
config.setMapper(PACKAGE_MAPPER);
config.setService(PACKAGE_SERVICE);
config.setServiceImpl(PACKAGE_SERVICE_IMPL);
config.setController(PACKAGE_CONTROLLER);
return config;
}
/**
* 代码生成模板配置 - Freemarker
* @return {@link TemplateConfig}
*/
private static TemplateConfig templateConfig() {
TemplateConfig templateConfig = new TemplateConfig();
templateConfig.setEntity("templates/entity.java");
templateConfig.setMapper("templates/mapper.java");
templateConfig.setService("templates/service.java");
templateConfig.setServiceImpl("templates/serviceImpl.java");
templateConfig.setController("templates/controller.java");
templateConfig.setXml(null);
return templateConfig;
}
/**
* 代码生成策略配置
* @return {@link StrategyConfig}
*/
private static StrategyConfig strategyConfig() {
// 策略配置,数据库表配置
StrategyConfig config = new StrategyConfig();
// 数据库表映射到实体的命名策略
config.setNaming(NamingStrategy.underline_to_camel);
// 数据库表字段映射到实体类的命名策略
config.setColumnNaming(NamingStrategy.underline_to_camel);
// 实体是否为 lombok 模型
config.setEntityLombokModel(true);
config.setInclude(TABLES.split(","));
// 驼峰转连字符串
config.setControllerMappingHyphenStyle(true);
// REST 风格
config.setRestControllerStyle(true);
// 表前缀
config.setTablePrefix(packageConfig().getModuleName() + "_");
return config;
}
/**
* 自定义配置
*/
private static InjectionConfig injectionConfig() {
InjectionConfig config = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};
// 自定义输出 mapper.xml 到 resources 目录下
String mapperPath = "/templates/mapper.xml.ftl";
List<FileOutConfig> focList = new ArrayList<>();
// 自定义配置会被优先输出
focList.add(new FileOutConfig(mapperPath) {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
return USER_DIR + "/src/main/resources/mapper/" + tableInfo.getEntityName() + "Mapper"
+ StringPool.DOT_XML;
}
});
config.setFileOutConfigList(focList);
return config;
}
public static void main(String[] args) {
AutoGenerator generator = new AutoGenerator();
generator.setGlobalConfig(globalConfig());
generator.setDataSource(dataSourceConfig());
generator.setPackageInfo(packageConfig());
generator.setTemplate(templateConfig());
generator.setTemplateEngine(new FreemarkerTemplateEngine());
generator.setCfg(injectionConfig());
generator.setStrategy(strategyConfig());
generator.execute();
}
}
代码格式化
使用 javaformat
代码格式化插件格式化成 Spring
风格的代码
通用的数据响应对象
在 commons/response
目录创建 ResponseResult
类
/**
* @ClassName: ResponseResult
* @Auther: Yuu
* @Date: 2020/9/7 21:00
* @Description: 通用的数据响应结果
*/
@Data
public class ResponseResult implements Serializable {
private static final long serialVersionUID = 5907202414434691737L;
/**
* 返回失败状态码
*/
private static final Integer SUCCESS_CODE = 200;
/**
* 返回失败状态码
*/
private static final Integer FAIL_CODE = 500;
/**
* 请求成功默认消息
*/
private static final String SUCCESS_MESSAGE = "请求成功";
/**
* 请求失败默认消息
*/
private static final String FAIL_MESSAGE = "请求失败";
/**
* 状态码
*/
private Integer code;
/**
* 消息
*/
private String message;
/**
* 需要返回的数据对象
*/
private Object data;
/**
* 构造函数
* @param code
* @param message
* @param data
*/
private ResponseResult(Integer code, String message, Object data) {
this.code = code;
this.message = message;
this.data = data;
}
/**
* 返回成功,默认 200,消息:请求成功
* @return
*/
public static ResponseResult success() {
return new ResponseResult(SUCCESS_CODE, SUCCESS_MESSAGE, null);
}
/**
* 返回成功,自定义消息
* @param message
* @return
*/
public static ResponseResult success(String message) {
return new ResponseResult(SUCCESS_CODE, message, null);
}
/**
* 返回成功,自定义数据
* @param data
* @return
*/
public static ResponseResult success(Object data) {
return new ResponseResult(SUCCESS_CODE, SUCCESS_MESSAGE, data);
}
/**
* 返回成功,自定义消息,自定义数据
* @param message
* @param data
* @return
*/
public static ResponseResult success(String message, Object data) {
return new ResponseResult(SUCCESS_CODE, message, data);
}
/**
* 返回失败,默认 500,消息:请求失败
* @return
*/
public static ResponseResult fail() {
return new ResponseResult(FAIL_CODE, FAIL_MESSAGE, null);
}
/**
* 返回失败,自定义消息
* @param message
* @return
*/
public static ResponseResult fail(String message) {
return new ResponseResult(FAIL_CODE, message, null);
}
}
入口类配置
增加 Mapper
包扫描注解
@SpringBootApplication
@MapperScan(basePackages = "com.yuu.boot.mybatis.plus.generator.mp.mapper")
public class MpGeneratorApplication{
public static void main(String[] args) {
SpringApplication.run(MpGeneratorApplication.class, args);
}
}