老冯笔记MyBatisPlus&lombok

发布时间 2023-04-13 16:32:11作者: lkjlwq

1.MyBatis-Plus介绍

参考资料

特点

  • 只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑。

  • 只需简单配置,即可快速进行单表 CRUD 操作,从而节省大量时间。

  • 代码生成、自动分页、逻辑删除、自动填充等功能一应俱全。

2.MyBatis-Plus快速入门

2.1 导入依赖坐标

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.darksnow</groupId>
    <artifactId>SpringBoot_Demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!--  继承SpringBoot父POM文件  -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.13</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.2</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- SpringBoot开发工具jar包,支持热部署 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- web开发的相关依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
        </dependency>

        <!--  SpringBoot与Mybatis整合的坐标 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.1</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
    </dependencies>

    <!-- 作用:将一个SpringBoot工程打包成为可执行的jar包-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

2.2 创建表

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(8) NOT NULL,
  `sex` tinyint(4) DEFAULT NULL,
  `birthday` datetime DEFAULT NULL,
  `created` datetime DEFAULT NULL,
  `modified` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4;

INSERT INTO `user` VALUES ('1', '张一山', '0', '2000-01-01 00:00:00', '2023-04-03 14:46:16', '2023-04-03 14:46:16');
INSERT INTO `user` VALUES ('2', '李二龙', '0', '2000-01-01 00:00:00', '2023-04-03 14:46:16', '2023-04-03 14:46:16');
INSERT INTO `user` VALUES ('3', '刘三姐', '0', '2000-01-01 00:00:00', '2023-04-03 14:46:16', '2023-04-03 14:46:16');
INSERT INTO `user` VALUES ('4', '李四飞', '0', '2000-01-01 00:00:00', '2023-04-03 14:46:16', '2023-04-03 14:46:16');
INSERT INTO `user` VALUES ('5', '周五输', '0', '2000-01-01 00:00:00', '2023-04-03 14:46:16', '2023-04-03 14:46:16');
INSERT INTO `user` VALUES ('6', '赵六赢', '0', '2000-01-01 00:00:00', '2023-04-03 14:46:16', '2023-04-03 14:46:16');
INSERT INTO `user` VALUES ('7', '龙七七', '0', '2000-01-01 00:00:00', '2023-04-03 14:46:16', '2023-04-03 14:46:16');
INSERT INTO `user` VALUES ('8', '王八衰', '0', '2000-01-01 00:00:00', '2023-04-03 14:46:16', '2023-04-03 14:46:16');
INSERT INTO `user` VALUES ('9', '落小月', '0', '2010-03-01 00:00:00', '2023-04-03 14:46:16', '2023-04-03 14:46:16');
INSERT INTO `user` VALUES ('10', '张小雅', '1', '2010-04-01 00:00:00', '2023-04-03 14:46:16', '2023-04-03 14:46:16');

2.3 创建实体类

package com.darksnow.pojo;


import lombok.Data;

import java.time.LocalDate;
import java.util.Date;

//注意安装lombok插件,实体名目前和表名一致
@Data //使用它以后就可以不写,getter,setter,toString等这样的方法
public class User {
    private Long id;
    private String name;
    private Integer sex;
    private LocalDate birthday;
    private Date created;
    private Date modified;
}

2.4 UserMapper

package com.darksnow.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.darksnow.pojo.User;
import org.apache.ibatis.annotations.Mapper;

/**
 * 使用@Mapper(加载mapper接口上),与@MapperScan(加载引导类上),二选一即可
 * 继承BaseMapper之后会让自定义的mapper拥有最基本的增删改查能力
 * BaseMapper接口的泛型对应实体类型
 */
@Mapper
public interface UserMapper extends BaseMapper<User> {
}

2.5 UserController

package com.darksnow.controller;

import com.darksnow.mapper.UserMapper;
import com.darksnow.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserMapper userMapper;

    @RequestMapping("/findAll")
    public List<User> findAll() {
        return userMapper.selectList(null);
    }
}

