暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Spring Boot 整合 MyBatis 通用 Mapper(TkMybatis)

程序员35 2020-05-23
1222

学习在 Spring Boot 中整合 MyBatis 通用 Mapper(TkMybatis)。通用 Mapper 是一个可以实现任意 MyBatis 通用方法的框架,项目提供了常规的增删改查操作以及 Example 相关的单表操作。通用 Mapper 是为了解决 MyBatis 使用中 90% 的基本操作,使用它可以很方便的进行开发,可以节省开发人员大量的时间。

1 概述

通用 Mapper 都可以极大的方便开发人员。可以随意的按照自己的需要选择通用方法,还可以很方便的开发自己的通用方法。

极其方便的使用 MyBatis 单表的增删改查。

支持单表操作,不支持通用的多表联合查询。

使用通用 Mapper 可以无 xml 文件实现数据库操作,只需要继承 TkMybatis 中相关的 Mapper 接口即可。但如果有特殊需求,可以自定义 XXXMapper.xml 文件,实现复杂 sql 语句的操作。

为什么需要通用 Mapper ?

我个人最早用 MyBatis 时,先是完全手写,然后用上了 MyBatis 代码生成器(简称为 MBG),在使用 MBG 过程中,发现一个很麻烦的问题,如果数据库字段变化很频繁,就需要反复重新生成代码,并且由于 MBG 覆盖生成代码和追加方式生成 XML,导致每次重新生成都需要大量的比对修改。除了这个问题外,还有一个问题,仅仅基础的增删改查等方法,就已经产生了大量的 XML 内容,还没有添加一个自己手写的方法,代码可能就已经几百行了,内容多,看着比较碍事。

因为很多人都在使用 MBG,MBG 中定义了很多常用的单表方法,为了解决前面提到的问题,也为了兼容 MBG 的方法避免项目重构太多,在 MBG 的基础上结合了部分 JPA 注解产生了通用 Mapper。通用 Mapper 可以很简单的让你获取基础的单表方法,也很方便扩展通用方法。使用通用 Mapper 可以极大的提高你的工作效率。

说明:我们也可以改造 MBG ,比如自动生成一套基本的 model/mapper/service 等,与表对应,不去做修改,自定义的都写在对应的另一个子类上,这样,当表字段修改后,只需全部重新生成上述基本的那些文件,再手动修改自定义的文件(如果有需要)即可。

2 基本使用

  1. 创建项目,引入依赖

创建 Spring Boot 项目 spring-boot-mybatis-tkmybatis
,添加 Web/MySQL Driver
依赖,如下:

之后手动在 pom 文件中添加 Druid/
依赖(Spring Boot 版本),最终的依赖如下:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.1.10</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
        <version>5.1.27</version>
    </dependency>
    <dependency>
        <groupId>tk.mybatis</groupId>
        <artifactId>mapper-spring-boot-starter</artifactId>
        <version>2.1.5</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>

复制

接着在 application.properties
配置文件中添加数据库相关信息的配置,如下:

spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=000000
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/cxy35?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&autoReconnectForPools=true

复制

  1. 新建实体类

手动新建或用代码生成器生成 User
实体类,并增加相关注解,如下:

@Table(name = "t_user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY, generator = "JDBC")
    private Integer id;
    private String username;
    private String password;
    private Boolean enabled;
    private Boolean locked;
    // @Column(name = "c_address")
    private String address;
    private String nickName;
    private Date createTime;
    private Date updateTime;

    // getter/setter
}

复制

注解说明:

  • @Table
    :指定该实体类对应的表名,如果表名为 t_user ,类名为 TUser ,则可以不需要此注解(默认驼峰命名规则)。
  • @Column
    :指定该属性对应的列名,如果列名为 create_time ,属性名为 createTime ,则可以不需要此注解(默认驼峰命名规则)。
  • @Id
    :标识该字段对应数据库表的主键 id 。
  • @GeneratedValue
    :指定主键 id 生成规则,其中 strategy 表示使用数据库自带的主键生成策略, generator 配置为"JDBC",在数据插入完毕之后,会自动将主键id填充到实体类中,类似普通 mapper.xml 中配置的 selectKey 标签。

  1. 新建 Mapper 接口
