專門為小白準備的入門級mybatis-plus-generator代碼自動生成器,提高開發效率。值得收藏
- 2022 年 5 月 7 日
- 筆記
- JAVA, springboot
引入依賴
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
<!--糊塗工具包-->
<!-- //mvnrepository.com/artifact/cn.hutool/hutool-core -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
<version>5.7.20</version>
</dependency>
MyBatisPlus提高高度封裝好的代碼生成器模塊,只需要簡單的幾行代碼就能實現。同時也可以根據自己的需求靈活的通過模板話的方式生成代碼。下面我們分別通過這兩種方式來了解一些。
簡單的代碼生成
package com.didiplus;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import org.junit.jupiter.api.Test;
import java.util.Collections;
/**
* Author: didiplus
* Email: [email protected]
* CreateTime: 2022/5/6
* Desc:快速生成
*/
public class FastAutoGeneratorTest {
@Test
public void fastAutoGeneratorTest(){
String url="jdbc:mysql://127.0.0.1:3306/didiadmin?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true";
FastAutoGenerator.create(url,"root","123456")
.globalConfig(builder -> {
builder.author("didiplus") // 設置作者
.enableSwagger() //開啟 swagger 模式
.outputDir("D://autocode");// 指定輸出目錄
})
.packageConfig(builder -> {
builder.parent("com.didiplus.models") // 設置父包名
.moduleName("sys") // 設置父包模塊名
.pathInfo(Collections.singletonMap(OutputFile.xml,"D://autocode/xml"));
})
.strategyConfig(builder -> {
builder.addInclude("sys_dict_data") // 設置需要生成的表名
.addTablePrefix("t_","c_") ; // 設置過濾表前綴
})
// .templateEngine(new FreemarkerTemplateEngine()) 使用Freemarker引擎模板,默認的是Velocity引擎模板
.execute();
}
}
運行以上代碼,會自動的在D盤生成代碼,但是,生成的代碼只是最基本的模板。
以上生成的代碼都是基於MybatisPlus代碼生成默認模板去生成的。適合絕大多數場景。我們也可以根據自己的模板文件去生成代碼的。
自定義模板生成代碼
實現思路
- 從數據庫中讀取表的相關信息和表的相關字段
- 定義相對於的模板文件
- 組裝模板屬性
定義代碼生成常量
這些常量主要用戶後期在組裝模板時,把數據庫類型轉換成Java數據類型需要用到的。
package com.didiplus.constant;
/**
* Author: didiplus
* Email: [email protected]
* CreateTime: 2022/5/6
* Desc: 碼 生 成 通 用 常 量
*/
public class GenerateConstant {
/**
* 數據庫字符串類型
*/
public static final String[] COLUMN_TYPE_STR = {"char", "varchar", "nvarchar", "varchar2", "tinytext", "text", "mediumtext", "longtext"};
/**
* 數據庫時間類型
*/
public static final String[] COLUMN_TYPE_TIME = {"datetime", "time", "date", "timestamp"};
/**
* 數據庫數字類型
*/
public static final String[] COLUMN_TYPE_NUMBER = {"tinyint", "smallint", "mediumint", "int", "number", "integer", "bit"};
/**
* 數據庫bigint類型
*/
public static final String[] COLUMN_TYPE_BIGINT = {"bigint"};
/**
* 數據庫float類型
*/
public static final String[] COLUMN_TYPE_FLOAT = {"float"};
/**
* 數據庫double類型
*/
public static final String[] COLUMN_TYPE_DOUBLE = {"double"};
/**
* 數據庫decimal類型
*/
public static final String[] COLUMN_TYPE_DECIMAL = {"decimal"};
/**
* 字符串類型
*/
public static final String TYPE_STRING = "String";
/**
* 整型
*/
public static final String TYPE_INTEGER = "Integer";
/**
* 長整型
*/
public static final String TYPE_LONG = "Long";
/**
* 浮點型
*/
public static final String TYPE_DOUBLE = "Double";
/**
* 高精度計算類型
*/
public static final String TYPE_BIGDECIMAL = "BigDecimal";
/**
* 時間類型
*/
public static final String TYPE_DATE = "Date";
}
全局配置
/**
* 全局配置
*/
private GlobalConfig.Builder globalConfig() {
String projectPath = System.getProperty("user.dir");
return new GlobalConfig.Builder()
.fileOverride() // 覆蓋已生成文件
.disableOpenDir() // 禁止打開輸出目錄 默認值:true
.author("didiplus") //作者名
.outputDir(projectPath+"/src/main/resources/autocode") // 指定輸出目錄
.enableSwagger(); // 開啟 swagger 模式 默認值:false
}
定義生成代碼模板的路徑
/**
* 模板配置
*/
private TemplateConfig.Builder templateConfig() {
return new TemplateConfig.Builder()
.entity("/templates/vm/entity.java")
.mapper("/templates/vm/mapper.java")
.service("/templates/vm/service.java")
.serviceImpl("/templates/vm/serviceimpl.java")
.controller("/templates/vm/controller.java")
.xml("/templates/vm/mapper.xml");
}
以上的函數是聲明代碼生成根據這些模板去生成對應的模板。
定義各文件生成存儲路徑
/**
* 包配置
*/
private PackageConfig.Builder packageConfig() {
return new PackageConfig.Builder()
.parent(packageName)
.moduleName(moduleName)
.entity("domain.entity")
.mapper("mapper")
.service("service")
.serviceImpl("service.impl")
.xml("mapper.xml")
.controller("controller");
}
數據源配置
/**
* 數據源配置
*/
private static final DataSourceConfig DATA_SOURCE_CONFIG = new DataSourceConfig
.Builder("jdbc:mysql://127.0.0.1:3306/didiadmin?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true","root","123456")
.build();
配置策略
/**
* 策略配置
*/
private StrategyConfig.Builder strategyConfig() {
return new StrategyConfig.Builder()
.addInclude(tableName);
}
組裝模板屬性
/**
* 注入配置
*/
private InjectionConfig.Builder injectionConfig(){
Map<String, Object> map = new HashMap<>();
setAttr(tableName, DATA_SOURCE_CONFIG, map);
return new InjectionConfig.Builder().customMap(map);
}
/**
* 組裝模板屬性
*
* @param tableName 表名
* @param dataSourceConfig 數據源
* @param map 模板裏面 自定義的屬性
* @param 表前綴
*/
private void setAttr(String tableName, DataSourceConfig dataSourceConfig, Map<String, Object> map ){
List<Map<String, Object>> columns = new ArrayList<>();
// 獲取表信息sql
String tableSql = "select table_name , table_comment from information_schema.tables " +
"where table_schema = (select database()) and table_name = '" + tableName + "'";
// 獲取字段信息sql
String columnSql = "select column_name , data_type , column_comment from information_schema.columns " +
"where table_name = '" + tableName + "' and table_schema = (select database()) and column_name != 'id_new'";
// 利用現有的dataSourceConfig來獲取數據庫連接,查詢表字段及備註等信息
try(
Connection conn = dataSourceConfig.getConn();
PreparedStatement psTable = conn.prepareStatement(tableSql);
ResultSet rsTable = psTable.executeQuery();
PreparedStatement pscolumns= conn.prepareStatement(columnSql);
ResultSet rscolumns = pscolumns.executeQuery();
){
if(rsTable.next()){
String table_name = rsTable.getString("table_name");
map.put("tableName",table_name);
map.put("comment",rsTable.getString("table_comment"));
// 類名 大駝峰
map.put("upperClassName", StrUtil.upperFirst(StrUtil.toCamelCase(table_name)));
// 對象名 小駝峰
map.put("lowerClassName",StrUtil.toCamelCase(table_name));
}
while (rscolumns.next()){
Map<String, Object> columnMap = new HashMap<>();
// 列名字、數據類型、java屬性名字、java屬性類型、備註
columnMap.put("column_name",rscolumns.getString("column_name"));
columnMap.put("data_type",rscolumns.getString("data_type"));
columnMap.put("javaLowerAttrName",StrUtil.toCamelCase(rscolumns.getString("column_name")));
columnMap.put("javaAttrType",columnTypeToJavaType(rscolumns.getString("data_type")));
columnMap.put("column_comment", rscolumns.getString("column_comment"));
columns.add(columnMap);
}
} catch (Exception e) {
log.info("----------sql執行出錯");
e.printStackTrace();
}
map.put("columns",columns);
map.put("datetime", DateUtil.now());
map.put("packageName", packageName);
map.put("moduleName", moduleName);
}
/**
* 數據庫類型轉換為java類型
*
* @param columnType 數據庫類型
* @return java類型
*/
private String columnTypeToJavaType(String columnType) {
if(StrUtil.isNotEmpty(columnType)){
if(Arrays.asList(GenerateConstant.COLUMN_TYPE_STR).contains(columnType)){
return GenerateConstant.TYPE_STRING;
}
if(Arrays.asList(GenerateConstant.COLUMN_TYPE_TIME).contains(columnType)){
return GenerateConstant.TYPE_DATE;
}
if (Arrays.asList(GenerateConstant.COLUMN_TYPE_NUMBER).contains(columnType)) {
return GenerateConstant.TYPE_INTEGER;
}
if (Arrays.asList(GenerateConstant.COLUMN_TYPE_BIGINT).contains(columnType)) {
return GenerateConstant.TYPE_LONG;
}
if (Arrays.asList(GenerateConstant.COLUMN_TYPE_FLOAT).contains(columnType)) {
return GenerateConstant.TYPE_DOUBLE;
}
if (Arrays.asList(GenerateConstant.COLUMN_TYPE_DOUBLE).contains(columnType)) {
return GenerateConstant.TYPE_DOUBLE;
}
if (Arrays.asList(GenerateConstant.COLUMN_TYPE_DECIMAL).contains(columnType)) {
return GenerateConstant.TYPE_BIGDECIMAL;
}
}
return null;
}
定義對應的模板文件
在項目的資源文件夾templats
中創建vm
文件夾存放模板文件
entity.java.vm
package ${packageName}.${moduleName}.domain.entity;
#set($list=["createBy","createTime","createName", "updateBy", "updateName","updateTime", "deleteFlag"])
import com.didiplus.common.base.BaseDomain;
import lombok.Data;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.Date;
import com.baomidou.mybatisplus.annotation.TableName;
/**
* @author ${author}
* @date ${datetime}
*
* @description ${comment}(${upperClassName}實體類)
*/
@Data
@TableName("${tableName}")
@ApiModel(value = "${comment}", description = "${comment}對象 ${lowerClassName}")
public class ${upperClassName}Entity extends BaseDomain {
#foreach ($column in $columns)
## 排除父類字段
#if($list.contains($column.javaLowerAttrName))
#else
/**
* $column.column_comment
*/
@ApiModelProperty(value = "$column.column_comment")
private $column.javaAttrType $column.javaLowerAttrName;
#end
#end
}
mapper.java.vm
package ${packageName}.${moduleName}.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import ${packageName}.${moduleName}.domain.entity.${upperClassName}Entity;
import org.apache.ibatis.annotations.Mapper;
/**
* @author ${author}
* @date ${datetime}
*
* @description ${comment}
*/
@Mapper
public interface ${upperClassName}Mapper extends BaseMapper<${upperClassName}Entity> {
}
mapper.xml.vm
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "//mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="${packageName}.${moduleName}.mapper.${upperClassName}Mapper">
<resultMap id="${lowerClassName}Map" type="${packageName}.${moduleName}.domain.${upperClassName}">
#foreach($column in $columns)
<result column="${column.column_name}" property="${column.javaLowerAttrName}"/>
#end
</resultMap>
</mapper>
service.java.vm
package ${packageName}.${moduleName}.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import ${packageName}.${moduleName}.domain.entity.${upperClassName};
import com.didiplus.common.web.domain.PageDomain;
/**
* @author ${author}
* @date ${datetime}
*
* @description ${comment}
*/
public interface I${upperClassName}Service extends IService<${upperClassName}Entity> {
/**
* 分頁查詢
* @param pageDomain
* @return
*/
IPage<${upperClassName}Entity> page(PageDomain pageDomain);
}
serviceImpl.java.vm
package ${packageName}.${moduleName}.service.impl;
import com.didiplus.common.web.domain.PageDomain;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import ${packageName}.${moduleName}.domain.entity.${upperClassName}Entity;
import ${packageName}.${moduleName}.mapper.${upperClassName}Mapper;
import ${packageName}.${moduleName}.service.I${upperClassName}Service;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
/**
* @author ${author}
* @date ${datetime}
*
* @description ${comment}
*/
@Service
public class ${upperClassName}ServiceImpl extends ServiceImpl<${upperClassName}Mapper, ${upperClassName}Entity> implements I${upperClassName}Service {
@Resource
${upperClassName}Mapper ${lowerClassName}Mapper;
@Override
public IPage<${upperClassName}Entity> page(PageDomain pageDomain) {
IPage<${upperClassName}Entity> page = new Page<>(pageDomain.getPage(),pageDomain.getLimit());
return ${lowerClassName}Mapper.selectPage(page,null);
}
}
controller.java.vm
package ${packageName}.${moduleName}.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import ${packageName}.${moduleName}.domain.entity.${upperClassName}Entity;
import ${packageName}.${moduleName}.service.I${upperClassName}Service;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import com.didiplus.common.web.domain.PageDomain;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import com.didiplus.common.base.ValidGroup;
import javax.annotation.Resource;
/**
* @author ${author}
* @date ${datetime}
*
* @description ${comment}
*/
@Slf4j
@RestController
@RequestMapping("/${lowerClassName}")
@Api(value = "${lowerClassName}", tags = "${comment}管理模塊")
public class ${upperClassName}Controller {
@Resource
private I${upperClassName}Service ${lowerClassName}Service;
/**
* 分頁查詢
* @param pageDomain 分頁對象
* @param ${lowerClassName}Entity ${comment}
* @return IPage
*/
@ApiOperation(value = "分頁查詢", notes = "分頁查詢")
@GetMapping("/page")
public IPage get${upperClassName}Page(@RequestBody PageDomain pageDomain) {
return ${lowerClassName}Service.page(pageDomain);
}
/**
* 新增${comment}
* @param ${lowerClassName}Entity ${comment}
* @return Result
*/
@ApiOperation(value = "新增${comment}", notes = "新增${comment}")
@PostMapping
public String save(@Validated(ValidGroup.Crud.Create.class) @RequestBody ${upperClassName}Entity ${lowerClassName}Entity) {
return ${lowerClassName}Service.save(${lowerClassName}Entity)? "添加成功":"添加失敗";
}
/**
* 修改${comment}
* @param ${lowerClassName}Entity ${comment}
* @return Result
*/
@ApiOperation(value = "修改${comment}", notes = "修改${comment}")
@PutMapping
public String updateById(@Validated(ValidGroup.Crud.Update.class) @RequestBody ${upperClassName}Entity ${lowerClassName}Entity) {
return ${lowerClassName}Service.updateById(${lowerClassName}Entity)? "修改成功":"修改失敗";
}
/**
* 通過id刪除${comment}
* @param id id
* @return Result
*/
@ApiOperation(value = "通過id刪除${comment}", notes = "通過id刪除${comment}")
@DeleteMapping("/{id}")
public String removeById(@PathVariable Integer id) {
return ${lowerClassName}Service.removeById(id)? "刪除成功":"刪除失敗";
}
}
定義啟動類
@Test
public void generatorCode(){
AutoGenerator generator = new AutoGenerator(DATA_SOURCE_CONFIG);
generator.strategy(strategyConfig().build());
generator.injection(injectionConfig().build());
generator.global(globalConfig().build());
generator.template(templateConfig().build());
generator.packageInfo(packageConfig().build());
generator.execute();
}
執行以上函數就可以自動生成代碼了,如下圖:
目前代碼自動生成器只是一個腳本方式運行,後續我們會把它集成到頁面上,通過圖形界面的方式去操作。好了今天就分享到這裡了,有什麼問題歡迎留意。更多關注公眾號「攻城獅成長日記」。