花了两天的时间研究了下mybatis的generator大体了解了其生成原理以及实现过程。感觉generator做的非常不错,给开发者也留足了空间。看完之后在generator的基础上实现了自定义的生成器。代码start.....
建立了一个maven工程(common)项目结构:
---------------------------------------------------------------
-pom.xml-----------------------------------------------------------
[html]
view plain
copy
<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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.yangchao</groupId> <artifactId>project-common</artifactId> <version>0.0.1-SNAPSHOT</version> <name>project-common Maven Webapp</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifactId> <version>7.0</version> </dependency> <dependency> <groupId>org.compass-project</groupId> <artifactId>compass</artifactId> <version>2.0.2</version> </dependency> <dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-core</artifactId> <version>1.3.2</version> </dependency> </dependencies> </project>
-------------------------------------------------------------------
jdbc.properties--------------------------------------------------------------------
[plain]
view plain
copy
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/demo1 jdbc.username=root jdbc.password=root initialSize=0 maxActive=20 maxIdle=20 minIdle=1 maxWait=60000
--------------------------------------------------------------------
generatorConfig.xml--------------------------------------------------------------------------------------
[html]
view plain
copy
<?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> <properties resource="jdbc.properties" /> <context id="context1" targetRuntime="MyBatis3"> <plugin type="mybatis.PaginationPlugin" /> <commentGenerator> <property name="suppressDate" value="true" /> <property name="suppressAllComments" value="true" /> </commentGenerator> <jdbcConnection driverClass="${jdbc.driver}" connectionURL="${jdbc.url}" userId="${jdbc.username}" password="${jdbc.password}" /> <javaModelGenerator targetPackage="common.model" targetProject="project-common/src/main/java/" /> <sqlMapGenerator targetPackage="common.model" targetProject="project-common/src/main/java/" /> <javaClientGenerator targetPackage="common.dao" targetProject="project-common/src/main/java" type="XMLMAPPER" /> <table tableName="%" enableSelectByExample="false" enableDeleteByExample="false" enableCountByExample="false" enableUpdateByExample="false" selectByExampleQueryId="false"> <property name="rootClass" value="common.BaseEntity" /> </table> </context> </generatorConfiguration>
-------------------------------------------------------
PaginationPlugin.java------------------------------------------------------
[java]
view plain
copy
public class PaginationPlugin extends PluginAdapter { @Override public boolean clientGenerated(Interface interfaze, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { FullyQualifiedJavaType fqjt = new FullyQualifiedJavaType("BaseDao<" + introspectedTable.getBaseRecordType() + ">"); FullyQualifiedJavaType imp = new FullyQualifiedJavaType("common.BaseDao"); interfaze.addSuperInterface(fqjt); interfaze.addImportedType(imp); interfaze.getMethods().clear(); return true; } @Override public boolean modelGetterMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedColumn introspectedColumn, IntrospectedTable introspectedTable, ModelClassType modelClassType) { return true; } @Override public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { addSerialVersionUID(topLevelClass, introspectedTable); return super.modelBaseRecordClassGenerated(topLevelClass, introspectedTable); } @Override public boolean sqlMapGenerated(GeneratedXmlFile sqlMap, IntrospectedTable introspectedTable) { return super.sqlMapGenerated(sqlMap, introspectedTable); } @Override public boolean sqlMapDocumentGenerated(Document document, IntrospectedTable introspectedTable) { String tableName = introspectedTable.getAliasedFullyQualifiedTableNameAtRuntime(); List<IntrospectedColumn> columns = introspectedTable.getAllColumns(); XmlElement parentElement = document.getRootElement(); XmlElement sql = new XmlElement("sql"); sql.addAttribute(new Attribute("id", "sql_where")); XmlElement where = new XmlElement("where"); StringBuilder sb = new StringBuilder(); for (IntrospectedColumn introspectedColumn : introspectedTable.getNonPrimaryKeyColumns()) { XmlElement isNotNullElement = new XmlElement("if"); sb.setLength(0); sb.append(introspectedColumn.getJavaProperty()); sb.append(" != null"); isNotNullElement.addAttribute(new Attribute("test", sb.toString())); where.addElement(isNotNullElement); sb.setLength(0); sb.append(" and "); sb.append(MyBatis3FormattingUtilities.getEscapedColumnName(introspectedColumn)); sb.append(" = "); sb.append(MyBatis3FormattingUtilities.getParameterClause(introspectedColumn)); isNotNullElement.addElement(new TextElement(sb.toString())); } sql.addElement(where); parentElement.addElement(sql); XmlElement select = new XmlElement("select"); select.addAttribute(new Attribute("id", "getList")); select.addAttribute(new Attribute("resultMap", "BaseResultMap")); select.addAttribute(new Attribute("parameterType", introspectedTable.getBaseRecordType())); select.addElement(new TextElement(" select * from "+ introspectedTable.getFullyQualifiedTableNameAtRuntime())); XmlElement include = new XmlElement("include"); include.addAttribute(new Attribute("refid", "sql_where")); select.addElement(include); parentElement.addElement(select); return super.sqlMapDocumentGenerated(document, introspectedTable); } @Override public boolean sqlMapUpdateByPrimaryKeyWithoutBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) { return false; } @Override public boolean sqlMapInsertElementGenerated(XmlElement element, IntrospectedTable introspectedTable) { return false; } @Override public boolean sqlMapSelectByExampleWithoutBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) { return super.sqlMapSelectByExampleWithoutBLOBsElementGenerated(element, introspectedTable); } public boolean sqlMapDocumentGenerated2(Document document, IntrospectedTable introspectedTable) { String tableName = introspectedTable.getAliasedFullyQualifiedTableNameAtRuntime(); List<IntrospectedColumn> columns = introspectedTable.getAllColumns(); XmlElement sql = new XmlElement("select"); XmlElement parentElement = document.getRootElement(); XmlElement deleteLogicByIdsElement = new XmlElement("update"); deleteLogicByIdsElement.addAttribute(new Attribute("id", "deleteLogicByIds")); deleteLogicByIdsElement .addElement(new TextElement( "update " + tableName + " set deleteFlag = #{deleteFlag,jdbcType=INTEGER} where id in " + " <foreach item=\"item\" index=\"index\" collection=\"ids\" open=\"(\" separator=\",\" close=\")\">#{item}</foreach> ")); parentElement.addElement(deleteLogicByIdsElement); XmlElement queryPage = new XmlElement("select"); queryPage.addAttribute(new Attribute("id", "queryPage")); queryPage.addAttribute(new Attribute("resultMap", "BaseResultMap")); queryPage.addElement(new TextElement("select ")); XmlElement include = new XmlElement("include"); include.addAttribute(new Attribute("refid", "Base_Column_List")); queryPage.addElement(include); queryPage.addElement(new TextElement(" from " + tableName + " ${sql}")); parentElement.addElement(queryPage); return super.sqlMapDocumentGenerated(document, introspectedTable); } private void addSerialVersionUID(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { CommentGenerator commentGenerator = context.getCommentGenerator(); Field field = new Field(); field.setVisibility(JavaVisibility.PRIVATE); field.setType(new FullyQualifiedJavaType("long")); field.setStatic(true); field.setFinal(true); field.setName("serialVersionUID"); field.setInitializationString("1L"); commentGenerator.addFieldComment(field, introspectedTable); topLevelClass.addField(field); } private Method generateDeleteLogicByIds(Method method, IntrospectedTable introspectedTable) { Method m = new Method("deleteLogicByIds"); m.setVisibility(method.getVisibility()); m.setReturnType(FullyQualifiedJavaType.getIntInstance()); m.addParameter(new Parameter(FullyQualifiedJavaType.getIntInstance(), "deleteFlag", "@Param(\"deleteFlag\")")); m.addParameter(new Parameter(new FullyQualifiedJavaType("Integer[]"), "ids", "@Param(\"ids\")")); context.getCommentGenerator().addGeneralMethodComment(m, introspectedTable); return m; } private void addLimit(TopLevelClass topLevelClass, IntrospectedTable introspectedTable, String name) { CommentGenerator commentGenerator = context.getCommentGenerator(); Field field = new Field(); field.setVisibility(JavaVisibility.PROTECTED); field.setType(FullyQualifiedJavaType.getIntInstance()); field.setName(name); field.setInitializationString("-1"); commentGenerator.addFieldComment(field, introspectedTable); topLevelClass.addField(field); char c = name.charAt(0); String camel = Character.toUpperCase(c) + name.substring(1); Method method = new Method(); method.setVisibility(JavaVisibility.PUBLIC); method.setName("set" + camel); method.addParameter(new Parameter(FullyQualifiedJavaType.getIntInstance(), name)); method.addBodyLine("this." + name + "=" + name + ";"); commentGenerator.addGeneralMethodComment(method, introspectedTable); topLevelClass.addMethod(method); method = new Method(); method.setVisibility(JavaVisibility.PUBLIC); method.setReturnType(FullyQualifiedJavaType.getIntInstance()); method.setName("get" + camel); method.addBodyLine("return " + name + ";"); commentGenerator.addGeneralMethodComment(method, introspectedTable); topLevelClass.addMethod(method); } public boolean validate(List<String> arg0) { return true; } public static void generate() { String config = PaginationPlugin.class.getClassLoader().getResource("mybatisConfig.xml").getFile(); String[] arg = { "-configfile", config, "-overwrite" }; ShellRunner.main(arg); } public static void main(String[] args) { generate(); } }
------------------------------------------------
BaseDao.java--------------------------------------------
[java]
view plain
copy
public interface BaseDao<T> { public T selectByPrimaryKey(Integer id); public int deleteByPrimaryKey(Integer id); public int insertSelective(T t); public int updateByPrimaryKeySelective(T t); public List<T> getList(T t); public int getCountSelective(T t); public PageView<T> findPage(final PageView<T> page, final String sql, final Map<String, Object> values); }
-------------------------------------------------
BaseEntity.java---------------------------------------------------
[java]
view plain
copy
public abstract class BaseEntity implements Serializable { private static final long serialVersionUID = 1L; private Integer id; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } }
---------------------------------------------------------------------------------
最终生成dao&&model------------------------------------------------------------------------------------------------
--dao--
UserMapper.java:
[java]
view plain
copy
package common.dao; import common.BaseDao; import common.model.User; public interface UserMapper extends BaseDao<User> { }
---model---
User.java
[java]
view plain
copy
package common.model; import common.BaseEntity; public class User extends BaseEntity { private Integer accountId; private String loginname; private String password; private Integer status; private static final long serialVersionUID = 1L; public Integer getAccountId() { return accountId; } public void setAccountId(Integer accountId) { this.accountId = accountId; } public String getLoginname() { return loginname; } public void setLoginname(String loginname) { this.loginname = loginname; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Integer getStatus() { return status; } public void setStatus(Integer status) { this.status = status; } }
UserMapper.xml
[html]
view plain
copy
<?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="common.dao.UserMapper" > <resultMap id="BaseResultMap" type="common.model.User" > <id column="id" property="id" jdbcType="INTEGER" /> <result column="account_id" property="accountId" jdbcType="INTEGER" /> <result column="loginname" property="loginname" jdbcType="VARCHAR" /> <result column="password" property="password" jdbcType="VARCHAR" /> <result column="status" property="status" jdbcType="INTEGER" /> </resultMap> <sql id="Base_Column_List" > id, account_id, loginname, password, status </sql> <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" > select <include refid="Base_Column_List" /> from user where id = #{id,jdbcType=INTEGER} </select> <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" > delete from user where id = #{id,jdbcType=INTEGER} </delete> <insert id="insertSelective" parameterType="common.model.User" > insert into user <trim prefix="(" suffix=")" suffixOverrides="," > <if test="id != null" > id, </if> <if test="accountId != null" > account_id, </if> <if test="loginname != null" > loginname, </if> <if test="password != null" > password, </if> <if test="status != null" > status, </if> </trim> <trim prefix="values (" suffix=")" suffixOverrides="," > <if test="id != null" > #{id,jdbcType=INTEGER}, </if> <if test="accountId != null" > #{accountId,jdbcType=INTEGER}, </if> <if test="loginname != null" > #{loginname,jdbcType=VARCHAR}, </if> <if test="password != null" > #{password,jdbcType=VARCHAR}, </if> <if test="status != null" > #{status,jdbcType=INTEGER}, </if> </trim> </insert> <update id="updateByPrimaryKeySelective" parameterType="common.model.User" > update user <set > <if test="accountId != null" > account_id = #{accountId,jdbcType=INTEGER}, </if> <if test="loginname != null" > loginname = #{loginname,jdbcType=VARCHAR}, </if> <if test="password != null" > password = #{password,jdbcType=VARCHAR}, </if> <if test="status != null" > status = #{status,jdbcType=INTEGER}, </if> </set> where id = #{id,jdbcType=INTEGER} </update> <sql id="sql_where" > <where > <if test="accountId != null" > and account_id = #{accountId,jdbcType=INTEGER} </if> <if test="loginname != null" > and loginname = #{loginname,jdbcType=VARCHAR} </if> <if test="password != null" > and password = #{password,jdbcType=VARCHAR} </if> <if test="status != null" > and status = #{status,jdbcType=INTEGER} </if> </where> </sql> <select id="getList" resultMap="BaseResultMap" parameterType="common.model.User" > select * from user <include refid="sql_where" /> </select> </mapper>
-----------------------------------代码end------------------------------------
心得:由于开始使用原始的generator生成代码存在,生成后的代码继承结构不存在,重复性代码过多。其实生成所有的代码都是可自定义的,在此我只是将dao中所有的crud方法提取出去放到BaseDao中,以方便之后在具体的dao中添加特殊的需求,让代码简单明了。