3

Spring Boot 中使用 tkMapper - luis林威

 1 year ago
source link: https://www.cnblogs.com/luisblog/p/16875672.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

说明:基于 MyBatis 有很多第三方功能插件,这些插件可以完成数据操作方法的封装、数据库逆向工程的生成等。

tkMapperMyBatis-plus 都是基于 MyBatis 提供的第三方插件,功能类似,下面介绍 tkMapper 的使用。

tkMapper 就是一个 MyBatis 插件,基于 MyBatis 提供很多工具,提高开发效率,主要有以下两个功能。

  • 提供针对单表通用的数据库操作方法
  • 逆向工程(根据数据表自动生成实体类、Dao 接口、Mapper 映射文件)

MyBatis 基础环境

tkMapper 的使用需要基于 MyBatis。

  1. 创建 Spring Boot 项目,选中 Lombok、Spring Web、MyBatis Framework、MySQL Driver 依赖

  2. application.yml 配置文件中配置相关信息

    spring:
      datasource:
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://localhost:3306/springdb?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8
        username: root
        password: luis
    
    mybatis:
      type-aliases-package: com.luis.beans
      mapper-locations: classpath:mappers/*Mapper.xml
    

    注意:配置后,手动创建 beans 和 mappers 文件夹

  3. 创建 dao 文件夹,在启动类上添加 dao 的包扫描器 @MapperScan(basePackages = {"com.luis.dao"})

tkMapper 环境搭建

  1. <!-- tkMapper -->
    <dependency>
        <groupId>tk.mybatis</groupId>
        <artifactId>mapper-spring-boot-starter</artifactId>
        <version>2.1.5</version>
    </dependency>
    

    如果自己在 maven 仓库中搜索,注意搜索关键词:mapper starter

    image-20221109104950352

    PS:添加后,注意手动刷新 pom

  2. 更换启动类上 dao 包的包扫描器来源,不使用原先的 @MapperScan,要使用新添加的 tkMapper 的 @MapperScan

    import tk.mybatis.spring.annotation.MapperScan;
    
    @SpringBootApplication
    @MapperScan(basePackages = {"com.luis.dao"}) //使用tkMapper的包扫描器注解
    public class SpringbootTkMapperDemoApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringbootTkMapperDemoApplication.class, args);
        }
    
    }
    

    PS:注意注解的包来源 import tk.mybatis.spring.annotation.MapperScan

  3. 以上,tkMapper 环境已经搭建完成

tkMapper 对数据的通用操作

tkMapper 提供针对单表通用的数据库操作方法。

1. 创建数据库表
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users`  (
  `user_id` int(11) NOT NULL AUTO_INCREMENT,
  `user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `user_pwd` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `user_realname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `user_img` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`user_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Compact;
2. 创建实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "users") //数据库表名和实体类类名不一致需要指定映射关系!
public class User {

    @Id //指定主键
    private Integer userId;
    private String userName;
    private String userPwd;
    private String userRealname;
    private String userImg;

}
3. 创建 Dao 接口【重点】

注意:创建的 Dao 接口需要继承 tkMapper 中提供的 MapperMySqlMapper 两个接口,这两个接口提供了对单表的通用操作。

public interface UserDao extends Mapper<User>, MySqlMapper<User> {
}

可选优化策略【建议使用】:

如果不想每次创建 dao 接口时都继承 tkMapper 中的两个接口,可以自己写一个通用的接口模板,只需要让这个通用的接口模板继承 tkMapper 中的两个接口,然后自己创建的 dao 接口只需要继承这个通用的接口模板即可!

但是,需要注意的是,这个通用的接口模板千万不能写在 dao 目录下!因为 dao 目录下的接口会被扫描到,有固定的功能用处;而我们自定义的通用接口模板只是为了继承,没有其他特殊功能!

使用示例:

1、可在 dao 目录同级创建 general 目录,在 general 目录下创建 GeneralDao 接口,并继承 tkMapper 中的两个接口。

package com.luis.general;

import tk.mybatis.mapper.common.Mapper;
import tk.mybatis.mapper.common.MySqlMapper;

/**
 * @Author: Luis
 * @date: 2022/11/9 14:39
 * @description: 自定义的通用接口模板
 */