2.6 启动类

package com.darksnow;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

2.7 application.yml

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql:///darksnow?characeter=utf-8
    username: root
    password: root
#mybatis:
#  type-aliases-package: com.darksnow.pojo
#  mapper-locations: classpath:mapper/*Mapper.xml
server:
  port: 8081

3.MyBatis-Plus基本使用

3.1 根据id查询

	//根据id查询
    @RequestMapping("/findById")
    public User findById() {
        return userMapper.selectById(9);
    }

3.2 新增

	/**
        新增操作的注意事项:
            1.如果提供id,那么主键就会采用你提供的id
            2.如果没有提供id,虽然我们建表的时候采用了主键自增,但是实际上会发现id是一个很长的数字:1642790778357526530
            这是因为MyBatis-Plus默认的主键生成策略有五种,默认是其中的ASSING_ID
     */
    @RequestMapping("/insert")
    public String insert() {
        User user = new User();
        user.setName("龙傲天");
        user.setSex(1);
        user.setBirthday(LocalDate.of(2000,10,1));
        Date date = new Date();
        user.setCreated(date);
        user.setModified(date);
        user.setId(110L);
        userMapper.insert(user);
        return "Success~";
    }
package com.baomidou.mybatisplus.annotation;

import lombok.Getter;

/**
 * 生成ID类型枚举类
 *
 * @author hubin
 * @since 2015-11-10
 */
@Getter
public enum IdType {
    /**
     * 数据库ID自增
     * <p>该类型请确保数据库设置了 ID自增 否则无效</p>
     */
    AUTO(0),
    /**
     * 该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
     */
    NONE(1),
    /**
     * 用户输入ID
     * <p>该类型可以通过自己注册自动填充插件进行填充</p>
     */
    INPUT(2),

    /* 以下3种类型、只有当插入对象ID 为空,才自动填充。 */
    /**
     * 分配ID (主键类型为number或string),
     * 默认实现类 {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(雪花算法)
     *
     * @since 3.3.0
     */
    ASSIGN_ID(3),
    /**
     * 分配UUID (主键类型为 string)
     * 默认实现类 {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(UUID.replace("-",""))
     */
    ASSIGN_UUID(4),
    /**
     * @deprecated 3.3.0 please use {@link #ASSIGN_ID}
     */
    @Deprecated
    ID_WORKER(3),
    /**
     * @deprecated 3.3.0 please use {@link #ASSIGN_ID}
     */
    @Deprecated
    ID_WORKER_STR(3),
    /**
     * @deprecated 3.3.0 please use {@link #ASSIGN_UUID}
     */
    @Deprecated
    UUID(4);

    private final int key;

    IdType(int key) {
        this.key = key;
    }
}
  • AUTO:采用数据库自增主键
  • NONE:没啥用
  • INPUT:用户自行指定
  • ASSIGN_ID:用于分布式场景,采用雪花算法(默认)
  • ASSIGN_UUID:UUID算法

我们如何改变默认生成策略?

方法一:注解(局部处理)

package com.darksnow.pojo;


import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;

import java.time.LocalDate;
import java.util.Date;

@Data
public class User {
    @TableId(type = IdType.AUTO)  //指定生成策略
    private Long id;

    private String name;
    private Integer sex;
    private LocalDate birthday;
    private Date created;
    private Date modified;
}

方式二:spring配置(全局处理)

mybatis-plus:
  global-config:
    db-config:
      id-type: auto

3.3 修改

	/**
     * 修改时会根据实体对象的属性值来动态生成sql,比如下面的案例中的User的id,name不为空,而其他值为null的属性不会出现在最终的sql中
     *
     * update user set name = ? where id = ?
     */
    @RequestMapping("/update")
    public String update() {
        User user = new User();
        user.setId(9L);
        user.setName("落小雪");
        userMapper.updateById(user);
        return "Success~";
    }