public interface UserMapper extends Mapper<User{
}

复制

这里继承 TkMybatis 中最基本的一个通用 Mapper 接口,这样就自动拥有了这个 Mapper 中的一些接口,不用写 XXXMapper.xml 文件。

相关接口如下:


除了 Mapper 接口,官方还提供了一些几个好用的通用 Mapper 接口,都可以用来继承使用,汇总如下:

  • Mapper 接口:

IdsMapper 接口:

ConditionMapper 接口:

  • MySqlMapper 接口:
  • SqlServerMapper 接口:

当然,我们也可以根据自己的实际业务需求,抽取通用业务逻辑,自定义通用 Mapper 接口,参考 通用 Mapper 进阶实例:为什么好久都没更新了? 。

  1. 配置 Mapper 接口的扫描

可以在启动类上或自定义 MyBatis 的配置类上,通过 @MapperScan
注解配置。

@SpringBootApplication
@tk.mybatis.spring.annotation.MapperScan(basePackages = "com.cxy35.sample.springboot.mybatis.tkmybatis.mapper")
public class SpringBootMybatisTkmybatisApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootMybatisTkmybatisApplication.class, args);
    }

}

复制

  1. 测试

在测试类中注入 UserMapper
完成测试,如下:

@SpringBootTest
class SpringBootMybatisTkmybatisApplicationTests {

    @Autowired
    UserMapper userMapper;

    @Test
    public void insertSelective() {
        User user = new User();
        user.setUsername("zhangsan");
        user.setPassword("123456");
        user.setAddress("杭州");
        user.setNickName("zs");
        user.setCreateTime(new Date());
        user.setUpdateTime(new Date());
        userMapper.insertSelective(user);
    }

    @Test
    public void deleteByPrimaryKey() {
        userMapper.deleteByPrimaryKey(2);
    }

    @Test
    public void updateByPrimaryKeySelective() {
        User user = new User();
        user.setId(1);
        user.setUsername("zhangsan2");
        user.setPassword("654321");
        user.setNickName("zs2");
        user.setAddress("上海");
        userMapper.updateByPrimaryKeySelective(user);
    }

    @Test
    public void selectAll() {
        List<User> users = userMapper.selectAll();
        System.out.println(users);
    }

    @Test
    public void selectByExample() {
        Example example = new Example(User.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andLike("username""zhangsan%");
        criteria.andEqualTo("address""杭州");
        List<User> users = userMapper.selectByExample(example);
        System.out.println(users);
    }

}

复制

3 自定义 XXXMapper.xml(非必须)

虽然大多数复杂的需求,都能通过 TkMyBatis 的组合完成操作。但如果有特殊需求,可以自定义 XXXMapper.xml 文件,实现复杂 sql 语句的操作,这里以联表查询为例。

UserMapper.java
所在包下新建 UserMapper.xml
,增加如下内容:

<?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.cxy35.sample.springboot.mybatis.tkmybatis.mapper.UserMapper">
    <select id="selectByRoleId" parameterType="java.lang.Integer" resultType="com.cxy35.sample.springboot.mybatis.tkmybatis.pojo.User">
        SELECT
            u.*
        FROM
            t_user u
        INNER JOIN t_user_role ur ON u.id = ur.user_id
        WHERE
            ur.role_id = #{roleId, jdbcType=INTEGER};
    </select>
</mapper>

复制

上述 xml 文件与普通 xml 文件的不同之处在于:这里不需要使用 resultMap 进行字段的映射。当然,如果想在返回的 Map 中新增返回字段映射,直接添加新的字段即可。

注意:不要在 xml 文件中写 TkMyBatis 中已经有的一些基础方法,否则会报错,提示方法重复。

接着,修改 UserMapper.java ,增加对应的接口:

public interface UserMapper extends Mapper<User{
    // 测试用,非必须
    List<User> selectByRoleId(Integer roleId);
}

复制

上述 UserMapper.xml 放在 UserMapper.java 所在的包下面,会被自动扫描到。但在项目打包时会被忽略掉,因此需要在 pom.xml 中配置 Maven 构建时的资源路径。

<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.xml</include>
            </includes>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
        </resource>
    </resources>
</build>

复制

关于 XXXMapper.xml 文件位置,还有其他方案,这里不再赘述,具体可参考 Spring Boot 整合 MyBatis

最后在测试类中增加方法,完成测试:

@Test
public void selectByRoleId() {
    List<User> users = userMapper.selectByRoleId(2);
    System.out.println(users);
}

复制

4 代码生成器插件