public interface GeneralDao<T> extends Mapper<T>, MySqlMapper<T> {
}

2、创建 dao 接口,继承 GeneralDao 即可!

public interface UserDao extends GeneralDao<User> {
}

添加 Junit 和 springboot test 两个测试依赖:

<!-- junit -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <scope>test</scope>
</dependency>
<!-- springboot test -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>

写测试类进行测试:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringbootTkMapperDemoApplication.class) //启动类.class
public class UserDaoTest {

    @Autowired
    private UserDao userDao; //如果爆红线不用管(或Dao接口上添加@Repository注解)

    @Test
    public void test() {

        User user = new User();
        user.setUserName("mike");
        user.setUserPwd("123");
        user.setUserRealname("zhangsan");
        user.setUserImg("user/default.jpg");

        int i = userDao.insert(user);
        System.out.println("========> i = " + i);
    }
}

tkMapper 常用方法之增删改

  • insert:普通添加
  • insertUseGeneratedKeys:可返回自增 id 的添加
  • updateByPrimaryKey:根据主键修改
  • deleteByPrimaryKey:根据主键删除
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringbootTkMapperDemoApplication.class) //启动类.class
public class UserDaoTest {

    @Autowired
    private UserDao userDao; //如果爆红线不用管(或Dao接口上添加@Repository注解)

    @Test
    public void testInsert() {

        User user = new User();
        user.setUserName("juno4");
        user.setUserPwd("321");
        user.setUserRealname("lin");
        user.setUserImg("user/default.jpg");

        /**
         * insert: 添加(自增的id不会返回)
         */
        int i = userDao.insert(user);
        System.out.println("========> i = " + i);
        System.out.println(user.getUserId()); //null
    }

    @Test
    public void testInsertUseGeneratedKeys() {

        User user = new User();
        user.setUserName("juno3");
        user.setUserPwd("321");
        user.setUserRealname("lin");
        user.setUserImg("user/default.jpg");

        /**
         * insertUseGeneratedKeys: 添加(自增的id可以返回)
         * 注意:
         *  1. 数据库中主键字段需要设置为自增
         *  2. 实体类中主键属性需要使用@Id注解指定;并且需要使用包装类型Integer,不要使用int
         */
        int i = userDao.insertUseGeneratedKeys(user);
        System.out.println("========> i = " + i);
        System.out.println(user.getUserId()); //10
    }

    @Test
    public void testUpdateByPrimaryKey() {

        User user = new User();
        user.setUserId(10); //必须指定要修改的id
        user.setUserName("juno new");
        user.setUserPwd("000");
        user.setUserRealname("lin new");
        user.setUserImg("new.jpg");

        /**
         * updateByPrimaryKey:根据主键修改
         */
        int i = userDao.updateByPrimaryKey(user);
        System.out.println("========> i = " + i);
        System.out.println(user);
    }

    @Test
    public void testDeleteByPrimaryKey() {
        /**
         * deleteByPrimaryKey:根据主键删除
         */
        int i = userDao.deleteByPrimaryKey(9);
        System.out.println("========> i = " + i);
    }
}

PS:其实还有根据自定义条件修改或删除的方法(使用方法参考带条件的查询示例)

tkMapper 常用方法之查询

  • selectAll:查所有
  • selectByPrimaryKey:根据主键查所有
  • selectByExample:根据条件查所有
  • selectByRowBounds:分页查询
  • selectByExampleAndRowBounds:带条件的分页查询
  • selectCount:查总记录数
  • selectCountByExample:根据条件查总记录数
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringbootTkMapperDemoApplication.class) //启动类.class
public class UserDaoTest {

    @Autowired
    private UserDao userDao; //如果爆红线不用管(或Dao接口上添加@Repository注解)

    @Test
    public void testSelectAll() {
        /**
         * selectAll:查询所有
         */
        List<User> users = userDao.selectAll();
        for (User user : users) {
            System.out.println(user);
        }
    }