3.4 删除

	@RequestMapping("/delete")
    public String delete() {
        userMapper.deleteById(1);
        return "Success~";
    }

3.5 分页

pom.xml

		<!-- 分页插件 -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>5.1.10</version>
        </dependency>
        <!--
            如果运行遇到java.lang.NuSuchMethodError
            .....select.GroupByElement
            .....PlainSelect.getGroupBy(
            那就需要引入下面的依赖就能解决
         -->
        <dependency>
            <groupId>com.github.jsqlparser</groupId>
            <artifactId>jsqlparser</artifactId>
            <version>3.1</version>
        </dependency>

配置类

package com.darksnow.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class PageHelperConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }

    @Bean
    public ConfigurationCustomizer configurationCustomizer() {
        return configuration -> configuration.setUseDeprecatedExecutor(false);
    }
}

测试类

	@RequestMapping("/findPage")
    public Page<User> findPage() {
       return userMapper.selectPage(new Page<>(2,4),null);
    }

3.6 带条件查询

mybatis-plus支持基于java代码的多条件组合查询,好处是可以避免mapper xml中标签的使用

	@RequestMapping("/findByConditionCase1")
    public List<User> findByConditionCase1() {
        //select * from user where name like '%小%'
        return query("小", null, null);
    }

    @RequestMapping("/findByConditionCase2")
    public List<User> findByConditionCase2() {
        //select * from user where name like '%小%' and sex = 1
        return query("小", 1, null);
    }

    @RequestMapping("/findByConditionCase3")
    public List<User> findByConditionCase3() {
        //select * from user where name like '%小%' and sex = 0 and birthday <= '2023-04-04'
        LocalDate birthday = LocalDate.of(2023,4,4);
        return query("小", 0, birthday);
    }

    private List<User> query(String name,Integer sex,LocalDate birthday) {
        QueryWrapper<User> qw = new QueryWrapper<>();
        //根据姓名模糊查询
        if (StringUtils.hasLength(name)){
            qw.like("name",name);
        }

        //根据性别查询
        if (sex != null) {
            qw.eq("sex",sex);
        }

        //根据生日小于等于查询
        if (birthday != null) {
            qw.le("birthday",birthday);
        }

        return userMapper.selectList(qw);
    }

也可以避免标签的使用,例如

	@RequestMapping("/findByConditionCase4")
    public List<User> findByConditionCase4() {
        //select * from user where id in(1,2,3,18)
        QueryWrapper<User> qw = new QueryWrapper<>();
        qw.in("id", Arrays.asList(1,2,3,18));
        return userMapper.selectList(qw);
    }

如果你喜欢lambda,还可以将构造QueryWrapper的语法做如下修改:

	private List<User> query(String name,Integer sex,LocalDate birthday) {
        QueryWrapper<User> qw = new QueryWrapper<>();

        /*
            下面的like,eq,le方法都用了三个参数
            参数1:返回结果为布尔值,条件成立才会将列名与值拼接进sql,相当于之前的if判断
            参数2:代表列名,使用方法引用,目的是根据方法引用找到真正的别名
            参数3:代表值,比如 select ... from ... where birthday = xxx  ,代表的这个xxx(值)
         */
        qw.lambda()
                .like(StringUtils.hasLength(name), User::getName, name)
                .eq(sex != null, User::getSex, sex)
                .le(birthday != null, User::getBirthday, birthday);
        return userMapper.selectList(qw);
    }

3.7 带条件更新

	/*
        带条件更新,下面相当于执行了SQL:update user set sex = 1 where sex = 0
     */
    @RequestMapping("/updateByCondition")
    public String updateByCondition() {
        User user = new User();
        user.setSex(1);

        UpdateWrapper<User> uw = new UpdateWrapper<>();
        uw.eq("sex",0);

        int rs = userMapper.update(user, uw);

        return String.valueOf(rs);
    }
	/*
        带条件更新,下面相当于执行了SQL:delete from user where id < 3;
     */
    @RequestMapping("/deleteByCondition")
    public String deleteByCondition() {
        QueryWrapper<UserData> qw = new QueryWrapper<>();
        qw.lt("id",3);  //lt:小于
        int rs = userMapper.delete(qw);
        return String.valueOf(rs);
    }

