MyBatis-Generator 帮我们自动生成了基础的增删改查SQL,这解决了大部分简单操作。但对于复杂的查询(比如多条件动态查询、多表关联),它就无法满足了。这时,我们如何在自动生成的 Mapper.xml 文件基础上,安全、高效地添加我们自定义的SQL,而不与自动生成的代码冲突?下面是我总结的方法。
1.修改generatorConfig.xml配置文件
在文件生成表的地方加一行,这样生成的mapper接口可以继承指定的拓展类。
<property name="rootInterface" value="com.sf.lams.portal.core.mapper.GoodMapperExt"/>
<table tableName="good" domainObjectName="Good" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"> <property name="rootInterface" value="com.sf.lams.portal.core.mapper.GoodMapperExt"/> </table>
<?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="application.properties"/> <context id="MallTables" targetRuntime="MyBatis3"> <property name="javaFileEncoding" value="UTF-8"/> <property name="beginningDelimiter" value="`"/> <property name="endingDelimiter" value="`"/> <commentGenerator> <property name="suppressAllComments" value="true"/> <property name="suppressDate" value="true"/> <property name="addRemarkComments" value="true"/> </commentGenerator>
<jdbcConnection driverClass="${spring.datasource.driver-class-name}" connectionURL="${spring.datasource.url}" userId="${spring.datasource.username}" password="${spring.datasource.password}"/>
<javaTypeResolver> <property name="forceBigDecimals" value="false"/> <property name="useJSR310Types" value="true"/> </javaTypeResolver>
<javaModelGenerator targetPackage="com.sf.lams.olcp.dao.domain" targetProject="src/main/java"> <property name="enableSubPackages" value="true"/> <property name="trimStrings" value="true"/> </javaModelGenerator>
<sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources"> <property name="enableSubPackages" value="true"/> </sqlMapGenerator>
<javaClientGenerator type="XMLMAPPER" targetPackage="com.sf.lams.olcp.dao.mapper" targetProject="src/main/java"> <property name="enableSubPackages" value="true"/> </javaClientGenerator>
tableName:数据库表名 domainObjectName:实体类名 enableCountByExample(默认true):MyBatis3Simple为false, 指定是否生成动态查询总条数语句(用于分页的总条数查询); enableUpdateByExample:(默认true):MyBatis3Simple为false, 指定是否生成动态修改语句(只修改对象中不为空的属性); enableDeleteByExample:enableDeleteByExample(默认true): MyBatis3Simple为false,指定是否生成动态删除语句; enableSelectByExample:enableSelectByExample(默认true): MyBatis3Simple为false,指定是否生成动态查询语句; selectByExampleQueryId: enableInsert(默认true):指定是否生成insert语句; enableSelectByPrimaryKey(默认true):指定是否生成按照主键查询对象的语句(就是getById或get); enableUpdateByPrimaryKey(默认true):指定是否生成按照主键修改对象的语句(即update); enableDeleteByPrimaryKey(默认true):指定是否生成按照主键删除对象的语句(即delete); modelType:参考context元素的defaultModelType,相当于覆盖; --> <table tableName="good" domainObjectName="Good" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"> <property name="rootInterface" value="com.sf.lams.olcp.dao.mapper.GoodMapperExt"/>
</table> </context></generatorConfiguration>
2.新增GoodMapperExt接口
这个接口是我们拓展的接口,需要手动创建。
public interface GoodMapperExt { Good selectByPrimaryKey (Integer id);}
public class Good { private Integer id;
private String name;
private Date createdTime;
private Date updatedTime;
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name == null ? null : name.trim(); }
public Date getCreatedTime() { return createdTime; }
public void setCreatedTime(Date createdTime) { this.createdTime = createdTime; }
public Date getUpdatedTime() { return updatedTime; }
public void setUpdatedTime(Date updatedTime) { this.updatedTime = updatedTime; }}
public interface GoodMapper extends GoodMapperExt { int insert(Good record);
int insertSelective(Good record);}
<?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="com.sf.lams.olcp.dao.mapper.GoodMapper"> <resultMap id="BaseResultMap" type="com.sf.lams.olcp.dao.domain.Good"> <result column="id" jdbcType="INTEGER" property="id" /> <result column="name" jdbcType="VARCHAR" property="name" /> <result column="created_time" jdbcType="TIMESTAMP" property="createdTime" /> <result column="updated_time" jdbcType="TIMESTAMP" property="updatedTime" /> </resultMap> <insert id="insert" parameterType="com.sf.lams.olcp.dao.domain.Good"> insert into good (id, name, created_time, updated_time) values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{createdTime,jdbcType=TIMESTAMP}, #{updatedTime,jdbcType=TIMESTAMP}) </insert> <insert id="insertSelective" parameterType="com.sf.lams.olcp.dao.domain.Good"> insert into good <trim prefix="(" suffix=")" suffixOverrides=","> <if test="id != null"> id, </if> <if test="name != null"> name, </if> <if test="createdTime != null"> created_time, </if> <if test="updatedTime != null"> updated_time, </if> </trim> <trim prefix="values (" suffix=")" suffixOverrides=","> <if test="id != null"> #{id,jdbcType=INTEGER}, </if> <if test="name != null"> #{name,jdbcType=VARCHAR}, </if> <if test="createdTime != null"> #{createdTime,jdbcType=TIMESTAMP}, </if> <if test="updatedTime != null"> #{updatedTime,jdbcType=TIMESTAMP}, </if> </trim> </insert></mapper>
<?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="com.sf.lams.olcp.dao.mapper.GoodMapper">
<select id="selectByPrimaryKey" resultMap="BaseResultMap"> select * from good where id=#{id} </select>
</mapper>
需注意的是,GoodMapperExt.xml文件里面的namespace必须和GoodMapper接口的包名一致。但方法id 必须和GoodMapperExt.java里面的方法一致。这样方法的resultMap才可以使用BaseResultMap,这个是在(GoodMapper.xml文件里面定义的)。
@SpringBootTestclass GoodMapperTest { @Resource private GoodMapper goodMapper;
@Test void insert() { Good good = new Good(); good.setName("good"); int result = goodMapper.insert(good); assertEquals(1, result); assertNotNull(good.getId()); System.out.println(good.getId());*/ }
@Test void selectByPrimaryKey() { Good good = goodMapper.selectByPrimaryKey(1); assertNotNull(good); assertEquals("good", good.getName()); System.out.println(good); }
}
通过注入GoodMapper接口,便可以使用GoodMapperExt接口里面的方法。每次生成的代码也只会覆盖GoodMapper接口,对于拓展的接口GoodMapperExt不用改。
我们只需要把复杂业务逻辑写在GoodMapperExt接口里,同时它又具备了GoodMapper接口生成的基本功能,当表的字段变化的时候,只需重新生成覆盖原先自动生成的文件,而拓展的功能部分不需要变动。