    @Test
    public void testSelectByPrimaryKey() {
        /**
         * selectByPrimaryKey:根据主键查询
         */
        User user = userDao.selectByPrimaryKey(10);
        System.out.println(user);
    }

    @Test
    public void testSelectByExample() {

        //封装查询条件
        Example example = new Example(User.class);
        Example.Criteria criteria = example.createCriteria();
        //条件信息(根据Criteria对象的各种方法进行设置)
        criteria.andEqualTo("userRealname", "lin");
        // criteria.orEqualTo("userPwd", "123");
        // criteria.andLike("userName", "%i%");

        /**
         * selectByPrimaryKey:根据条件查询(PS:根据条件修改或删除与此类似)
         *      注意:需要设置查询条件信息,并传入条件对象
         */
        List<User> users = userDao.selectByExample(example);
        for (User user : users) {
            System.out.println("========> " + user);
        }
    }

    @Test
    public void testSelectByRowBounds() {

        //分页查询信息
        int pageNum = 2; //第几页
        int pageSize = 3; //每页显示多少行
        int start = (pageNum - 1) * pageSize; //起始显示的下标
        RowBounds rowBounds = new RowBounds(start, pageSize);

        /**
         * selectByRowBounds:查所有的分页查询
         */
        List<User> users = userDao.selectByRowBounds(new User(), rowBounds);
        for (User user : users) {
            System.out.println("========> " + user);
        }

        /**
         * selectCount:查询总记录数
         */
        int count = userDao.selectCount(new User());
        System.out.println("========> count = " + count);
    }

    @Test
    public void testSelectByExampleAndRowBounds() {

        //封装查询条件
        Example example = new Example(User.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("userRealname", "lin");

        //分页查询信息
        int pageNum = 2; //第几页
        int pageSize = 2; //每页显示多少行
        int start = (pageNum - 1) * pageSize; //起始显示的下标
        RowBounds rowBounds = new RowBounds(start, pageSize);

        /**
         * selectByExampleAndRowBounds:带条件的分页查询
         */
        List<User> users = userDao.selectByExampleAndRowBounds(example, rowBounds);
        for (User user : users) {
            System.out.println("========> " + user);
        }

        /**
         * selectCountByExample:根据条件查询总记录数
         */
        int count = userDao.selectCountByExample(example);
        System.out.println("========> count = " + count);
    }
}

tkMapper 关联/多表查询

说明:所有的关联/多表查询都可以由多个单表查询组成

关联/多表查询实现方式:

方式一:多次使用单表查询,然后封装数据

方式二:自定义查询方法和 SQL

情景:基于以上的用户表,新添加一个订单表 orders,订单表中有订单信息,但是也有用户 id;

要求:在查询用户表的同时还要查询出用户的订单信息,这就涉及到了两张表的查询。

具体业务要求:根据用户名查询用户的所有信息,包括订单信息。

新建订单表 orders:

DROP TABLE IF EXISTS `orders`;
CREATE TABLE `orders`  (
  `order_id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `receiver_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `receiver_mobile` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `receiver_address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  PRIMARY KEY (`order_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Compact;

INSERT INTO `orders` VALUES (1, 1, 'luis', '13344445555', '湖北武汉');

新建实体类 Order:

@Data
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "orders")
public class Order {

    @Id
    private Integer orderId;
    private Integer userId;
    private String receiverName;
    private String receiverMobile;
    private String receiverAddress;

}

新建 dao 接口:

注意,此处 dao 接口继承的是自定义的通用接口模板,相关说明参见之前创建示例 UserDao 的步骤。

也可以直接继承 tkMapper 的两个接口。(注意灵活运用!)

public interface OrderDao extends GeneralDao<Order> {
}

说明:进行关联/多表查询前,需要修改下之前的 User 实体类,在实体类中需要添加一个订单的字段,以便查询出用户所关联的订单信息。

@Data
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "users") //数据库表名和实体类类名不一致需要指定映射关系!
public class User {