4.MyBatis-Plus进阶使用

4.1 当映射不一致时

若数据库表不变,实体类和mapper变化为:

@Data
public class UserData {
    private Long id;

    private String name;
    private Integer sex;
    private LocalDate birthday;
    private Date created;
    private Date modified;
}
@Mapper
public interface UserDataMapper extends BaseMapper<UserData> {
}

再访问下面的controller

	@RequestMapping("/findAll")
    public List<UserData> findAll() {
        return userMapper.selectList(null);
    }

直接报错,原因时表名与实体类名对应不上

Error querying database. Cause: java.sql.SQLSyntaxErrorException: Table 'darksnow.user_data' doesn't exist

改进如下:

@TableName("user")  //实体类名与表名的映射
@Data
public class UserData {
    private Long id;
    @TableField("name")  //实体类中的属性与表中的字段的映射
    private String name;
    private Integer sex;
    private LocalDate birthday;
    private Date created;
    private Date modified;
}

4.2 需要统一填充时

有些实体对象有一些通用的属性需要填充,比如:

  • 新增时,需要填充created,modified这两个时间
  • 修改时,需要填充modified这个时间

首先需要标注哪些属性需要填充

@TableName("user")  //实体类名与表名的映射
@Data
public class UserData {
    private Long id;
    private String name;
    private Integer sex;
    private LocalDate birthday;

    // 新增时需要填充
    @TableField(fill = FieldFill.INSERT)
    private Date created;
    // 新增以及修改时需要填充
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date modified;
}

其次设置填充处理器

	@Bean
    public MetaObjectHandler metaObjectHandler() {
        //MetaObjectHandler:提供的方法的策略均为如果属性指定了值则不覆盖,没指定值就生成
        return new MetaObjectHandler() {
            //新增时提供的值
            @Override
            public void insertFill(MetaObject metaObject) {
                Date now = new Date();
                /*
                 * 参数一:需要MetaObject
                 * 参数二:属性名
                 * 参数三:属性类型
                 * 参数四:属性的值
                 */
                this.strictInsertFill(metaObject,"created", Date.class, now);
                this.strictInsertFill(metaObject,"modified",Date.class, now);
            }

            //修改时提供的值
            @Override
            public void updateFill(MetaObject metaObject) {
                Date now = new Date();
                this.strictUpdateFill(metaObject, "modified", Date.class, now);
            }
        };
    }

测试方法

	@RequestMapping("/fillInsert")
    public String fillInsert() {
        UserData userData = new UserData();
        userData.setName("龙傲天");
        userData.setSex(1);
        userData.setBirthday(LocalDate.of(1990,1,1));
        userMapper.insert(userData);
        return "success~";
    }

    @RequestMapping("/fillUpdate")
    public String fillUpdate() {
        UserData userData = new UserData();
        userData.setId(11L);
        userData.setName("龙霸天");
        userMapper.updateById(userData);
        return "success~";
    }

4.3 需要复杂查询时

虽然MyBatis-Plus提供了很方便的方法,但如果是需要连表查询,仍然会用到MyBatis原始方式

建表语句

DROP TABLE IF EXISTS `skill_info`;
CREATE TABLE `skill_info` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(8) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4;

INSERT INTO `skill_info` VALUES ('1', '唱');
INSERT INTO `skill_info` VALUES ('2', '跳');
INSERT INTO `skill_info` VALUES ('3', 'rap');
INSERT INTO `skill_info` VALUES ('4', '打篮球');

