本文提供一種方法,目標是讓MyBatis Generator產生的Mapper更簡潔。html
主要體如今以下幾個方面:java
好比,咱們創建兩個測試表,一個是t_user, 一個是t_news。其建表語句以下:sql
CREATE TABLE `t_user` ( `user_id` int(11) NOT NULL AUTO_INCREMENT, `email` varchar(64) DEFAULT NULL, `name` varchar(30) DEFAULT NULL, PRIMARY KEY (`user_id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
CREATE TABLE `t_news` ( `news_id` int(11) NOT NULL AUTO_INCREMENT, `title` varchar(150) NOT NULL, `content` text NOT NULL, `brief_intro` varchar(255) DEFAULT NULL, `pic_url` varchar(255) DEFAULT NULL, `news_from` varchar(100) DEFAULT NULL, `news_author` varchar(50) DEFAULT NULL, `news_url` varchar(255) DEFAULT NULL, `keywords` varchar(150) DEFAULT NULL, `meta_desc` varchar(150) DEFAULT NULL, `create_time` datetime DEFAULT NULL, PRIMARY KEY (`news_id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
而後,咱們比較一下自動產生的Mapper有什麼區別?數據庫
UserMapper.javaapache
import java.util.List; import my.mybatis.generator.auto.entity.User; import my.mybatis.generator.auto.entity.UserExample; import org.apache.ibatis.annotations.Param; public interface UserMapper { /** * This method was generated by MyBatis Generator. * This method corresponds to the database table t_user * * @mbggenerated Wed Nov 09 10:23:34 CST 2016 */ int countByExample(UserExample example); /** * This method was generated by MyBatis Generator. * This method corresponds to the database table t_user * * @mbggenerated Wed Nov 09 10:23:34 CST 2016 */ int deleteByExample(UserExample example); /** * This method was generated by MyBatis Generator. * This method corresponds to the database table t_user * * @mbggenerated Wed Nov 09 10:23:34 CST 2016 */ int deleteByPrimaryKey(Integer userId); /** * This method was generated by MyBatis Generator. * This method corresponds to the database table t_user * * @mbggenerated Wed Nov 09 10:23:34 CST 2016 */ int insert(User record); /** * This method was generated by MyBatis Generator. * This method corresponds to the database table t_user * * @mbggenerated Wed Nov 09 10:23:34 CST 2016 */ int insertSelective(User record); /** * This method was generated by MyBatis Generator. * This method corresponds to the database table t_user * * @mbggenerated Wed Nov 09 10:23:34 CST 2016 */ List<User> selectByExample(UserExample example); /** * This method was generated by MyBatis Generator. * This method corresponds to the database table t_user * * @mbggenerated Wed Nov 09 10:23:34 CST 2016 */ User selectByPrimaryKey(Integer userId); /** * This method was generated by MyBatis Generator. * This method corresponds to the database table t_user * * @mbggenerated Wed Nov 09 10:23:34 CST 2016 */ int updateByExampleSelective(@Param("record") User record, @Param("example") UserExample example); /** * This method was generated by MyBatis Generator. * This method corresponds to the database table t_user * * @mbggenerated Wed Nov 09 10:23:34 CST 2016 */ int updateByExample(@Param("record") User record, @Param("example") UserExample example); /** * This method was generated by MyBatis Generator. * This method corresponds to the database table t_user * * @mbggenerated Wed Nov 09 10:23:34 CST 2016 */ int updateByPrimaryKeySelective(User record); /** * This method was generated by MyBatis Generator. * This method corresponds to the database table t_user * * @mbggenerated Wed Nov 09 10:23:34 CST 2016 */ int updateByPrimaryKey(User record); }
NewsMapper.javaapi
import java.util.List; import my.mybatis.generator.auto.entity.News; import my.mybatis.generator.auto.entity.NewsExample; import org.apache.ibatis.annotations.Param; public interface NewsMapper { /** * This method was generated by MyBatis Generator. * This method corresponds to the database table m_news * * @mbggenerated Wed Nov 09 10:23:34 CST 2016 */ int countByExample(NewsExample example); /** * This method was generated by MyBatis Generator. * This method corresponds to the database table m_news * * @mbggenerated Wed Nov 09 10:23:34 CST 2016 */ int deleteByExample(NewsExample example); /** * This method was generated by MyBatis Generator. * This method corresponds to the database table m_news * * @mbggenerated Wed Nov 09 10:23:34 CST 2016 */ int deleteByPrimaryKey(Integer newsId); /** * This method was generated by MyBatis Generator. * This method corresponds to the database table m_news * * @mbggenerated Wed Nov 09 10:23:34 CST 2016 */ int insert(News record); /** * This method was generated by MyBatis Generator. * This method corresponds to the database table m_news * * @mbggenerated Wed Nov 09 10:23:34 CST 2016 */ int insertSelective(News record); /** * This method was generated by MyBatis Generator. * This method corresponds to the database table m_news * * @mbggenerated Wed Nov 09 10:23:34 CST 2016 */ List<News> selectByExampleWithBLOBs(NewsExample example); /** * This method was generated by MyBatis Generator. * This method corresponds to the database table m_news * * @mbggenerated Wed Nov 09 10:23:34 CST 2016 */ List<News> selectByExample(NewsExample example); /** * This method was generated by MyBatis Generator. * This method corresponds to the database table m_news * * @mbggenerated Wed Nov 09 10:23:34 CST 2016 */ News selectByPrimaryKey(Integer newsId); /** * This method was generated by MyBatis Generator. * This method corresponds to the database table m_news * * @mbggenerated Wed Nov 09 10:23:34 CST 2016 */ int updateByExampleSelective(@Param("record") News record, @Param("example") NewsExample example); /** * This method was generated by MyBatis Generator. * This method corresponds to the database table m_news * * @mbggenerated Wed Nov 09 10:23:34 CST 2016 */ int updateByExampleWithBLOBs(@Param("record") News record, @Param("example") NewsExample example); /** * This method was generated by MyBatis Generator. * This method corresponds to the database table m_news * * @mbggenerated Wed Nov 09 10:23:34 CST 2016 */ int updateByExample(@Param("record") News record, @Param("example") NewsExample example); /** * This method was generated by MyBatis Generator. * This method corresponds to the database table m_news * * @mbggenerated Wed Nov 09 10:23:34 CST 2016 */ int updateByPrimaryKeySelective(News record); /** * This method was generated by MyBatis Generator. * This method corresponds to the database table m_news * * @mbggenerated Wed Nov 09 10:23:34 CST 2016 */ int updateByPrimaryKeyWithBLOBs(News record); /** * This method was generated by MyBatis Generator. * This method corresponds to the database table m_news * * @mbggenerated Wed Nov 09 10:23:34 CST 2016 */ int updateByPrimaryKey(News record); }
從上述兩個自動產生的Mapper能夠看出,session
除了Entity、Entity對應的Example以及Primary Key可能會變化以外,其他全部的方法名都是同樣的。mybatis
若是是這樣自動產生代碼,那麼各個Mapper勢必有不少重複的代碼,不直觀。app
那麼,問題來了?dom
可不能夠將這些通用的方法定義在一個BaseMapper中,而後,其他自動產生的Mapper繼承自BaseMapper,且與各自的Entity、Example、Primary KEY綁定在一塊兒呢?
好比:
定義一個BaseMapper.java,其中,
- T表示與table表對應的實體類(Entity)
- E表示Entity對應的Example類
- PK表示可能會用到主鍵 (好比Integer等)
以下所示:
package my.mabatis.example.base; import java.io.Serializable; import java.util.List; import org.apache.ibatis.annotations.Param; /** * * @author wangmengjun * */ public interface BaseMapper<T, E, PK extends Serializable> { long countByExample(E example); int deleteByExample(E example); int deleteByPrimaryKey(PK pk); int insert(T record); int insertSelective(T record); List<T> selectByExample(E example); T selectByPrimaryKey(PK pk); int updateByExampleSelective(@Param("record") T record, @Param("example") E example); int updateByExample(@Param("record") T record, @Param("example") E example); int updateByPrimaryKeySelective(T record); int updateByPrimaryKey(T record); }
那麼,
UserMapper.java就變成相似以下的樣子了。
public interface NewsMapper extends BaseMapper<News, NewsExample, Integer> { }
接下來,咱們就來看看如何完成去達到這樣的目標。Let‘s GO~~~~
改源代碼?
若是一個工具,讓產生的Dao繼承一個BaseMapper,都須要經過源碼來完成,那其擴展性可見通常。 不建議使用,這個只能是沒有辦法的時候纔會使用。
由於,上述考慮的都是Mapper,那麼,若是改動源代碼的話,咱們就在org.mybatis.generator.codegen.mybatis3.javamapper.JavaMapperGenerator類中修改便可。
修改包含兩個部分,
- 不在Mapper中添加任何方法,由於這些都在BaseMapper中存在了,只要繼承便可。
- 產生Mapper的時候,指定父類接口BaseMapper, 實體類類型、Example類型、主鍵類型。
具體在JavaMapperGenerator類的getCompilationUnits方法下進行:
public List<CompilationUnit> getCompilationUnits() { //省略全部方法內容 }
addCountByExampleMethod(interfaze); addDeleteByExampleMethod(interfaze); addDeleteByPrimaryKeyMethod(interfaze); addInsertMethod(interfaze); addInsertSelectiveMethod(interfaze); addSelectByExampleWithBLOBsMethod(interfaze); addSelectByExampleWithoutBLOBsMethod(interfaze); addSelectByPrimaryKeyMethod(interfaze); addUpdateByExampleSelectiveMethod(interfaze); addUpdateByExampleWithBLOBsMethod(interfaze); addUpdateByExampleWithoutBLOBsMethod(interfaze); addUpdateByPrimaryKeySelectiveMethod(interfaze); addUpdateByPrimaryKeyWithBLOBsMethod(interfaze); addUpdateByPrimaryKeyWithoutBLOBsMethod(interfaze);
在上述移除的代碼塊中添加相似以下代碼塊。
/** * 主鍵默認採用java.lang.Integer */ FullyQualifiedJavaType fqjt = new FullyQualifiedJavaType("BaseMapper<" + introspectedTable.getBaseRecordType() + "," + introspectedTable.getExampleType() + "," + "java.lang.Integer" + ">"); FullyQualifiedJavaType imp = new FullyQualifiedJavaType( "my.mabatis.example.base.BaseMapper"); /** * 添加 extends MybatisBaseMapper */ interfaze.addSuperInterface(fqjt); /** * 添加import my.mabatis.example.base.MybatisBaseMapper; */ interfaze.addImportedType(imp); /** * 方法不須要 */ interfaze.getMethods().clear();
而後,而後就搞定了。 : )
儘管修改源代碼的方式可行,可是侵入性太強。
其實,MyBatis Generator自動代碼產生工具已經提供插件適配擴展的功能,咱們只要繼承PluginAdapter便可。而後,重寫clientGenerated方法便可。
@Override public boolean clientGenerated(Interface interfaze, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { }
具體代碼以下:
默認採用java.lang.Integer做爲主鍵。
package my.mabatis.example.plugin; import java.util.List; import org.mybatis.generator.api.IntrospectedTable; import org.mybatis.generator.api.PluginAdapter; import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType; import org.mybatis.generator.api.dom.java.Interface; import org.mybatis.generator.api.dom.java.TopLevelClass; /** * @author wangmengjun * */ public class BaseMapperGeneratorPlugin extends PluginAdapter { public boolean validate(List<String> warnings) { return true; } /** * 生成dao */ @Override public boolean clientGenerated(Interface interfaze, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { /** * 主鍵默認採用java.lang.Integer */ FullyQualifiedJavaType fqjt = new FullyQualifiedJavaType("BaseMapper<" + introspectedTable.getBaseRecordType() + "," + introspectedTable.getExampleType() + "," + "java.lang.Integer" + ">"); FullyQualifiedJavaType imp = new FullyQualifiedJavaType( "my.mabatis.example.base.BaseMapper"); /** * 添加 extends MybatisBaseMapper */ interfaze.addSuperInterface(fqjt); /** * 添加import my.mabatis.example.base.MybatisBaseMapper; */ interfaze.addImportedType(imp); /** * 方法不須要 */ interfaze.getMethods().clear(); interfaze.getAnnotations().clear(); return true; } }
接着,在用於自動產生代碼的配置文件中generatorConfig.xml指定自定義的plugin。
如:
<!-- 配置內置的或者自定義的Plugin --> <plugin type="my.mabatis.example.plugin.BaseMapperGeneratorPlugin" />
詳細配置如:
<?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 --> <plugin type="my.mabatis.example.plugin.BaseMapperGeneratorPlugin" /> <!-- 註釋產生配置 --> <commentGenerator> <property name="suppressAllComments" value="false" /> <property name="suppressDate" value="false" /> </commentGenerator> <!-- 數據庫鏈接信息 --> <jdbcConnection driverClass="${jdbc.driverClassName}" connectionURL="${jdbc.url}" userId="${jdbc.username}" password="${jdbc.password}" /> <!-- 生成Model對象路徑配置 --> <javaModelGenerator targetPackage="my.mybatis.generator.auto.entity" targetProject="src\main\java"> <property name="enableSubPackages" value="true" /> <property name="trimStrings" value="true" /> </javaModelGenerator> <!-- 生成sqlXML文件路徑配置 --> <sqlMapGenerator targetPackage="my.mybatis.generator.auto.entity.xml" targetProject="src\main\java"> <property name="enableSubPackages" value="true" /> </sqlMapGenerator> <!-- 生成DAO的類文件路徑配置 --> <javaClientGenerator targetPackage="my.mybatis.generator.auto.dao" targetProject="src\main\java" type="XMLMAPPER"> <property name="enableSubPackages" value="true" /> </javaClientGenerator> <!--要生成哪些表 --> <table tableName="t_user" domainObjectName="User" /> <table tableName="t_news" domainObjectName="News" /> </context> </generatorConfiguration>
通過上述幾個步驟,從新生成代碼,就能夠看到生成的Mapper,包括UserMapper和NewsMapper都已經發生了變化,而這正是咱們所指望的。
public interface NewsMapper extends BaseMapper<News, NewsExample, Integer> { }
public interface UserMapper extends BaseMapper<User, UserExample, Integer> { }
自動產生的Mapper繼承於BaseMapper,變得相對較爲乾淨。
接下來,咱們就來測試一下,是否管用。
在src/main/resource目錄下建立mybatis-config.xml配置文件。內容以下:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <properties resource="jdbc.properties" /> <typeAliases> <typeAlias type="my.mybatis.generator.auto.entity.User" alias="User" /> </typeAliases> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driverClassName}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </dataSource> </environment> </environments> <mappers> <mapper resource="my/mybatis/generator/auto/entity/xml/UserMapper.xml" /> </mappers> </configuration>
package my.mabatis.example.util; import java.io.IOException; import java.io.Reader; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; /** * * @author wangmengjun * */ public class MyBatisUtil { private static SqlSessionFactory factory; private MyBatisUtil() { } static { Reader reader = null; try { reader = Resources.getResourceAsReader("mybatis-config.xml"); } catch (IOException e) { throw new RuntimeException(e.getMessage()); } factory = new SqlSessionFactoryBuilder().build(reader); } public static SqlSessionFactory getSqlSessionFactory() { return factory; } }
由於只是很簡單的操做,因此service就不分接口和實現了,直接上代碼。
package my.mabatis.example.service; import java.util.List; import my.mabatis.example.util.MyBatisUtil; import my.mybatis.generator.auto.dao.UserMapper; import my.mybatis.generator.auto.entity.User; import my.mybatis.generator.auto.entity.UserExample; import my.mybatis.generator.auto.entity.UserExample.Criteria; import org.apache.ibatis.session.SqlSession; /** * * @author wangmengjun * */ public class UserService { /** * 保存用戶 * @param user 待保存用戶對象 */ public void insertUser(User user) { SqlSession sqlSession = MyBatisUtil.getSqlSessionFactory() .openSession(); try { UserMapper userDao = sqlSession.getMapper(UserMapper.class); userDao.insert(user); sqlSession.commit(); } finally { sqlSession.close(); } } /** * 按照指定email返回用戶 * @param email * @return 按照指定email返回用戶 */ public User findUserByEmail(String email) { SqlSession sqlSession = MyBatisUtil.getSqlSessionFactory() .openSession(); try { UserMapper userDao = sqlSession.getMapper(UserMapper.class); /** * 使用Example來操做 */ UserExample example = new UserExample(); Criteria criteria = example.createCriteria(); criteria.andEmailEqualTo(email); List<User> users = userDao.selectByExample(example); /** * 假定email惟一 */ return users.isEmpty() ? null : users.get(0); } finally { sqlSession.close(); } } }
package my.mabatis.example.runner; import my.mabatis.example.service.UserService; import my.mybatis.generator.auto.entity.User; public class Test { public static void main(String[] args) { UserService userService = new UserService(); User userToInsert = new User(); userToInsert.setEmail("wmj123456@test.com"); userToInsert.setName("mengjun"); userService.insertUser(userToInsert); User user = userService.findUserByEmail("wmj123456@test.com"); System.out.println(user.getEmail()); System.out.println(user.getName()); } }
輸出結果:
log4j:WARN No appenders could be found for logger (org.apache.ibatis.logging.LogFactory). log4j:WARN Please initialize the log4j system properly. log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info. wmj123456@test.com mengjun
保存用戶信息和查看用戶信息都能成功執行,代碼可用。至此,整個流程就結束了。
Note:
整個代碼都是在上一篇文章<<使用MyBatis Generator自動生成代碼>>的基礎上改動的,如對generatorConfig.xml等配置文件或者對如何自動產生代碼有疑問,能夠參考一下。
工程結構