MyBatis逆向工程生成
mybatis需要程序員自己編寫sql語句,mybatis官方提供逆向工程,可以針對單表自動生成mybatis執行所需要的代碼(mapper.java、mapper.xml、pojo…),可以讓程序員將更多的精力放在繁雜的業務邏輯上。
企業實際開發中,常用的逆向工程方式:由數據庫的表生成java代碼。
之所以強調單表兩個字,是因為Mybatis逆向工程生成的Mapper所進行的操作都是針對單表的,也許你可能會覺得那這就有點雞肋了,但是在大型項目中,很少有復雜的多表關聯查詢,所以作用還是很大的。
介紹
MyBatis生成器(MBG)是MyBatis MyBatis 和iBATIS的代碼生成器。它將為MyBatis的所有版本以及版本2.2.0之后的iBATIS生成代碼。它將內省一個數據庫表(或多個表),並將生成可用於訪問表的工件。這減輕了設置對象和配置文件以與數據庫表進行交互的麻煩。MBG試圖對簡單CRUD(創建,檢索,更新,刪除)的大部分數據庫操作產生重大影響。您仍將需要手工編寫SQL和對象代碼以進行聯接查詢或存儲過程。
開始上代碼
目錄總體結構:

主要文件
pom依賴
<!--mybatis依賴-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!--逆向工程生成-->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.5</version>
</dependency>
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.5</version>
</dependency>
分頁配置類
MySQLLimitPlugin.java
package com.meng.device.util;
import org.mybatis.generator.api.GeneratedJavaFile;
import org.mybatis.generator.api.GeneratedXmlFile;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.api.dom.xml.Attribute;
import org.mybatis.generator.api.dom.xml.Document;
import org.mybatis.generator.api.dom.xml.TextElement;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.codegen.XmlConstants;
import org.mybatis.generator.config.PropertyRegistry;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
/**
* Created by meng
*/
public class MySQLLimitPlugin extends PluginAdapter {
private static String XMLFILE_POSTFIX = "Ext";
private static String JAVAFILE_POTFIX = "Ext";
private static String ANNOTATION_RESOURCE = "javax.annotation.Resource";
@Override
public boolean validate(List<String> list) {
return true;
}
/**
* 為每個Example類添加limit和offset屬性已經set、get方法
*/
@Override
public boolean modelExampleClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
PrimitiveTypeWrapper integerWrapper = FullyQualifiedJavaType.getIntInstance().getPrimitiveTypeWrapper();
Field limit = new Field();
limit.setName("limit");
limit.setVisibility(JavaVisibility.PRIVATE);
limit.setType(integerWrapper);
topLevelClass.addField(limit);
Method setLimit = new Method();
setLimit.setVisibility(JavaVisibility.PUBLIC);
setLimit.setName("setLimit");
setLimit.addParameter(new Parameter(integerWrapper, "limit"));
setLimit.addBodyLine("this.limit = limit;");
topLevelClass.addMethod(setLimit);
Method getLimit = new Method();
getLimit.setVisibility(JavaVisibility.PUBLIC);
getLimit.setReturnType(integerWrapper);
getLimit.setName("getLimit");
getLimit.addBodyLine("return limit;");
topLevelClass.addMethod(getLimit);
Field offset = new Field();
offset.setName("offset");
offset.setVisibility(JavaVisibility.PRIVATE);
offset.setType(integerWrapper);
topLevelClass.addField(offset);
Method setOffset = new Method();
setOffset.setVisibility(JavaVisibility.PUBLIC);
setOffset.setName("setOffset");
setOffset.addParameter(new Parameter(integerWrapper, "offset"));
setOffset.addBodyLine("this.offset = offset;");
topLevelClass.addMethod(setOffset);
Method getOffset = new Method();
getOffset.setVisibility(JavaVisibility.PUBLIC);
getOffset.setReturnType(integerWrapper);
getOffset.setName("getOffset");
getOffset.addBodyLine("return offset;");
topLevelClass.addMethod(getOffset);
return true;
}
// 添刪改Document的sql語句及屬性
@Override
public boolean sqlMapDocumentGenerated(Document document,
IntrospectedTable introspectedTable) {
XmlElement parentElement = document.getRootElement();
// updateDocumentNameSpace(introspectedTable, parentElement);
// moveDocumentInsertSql(parentElement);
//
// updateDocumentInsertSelective(parentElement);
//
// moveDocumentUpdateByPrimaryKeySql(parentElement);
//
// generateMysqlPageSql(parentElement, introspectedTable);
//
// generateDataAccessSql(parentElement);
return super.sqlMapDocumentGenerated(document, introspectedTable);
}
private void updateDocumentNameSpace(IntrospectedTable introspectedTable,
XmlElement parentElement) {
Attribute namespaceAttribute = null;
for (Attribute attribute : parentElement.getAttributes()) {
if (attribute.getName().equals("namespace")) {
namespaceAttribute = attribute;
}
}
parentElement.getAttributes().remove(namespaceAttribute);
parentElement.getAttributes().add(
new Attribute("namespace", introspectedTable
.getMyBatis3JavaMapperType() + JAVAFILE_POTFIX));
}
/**
* 為Mapper.xml的selectByExample添加limit
*/
@Override
public boolean sqlMapSelectByExampleWithoutBLOBsElementGenerated(XmlElement element,
IntrospectedTable introspectedTable) {
XmlElement ifLimitNotNullElement = new XmlElement("if");
ifLimitNotNullElement.addAttribute(new Attribute("test", "limit != null"));
XmlElement ifOffsetNotNullElement = new XmlElement("if");
ifOffsetNotNullElement.addAttribute(new Attribute("test", "offset != null"));
ifOffsetNotNullElement.addElement(new TextElement("limit ${offset}, ${limit}"));
ifLimitNotNullElement.addElement(ifOffsetNotNullElement);
XmlElement ifOffsetNullElement = new XmlElement("if");
ifOffsetNullElement.addAttribute(new Attribute("test", "offset == null"));
ifOffsetNullElement.addElement(new TextElement("limit ${limit}"));
ifLimitNotNullElement.addElement(ifOffsetNullElement);
element.addElement(ifLimitNotNullElement);
return true;
}
// 生成XXExt.xml
@Override
public List<GeneratedXmlFile> contextGenerateAdditionalXmlFiles(
IntrospectedTable introspectedTable) {
String[] splitFile = introspectedTable.getMyBatis3XmlMapperFileName()
.split("\\.");
String fileNameExt = null;
if (splitFile[0] != null) {
fileNameExt = splitFile[0] + XMLFILE_POSTFIX + ".xml";
}
if (isExistExtFile(context.getSqlMapGeneratorConfiguration()
.getTargetProject(),
introspectedTable.getMyBatis3XmlMapperPackage(), fileNameExt)) {
return super.contextGenerateAdditionalXmlFiles(introspectedTable);
}
Document document = new Document(
XmlConstants.MYBATIS3_MAPPER_PUBLIC_ID,
XmlConstants.MYBATIS3_MAPPER_SYSTEM_ID);
XmlElement root = new XmlElement("mapper");
document.setRootElement(root);
String namespace = introspectedTable.getMyBatis3SqlMapNamespace()
+ XMLFILE_POSTFIX;
root.addAttribute(new Attribute("namespace", namespace));
GeneratedXmlFile gxf = new GeneratedXmlFile(document, fileNameExt,
introspectedTable.getMyBatis3XmlMapperPackage(), context
.getSqlMapGeneratorConfiguration().getTargetProject(),
false, context.getXmlFormatter());
List<GeneratedXmlFile> answer = new ArrayList<GeneratedXmlFile>(1);
answer.add(gxf);
return answer;
}
// 生成XXExt.java
@Override
public List<GeneratedJavaFile> contextGenerateAdditionalJavaFiles(
IntrospectedTable introspectedTable) {
FullyQualifiedJavaType type = new FullyQualifiedJavaType(
introspectedTable.getMyBatis3JavaMapperType() + JAVAFILE_POTFIX);
Interface interfaze = new Interface(type);
interfaze.setVisibility(JavaVisibility.PUBLIC);
context.getCommentGenerator().addJavaFileComment(interfaze);
FullyQualifiedJavaType baseInterfaze = new FullyQualifiedJavaType(
introspectedTable.getMyBatis3JavaMapperType());
interfaze.addSuperInterface(baseInterfaze);
FullyQualifiedJavaType annotation = new FullyQualifiedJavaType(
ANNOTATION_RESOURCE);
interfaze.addAnnotation("@Resource");
interfaze.addImportedType(annotation);
CompilationUnit compilationUnits = interfaze;
GeneratedJavaFile generatedJavaFile = new GeneratedJavaFile(
compilationUnits,
context.getJavaModelGeneratorConfiguration().getTargetProject(),
context.getProperty(PropertyRegistry.CONTEXT_JAVA_FILE_ENCODING),
context.getJavaFormatter());
if (isExistExtFile(generatedJavaFile.getTargetProject(),
generatedJavaFile.getTargetPackage(),
generatedJavaFile.getFileName())) {
return super.contextGenerateAdditionalJavaFiles(introspectedTable);
}
List<GeneratedJavaFile> generatedJavaFiles = new ArrayList<GeneratedJavaFile>(
1);
generatedJavaFile.getFileName();
generatedJavaFiles.add(generatedJavaFile);
return generatedJavaFiles;
}
private boolean isExistExtFile(String targetProject, String targetPackage,
String fileName) {
File project = new File(targetProject);
if (!project.isDirectory()) {
return true;
}
StringBuilder sb = new StringBuilder();
StringTokenizer st = new StringTokenizer(targetPackage, ".");
while (st.hasMoreTokens()) {
sb.append(st.nextToken());
sb.append(File.separatorChar);
}
File directory = new File(project, sb.toString());
if (!directory.isDirectory()) {
boolean rc = directory.mkdirs();
if (!rc) {
return true;
}
}
File testFile = new File(directory, fileName);
if (testFile.exists()) {
return true;
} else {
return false;
}
}
}
主要配置 映射哪些表也是在這個里面配置(每次只需要修改這個)
generatorConfig_local.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="C:/Project/DB/mysql-connector-java-5.1.40-bin.jar"/>-->
<context id="base_resource" targetRuntime="MyBatis3">
<property name="useActualColumnNames" value="false"/>
<plugin type="com.meng.device.util.MySQLLimitPlugin"/>
<commentGenerator>
<property name="suppressDate" value="true"/>
</commentGenerator>
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://127.0.0.1:3306/springboot?useUnicode=true&characterEncoding=UTF-8"
userId="root"
password="root">
</jdbcConnection>
<!-- targetProject:生成PO類的位置 根據自己項目位置更改 -->
<javaModelGenerator targetPackage="com.meng.device.dao"
targetProject="E:\project\IdeaProjects\device\src\main\java">
<!-- enableSubPackages:是否讓schema作為包的后綴 -->
<property name="enableSubPackages" value="true"/>
<!-- 從數據庫返回的值被清理前后的空格 -->
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- targetProject:mapper映射文件生成的位置 根據自己項目位置更改-->
<sqlMapGenerator targetPackage="com.meng.device.mapper"
targetProject="E:\project\IdeaProjects\device\src\main\resources">
<!-- enableSubPackages:是否讓schema作為包的后綴 -->
<property name="enableSubPackages" value="true"/>
</sqlMapGenerator>
<!-- targetPackage:mapper接口生成的位置 根據自己項目位置更改-->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.meng.device.mapper"
targetProject="E:\project\IdeaProjects\device\src\main\java">
<!-- enableSubPackages:是否讓schema作為包的后綴 -->
<property name="enableSubPackages" value="true"/>
</javaClientGenerator>
<!-- 指定數據庫表 -->
<!--映射表名 多個表可以寫多個-->
<!--<table tableName="表名" domainObjectName="實體名">
<property name="useActualColumnNames" value="false"/>
<generatedKey column="id" sqlStatement="MySql" identity="true"/>
</table>-->
<!-- 有些表的字段需要指定java類型
<table schema=""tableName="">
<columnOverridecolumn="" javaType="" />
</table> -->
</context>
</generatorConfiguration>
啟動類
Generator.java
package com.meng.device.generator;
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;
import java.util.ArrayList;
import java.util.List;
/**
* @description: mybatis逆向工程 自動生成mybatis-Mapper工具
* @author: meng
* @create: 2019-09-11 08:58
**/
public class Generator {
/**
* 目前在系統中本地環境使用local來配置mapper生成規則
*/
//指定逆向工程配置文件
private static final String config_url = "generatorConfig_local.xml";
public void generator() throws Exception {
List<String> warnings = new ArrayList<String>();
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(Generator.class.getClassLoader().getResourceAsStream(config_url));
DefaultShellCallback callback = new DefaultShellCallback(true);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);
}
/**
* 主函數
*/
public static void main(String[] args) throws Exception {
try {
Generator generatorSqlmap = new Generator();
generatorSqlmap.generator();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("generator 執行成功!");
}
}
配置完成后執行Generator類中主函數
