目录
一、背景
MybatisPlus可以节省大量时间,所有的CRUD代码都可以自动化完成
MyBatis-Plus是一个MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
二、实现

1、起步依赖
可以替换掉Mybatis的依赖。
            
            
              XML
              
              
            
          
          <!--mybatisplus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.3.1</version>
        </dependency>2、定义Mapper
自定义自己的Mapper继承MybatisPlus提供的BaseMapper接口:
指定操作的实体类表User
            
            
              java
              
              
            
          
          public interface UserMapper extends BaseMapper<User> {
    
}并且其中不用再写方法,直接调用BaseMapper的方法。
            
            
              java
              
              
            
          
          public interface UserMapper extends BaseMapper<User> {
    void saveUser(User user);
    void deleteUser(Long id);
    void updateUser(User user);
    User queryUserById(@Param("id") Long id);
    List<User> queryUserByIds(@Param("ids") List<Long> ids);
}UserMapper.xml不用再写sql语句
            
            
              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.itheima.mp.mapper.UserMapper">
</mapper>而不是:
            
            
              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.itheima.mp.mapper.UserMapper">
    <insert id="saveUser" parameterType="com.itheima.mp.domain.po.User">
        INSERT INTO `user` (`id`, `username`, `password`, `phone`, `info`, `balance`)
        VALUES
        (#{id}, #{username}, #{password}, #{phone}, #{info}, #{balance});
    </insert>
    <update id="updateUser" parameterType="com.itheima.mp.domain.po.User">
        UPDATE `user`
        <set>
            <if test="username != null">
                `username`=#{username}
            </if>
            <if test="password != null">
                `password`=#{password}
            </if>
            <if test="phone != null">
                `phone`=#{phone}
            </if>
            <if test="info != null">
                `info`=#{info}
            </if>
            <if test="status != null">
                `status`=#{status}
            </if>
            <if test="balance != null">
                `balance`=#{balance}
            </if>
        </set>
        WHERE `id`=#{id};
    </update>
    <delete id="deleteUser" parameterType="com.itheima.mp.domain.po.User">
        DELETE FROM user WHERE id = #{id}
    </delete>
    <select id="queryUserById" resultType="com.itheima.mp.domain.po.User">
        SELECT *
        FROM user
        WHERE id = #{id}
    </select>
    <select id="queryUserByIds" resultType="com.itheima.mp.domain.po.User">
        SELECT *
        FROM user
        <if test="ids != null">
            WHERE id IN
            <foreach collection="ids" open="(" close=")" item="id" separator=",">
                #{id}
            </foreach>
        </if>
        LIMIT 10
    </select>
</mapper>调用BaseMapper的方法
            
            
              java
              
              
            
          
          userMapper.insert(user);而不是:
            
            
              java
              
              
            
          
          userMapper.saveUser(user);三、常用注解
它怎么知道访问哪张表,怎么知道表中有哪些信息?
MybatisPlus通过扫描实体类,并基于反射获取实体类信息作为数据库表信息。
约定:
• 类名驼峰转下划线作为表名
• 名为id的字段作为主键
• 变量名驼峰转下划线作为表的字段名
如果需要可以进行配置:
• @TableName:用来指定表名
• @TableId:用来指定表中的主键字段信息
• @TableField:用来指定表中的普通字段信息
使用@TableField的常见场景:
• 成员变量名与数据库字段名不一致
• 成员变量名以is开头,且是布尔值
• 成员变量名与数据库关键字冲突
• 成员变量不是数据库字段


四、常见配置
当你的sql语句比较复杂时,就需要自定义sql,即写xml文件。
application.yaml中:
            
            
              TypeScript
              
              
            
          
          mybatis-plus:
  type-aliases-package: com.itheima.mp.domain.po #别名扫描包
  mapper-locations: "classpath:mapper/*.xml" #mapper映射文件地址
  configuration:
    map-underscore-to-camel-case: true #开启下划线和驼峰的映射
    cache-enabled: false #开启二级缓存
  global-config:
    db-config:
      id-type: assign_id #默认id为雪花算法生成
      update-strategy: not_null #默认更新策略: not_null(不为null则更新)五、条件构造器(复杂条件)
执行复杂的(特殊的)sql语句。
基于QueryWrapper的查询
1、查询出名字中带o的;存款大于等于1000元的人的id、username、info、balance字段。
对于以下sql(模糊匹配)
            
            
              sql
              
              
            
          
          SELECT id,username,info,balance
FROM user
WHERE username LIKE ? AND balance >= ?可以写出以下方法
            
            
              java
              
              
            
          
          void testQueryWrapper(){
        QueryWrapper<User> wrapper = new QueryWrapper<User>()
                .select("id", "username", "info", "balance")
                .like("username", "o")
                .ge("balance", 1000);
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);
    }2、更新用户名为jack的用户的余额为2000 (相等匹配:eq)
