1、代码生成器概述
Spring Cloud 并没有提供类似于 Spring Data 中的“代码生成器”,因为它主要提供的是分布式系统中服务发现和配置管理的一套解决方案。如果你想要为你的微服务应用生成样板代码,你可能需要考虑使用其他工具或者方案,例如 Spring Roo 或者 MyBatis Generator。
Spring Roo 是一个为 Spring 应用快速开发的工具,它提供了一套命令行接口和可视化界面来生成项目的各个组件,包括域对象、控制器、视图等。但是它的更新频率不高,并且不再活跃维护。
MyBatis Generator 是一个 MyBatis 的代码生成器,它可以生成对应数据库表的实体类、Mapper接口和Mapper XML文件。虽然它不是专门为 Spring Cloud 设计,但它可以为你的微服务应用生成基础的数据访问层代码。
2、Mybatis Generator
2.1 基本概念
MyBatis Generator是MyBatis的代码生成器,顾名思义,使用MyBatis Generator可以很方便的将一个数据库表(或多个表)生成可用于访问该表的MyBatis代码。
MyBatis Generator能够简化大部分简单CRUD(创建、检索、更新、删除)的数据库操作。
2.2 建立公共库
1、建议建立一个公共库,用与所有项目的代码的生成
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.cloud</groupId>
<artifactId>microserver</artifactId>
<version>1.0.1</version>
</parent>
<artifactId>common</artifactId>
<name>common</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis.generator/mybatis-generator-maven-plugin -->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.4.2</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<!-- 补充mybatis缺少的JDBC-Type如postGis中的geometry类型
https://mvnrepository.com/artifact/net.postgis/postgis-jdbc -->
<dependency>
<groupId>net.postgis</groupId>
<artifactId>postgis-jdbc</artifactId>
<version>2.5.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.7</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
2、公共库与建立独立项目步骤类似,只是需要将pom.xml中生成war包改成生成jar包,然后在子项目中引用,
2.3 引入Mybatis插件
主要是在公共库中引入mybatis插件
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.4.2</version>
</dependency>
3、编写代码
3.1 代码备注生成代码
生成MybatisCommentGenerator插件代码,主要用于生成备注,可根据自我需要进行修改
package org.cloud.utils;
import org.mybatis.generator.api.CommentGenerator;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.config.MergeConstants;
import org.mybatis.generator.config.PropertyRegistry;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;
import java.util.Set;
public class MybatisCommentGenerator implements CommentGenerator {
private Properties properties;
private Properties systemPro;
private boolean suppressDate;
private boolean suppressAllComments;
private String nowTime;
public MybatisCommentGenerator() {
super();
properties = new Properties();
systemPro = System.getProperties();
suppressDate = false;
suppressAllComments = false;
nowTime = (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).format(new Date());
}
/**
* 类的注释
* @param innerClass
* @param introspectedTable
* @param markAsDoNotDelete
*/
@Override
public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable, boolean markAsDoNotDelete) {
if (suppressAllComments) {
return;
}
StringBuilder sb = new StringBuilder();
innerClass.addJavaDocLine("/**");
sb.append(" * ");
sb.append(introspectedTable.getFullyQualifiedTable());
innerClass.addJavaDocLine(sb.toString().replace("\n", " "));
sb.setLength(0);
sb.append(" * @author ");
sb.append(systemPro.getProperty("user.name"));
sb.append(" ");
sb.append(nowTime);
innerClass.addJavaDocLine(" */");
}
@Override
public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable) {
if (suppressAllComments) {
return;
}
StringBuilder sb = new StringBuilder();
innerClass.addJavaDocLine("/**");
sb.append(" * ");
sb.append(introspectedTable.getFullyQualifiedTable());
sb.append(" ");
sb.append(getDateString());
innerClass.addJavaDocLine(sb.toString().replace("\n", " "));
innerClass.addJavaDocLine(" */");
}
/**
* 设置字段注释
*/
@Override
public void addFieldComment(Field field, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn) {
if (suppressAllComments) {
return;
}
StringBuilder sb = new StringBuilder();
field.addJavaDocLine("/**");
sb.append(" * ");
sb.append(introspectedColumn.getRemarks());
field.addJavaDocLine(sb.toString().replace("\n", " "));
field.addJavaDocLine(" */");
}
@Override
public void addFieldComment(Field field, IntrospectedTable introspectedTable) {
if (suppressAllComments) {
return;
}
StringBuilder sb = new StringBuilder();
field.addJavaDocLine("/**");
sb.append(" * ");
sb.append(introspectedTable.getFullyQualifiedTable());
field.addJavaDocLine(sb.toString().replace("\n", " "));
field.addJavaDocLine(" */");
}
/**
* 设置setter方法注释
*/
@Override
public void addSetterComment(Method method, IntrospectedTable introspectedTable,
IntrospectedColumn introspectedColumn) {
if (suppressAllComments) {
return;
}
method.addJavaDocLine("/**");
StringBuilder sb = new StringBuilder();
sb.append(" * ");
sb.append(introspectedColumn.getRemarks());
method.addJavaDocLine(sb.toString().replace("\n", " "));
sb.setLength(0);
sb.append(" * @author ");
sb.append(systemPro.getProperty("user.name"));
method.addJavaDocLine(sb.toString().replace("\n", " "));
sb.setLength(0);
if(suppressDate){
sb.append(" * @date " + nowTime);
method.addJavaDocLine(sb.toString().replace("\n", " "));
sb.setLength(0);
}
Parameter parm = method.getParameters().get(0);
sb.append(" * @param ");
sb.append(parm.getName());
sb.append(" ");
sb.append(introspectedColumn.getRemarks());
method.addJavaDocLine(sb.toString().replace("\n", " "));
method.addJavaDocLine(" */");
}
/**
* 设置getter方法注释
*/
@Override
public void addGetterComment(Method method, IntrospectedTable introspectedTable,
IntrospectedColumn introspectedColumn) {
if (suppressAllComments) {
return;
}
method.addJavaDocLine("/**");
StringBuilder sb = new StringBuilder();
sb.append(" * ");
sb.append(introspectedColumn.getRemarks());
method.addJavaDocLine(sb.toString().replace("\n", " "));
sb.setLength(0);
sb.append(" * @author ");
sb.append(systemPro.getProperty("user.name"));
method.addJavaDocLine(sb.toString().replace("\n", " "));
sb.setLength(0);
if(suppressDate){
sb.append(" * @date " + nowTime);
method.addJavaDocLine(sb.toString().replace("\n", " "));
sb.setLength(0);
}
sb.append(" * @return ");
sb.append(introspectedColumn.getActualColumnName());
sb.append(" ");
sb.append(introspectedColumn.getRemarks());
method.addJavaDocLine(sb.toString().replace("\n", " "));
method.addJavaDocLine(" */");
}
@Override
public void addJavaFileComment(CompilationUnit compilationUnit) {
if (suppressAllComments) {
return;
}
return;
}
@Override
public void addComment(XmlElement xmlElement) {
return;
}
@Override
public void addRootComment(XmlElement rootElement) {
return;
}
@Override
public void addConfigurationProperties(Properties properties) {
this.properties.putAll(properties);
suppressDate = Boolean.valueOf(properties.getProperty(PropertyRegistry.COMMENT_GENERATOR_SUPPRESS_DATE));
suppressAllComments = Boolean.valueOf(properties.getProperty(PropertyRegistry.COMMENT_GENERATOR_SUPPRESS_ALL_COMMENTS));
}
protected void addJavadocTag(JavaElement javaElement, boolean markAsDoNotDelete, String desc) {
javaElement.addJavaDocLine(" * " + desc);
StringBuilder sb = new StringBuilder();
sb.append(" * ");
sb.append(MergeConstants.NEW_ELEMENT_TAG);
if (markAsDoNotDelete) {
sb.append(" do_not_delete_during_merge");
}
String s = getDateString();
if (s != null) {
sb.append(' ');
sb.append(s);
}
javaElement.addJavaDocLine(sb.toString());
}
protected String getDateString() {
String result = null;
if (!suppressDate) {
result = nowTime;
}
return result;
}
@Override
public void addEnumComment(InnerEnum innerEnum, IntrospectedTable introspectedTable) {
if (suppressAllComments) {
return;
}
StringBuilder sb = new StringBuilder();
innerEnum.addJavaDocLine("/**");
sb.append(" * ");
sb.append(introspectedTable.getFullyQualifiedTable());
innerEnum.addJavaDocLine(sb.toString().replace("\n", " "));
innerEnum.addJavaDocLine(" */");
}
@Override
public void addGeneralMethodComment(Method method, IntrospectedTable introspectedTable) {
if (suppressAllComments) {
return;
}
String methodName = method.getName();
String descString = "";
switch (methodName) {
case "deleteByPrimaryKey":
descString = "根据主键删除数据";
break;
case "insert":
descString = "全值插入数据";
break;
case "insertSelective":
descString = "非空插入数据";
break;
case "selectByExample":
descString = "根据样例选择数据";
break;
case "selectByPrimaryKey":
descString = "根据主键选择数据";
break;
case "updateByPrimaryKey":
descString = "根据主键更新全部数据";
break;
case "updateByPrimaryKeySelective":
descString = "根据主键更新部分数据";
break;
case "setOrderByClause":
descString = "设置排序";
break;
case "getOrderByClause":
descString = "获取排序";
break;
case "setDistinct":
descString = "去除重复的结果";
break;
case "or":
descString = "或者";
break;
case "createCriteria":
descString = "创建查询条件";
break;
default:
break;
}
method.addJavaDocLine("/**");
addJavadocTag(method, false, descString);
method.addJavaDocLine(" */");
}
@Override
public void addModelClassComment(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
// TODO Auto-generated method stub
String dateFormat = properties.getProperty("dateFormat", "yyyy-MM-dd");
SimpleDateFormat dateFormatter = new SimpleDateFormat(dateFormat);
// 获取表注释
String remarks = introspectedTable.getRemarks();
topLevelClass.addJavaDocLine("/**");
topLevelClass.addJavaDocLine(" * @Date:" + dateFormatter.format(new Date()));
topLevelClass.addJavaDocLine(" * @Description:" + remarks);
topLevelClass.addJavaDocLine(" */");
}
@Override
public void addGeneralMethodAnnotation(Method method, IntrospectedTable introspectedTable,
Set<FullyQualifiedJavaType> imports) {
// TODO Auto-generated method stub
}
@Override
public void addGeneralMethodAnnotation(Method method, IntrospectedTable introspectedTable,
IntrospectedColumn introspectedColumn, Set<FullyQualifiedJavaType> imports) {
// TODO Auto-generated method stub
}
@Override
public void addFieldAnnotation(Field field, IntrospectedTable introspectedTable,
Set<FullyQualifiedJavaType> imports) {
// TODO Auto-generated method stub
}
@Override
public void addFieldAnnotation(Field field, IntrospectedTable introspectedTable,
IntrospectedColumn introspectedColumn, Set<FullyQualifiedJavaType> imports) {
// TODO Auto-generated method stub
}
@Override
public void addClassAnnotation(InnerClass innerClass, IntrospectedTable introspectedTable,
Set<FullyQualifiedJavaType> imports) {
// TODO Auto-generated method stub
}
}
3.2 生成代码
用于代码的生成
package org.cloud.utils;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;
public class CodeGenUtils {
static public void genCode() {
try {
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
File configFile = new File("src/main/resources/mybatis-generator.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
3.3 新建配置文件
在需要生成代码的文件中,新建配置mybatis-generator.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!--数据库驱动-->
<classPathEntry location="E:\javaProject\repos\org\postgresql\postgresql\42.6.2\postgresql-42.6.2.jar"/>
<context id="DB2Tables" targetRuntime="MyBatis3">
<!-- <commentGenerator>
<property name="suppressAllComments" value="false"/>
<property name="suppressDate" value="false"/>
此处为 true 时,生成的 Model 包含对应表字段注释
<property name="addRemarkComments" value="true"/>
此处为 true 时,生成的 Mapper 接口将增加 @Mapper 注解,Spring ComponentScan 时可自动识别
<property name="addMapperAnnotation" value="false"/>
</commentGenerator> -->
<plugin type="org.mybatis.generator.plugins.SerializablePlugin" />
<commentGenerator type="org.cloud.utils.MybatisCommentGenerator">
<property name="suppressAllComments" value="false"/>
<property name="suppressDate" value="false"/>
<property name="addRemarkComments" value="true"/>
</commentGenerator>
<!--数据库链接地址账号密码-->
<jdbcConnection driverClass="org.postgresql.Driver" connectionURL="jdbc:postgresql://192.168.0.21:5432/permission"
userId="postgres" password="postgres">
<property name="nullCatalogMeansCurrent" value="true"/>
<property name="remarksReporting" value="true"></property>
</jdbcConnection>
<javaTypeResolver>
<!-- 是否使用bigDecimal, false可自动转化以下类型(Long, Integer, Short, etc.) -->
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!--生成Model类存放位置-->
<javaModelGenerator targetPackage="org.permission.entity" targetProject="./src/main/java">
<!-- 是否在当前路径下新加一层schema,eg:fase路径com.oop.eksp.user.model, true:com.oop.eksp.user.model.[schemaName] -->
<property name="enableSubPackages" value="false"/>
<!-- 是否针对string类型的字段在set的时候进行trim调用 -->
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!--生成映射文件存放位置-->
<sqlMapGenerator targetPackage="mapper" targetProject="./src/main/resources">
<!-- 是否在当前路径下新加一层schema,eg:fase路径com.oop.eksp.user.model, true:com.oop.eksp.user.model.[schemaName] -->
<property name="enableSubPackages" value="false"/>
</sqlMapGenerator>
<!--生成Dao类存放位置-->
<javaClientGenerator type="XMLMAPPER" targetPackage="org.permission.mapper" targetProject="./src/main/java">
<!-- 是否在当前路径下新加一层schema,eg:fase路径com.oop.eksp.user.model, true:com.oop.eksp.user.model.[schemaName] -->
<property name="enableSubPackages" value="false"/>
</javaClientGenerator>
<!--生成对应表及类名-->
<!--<table tableName="big_table" domainObjectName="BigTable" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>-->
<table schema=""
tableName="organization"
enableCountByExample="true"
enableUpdateByExample="false"
enableDeleteByExample="false"
enableSelectByExample="true"
selectByExampleQueryId="false">
<property name="useActualColumnNames" value="false"/>
<columnOverride column="extension" property="extension" jdbcType="OTHER" javaType="com.alibaba.fastjson.JSONObject"
typeHandler="tianchen.cloud.handler.JsonTypeHandler"/>
</table>
<table schema=""
tableName="user_info"
enableCountByExample="true"
enableUpdateByExample="false"
enableDeleteByExample="false"
enableSelectByExample="true"
selectByExampleQueryId="false">
<property name="useActualColumnNames" value="false"/>
<columnOverride column="extension" property="extension" jdbcType="OTHER" javaType="com.alibaba.fastjson.JSONObject"
typeHandler="tianchen.cloud.handler.JsonTypeHandler"/>
</table>
<table schema=""
tableName="user_role"
enableCountByExample="true"
enableUpdateByExample="false"
enableDeleteByExample="false"
enableSelectByExample="true"
selectByExampleQueryId="false">
<property name="useActualColumnNames" value="false"/>
<columnOverride column="extension" property="extension" jdbcType="OTHER" javaType="com.alibaba.fastjson.JSONObject"
typeHandler="tianchen.cloud.handler.JsonTypeHandler"/>
</table>
<table schema=""
tableName="role"
enableCountByExample="true"
enableUpdateByExample="false"
enableDeleteByExample="false"
enableSelectByExample="true"
selectByExampleQueryId="false">
<property name="useActualColumnNames" value="false"/>
<columnOverride column="extension" property="extension" jdbcType="OTHER" javaType="com.alibaba.fastjson.JSONObject"
typeHandler="tianchen.cloud.handler.JsonTypeHandler"/>
</table>
<table schema=""
tableName="permission"
enableCountByExample="true"
enableUpdateByExample="false"
enableDeleteByExample="false"
enableSelectByExample="true"
selectByExampleQueryId="false">
<property name="useActualColumnNames" value="false"/>
<columnOverride column="extension" property="extension" jdbcType="OTHER" javaType="com.alibaba.fastjson.JSONObject"
typeHandler="tianchen.cloud.handler.JsonTypeHandler"/>
</table>
<table schema=""
tableName="permission_menu"
enableCountByExample="true"
enableUpdateByExample="false"
enableDeleteByExample="false"
enableSelectByExample="true"
selectByExampleQueryId="false">
<property name="useActualColumnNames" value="false"/>
<columnOverride column="extension" property="extension" jdbcType="OTHER" javaType="com.alibaba.fastjson.JSONObject"
typeHandler="tianchen.cloud.handler.JsonTypeHandler"/>
</table>
<table schema=""
tableName="menu"
enableCountByExample="true"
enableUpdateByExample="false"
enableDeleteByExample="false"
enableSelectByExample="true"
selectByExampleQueryId="false">
<property name="useActualColumnNames" value="false"/>
<columnOverride column="extension" property="extension" jdbcType="OTHER" javaType="com.alibaba.fastjson.JSONObject"
typeHandler="tianchen.cloud.handler.JsonTypeHandler"/>
</table>
</context>
</generatorConfiguration>
3.4 编写生成代码
public class Test {
public static void main(String[] args) {
try {
CodeGenUtils.genCode();
} catch (Exception e) {
e.printStackTrace();
}
}
}