前言
当我们新建一个表时,在项目中至少要新建3个文件:实体类*PO.java、接口类*POMapper.java、存放SQL的接口实现类*POMapper.xml。对于字段少的表来说,可能你不会在意,但是如果是一个字段超过几十个的表,那你可能要写的头昏眼花了。并且,当字段多了,手写错误的几率特别大。这个时候,我们就需要MyBatis来自动生成。
在src/main/resource/config/mybatis目录下新建配置文件generatorConfig.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> <context id="MysqlTables" targetRuntime="MyBatis3"> <commentGenerator> <property name="suppressDate" value="true"/> <!-- 是否去除自动生成的注释 true:是 : false:否 --> <property name="suppressAllComments" value="true"/> </commentGenerator> <!-- jdbc链接信息 --> <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://127.0.0.1:3306/joonwhee? autoReconnect=true&autoReconnectForPools=true& useUnicode=true&characterEncoding=utf-8" userId="root" password="root"> </jdbcConnection> <javaTypeResolver> <property name="forceBigDecimals" value="false"/> </javaTypeResolver> <!-- 生成PO类的位置 --> <javaModelGenerator targetPackage="com.dianping.open.joonwhee.po" targetProject="src/main/java"> <property name="enableSubPackages" value="true"/> <property name="trimStrings" value="true"/> </javaModelGenerator> <!-- mapper映射文件生成的位置 --> <sqlMapGenerator targetPackage="config.mapper" targetProject="src/main/resources"> <property name="enableSubPackages" value="true"/> </sqlMapGenerator> <!-- mapper接口生成的位置 --> <javaClientGenerator type="XMLMAPPER" targetPackage="com.dianping.open.joonwhee.mapper" targetProject="src/main/java"> <property name="enableSubPackages" value="true"/> </javaClientGenerator> <!-- 指定要生成的表 --> <table tableName="User" domainObjectName="UserPO"> <property name="useActualColumnNames" value="true"/> <generatedKey column="id" sqlStatement="MySql" identity="true"/> </table> </context> </generatorConfiguration>
引入mybatis自动生成的插件,放在build->plugin标签下,如下:
在Maven Projects页面找到项目的mybatis-generator插件,双击:
可能有些人并没有用过Example,简单介绍下基本的使用。
用法其实很简单,可以分为4步。
1. new一个Example
2. 使用Example创建一个Criteria
3. 使用Criteria设置要限制的条件
4. 通过Example查询结果
上面这个例子的SQL等同于:
SELECT Id, Name, Password, Age, Sex FROM `user` Where Name = 'admin' and Password = 'admin' and Age BETWEEN 24 and 26;
至此,MyBatis根据表结构自动生成PO、Mapper代码的基本使用已经完成。
首先看下表结构和自动生成的PO。
表结构:
自动生成的PO:
可以看到tinyint(4)自动生成的类型是Byte,这个地方会带来一个使用上的问题,每次使用sex都需要转成Byte,而我们希望他生成的是Integer,怎么解决这个问题?可以通过自定义类型解析器来解决这个问题。
mybatis自动生成默认使用的解析器是JavaTypeResolverDefaultImpl(该文件在mybatis-generator-core.jar,具体路径为org.mybatis.generator.internal.types),我们将JavaTypeResolverDefaultImpl的源码直接拷贝一份,作为自定义类型解析器的模板,在其基础上进行修改。
如图,将Byte.class.getName()改成Integer.class.getName(),修改后的内容如下:
package com.open.joonwhee; import org.mybatis.generator.api.IntrospectedColumn; import org.mybatis.generator.api.JavaTypeResolver; import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType; import org.mybatis.generator.config.Context; import org.mybatis.generator.config.PropertyRegistry; import org.mybatis.generator.internal.types.Jdbc4Types; import org.mybatis.generator.internal.util.StringUtility; import java.math.BigDecimal; import java.sql.Types; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; /** * 自定义Java类型解析器 * * @Author joonwhee * @Date 2018/5/19 */ public class MyJavaTypeResolver implements JavaTypeResolver { protected List<String> warnings; protected Properties properties; protected Context context; protected boolean forceBigDecimals; protected Map<Integer, JdbcTypeInformation> typeMap; public MyJavaTypeResolver() { super(); properties = new Properties(); typeMap = new HashMap<Integer, JdbcTypeInformation>(); typeMap.put(Types.ARRAY, new JdbcTypeInformation("ARRAY", //$NON-NLS-1$ new FullyQualifiedJavaType(Object.class.getName()))); typeMap.put(Types.BIGINT, new JdbcTypeInformation("BIGINT", //$NON-NLS-1$ new FullyQualifiedJavaType(Long.class.getName()))); typeMap.put(Types.BINARY, new JdbcTypeInformation("BINARY", //$NON-NLS-1$ new FullyQualifiedJavaType("byte[]"))); //$NON-NLS-1$ typeMap.put(Types.BIT, new JdbcTypeInformation("BIT", //$NON-NLS-1$ new FullyQualifiedJavaType(Boolean.class.getName()))); typeMap.put(Types.BLOB, new JdbcTypeInformation("BLOB", //$NON-NLS-1$ new FullyQualifiedJavaType("byte[]"))); //$NON-NLS-1$ typeMap.put(Types.BOOLEAN, new JdbcTypeInformation("BOOLEAN", //$NON-NLS-1$ new FullyQualifiedJavaType(Boolean.class.getName()))); typeMap.put(Types.CHAR, new JdbcTypeInformation("CHAR", //$NON-NLS-1$ new FullyQualifiedJavaType(String.class.getName()))); typeMap.put(Types.CLOB, new JdbcTypeInformation("CLOB", //$NON-NLS-1$ new FullyQualifiedJavaType(String.class.getName()))); typeMap.put(Types.DATALINK, new JdbcTypeInformation("DATALINK", //$NON-NLS-1$ new FullyQualifiedJavaType(Object.class.getName()))); typeMap.put(Types.DATE, new JdbcTypeInformation("DATE", //$NON-NLS-1$ new FullyQualifiedJavaType(Date.class.getName()))); typeMap.put(Types.DISTINCT, new JdbcTypeInformation("DISTINCT", //$NON-NLS-1$ new FullyQualifiedJavaType(Object.class.getName()))); typeMap.put(Types.DOUBLE, new JdbcTypeInformation("DOUBLE", //$NON-NLS-1$ new FullyQualifiedJavaType(Double.class.getName()))); typeMap.put(Types.FLOAT, new JdbcTypeInformation("FLOAT", //$NON-NLS-1$ new FullyQualifiedJavaType(Double.class.getName()))); typeMap.put(Types.INTEGER, new JdbcTypeInformation("INTEGER", //$NON-NLS-1$ new FullyQualifiedJavaType(Integer.class.getName()))); typeMap.put(Types.JAVA_OBJECT, new JdbcTypeInformation("JAVA_OBJECT", //$NON-NLS-1$ new FullyQualifiedJavaType(Object.class.getName()))); typeMap.put(Jdbc4Types.LONGNVARCHAR, new JdbcTypeInformation("LONGNVARCHAR", //$NON-NLS-1$ new FullyQualifiedJavaType(String.class.getName()))); typeMap.put(Types.LONGVARBINARY, new JdbcTypeInformation( "LONGVARBINARY", //$NON-NLS-1$ new FullyQualifiedJavaType("byte[]"))); //$NON-NLS-1$ typeMap.put(Types.LONGVARCHAR, new JdbcTypeInformation("LONGVARCHAR", //$NON-NLS-1$ new FullyQualifiedJavaType(String.class.getName()))); typeMap.put(Jdbc4Types.NCHAR, new JdbcTypeInformation("NCHAR", //$NON-NLS-1$ new FullyQualifiedJavaType(String.class.getName()))); typeMap.put(Jdbc4Types.NCLOB, new JdbcTypeInformation("NCLOB", //$NON-NLS-1$ new FullyQualifiedJavaType(String.class.getName()))); typeMap.put(Jdbc4Types.NVARCHAR, new JdbcTypeInformation("NVARCHAR", //$NON-NLS-1$ new FullyQualifiedJavaType(String.class.getName()))); typeMap.put(Types.NULL, new JdbcTypeInformation("NULL", //$NON-NLS-1$ new FullyQualifiedJavaType(Object.class.getName()))); typeMap.put(Types.OTHER, new JdbcTypeInformation("OTHER", //$NON-NLS-1$ new FullyQualifiedJavaType(Object.class.getName()))); typeMap.put(Types.REAL, new JdbcTypeInformation("REAL", //$NON-NLS-1$ new FullyQualifiedJavaType(Float.class.getName()))); typeMap.put(Types.REF, new JdbcTypeInformation("REF", //$NON-NLS-1$ new FullyQualifiedJavaType(Object.class.getName()))); typeMap.put(Types.SMALLINT, new JdbcTypeInformation("SMALLINT", //$NON-NLS-1$ new FullyQualifiedJavaType(Short.class.getName()))); typeMap.put(Types.STRUCT, new JdbcTypeInformation("STRUCT", //$NON-NLS-1$ new FullyQualifiedJavaType(Object.class.getName()))); typeMap.put(Types.TIME, new JdbcTypeInformation("TIME", //$NON-NLS-1$ new FullyQualifiedJavaType(Date.class.getName()))); typeMap.put(Types.TIMESTAMP, new JdbcTypeInformation("TIMESTAMP", //$NON-NLS-1$ new FullyQualifiedJavaType(Date.class.getName()))); typeMap.put(Types.TINYINT, new JdbcTypeInformation("TINYINT", //$NON-NLS-1$ new FullyQualifiedJavaType(Integer.class.getName()))); typeMap.put(Types.VARBINARY, new JdbcTypeInformation("VARBINARY", //$NON-NLS-1$ new FullyQualifiedJavaType("byte[]"))); //$NON-NLS-1$ typeMap.put(Types.VARCHAR, new JdbcTypeInformation("VARCHAR", //$NON-NLS-1$ new FullyQualifiedJavaType(String.class.getName()))); } @Override public void addConfigurationProperties(Properties properties) { this.properties.putAll(properties); forceBigDecimals = StringUtility .isTrue(properties .getProperty(PropertyRegistry.TYPE_RESOLVER_FORCE_BIG_DECIMALS)); } @Override public FullyQualifiedJavaType calculateJavaType(IntrospectedColumn introspectedColumn) { FullyQualifiedJavaType answer; JdbcTypeInformation jdbcTypeInformation = typeMap .get(introspectedColumn.getJdbcType()); if (jdbcTypeInformation == null) { switch (introspectedColumn.getJdbcType()) { case Types.DECIMAL: case Types.NUMERIC: if (introspectedColumn.getScale() > 0 || introspectedColumn.getLength() > 18 || forceBigDecimals) { answer = new FullyQualifiedJavaType(BigDecimal.class .getName()); } else if (introspectedColumn.getLength() > 9) { answer = new FullyQualifiedJavaType(Long.class.getName()); } else if (introspectedColumn.getLength() > 4) { answer = new FullyQualifiedJavaType(Integer.class.getName()); } else { answer = new FullyQualifiedJavaType(Short.class.getName()); } break; default: answer = null; break; } } else { answer = jdbcTypeInformation.getFullyQualifiedJavaType(); } return answer; } @Override public String calculateJdbcTypeName(IntrospectedColumn introspectedColumn) { String answer; JdbcTypeInformation jdbcTypeInformation = typeMap .get(introspectedColumn.getJdbcType()); if (jdbcTypeInformation == null) { switch (introspectedColumn.getJdbcType()) { case Types.DECIMAL: answer = "DECIMAL"; //$NON-NLS-1$ break; case Types.NUMERIC: answer = "NUMERIC"; //$NON-NLS-1$ break; default: answer = null; break; } } else { answer = jdbcTypeInformation.getJdbcTypeName(); } return answer; } @Override public void setWarnings(List<String> warnings) { this.warnings = warnings; } @Override public void setContext(Context context) { this.context = context; } public static class JdbcTypeInformation { private String jdbcTypeName; private FullyQualifiedJavaType fullyQualifiedJavaType; public JdbcTypeInformation(String jdbcTypeName, FullyQualifiedJavaType fullyQualifiedJavaType) { this.jdbcTypeName = jdbcTypeName; this.fullyQualifiedJavaType = fullyQualifiedJavaType; } public String getJdbcTypeName() { return jdbcTypeName; } public FullyQualifiedJavaType getFullyQualifiedJavaType() { return fullyQualifiedJavaType; } } }
自定义类型解析器的项目pom需要导入:
<dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-core</artifactId> <version>1.3.2</version> </dependency>
最简单的方法就是将该自定义类型解析器放在packaging为jar的项目中,最常见的就是定义api接口的项目,如下图:
在generatorConfig.xml配置文件中的javaTypeResolver标签中增加type属性,值为自定义类型加载器的路径
在Maven Projects页面找到项目的mybatis-generator插件,双击:
可以看到自动生成的PO中,sex的类型为Integer,而不是Byte。
至此,自定义类型解析器使用成功。
文中使用的MyJavaTypeResolver.java 和generatorConfig.xml代码文件:
链接:https://pan.baidu.com/s/1ezmMq67RPsge8QSNk_QgNQ
密码:m1gz
1. 如果你要自动生成的表不是第一次自动生成,并且没有删除原来生成的文件,存放SQL的Mapper.xml文件代码是会追加到末尾的,并不是直接覆盖原来的。
2. tinyint(1)会自动转为Boolean,true代表1,false代表0。