  • 通用 Mapper 插件:tk.mybatis.mapper.generator.MapperPlugin
    ,可以生成带 @Table/@Id/@Column
    等注解的实体类,方便自动与数据库字段进行映射。
  • 通用代码生成器插件:tk.mybatis.mapper.generator.TemplateFilePlugin
    ,实际上是对 MyBatis Generator 的一个扩展,使用这个扩展可以很方便的使用 Freemarker 模板语言编写代码。

首先,在 pom.xml 中增加 MBG 的依赖(因为基于 MBG 插件)和通用 Mapper 的插件依赖,如下:

<dependency>
    <groupId>org.mybatis.generator</groupId>
    <artifactId>mybatis-generator-core</artifactId>
    <version>1.3.7</version>
</dependency>
<dependency>
    <groupId>tk.mybatis</groupId>
    <artifactId>mapper-generator</artifactId>
    <version>1.1.5</version>
</dependency>

复制

接着,在 src/main/resources
目录下新建 generatorConfig.xml
文件,用于配置代码生成器。

<!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="Mysql" targetRuntime="MyBatis3Simple" defaultModelType="flat">
        <property name="beginningDelimiter" value="`"/>
        <property name="endingDelimiter" value="`"/>
        <property name="javaFileEncoding" value="UTF-8"/>
        <!--配置是否使用通用 Mapper 自带的注释扩展,默认 true-->
        <!--<property name="useMapperCommentGenerator" value="false"/>-->

        <!-- 为模型生成序列化方法-->
        <!--<plugin type="org.mybatis.generator.plugins.SerializablePlugin"/>-->
        <!-- 为生成的 Java 模型创建一个 toString 方法 -->
        <!--<plugin type="org.mybatis.generator.plugins.ToStringPlugin"/>-->

        <!-- 通用 Mapper 插件,可以生成带注解的实体类 -->
        <plugin type="tk.mybatis.mapper.generator.MapperPlugin">
            <!-- 生成的 Mapper 接口会自动继承这里配置的接口 -->
            <property name="mappers" value="tk.mybatis.mapper.common.Mapper"/>
            <!-- 是否区分大小写,默认值 false。如果数据库区分大小写,这里就需要配置为 true,这样当表名为 USER 时,会生成 @Table(name = "USER") 注解,否则使用小写 user 时会找不到表。 -->
            <property name="caseSensitive" value="true"/>
            <!-- 是否强制生成注解,默认 false,如果设置为 true,不管数据库名和字段名是否一致,都会生成注解(包含 @Table 和 @Column)。 -->
            <property name="forceAnnotation" value="true"/>
            <!-- 在生成的 model 中,增加字段名的常量,便于使用 Example 拼接查询条件的时候使用。 -->
            <property name="generateColumnConsts" value="true"/>
            <!-- -->
            <!--<property name="generateDefaultInstanceMethod" value="true"/>-->
            <!-- 开始和结束分隔符,对于有关键字的情况下适用。 -->
            <property name="beginningDelimiter" value="`"/>
            <property name="endingDelimiter" value="`"/>
            <!-- 配置是否启用lombok, 支持如下6种注解 -->
            <!-- 注意:当配置 Data 后,Getter Setter ToString EqualsAndHashCode 会被忽略-->
            <!--<property name="lombok" value="Getter,Setter,Data,ToString,Accessors,EqualsAndHashCode"/>-->
            <!--<property name="lombokEqualsAndHashCodeCallSuper" value="true"/>-->
            <!-- -->
            <!--<property name="swagger" value="true"/>-->
        </plugin>