对于以下sql
            
            
              sql
              
              
            
          
          UPDATE user
    SET balance = 2000
    WHERE(username = "jack")可以写出以下方法
            
            
              java
              
              
            
          
          @Test
    void testUpdateNByQueryWrapper(){
        User user = new User();
        user.setBalance(2000);
        QueryWrapper<User> wrapper = new QueryWrapper<User>()
                .eq("username","jack");
        userMapper.update(user,wrapper);
    }基于UpdateWrapper的修改
1、更新id为1,2,4的用户的余额,扣200(
            
            
              sql
              
              
            
          
          UPDATE user
    SET balance = balance - 200
    WHERE id in (1,2,4)
            
            
              java
              
              
            
          
          @Test
    void testUpdateWrapper(){
        List<Long> ids = List.of(1L, 2L, 4L);
        UpdateWrapper<User> wrapper = new UpdateWrapper<User>()
                .setSql("balance = balance - 200")
                .in("id", ids);
        userMapper.update(null,wrapper);
    }六、自定义SQL(复杂条件)
我们可以利用MybatisPlus的Wrapper来构建复杂的Where条件,然后自己定义SQL语句中剩下的部分。

将id在指定范围的用户(例如1、2、4)的余额扣减指定值。
1、构建Lambda表达式,调用方法
            
            
              java
              
              
            
          
          @Test
    void testCustomSqlUpdate(){
        List<Long> ids = List.of(1L, 2L, 4L);
        int amount = 200;
        QueryWrapper<User> wrapper = new QueryWrapper<User>()
                .in("User::id", ids);
        userMapper.updateBalance(amount,wrapper);
    }2、在mapper接口定义方法
            
            
              java
              
              
            
          
          void updateBalance(@Param("amount") int amount, @Param("ew") QueryWrapper<User> wrapper);3、直接写JAVA代码或写xml

Generate statement->
            
            
              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.itheima.mp.mapper.UserMapper">
    <update id="updateBalance">
        update user set balance = balance - #{amount} ${ew.customSqlSegment}
    </update>
</mapper>七、Lambda表达式(常用,硬编码)
运用了反射的机制(User::getId)。
使用Lambda表达式是为了解决硬编码问题。
硬编码:查询的条件写死,应该由用户输入的信息进行查询。
将以下查询代码
            
            
              java
              
              
            
          
           @Test
    void testQueryWrapper(){
        QueryWrapper<User> wrapper = new QueryWrapper<User>()
                .select("id", "username", "info", "balance")
                .like("username", "o")
                .ge("balance", 1000);
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);
    }改为
            
            
              java
              
              
            
          
           @Test
    void testLambdaQueryWrapper(){
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>()
                .select(User::getId, User::getUsername, User::getInfo, User::getBalance)
                .like(User::getUsername, "o")
                .ge(User::getBalance, 1000);
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);
    }八、Service接口(增删改查的另一种方法)
通过Service接口中的方法实现增删改查。

            
            
              java
              
              
            
          
          @Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService{
}
            
            
              java
              
              
            
          
          public interface IUserService extends IService<User> {
}
            
            
              java
              
              
            
          
          class IUserServiceTest {
    @Autowired
    private IUserService userService;
    // 测试新增
    @Test
    void testSaveUser() {
        User user = new User();
        user.setId(5L);
        user.setUsername("Lucy");
        user.setPassword("123");
        user.setPhone("18688990011");
        user.setBalance(200);
        user.setInfo("{\"age\": 24, \"intro\": \"英文老师\", \"gender\": \"female\"}");
        user.setCreateTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());
        
        userService.save(user);
    }
}基于Restful风格实现下列接口(实际应用)
Swagger,Web依赖
            
            
              XML
              
              
            
          
          <!--swagger-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.2.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.2.2</version>
        </dependency>
        <!--Web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>Controller
增删改查功能
            
            
              java
              
              
            
          
          @RestController
@RequestMapping("/users")
@RequiredArgsConstructor
public class UserController {
    private final IUserService userService;
    /**
     * 新增用户
     *
     */
    @PostMapping
    void save(UserFormDTO userFormDTO) {
        User user = BeanUtil.copyProperties(userFormDTO, User.class);
        userService.save(user);
    }
    /**
     * 删除用户
     */
    @PostMapping("{id}")
    void delete(@PathVariable("id") Long id) {
        userService.removeById(id);
    }
}九、插件(实现分页查询)
通过MybatisPlus的拦截器去拦截sql语句再进行拓展其功能,以实现分页查询。
1、配置插件

            
            
              java
              
              
            
          
          @Configuration