DROP TABLE IF EXISTS `user_info`;
CREATE TABLE `user_info` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(8) NOT NULL,
  `sex` tinyint(4) DEFAULT NULL,
  `birthday` datetime DEFAULT NULL,
  `created` datetime DEFAULT NULL,
  `modified` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1642794330148630535 DEFAULT CHARSET=utf8mb4;

INSERT INTO `user_info` VALUES ('3', '刘三姐', '1', '2000-01-01 00:00:00', '2023-04-03 14:46:16', '2023-04-03 14:46:16');
INSERT INTO `user_info` VALUES ('4', '李四飞', '1', '2000-01-01 00:00:00', '2023-04-03 14:46:16', '2023-04-03 14:46:16');
INSERT INTO `user_info` VALUES ('5', '周五输', '1', '2000-01-01 00:00:00', '2023-04-03 14:46:16', '2023-04-03 14:46:16');
INSERT INTO `user_info` VALUES ('6', '赵六赢', '1', '2000-01-01 00:00:00', '2023-04-03 14:46:16', '2023-04-03 14:46:16');
INSERT INTO `user_info` VALUES ('7', '龙七七', '1', '2000-01-01 00:00:00', '2023-04-03 14:46:16', '2023-04-03 14:46:16');
INSERT INTO `user_info` VALUES ('8', '王八衰', '1', '2000-01-01 00:00:00', '2023-04-03 14:46:16', '2023-04-03 14:46:16');
INSERT INTO `user_info` VALUES ('9', '落小雪', '1', '2010-03-01 00:00:00', '2023-04-03 14:46:16', '2023-04-03 14:46:16');
INSERT INTO `user_info` VALUES ('10', '张小雅', '1', '2010-04-01 00:00:00', '2023-04-03 14:46:16', '2023-04-03 14:46:16');
INSERT INTO `user_info` VALUES ('11', '龙霸天', '1', '1990-01-01 00:00:00', '2023-04-06 11:40:53', '2023-04-06 11:44:13');