        <!-- 通用代码生成器插件:支持基于 Freemarker 模板生成各种代码(未实测) -->
        <!-- mapper接口 -->
        <!--<plugin type="tk.mybatis.mapper.generator.TemplateFilePlugin">
            <property name="targetProject" value="spring-boot-dao/spring-boot-mybatis-tkmybatis/src/main/java"/>
            <property name="targetPackage" value="com.cxy35.sample.springboot.mybatis.tkmybatis.mbg.mapper"/>
            <property name="templatePath" value="generator/mapper.ftl"/>
            <property name="fileName" value="${tableClass.shortClassName}${mapperSuffix}.java"/>
            <property name="mapperSuffix" value="Dao"/>
        </plugin>-->


        <!-- mapper.xml -->
        <!--<plugin type="tk.mybatis.mapper.generator.TemplateFilePlugin">
            <property name="targetProject" value="spring-boot-dao/spring-boot-mybatis-tkmybatis/src/main/java"/>
            <property name="targetPackage" value="com.cxy35.sample.springboot.mybatis.tkmybatis.mbg.mapper"/>
            <property name="templatePath" value="generator/mapperXml.ftl"/>
            <property name="fileName" value="${tableClass.shortClassName}${mapperSuffix}.xml"/>
            <property name="mapperSuffix" value="Dao"/>
            <property name="mapperPackage" value="com.cxy35.sample.springboot.mybatis.tkmybatis.mbg.mapper"/>
        </plugin>-->


        <!-- 配置数据库连接 -->
        <jdbcConnection driverClass="${spring.datasource.driver-class-name}"
                        connectionURL="${spring.datasource.url}"
                        userId="${spring.datasource.username}"
                        password="${spring.datasource.password}">

            <!-- 解决 mysql 驱动升级到 8.0 后不生成指定数据库代码的问题 -->
            <property name="nullCatalogMeansCurrent" value="true" />
        </jdbcConnection>

        <!-- 指定生成 model 的路径 -->
        <javaModelGenerator targetPackage="com.cxy35.sample.springboot.mybatis.tkmybatis.mbg.model" targetProject="spring-boot-dao/spring-boot-mybatis-tkmybatis/src/main/java"/>

        <!-- 指定生成 mapper 接口的的路径 -->
        <javaClientGenerator targetPackage="com.cxy35.sample.springboot.mybatis.tkmybatis.mbg.mapper" targetProject="spring-boot-dao/spring-boot-mybatis-tkmybatis/src/main/java" type="XMLMAPPER"/>

        <!-- 非必须 -->
        <!-- 指定生成 mapper.xml 的路径 -->
        <!--<sqlMapGenerator targetPackage="com.cxy35.sample.springboot.mybatis.tkmybatis.mbg.mapper" targetProject="spring-boot-dao/spring-boot-mybatis-tkmybatis/src/main/java"/>-->

        <!-- tableName 可以使用 % 通配符 -->
        <table tableName="t_user">
            <generatedKey column="id" sqlStatement="JDBC"/>
        </table>
        <!--<table tableName="t_user_role">
            <generatedKey column="id" sqlStatement="JDBC"/>
        </table>-->

    </context>
</generatorConfiguration>

复制

最后,在 com.cxy35.sample.springboot.mybatis.tkmybatis
下新建 mbg
包,用来存放代码生成器相关配置代码和最终生成的业务代码。新建 Generator.java
如下:

public class Generator {

    public static InputStream getResourceAsStream(String path) {
        return Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
    }