    @Id //指定主键
    private Integer userId;
    private String userName;
    private String userPwd;
    private String userRealname;
    private String userImg;
    
    //订单
    private List<Order> orderList;

}
方式一:多次单表查询
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringbootTkMapperDemoApplication.class) //启动类.class
public class UserDaoTest {

    @Autowired
    private UserDao userDao; //如果爆红线不用管(或Dao接口上添加@Repository注解)
    @Autowired
    private OrderDao orderDao;

    @Test
    public void test() {

        //根据用户名查询用户信息
        Example example = new Example(User.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("userName", "luis");
        //条件查询
        List<User> users = userDao.selectByExample(example);
        User user = users.get(0);

        //根据用户id查询订单信息
        Example example1 = new Example(Order.class);
        Example.Criteria criteria1 = example.createCriteria();
        criteria.andEqualTo("userId", user.getUserId());
        //条件查询
        List<Order> orders = orderDao.selectByExample(example1);

        //将查询到的订单信息设置到user中
        user.setOrderList(orders);

        System.out.println("========> " + user);
    }
}    
方式二:自定义连接查询
  1. UserDao 接口中新建查询方法

    public interface UserDao extends GeneralDao<User> {
    
        public User selectByUserName(String userName);
    }
    
  2. mappers 目录下创建对应的 UserMapper.xml 文件,自定义查询 SQL

    <?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.luis.dao.UserDao">
        
        <resultMap id="userMap" type="com.luis.beans.User">
            <id column="user_id" property="userId"/>
            <result column="user_name" property="userName"/>
            <result column="user_pwd" property="userPwd"/>
            <result column="user_realname" property="userRealname"/>
            <result column="user_img" property="userImg"/>
            <collection property="orderList" ofType="com.luis.beans.Order">
                <id column="order_id" property="orderId"/>
                <result column="user_id" property="userId"/>
                <result column="receiver_name" property="receiverName"/>
                <result column="receiver_mobile" property="receiverMobile"/>
                <result column="receiver_address" property="receiverAddress"/>
            </collection>
        </resultMap>
    
        <select id="selectByUserName" resultMap="userMap">
            select u.user_id,u.user_name,u.user_pwd,u.user_realname,u.user_img,
                   o.order_id,o.user_id,o.receiver_name,o.receiver_mobile,o.receiver_address
            from users u inner join orders o
            on u.user_id = o.user_id;
      </select>
    </mapper>
    
  3. @RunWith(SpringRunner.class)
    @SpringBootTest(classes = SpringbootTkMapperDemoApplication.class) //启动类.class
    public class UserDaoTest {
    
        @Autowired
        private UserDao userDao; //如果爆红线不用管(或Dao接口上添加@Repository注解)
        @Autowired
        private OrderDao orderDao;
    
        @Test
        public void test02() {
    
            //使用自定义的查询方法
            User user = userDao.selectByUserName("luis");
            System.out.println("========> " + user);
        }
    }    
    

所谓逆向工程,就是通过数据库表,来自动生成实体类、dao 接口和 mapper 文件。

需要注意的是,本逆向工程是最好配合 tkMapper 环境使用,因为,有一些配置和 tkMapper 相关,如生成的 dao 接口会继承自定义的通用接口模板,而该通用的接口模板就是继承了 tkMapper 中的两个接口,从而才能使用 tkMapper 提供的通用数据操作方法;还有,生成的实体类上的注解需要依赖 tkMapper 环境。

重要说明:本逆向工程使用的 mysql 版本是低版本 5.1.36!经测试,如果使用高版本如 8.xxx,很大概率会生成有问题!所以建议项目中统一使用低版本的 MySQL。

  1. 在 pom.xml 中 build 的 plugins 下添加下列生成器插件