public class MybatisConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //1、创建分页插件
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
        paginationInnerInterceptor.setMaxLimit(1000L);
        //2、添加分页插件
        interceptor.addInnerInterceptor(paginationInnerInterceptor);
        return interceptor;
    }
}2、使用插件
            
            
              java
              
              
            
          
          @Component
public class ServiceTest {
    @Autowired
    private IUserService userService;
    // 测试分页
    void testPageQuery(){
        int pageNo = 1, pageSize = 2;
        //1.准备分页条件
        //1.1.分页条件
        Page<User> page = Page.of(pageNo, pageSize);
        //1.2.排序条件
        page.addOrder(new OrderItem("id", true));
        page.addOrder(new OrderItem("balance", true));
        
        //2.执行分页查询
        Page<User> userPage = userService.page(page);
        
        //3.获取分页结果
        long total = userPage.getTotal();
        System.out.println("总记录数:" + total);
        long pages = userPage.getPages();
        System.out.println("总页数:" + pages);
        List<User> records = userPage.getRecords();
        records.forEach(System.out::println);
    }
}实际开发(通用分页实体)

返回值:

这里需要定义3个实体:
- UserQuery/PageQuery:分页查询条件的实体,包含- 分页、- 排序参数、- 过滤条件
- PageDTO:分页结果实体,包含- 总条数、- 总页数、- 当前页数据
- UserVO/AddressVO:用户页面视图实体
UserQuery:

            
            
              java
              
              
            
          
          @Data
@ApiModel(description = "用户查询实体")
public class UserQuery extends PageQuery{
    @ApiModelProperty("用户名关键字")
    private String name;
    @ApiModelProperty("用户状态: 1-正常, 2-冻结")
    private Integer status;
    @ApiModelProperty("余额最小值")
    private Integer minBalance;
    @ApiModelProperty("余额最大值")
    private Integer maxBalance;
}PageQuery:
            
            
              java
              
              
            
          
          @Data
@ApiModel(description = "分页查询实体")
public class PageQuery {
    @ApiModelProperty("页码")
    private Integer pageNo;
    @ApiModelProperty("每页大小")
    private Integer pageSize;
    @ApiModelProperty("排序字段")
    private String sortBy;
    @ApiModelProperty("是否升序")
    private Boolean isAsc;
}PageDTO:

            
            
              java
              
              
            
          
          @Data
@ApiModel(description = "分页响应实体")
public class PageDTO<T> {
    @ApiModelProperty("总条数")
    private Long total;
    @ApiModelProperty("总页数")
    private Long pages;
    @ApiModelProperty("集合")
    private List<T> list;
}UserVO/AddressVO:

            
            
              java
              
              
            
          
          @Data
@ApiModel(description = "用户VO实体")
public class UserVO {
    @ApiModelProperty("用户id")
    private Long id;
    @ApiModelProperty("用户名")
    private String username;
    @ApiModelProperty("详细信息")
    private String info;
    @ApiModelProperty("使用状态(1正常 2冻结)")
    private Integer status;
    @ApiModelProperty("账户余额")
    private Integer balance;
    @ApiModelProperty("收获地址列表")
    private List<AddressVO> address;
}Controller:
            
            
              java
              
              
            
          
          @ApiOperation("分页查询")
    @GetMapping("/page")
    public PageDTO<UserVO> queryUserPage(UserQuery query) {
        return userService.queryUserPage(query);
    }service:(根据这段代码可以反推以上代码)
            
            
              java
              
              
            
          
          @Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService{
    @Override
    public PageDTO<UserVO> queryUserPage(UserQuery query) {
        String name = query.getName();
        Integer status = query.getStatus();
        Integer minBalance = query.getMinBalance();
        Integer maxBalance = query.getMaxBalance();
        //1.构建分页条件
        Page<User> page = new Page<>(query.getPageNo(), query.getPageSize());
        //2.排序条件
        if(StrUtil.isNotBlank(query.getSortBy())){
            // 不为空
            page.addOrder(new OrderItem(query.getSortBy(), query.getIsAsc()));
        }else{
            // 为空,默认按照更新时间排序
            page.addOrder(new OrderItem("update_time", false));
        }
        //3.分页查询
        Page<User> p = lambdaQuery()
                .like(name != null, User::getUsername, name)
                .eq(status != null, User::getStatus, status)
                .ge(minBalance != null, User::getBalance, minBalance)
                .le(maxBalance != null, User::getBalance, maxBalance)
                .page(page);
        //4.封装VO结果
        PageDTO<UserVO> dto = new PageDTO<>();
        //总条数
        dto.setTotal(p.getTotal());
        //总页数
        dto.setPages(p.getPages());
        //当前页数据
        List<User> records = p.getRecords();
        if(CollUtil.isEmpty(records)){
            dto.setList(Collections.emptyList());
            return dto;
        }
        dto.setList(BeanUtil.copyToList(records, UserVO.class));
        return dto;
    }
}