    public static void main(String[] args) throws Exception {
        //MBG 执行过程中的警告信息
        List<String> warnings = new ArrayList<String>();
        //当生成的代码重复时,覆盖原代码
        boolean overwrite = true;
        //读取我们的 MBG 配置文件
        InputStream is = Generator.class.getResourceAsStream("/generatorConfig.xml");
        ConfigurationParser cp = new ConfigurationParser(warnings);
        Configuration config = cp.parseConfiguration(is);
        is.close();

        DefaultShellCallback callback = new DefaultShellCallback(overwrite);
        //创建 MBG
        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
        //执行生成代码
        myBatisGenerator.generate(null);
        //输出警告信息
        for (String warning : warnings) {
            System.out.println(warning);
        }
    }
}

复制

运行上述 main 方法即可自动生成代码,分别如下:

  • TUser.java
@Table(name = "`t_user`")
public class TUser {
    /**
     * 主键id
     */

    @Id
    @Column(name = "`id`")
    @GeneratedValue(generator = "JDBC")
    private Integer id;

    /**
     * 用户名
     */

    @Column(name = "`username`")
    private String username;

    /**
     * 密码
     */

    @Column(name = "`password`")
    private String password;

    /**
     * 是否启用:1 启用;0 未启用
     */

    @Column(name = "`enabled`")
    private Boolean enabled;

    /**
     * 是否锁定:1 锁定;0 未锁定
     */

    @Column(name = "`locked`")
    private Boolean locked;

    /**
     * 地址
     */

    @Column(name = "`address`")
    private String address;

    /**
     * 昵称
     */

    @Column(name = "`nick_name`")
    private String nickName;

    /**
     * 创建时间
     */

    @Column(name = "`create_time`")
    private Date createTime;

    /**
     * 更新时间
     */

    @Column(name = "`update_time`")
    private Date updateTime;

    public static final String ID = "id";

    public static final String DB_ID = "id";

    public static final String USERNAME = "username";

    public static final String DB_USERNAME = "username";

    public static final String PASSWORD = "password";

    public static final String DB_PASSWORD = "password";

    public static final String ENABLED = "enabled";

    public static final String DB_ENABLED = "enabled";

    public static final String LOCKED = "locked";

    public static final String DB_LOCKED = "locked";

    public static final String ADDRESS = "address";

    public static final String DB_ADDRESS = "address";

    public static final String NICK_NAME = "nickName";

    public static final String DB_NICK_NAME = "nick_name";

    public static final String CREATE_TIME = "createTime";

    public static final String DB_CREATE_TIME = "create_time";

    public static final String UPDATE_TIME = "updateTime";

    public static final String DB_UPDATE_TIME = "update_time";

    // getter/setter
}

复制
  • TUserMapper.java
public interface TUserMapper extends Mapper<TUser{
}

复制
  • TUserMapper.xml(非必须)
<?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.cxy35.sample.springboot.mybatis.tkmybatis.mbg.mapper.TUserMapper">
  <resultMap id="BaseResultMap" type="com.cxy35.sample.springboot.mybatis.tkmybatis.mbg.model.TUser">
    <!--
      WARNING - @mbg.generated
    -->

    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="username" jdbcType="VARCHAR" property="username" />
    <result column="password" jdbcType="VARCHAR" property="password" />
    <result column="enabled" jdbcType="BIT" property="enabled" />
    <result column="locked" jdbcType="BIT" property="locked" />
    <result column="address" jdbcType="VARCHAR" property="address" />
    <result column="nick_name" jdbcType="VARCHAR" property="nickName" />
    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
    <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
  </resultMap>
</mapper>

复制

扩展阅读:

  • Mybatis 通用 Mapper 代码生成器
  • 通用 Mapper 专用代码生成器
  • MyBatis Generator 详解

  • Spring Boot 教程合集(微信左下方阅读全文可直达)。
  • Spring Boot 教程合集示例代码:https://github.com/cxy35/spring-boot-samples
  • 本文示例代码:https://github.com/cxy35/spring-boot-samples/tree/master/spring-boot-dao/spring-boot-mybatis-tkmybatis
文章转载自程序员35,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论