DROP TABLE IF EXISTS `user_skill_info`;
CREATE TABLE `user_skill_info` (
  `user_id` bigint(20) NOT NULL,
  `skill_id` bigint(20) NOT NULL,
  KEY `fk_user_id` (`user_id`),
  KEY `fk_skill_id` (`skill_id`),
  CONSTRAINT `fk_skill_id` FOREIGN KEY (`skill_id`) REFERENCES `skill_info` (`id`),
  CONSTRAINT `fk_user_id` FOREIGN KEY (`user_id`) REFERENCES `user_info` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

INSERT INTO `user_skill_info` VALUES ('3', '1');
INSERT INTO `user_skill_info` VALUES ('3', '2');
INSERT INTO `user_skill_info` VALUES ('5', '3');
INSERT INTO `user_skill_info` VALUES ('5', '4');
INSERT INTO `user_skill_info` VALUES ('9', '1');
INSERT INTO `user_skill_info` VALUES ('9', '2');
INSERT INTO `user_skill_info` VALUES ('9', '3');
INSERT INTO `user_skill_info` VALUES ('9', '4');

实体类

package com.darksnow.pojo;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import java.time.LocalDate;
import java.util.Date;
import java.util.Set;

@TableName("user_info")  //实体类名与表名的映射
@Data
public class UserData {
    private Long id;
    private String name;
    private Integer sex;
    private LocalDate birthday;

    // 新增时需要填充
    @TableField(fill = FieldFill.INSERT)
    private Date created;
    // 新增以及修改时需要填充
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date modified;

    //表达一对多关系  一个人可以有多个技能
    private Set<SkillInfo> skillInfos;
}
package com.darksnow.pojo;

import lombok.Data;

@Data
public class SkillInfo {
    private Long id;
    private String name;
}

现在要去查询某个用户,以及用户的技能,需要连表查询,此时需要扩展mapper接口的方法

package com.darksnow.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.darksnow.pojo.UserData;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserDataMapper extends BaseMapper<UserData> {
    UserData selectUserWithSkill(Long userId);
}

并且还需要添加xml mapper文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.darksnow.mapper.UserDataMapper">
    <resultMap id="userMap" type="com.darksnow.pojo.UserData">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="sex" property="sex" />
        <result column="birthday" property="birthday"/>
        <result column="created" property="created"/>
        <result column="modified" property="modified"/>
        <collection property="skillInfos" ofType="com.darksnow.pojo.SkillInfo">
            <id column="sid" property="id"/>
            <result column="sname" property="name"/>
        </collection>
    </resultMap>
    <select id="selectUserWithSkill" resultMap="userMap" >
        select ui.*,si.id sid,si.name sname
            from user_info ui
                left join user_skill_info usi on ui.id = usi.user_id
                left join skill_info si on si.id = usi.skill_id
            where ui.id = #{userId}
    </select>
</mapper>

测试方法

	@RequestMapping("/selectUserWithSkill")
    public UserData selectUserWithSkill() {
       return userMapper.selectUserWithSkill(9L);
    }

5.Lombok的使用

5.1 Lombok常用注解

package com.darksnow.pojo;

import lombok.*;

/*
    使用lombok简化操作
    @Setter  给所有属性加上set方法
    @Getter  给所有属性加上get方法
    @ToString   加上toString方法
    @EqualsAndHashCode  加上equals和hashcode方法
 */
@Data  //一个顶上面的四个
@NoArgsConstructor //加上无参构造
@AllArgsConstructor //加上带所有参数的构造
@Builder
public class ProductOne {
    private Long id;
    private String title;
    private Double price;
    private String images;
}

5.2 构建者设计模式

package com.darksnow.pojo;

//可以使用构建者模式创建ProductTwo对象
public class ProductTwo {
    private Long id;
    private String title;
    private Double price;
    private String images;

    public ProductTwo(Long id, String title, Double price, String images) {
        this.id = id;
        this.title = title;
        this.price = price;
        this.images = images;
    }

    @Override
    public String toString() {
        return "ProductTwo{" +
                "id=" + id +
                ", title='" + title + '\'' +
                ", price=" + price +
                ", images='" + images + '\'' +
                '}';
    }

    //获取构建者对象
    public static ProductTwoBuilder builder() {
        return new ProductTwoBuilder();
    }

    //PrudcotTwoBulder构建者类
    public static class ProductTwoBuilder {
        private Long id;
        private String title;
        private Double price;
        private String images;

        public ProductTwoBuilder() {
        }

        public ProductTwoBuilder id(Long id) {
            this.id = id;
            return this;
        }

        public ProductTwoBuilder title(String title) {
            this.title = title;
            return this;
        }

        public ProductTwoBuilder price(Double price) {
            this.price = price;
            return this;
        }

        public ProductTwoBuilder images(String images) {
            this.images = images;
            return this;
        }

        public ProductTwo build() {
            return new ProductTwo(this.id,this.title,this.price,this.images);
        }
    }
}
package com.darksnow.pojo;

public class Test {
    public static void main(String[] args) {
        ProductOne productOne = new ProductOne();
        productOne.setTitle("笔记本电脑");
        System.out.println(productOne.getTitle());
        new ProductOne(1L,"小米手机",3500d,"/images/xiaomi.jpg");

        System.out.println("----------------------------------");

        /*
            @Builder注解达到效果:链式编程,没有写new对象的代码但是却能得到一个对象,并且还是给成员赋值
            这里采用的是构建者设计模式的思想。

            SqlSessionFactory
            SqlSessionFactoryBuilder,把复杂的创建对象的过程,封装在一个对象中,构建者对象
         */
        ProductOne pp = ProductOne.builder().title("格力空调").id(2L).price(3000d).build();
        System.out.println(pp);


        ProductTwo pt = ProductTwo.builder().title("冰箱").id(3L).price(8000d).build();
        System.out.println(pt);
    }
}