    <!-- mybatis-generator-maven-plugin -->
    <plugin>
        <groupId>org.mybatis.generator</groupId>
        <artifactId>mybatis-generator-maven-plugin</artifactId>
        <version>1.3.6</version>
        <!-- 生成器配置文件位置;如果还没有添加,可以先注释,添加后再放开 -->
        <configuration>
            <configurationFile>
                ${basedir}/src/main/resources/generator/GeneratorConfig.xml
            </configurationFile>
        </configuration>
        <!-- 插件所需的两个依赖 -->
        <dependencies>
            <!-- mysql -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.36</version>
            </dependency>
            <!-- mapper -->
            <dependency>
                <groupId>tk.mybatis</groupId>
                <artifactId>mapper</artifactId>
                <version>4.1.5</version>
            </dependency>
        </dependencies>
    </plugin>
    

    注意:推荐直接复制,但如果想自己在 maven 仓库中搜索,注意关键词:mybatis-generator-maven-plugin,并且,千万注意,你搜索到的肯定是依赖,而并非插件!此时,你只需要复制依赖的 gav 坐标,自己在 pom 中创建空 plugin 标签,将 gav 坐标复制进去即可!(如果相关依赖刷新添加失败,可以复制到 dependences 下,重新刷新添加试试,添加成功后复制回来即可)

  2. 注意查看项目中是否自定义有通用接口模板 GeneralDao,使其继承 tkMapper 的两个接口;如果没有,则在 dao 同级目录,创建 general 目录,在 general 目录下创建自定义通用接口模板 GeneralDao,继承 tkMapper 的两个接口;

    public interface GeneralDao<T> extends Mapper<T>, MySqlMapper<T> {
    }
    
  3. resources/generator 下添加 GeneratorConfig.xml 生成器配置(创建并复制后改主要配置即可)

    主要需要配置:配置数据库连接、配置实体类存放路径、配置 XML 存放路径、配置 DAO 存放路径、配置 GeneralDao

    注意:默认配置是生成指定数据库中所有表,也可以自定义的指定只生成哪些表

    <?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="Mysql" targetRuntime="MyBatis3Simple" defaultModelType="flat">
            <property name="beginningDelimiter" value="`"/>
            <property name="endingDelimiter" value="`"/>
    
            <!-- 配置 GeneralDao -->
            <plugin type="tk.mybatis.mapper.generator.MapperPlugin">
                <property name="mappers" value="com.luis.general.GeneralDao"/>
            </plugin>
    
            <!-- 配置数据库连接(注意数据库版本问题,需要使用低版本的,高版本可能出现问题!) -->
            <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                    connectionURL="jdbc:mysql://localhost:3306/springdb?serverTimezone=UTC"
                    userId="root" password="luis">
            </jdbcConnection>
    
            <!-- 配置实体类存放路径 -->
            <javaModelGenerator targetPackage="com.luis.beans" targetProject="src/main/java"/>
    
            <!-- 配置 XML 存放路径 -->
            <sqlMapGenerator targetPackage="/" targetProject="src/main/resources/mappers"/>
    
            <!-- 配置 Dao 存放路径 -->
            <javaClientGenerator targetPackage="com.luis.dao" targetProject="src/main/java" type="XMLMAPPER"/>
    
            <!-- 配置需要指定生成的数据库和表,% 代表所有表 -->
            <table tableName="%">
                <!-- mysql 配置 -->
    <!--            <generatedKey column="id" sqlStatement="Mysql" identity="true"/>-->
            </table>
    <!--        <table tableName="tb_roles">-->
    <!--            <!– mysql 配置 –>-->
    <!--            <generatedKey column="roleid" sqlStatement="Mysql" identity="true"/>-->
    <!--        </table>-->
    <!--        <table tableName="tb_permissions">-->
    <!--            <!– mysql 配置 –>-->
    <!--            <generatedKey column="perid" sqlStatement="Mysql" identity="true"/>-->
    <!--        </table>-->
        </context>
    </generatorConfiguration>
    
  4. 打开 IDEA 右侧 Maven 窗口,找到项目--》Plugins--》mybatis-generator--》mybatis-generator:generate,双击执行逆向生成即可!

    image-20221109212212306
  5. 查看 beans、dao、mappers 目录下的生成情况,看生成的相关接口是否符合开发要求,根据情况可做相关修改,然后进行相关测试。

__EOF__


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK