SpringBoot整合MyBatis-Plus

前言

MyBatis-Plus 是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

我们的愿景是成为 MyBatis 最好的搭档,就像 魂斗罗 中的 1P、2P,基友搭配,效率翻倍。

特征

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
  • 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
  • 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
  • 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
  • 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
  • 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
  • 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
  • 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
  • 内置性能分析插件:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
  • 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作

架构图

数据准备

本例子用的是MySQL,下面是建表语句

sql 复制代码
CREATE TABLE `user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(128) NOT NULL DEFAULT '',
  `created_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

Maven 依赖

xml 复制代码
<properties>
	<mysql.version>5.1.49</mysql.version>
	<druid.version>1.1.21</druid.version>
	<mybatisplus.version>3.5.8</mybatisplus.version>
</properties>
<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter</artifactId>
	</dependency>

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

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

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>${mysql.version}</version>
    </dependency>

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>${druid.version}</version>
	</dependency>

	<dependency>
		<groupId>com.baomidou</groupId>
		<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
		<version>${mybatisplus.version}</version>
	</dependency>
	<dependency>
		<groupId>com.baomidou</groupId>
		<artifactId>mybatis-plus</artifactId>
		<version>${mybatisplus.version}</version>
	</dependency>

</dependencies>

配置 application.properties

property 复制代码
spring.application.name=mybatis-plus-demo
server.port=8081

spring.datasource.url=jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

定义实体

java 复制代码
package com.zxy.demo.mybatisplus.domain.entity;

import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Date;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;

@TableName("user")
public class UserEntity {
    // 配置自增ID, 在create接口返回id
    @TableId(type=IdType.AUTO)
    private Long id;
    private Date createdAt;
    private String name;

    @TableField(exist = false)
    private String ignoreColumn = "ignoreColumn";

    public ZonedDateTime getCreatedDateTime() {
        return ZonedDateTime.ofInstant(this.createdAt.toInstant(), ZoneId.systemDefault());
    }

    // get set
}

定义 mapper

UserMapper.java

java 复制代码
package com.zxy.demo.mybatisplus.domain.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zxy.demo.mybatisplus.domain.entity.UserEntity;

// 继承BaseMapper,默认就有了基础的CRUD
public interface UserMapper extends BaseMapper<UserEntity> {
    // 自定义 SQL
    UserEntity findByName(String name);
}

user_mapper.xml

无需配置mybatis.mapper-locations=classpath*:mapper/**/*.xml, mapper文件夹放在classpath下即可,也即resources下。

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.zxy.demo.mybatisplus.domain.mapper.UserMapper">

    <select id="findByName" resultType="com.zxy.demo.mybatisplus.domain.entity.UserEntity">
        SELECT * FROM user WHERE name LIKE #{name} LIMIT 1
    </select>

</mapper>

MybatisPlusConfig.java

配置mapper的扫描,配置分页插件

java 复制代码
package com.zxy.demo.mybatisplus;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;

@Configuration
@MapperScan("com.zxy.demo.mybatisplus.domain.mapper")
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 如果配置多个插件, 切记分页最后添加
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); 
        // 如果有多数据源可以不配具体类型, 否则都建议配上具体的 DbType
        return interceptor;
    }

}

Controller 使用

java 复制代码
package com.zxy.demo.mybatisplus.api;

import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.server.ResponseStatusException;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zxy.demo.mybatisplus.domain.entity.UserEntity;
import com.zxy.demo.mybatisplus.domain.mapper.UserMapper;
import com.zxy.demo.mybatisplus.domain.service.UserService;
import com.zxy.demo.mybatisplus.dto.User;

@Controller
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public class UserController {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserService userService;

    private UserEntity toUserEntity(User u) {
        if (null == u) {
            return null;
        }
        UserEntity userEntity = new UserEntity();
        userEntity.setId(u.id);
        userEntity.setName(u.name);
        return userEntity;
    }

    private User toUser(UserEntity userEntity) {
        if (null == userEntity) {
            return null;
        }
        User user = new User();
        user.id = userEntity.getId();
        user.name = userEntity.getName();

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        user.createdAt = formatter.format(userEntity.getCreatedDateTime());

        return user;
    }

    @ResponseBody
    @RequestMapping(value = "/users")
    public Map users(@RequestParam long page, @RequestParam long pageSize) {
        System.out.println("users page:" + page + ", pageSize:" + pageSize);
        QueryWrapper<UserEntity> wrapper = new QueryWrapper();
        IPage<UserEntity> ret = userMapper.selectPage(new Page(page, pageSize), wrapper);
        Map m = new HashMap();
        var users = ret.getRecords().stream().map(this::toUser).collect(Collectors.toList());
        m.put("list", users);
        m.put("current 当前页", ret.getCurrent());
        m.put("pageSize 每页显示条数", ret.getSize());
        m.put("pages 总页数", ret.getPages());
        m.put("total 总条数", ret.getTotal());
        return m;
    }

    @ResponseBody
    @RequestMapping(value = "/users/{id}")
    public User getUser(@PathVariable("id") long uid) {
        var user = userMapper.selectById(uid);
        if (user == null) {
            throw new ResponseStatusException(HttpStatus.NOT_FOUND);
        }

        return toUser(user);
    }

    @ResponseBody
    @RequestMapping(value = "/users/findByName/{name}")
    public User findByName(@PathVariable("name") String name) {
        var user = userMapper.findByName(name);
        return toUser(user);
    }

    @ResponseBody
    @PostMapping(value = "/users")
    public User creatUser(@RequestBody User u) {
        UserEntity userEntity = toUserEntity(u);

        long id = userService.createUser(userEntity);
        u.id = id;

        return u;
    }

}
java 复制代码
package com.zxy.demo.mybatisplus.domain.service.impl;

import java.util.Date;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.zxy.demo.mybatisplus.domain.entity.UserEntity;
import com.zxy.demo.mybatisplus.domain.mapper.UserMapper;
import com.zxy.demo.mybatisplus.domain.service.UserService;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public long createUser(UserEntity userEntity) {
        userEntity.setCreatedAt(new Date());
        userMapper.insert(userEntity);

        return userEntity.getId();
    }

}

问题列表

userMapper 获取不到

text 复制代码
 Invalid bean definition with name 'userMapper' defined in file [.../userMapper.class]: Invalid value type for attribute 'factoryBeanObjectType': java.lang.String

github.com/baomidou/my...

两种解决方式,调整mybatis-spring版本或spring-boot的包

xml 复制代码
<mybatisplus.version>3.5.8</mybatisplus.version>
<mybatis.version>3.0.3</mybatis.version>

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>${mybatisplus.version}</version>
    <exclusions>
        <exclusion>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>${mybatis.version}</version>
</dependency>
xml 复制代码
<mybatisplus.version>3.5.8</mybatisplus.version>

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
    <version>${mybatisplus.version}</version>
</dependency>

mapper 自定义SQL

无需配置mybatis.mapper-locations=classpath*:mapper/**/*.xml, mapper文件夹放在classpath下即可,也即resources下。

资料

相关推荐
ling1s9 分钟前
C#核心(18)面向对象多态vob
java·开发语言·c#
sin220112 分钟前
idea创建springBoot的五种方式
java·spring boot·intellij-idea
皓木.19 分钟前
苍穹外卖——准备工作
java·数据库·mybatis
愤怒的代码32 分钟前
Spring Boot对访问密钥加密解密——RSA
java·spring boot·后端
美美的海顿33 分钟前
springboot基于Java的校园导航微信小程序的设计与实现
java·数据库·spring boot·后端·spring·微信小程序·毕业设计
愤怒的代码35 分钟前
Spring Boot中幂等性的应用
java·spring boot·后端
silver68736 分钟前
JAVA8 Stream API 使用详解
java
武子康38 分钟前
大数据-259 离线数仓 - Griffin架构 修改配置 pom.xml sparkProperties 编译启动
xml·java·大数据·hive·hadoop·架构
天天打码1 小时前
ThinkPHP项目如何关闭runtime下Log日志文件记录
android·java·javascript
魔道不误砍柴功1 小时前
Java 中反射的高级用法:窥探 Java 世界的魔法之门
java·开发语言·python