Springboot

一.概念

  1. 什么是springboot
    springboot是spring快速开发脚手架,通过约定大于配置的方式,快速构建和启动spring项目
  2. 为什么要学习springboot
  • spring的缺点:
    • 复杂的配置(需要写大量的xml文件)
    • 混乱的依赖管理
      而springboot可以解决以上两个问题
  1. springboot的特点
  • 快速开发spring应用的框架
  • 内嵌tomcat和jetty容器,不需要单独安装容器,jar包直接发布一个web应用
  • 简化maven配置,parent这种方式,一站式引入需要的各种依赖
  • 基于注解的零配置思想
  • 和各种流行框架,spring web mvc,mybatis,spring cloud无缝整合

二.入门案例

  1. 创建好工程项目后添加依赖
  • 添加父工程坐标
<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.0.0.RELEASE</version>
</parent>
  • 添加web启动器

为了让SpringBoot帮我们完成各种自动配置,我们必须引入SpringBoot提供的自动配置依赖,我们称为 启动器 。
因为我们是web项目,这里我们引入web启动器:

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

需要注意的是,我们并没有在这里指定版本信息。因为SpringBoot的父工程已经对版本进行了管理了。

  • 管理jdk版本
<properties>
	<java.version>1.8</java.version>
</properties>
  1. 启动类

springboot项目通过main函数即可启动,我们需要创建一个启动类,然后编写main函数。

在这里插入图片描述

@SpringBootApplication
public class Application {
	public static void main(String[] args) {
	SpringApplication.run(Application.class, args);
	}
}
  1. 编写controller

接下来,就可以像以前一样开发springmvc项目了!

在这里插入图片描述

@RestController
public class HelloController {

	@GetMapping("/hello")
	public String hello(){
		return "hello, spring boot!";
	}
}

补充:

  1. @RestController表明当前类是Controller,有该注解的类返回具体的数据,不能返回json,xml等类型数据。详情查看
  2. @GetMapping表明当前方法采用GET请求方式,在@RequestMapping的基础上做了改进,用起来更加简洁高效。详情查看
  1. 启动测试

通过运行main函数,访问localhost:8080/hello即可

三.全注解配置和属性注入

在入门案例中,我们没有任何的配置,就可以实现一个SpringMVC的项目了。也许有的人会有疑问,没有xml,如何配置bean呢?

  • 以连接池为例:以前会这样配置
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
	init-method="init" destroy-method="close">
	<property name="url" value="${jdbc.url}" />
	<property name="username" value="${jdbc.username}" />
	<property name="password" value="${jdbc.password}" />
</bean>

而现在3.0以后的Spring的注解已经非常完善了,所以现在将采用注解代替xml的方式对bean进行配置

3.1 Spring全注解配置

spring全注解配置主要靠java类和一些注解,比较常用的注解有:

  • @Configuration :声明一个类作为配置类,代替xml文件
  • @Bean :声明在方法上,将方法的返回值加入Bean容器,代替< bean>标签
  • @value :属性注入(给bean属性赋值)
  • @PropertySource :指定外部属性文件(有了外部文件,@Value才能注入值)
  1. 接下来用java配置来尝试实现连接池配置
  • 引入Druid连接池依赖
<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>druid</artifactId>
	<version>1.1.10</version>
</dependency>
  • 创建一个jdbc.properties文件
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/lxs
jdbc.username=root
jdbc.password=123

在这里插入图片描述
2. 在任意位置通过@Autowired注入DataSource

	@RestController
	public class HelloController {
	
	@Autowired
	private DataSource dataSource;
	@GetMapping("hello")
	public String hello() {
	return "hello, spring boot!" + dataSource;
	}
}
  1. 通过Debug运行查看
    在这里插入图片描述
    发现注入成功,即bean配置成功!

3.2 SpringBoot属性注入

在上面的案例中,我们实验了java配置方式。不过属性注入使用的是@Value注解。这种方式虽然可行,但是不够
强大,因为它只能注入基本类型值。
在SpringBoot中,提供了一种新的属性注入方式,支持各种java基本数据类型及复杂类型的注入。

  1. 新建一个类JdbcProperties并配置注解@ConfigurationProperties
  2. 将jdbc.properties改名为application.properties,这是Springboot默认读取的属性文件名。
  3. 在配置有@Configuration的类中开启注解@EnableConfigurationProperties
    在这里插入图片描述
  • @ConfigurationProperties注解声明当前类为属性读取类,刚创建时如果没有类对其进行引用将报错。
  • prefix=“jdbc” 读取属性文件中,前缀为jdbc的值。
  • 这里我们并没有指定属性文件的地址,所以我们需要把jdbc.properties名称改为
    application.properties,这是SpringBoot默认读取的属性文件名:
  • 配置带@ConfigurationProperteis的类的引入总共有3种方式,个人推荐更为简单直观的第三种。
//方式一:作为成员变量
	@Autowired
	private JdbcProperties prop;
//方式二:构造函数
	private JdbcProperties prop;
	public JdbcConfig(Jdbcproperties prop){
			this.prop = prop;
	}
//声明有@Bean的方法参数注入
	@Bean
	public Datasource dataSource(JdbcProperties prop){
// ...
  • 或许有人觉得这种方式更加麻烦了,然而比起@Value这种方式有着更强大的功能,下面来看下两者的比较。

在这里插入图片描述

  • Relaxed binding:松散绑定
    • 不严格要求属性文件中的属性名与成员变量名一致。支持驼峰,中划线,下划线等等转换。比如user.frinder.name,这里friend也是对象,而@Value注解就无法完成这种注入。
  • meta-data support:元数据支持
    • 帮助IDE生成属性提示(写开源框架会用到)。

总结:

  • 如果只是为了获取配置文件中某个值,则使用 @Value
  • 如果是一组配置和javaBean进行映射,则使用 @ConfigurationProperties

3.3 更优雅的注入

事实上,如果一段属性只有一个Bean使用,则无需注入到类中,而是直接在需要的地方声明即可。
在这里插入图片描述

四.自动配置原理

通过刚才的案例看到,一个整合了SpringMVC的WEB工程开发,变的无比简单,那些繁杂的配置都消失不见了,这是如何做到的?这些都得从springboot启动器开始讲起。

在这里插入图片描述

  1. @SpringBootApplication
    在这里插入图片描述

通过查看源码可以发现,这里重点的注解有3个

  • @SpringBootConfiguration
  • @ComponentScan
  • @EnableAutoConfiguration
  1. @SpringBootConfiguration
    在这里插入图片描述

通过这段我们可以看出,在这个注解上面,又有一个 @Configuration 注解。这个注解的作用就是声明当前类是一个配置类,然后Spring会自动扫描到添加了 @Configuration 的类,并且读取其中的配置信息。

  1. @ComponentScan
    在这里插入图片描述
    并没有看到什么特殊的地方,查看注释:
    在这里插入图片描述

大意是:
配置组件扫描的指令。提供了类似与 context:component-scan 标签的作用
通过basePackageClasses或者basePackages属性来指定要扫描的包。如果没有指定这些属性,那么将从声明这个注解的类所在的包开始,扫描包及子包.

  • 而我们的@SpringBootApplication注解声明的类就是main函数所在的启动类,因此扫描的包是该类所在包及其子包。
  • 因此,一般启动类会放在一个比较前的包目录中。
  1. @EnableAutoConfiguration

关于这个注解,官网上有一段说明:
第二级的注解 @EnableAutoConfiguration ,告诉SpringBoot基于你所添加的依赖,去“猜测”你想要如何配置
Spring。比如我们引入了 spring-boot-starter-web ,而这个启动器中帮我们添加了 tomcat 、 SpringMVC 的
依赖。此时自动配置就知道你是要开发一个web应用,所以就帮你完成了web及SpringMVC的默认配置了!

4.1 默认配置原理

@EnableAutoConfiguration会开启SpringBoot的自动配置,并且根据你引入的依赖来生效对应的默认配置,
springboot如何做到的?
其实在我们的项目中,已经引入了一个依赖:spring-boot-autoconfigure,其中定义了大量自动配置类,几乎涵盖了现在主流的开源框架,以下只列举一部分。

在这里插入图片描述
我们来看一个熟悉的,例如SpringMVC,查看mvc的自动配置类。
在这里插入图片描述
在这里插入图片描述

查看源码发现,这里有两个注解值得我们重点关注:

  • @ConditionalOnClass
    • 这里的条件是OnClass,也就是满足以下类存在:Servlet、DispatcherServlet、WebMvcConfigurer,其中Servlet只要引入了tomcat依赖自然会有,后两个需要引入SpringMVC才会有。这里就是判断你是否引入了相关依赖,引入依赖后该条件成立,当前类的配置才会生效。
  • @ConditionalOnMissingBean
    • 这个条件与上面不同,OnMissingBean,即环境中没有指定的Bean这个才生效。其实这就是自定义配置的入口,也就是说,如果我们自己配置了一个WebMVCConfigurationSupport的类,那么这个默认配置就会失效。

我们接着查看该类中定义了什么内容

  1. 视图解析器
    在这里插入图片描述
  2. 处理器适配器(HandlerAdapter)
    在这里插入图片描述

总结:
SpringBoot为我们提供了默认配置,而默认配置生效的条件一般有两个:

  • 引入了相关依赖
  • 无自定义配置类

五.整合SpringMVC

刚才的案例已经实现mvc自动配置,接下来我们要解决三个问题:

  • 修改端口
  • 静态资源
  • 拦截器配置

5.1 修改端口

在全局配置文件(application.properties)中进行修改:server.port=80

5.2 静态资源

ResourceProperteis的类,定义了静态资源的默认查找路径

在这里插入图片描述
一般习惯放在classpath:/static/目录下

在这里插入图片描述

5.3 拦截器

  1. 定义拦截器
public class LoginInterceptor implements HandlerInterceptor {
    private Logger logger = LoggerFactory.getLogger(LoginInterceptor.class);
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        logger.debug("处理器执行前");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        logger.debug("处理器执行后");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        logger.debug("跳转后执行");
    }
}
  1. 配置拦截器

通过实现 WebMvcConfigurer 并添加 @Configuration 注解来实现自定义部分SpringMvc配置:

@Configuration
public class MvcConfig implements WebMvcConfigurer {

    /**
     * 将定义的拦截器注册到Spring容器
     * @return
     */
    @Bean
    public LoginInterceptor loginInterceptor() {
        return new LoginInterceptor();
    }

    /**
     * 添加自定义拦截器
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(this.loginInterceptor()).addPathPatterns("/**");
    }
}

路径通配符

  • ‘?’ 匹配任何单字符
  • ‘*’ 匹配0或者任意数量的字符
  • ‘/**’ 匹配0或者更多的目录

结构如下:
在这里插入图片描述

但是当我们查看日志的时候会发现什么都没有,因为我们记录的log级别是debug,默认是显示info以上,所以要对日志级别进行配置,依旧是在全局配置文件中进行配置:logging.level.com.leyou=debug

六.通用mapper

6.1 概念

使用Mybatis时,最大的问题是,要写大量的重复SQL语句在xml文件中,除了特殊的业务逻辑SQL语句之外,还有大量结构类似的增删改查SQL。而且,当数据库表结构改动时,对应的所有SQL以及实体类都需要更改。因此避免重复书写CRUD映射的框架有两个

  • 通用mybatis(tk mybatis)
  • mybatis plus,通能更加强大。

6.2 配置

  1. 引入依赖
<!-- 通用mapper -->
<dependency>
	<groupId>tk.mybatis</groupId>
	<artifactId>mapper-spring-boot-starter</artifactId>
	<version>2.0.2</version>
</dependency>
  1. 实体类

tk mybatis 实体类使用的注解是jpa注解

@Table(name = "tb_user")
public class User{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// 用户名
private String userName;
  1. 默认表名=类名,也可通过@Table(name="tableName")注解指定
  2. 默认列名=属性名,也可通过@Column(name="fieldName")指定
  3. 主键使用注解@Id,若是自增id还应加上注解@GenerateValue(strategy=GenerationType.IDENTITY)
  4. 表中无该字段,而实体类需要使用,则添加@Transient注解,但该类要实现序列化接口
  1. 定义一个接口继承Mapper类即可使用
import com.lsy.domain.User;
import tk.mybatis.mapper.common.Mapper;

public interface UserMapper extends Mapper<User> {
}

若有特殊的业务逻辑需求,可自定义方法再对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.lxs.demo.dao.UserMapper">
<select id="findByUser" resultType="user">
	SELECT
	*
	FROM
	tb_user
	<where>
	<if test="name != null">
	name like '%${name}%'
	</if>
	<if test="note != null">
	and note like '%${note}%'
	</if>
	</where>
</select>

七.Thymeleaf

7.1 概念

Thymeleaf 是一个跟 FreeMarker 类似的模板引擎,它可以完全替代 JSP
特点:

  • 动静结合:运行与网络状态无关,无网络显示静态内容,有网络用后台得到数据替换静态内容
  • 与SpringBoot完美整合,springboot默认整合thymeleaf

动静结合该怎么理解呢,也许有人会说可以先写好静态页面,等有网络再用ajax获得数据也可以。
答案是当然可以,但那样做效率会低很多,例如一个form表单中有一个table,以往的做法就是先填充些虚拟的数据,等有网络了再通过ajax获得新的数据进行填充,但是这样的话我们写的静态页面就仅是为了预览,对后期的页面布局以及数据获取没什么帮助,而Thymeleaf就能很好的帮我们解决这个问题,接下来就通过一个案例进行讲解吧。

7.2 案例

  1. service
@Service
public class UserService {
	@Autowired
	private UserDao userDao;
	public List<User> queryAll() {
	return this.userDao.selectAll();
	}
}
  1. controller
@Controller
public class UserController {
	@Autowired
	private UserService userService;
	@RequestMapping("/all")
	public String all(Model model) {
	List<User> list = userService.findAll();
	model.addAttribute("users", list);
	// 返回模板名称(就是classpath:/templates/目录下的html文件名)
	return "users";
	}	
}
  1. 引入启动器
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

SpringBoot会自动为Thymeleaf注册一个视图解析器.
与解析JSP的InternalViewResolver类似,Thymeleaf也会根据前缀和后缀来确定模板文件的位置

在这里插入图片描述

  • 默认前缀: classpath:/templates/
  • 默认后缀: .html
    所以如果我们返回视图: users ,会指向到 classpath:/templates/users.html
    一般我们无需进行修改,默认即可
  1. 静态页面

把html 的名称空间,改成: xmlns:th="http://www.thymeleaf.org"会有语法提示

<tr th:each="user, status : ${users}" th:object="${user}">
	<td th:text="${user.id}">1</td>
	<td th:text="*{name}">张三</td>
	<td th:text="*{userName}">zhangsan</td>
	<td th:text="${user.age}">20</td>
	<td th:text="${user.sex} == 1 ? '': ''"></td>
	<td th:text="${#dates.format(user.birthday, 'yyyy-MM-dd')}">1980-02-30</td>
	<td th:text="${user.note}">1</td>
	<td>
		<a th:href="@{/delete(id=${user.id},%20userName=*{userName})}">删除</a>
		<a th:href="|/update/${user.id}|">修改</a>
		<a th:href="'/approve/' + ${user.id}">审核</a>
	</td>	
</tr>

基础语法解析:

  • th:each="user, status : ${users}" th:object="${user}">
    • th-: th- 是利用了h5中的自定义属性来实现的。如果不支持H5,可以用 data-th- 来代替
    • th:each :获取集合里的每个元素,类似c:foreach
    • user:集合里元素的指代,名字任意。
    • status:返回的集合模板名称
    • ${users}:获取返回的集合值,比el表达式更强大
  • th:object="${user}"
    • th:object :指定一个对象,如果返回的结果不是集合,则单独使用th:object即可
    • ${user}:获取user的值。因为前面已经指定集合里每个元素名称是user
  • th:text:声明标签中的文本
  • 关于*{name}以及超链接将会在后续继续介绍。

7.3 表达式

  1. 分类

表达式总共有三类:

  1. 变量表达式
  2. 选择或星号表达式
  3. URL表达式
  1. 变量表达式

变量表达式即OGNL表达式或Spring EL表达式(在Spring中用来获取model attribute的数据)。它们将以HTML标签的一个属性来表示,如上述的${users},th:object="${user}"

  1. 选择(星号)表达式

选择表达式很像变量表达式,不过它们用一个预先选择的对象来代替上下文变量容器(map)来执行,如上述的*{name},星号代替的就是th:object中的对象

  1. URL表达式

该表达式一般用于超链接标签,总共有三类

  • url表达式:
    <a th:href="@{/delete(id=${user.id},%20userName=*{userName})}">删除</a>,变量表达式可用星号表达式替换。
  • 文本替换 (推荐)
    <a th:href="|/update/${user.id}|">修改</a>,${user.id}可用星号表达式进行替换。
  • 字符串拼接
    <a th:href="'/approve/'%20+%20${user.id}">审核</a>,变量表达式可用星号表达式替换。

7.4 内联文本

内联文本:通过[[…]]方式,使用时,必须先用th:inline=”text/javascript/none”激活,用法主要是用于引用以及定义变量

  • 例如<h6 th:text="${text}">静态内容<h6>,然后在别处引用$ {text}的值<h6 th:inline="text">[[${text}]]</h6>

7.5 内嵌变量

为了模板更加易用,Thymeleaf还提供了一系列Utility对象(内置于Context中),可以通过 # 直接访问,下面只简单介绍两个。

  • dates
    <h6 th:text="${#dates.createNow()}">获取当前日期</h6>
  • strings
    <h6 th:text="${#strings.substring(text, 6, 9)}">截取字符串</h6>

7.6 缓存

Thymeleaf会在第一次对模板解析之后进行缓存,但是这给我们开发带来了不便,修改页面后并不会立刻看到效果,因此开发阶段可以关掉缓存使用:

# 开发阶段关闭thymeleaf的模板缓存
spring.thymeleaf.cache=false

八.Mybatis plus

8.1基础配置

  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.lxs</groupId>
	<artifactId>mybatis-plus-demo-quickstart</artifactId>
	<version>1.0-SNAPSHOT</version>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.3.0.RELEASE</version>
		<relativePath/>
	</parent>
	
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
		<mybatisplus.version>3.3.2</mybatisplus.version>
		<skipTests>true</skipTests>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId> 
			<artifactId>spring-boot-starter</artifactId>
		</dependency>
		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>com.baomidou</groupId>
			<artifactId>mybatis-plus-boot-starter</artifactId>
			<version>${mybatisplus.version}</version>
		</dependency>
		<dependency>
			<groupId>org.assertj</groupId>
			<artifactId>assertj-core</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>
  1. 配置文件application.yml

在Springboot中,推荐使用properties或者YAML文件来完成配置,但是对于较复杂的数据结构来说,YAML又远远优于properties。先来看一个Springboot中的properties文件和对应YAML文件的对比:

  • properties
environments.dev.url=http://dev.bar.com
environments.dev.name=Developer Setup
environments.prod.url=http://foo.bar.com
environments.prod.name=My Cool App
my.servers[0]=dev.bar.com
my.servers[1]=foo.bar.com
  • yaml
environments:
	dev:
		url: http://dev.bar.com
		name: Developer Setup
	prod:
		url: http://foo.bar.com
		name: My Cool App
my:
	servers:
		- dev.bar.com
		- foo.bar.com

可以明显的看到,在处理层级关系的时候,properties需要使用大量的路径来描述层级(或者属性),比如
environments.dev.url和environments.dev.name。其次,对于较为复杂的结构,比如数组(my.servers),写起来更为复杂。而对应的YAML格式文件就简单很多.
下面是application.yaml

# DataSource Config
spring:
	datasource:
		driver-class-name: org.h2.Driver
		schema: classpath:db/schema-h2.sql
		data: classpath:db/data-h2.sql
		url: jdbc:h2:mem:test
		username: root
		password: test
		
# Logger Config
logging:
	level:
		com.lxs.quickstart: debug

h2数据库是一个基于内存的数据库,在jvm启动时,自动执行脚本加载相应的数据
springboot 中使用h2数据库直接按照上面配置,配置schema表结构脚本和data数据脚本即可
注意这里用户名密码可以省略不写,或者随意设定

8.2 入门案例

  • 此处只写实体层和dao层,其它层和tk mapper流程类似
@Data
public class User {
	private Long id;
	private String name;
	private Integer age;
	private String email;
}

@Data注解可自动为该类提供get,set,equal,toString等方法,且成员变量改变时get,set方法可自动改变,不再像以前那样需要手动更改,但是该注解生效的前提是引入lombok依赖

public interface UserMapper extends BaseMapper<User> {
}

8.3 常用注解

  • @TableName:类名表名不一致使用(@TableName(value=””))
  • @TableId:主键名不一致使用
    • 如果主键策略默认什么也没配,MP会自动找ID作为主键 而没配@TableId但是主键不是ID而是user_id 此时MP会报错
    • 解决方式:要么改成ID后MP会自动找,要么还使用user_id同时加上@TableId
  • @TableFiled:成员名字段名不一致使用
  • 主键策略
  1. 表中有主键
   @TableId(type=IdType.AUTO)
   private Long id;
  1. 表中无主键
/**
* 采用雪花算法生成全局唯一主键
**/
ASSIGN_ID(3),
  • 字段策略
  • 排除实体类中非表字段
    使用@TableField(exist = false)注解

8.4 内置CRUD

//删除
	//批量删除:1
	mapper.delete(new QueryWrapper<User>().like("name", "J"));
	//批量删除:2
	mapper.delete(Wrappers.<User>query().like("name", "J"));
	//批量删除:3
	mapper.delete(Wrappers.<User>query().lambda().like(User::getName, "J"));
	
//修改
	//批量修改:1
	mapper.update(null, Wrappers.<User>update().set("email","huike@163.com")
												.like("name","J"));
	//批量修改:2
	mapper.update(new User().setEmail("huike@163.com"), Wrappers.<User>update()
							.like("name","J"));

8.5 分页

8.5.1 内置分页

  • 配置分页插件
@Configuration
public class MybatisPlusConfig {
/**
* 分页插件
*/
@Bean
 public PaginationInterceptor paginationInterceptor() {
	// 开启 count 的 join 优化,只针对 left join !!!
   return new PaginationInterceptor().setCountSqlParser(new JsqlParserCountOptimize(true));
	}
}
  • 测试
@Test
public void testPage() {
	System.out.println("------ baseMapper 自带分页 ------");
	Page<User> page = new Page<>(1, 5);
	IPage<User> pageResult=mapper.selectPage(page, new QueryWrapper<User>().eq("age", 20));
	System.out.println("总条数 ------> " + pageResult.getTotal());
	System.out.println("当前页数 ------> " + pageResult.getCurrent());
	System.out.println("当前每页显示数 ------> " + pageResult.getSize());
	pageResult.getRecords().forEach(System.out :: println);
}

通过上例可知,用内置分页插件时,需要传递一个page对象。上例的条件查询只有一个,若是有多个,则查询时较为麻烦,此时推荐使用自定义sql语句,然后selectPage的第二个参数传递封装好的对象即可。步骤如下:

8.5.2 自定义分页

  1. application.yml文件配置
# 配置mybatis plus
mybatis-plus:
type-aliases-package: com.lxs.crud.entity #别名搜索
mapper-locations: classpath:/mappers/*.xml #加载映射文件
  1. 编写接口
public interface UserMapper extends BaseMapper<User> {
	/**
	* 如果映射的接口方法有2个参数需要@Param定义参数名
	* 定义参数名后,映射文件中使用p.属性 c.属性,具体访问
	*
	* @param page
	* @param conditioin
	* @return
	*/
	public IPage<User> selectUserByPage(@Param("p") IPage<User> page, 
										@Param("c") User conditioin);
	}
  1. 映射文件
<mapper namespace="com.lxs.mybatisplus.samples.crud.mapper.UserMapper">
	<sql id="selectSql">
		SELECT
			*
		FROM
			user
	</sql>
	
	<select id="selectUserByPage" resultType="user">
		<include refid="selectSql"></include>
		<where>
			<if test="c.age !=null">
				age = #{c.age}
			</if>
			<if test="c.email !=null">
				and email like '%${c.email}%'
			</if>
		</where>
	</select>
</mapper>
  1. 测试
Page<User> page = new Page<>(1, 5);
User user = new User();
user.setAge(20);
user.setEmail("test");
IPage<User> pr = mapper.selectUserByPage(page, user);

8.5.3 pagehelper分页

  • 引入依赖
<dependency>
	<groupId>com.github.pagehelper</groupId>
	<artifactId>pagehelper</artifactId>
	<version>5.1.11</version>
</dependency>
  • 配置类
@Configuration
@MapperScan("com.lxs.mybatisplus.samples.crud.mapper")
public class MybatisPlusConfig {
/**
* mp分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
// 开启 count 的 join 优化,只针对 left join !!!
   return new PaginationInterceptor().setCountSqlParser(new JsqlParserCountOptimize(true));
}
/**
* 两个分页插件都配置,不会冲突
* pagehelper的分页插件
*/
@Bean
public PageInterceptor pageInterceptor() {
	return new PageInterceptor();
}
  • 测试
@Test
public void testPageHelper() {
	//链式查询,不带条件
	PageInfo<User> page = PageHelper.startPage(1, 2).doSelectPageInfo(() ->
	mapper.selectList(Wrappers.<User>query()));
	//分步查询,不带条件,这种方式更容易理解
	PageHelper.startPage(1,2);
	PageInfo<User> page = new PageInfo<>(mapper.selectList(Wrappers.<User>query()));
	//分步查询,带有条件,这种方式更容易理解
	User u = new User();
	u.setAge(20);
	PageInfo<User> page = new PageInfo<User>(mapper.selectUserByPage2(u));
}

8.5.4 总结

  • 内置分页
  1. 查询前使用Page<T> page = new Page<>(pageNum, pageSize)实现分页
  2. 通过IPage<T> pr = mapper.查询方法获取结果
  • PageHelper
  1. 查询前使用PageHelper.startPage(pageNum,pageSize)确定分页
  2. 通过mapper.方法获取结果
  3. 通过PageInfo<T>对查询结果进行封装才能实现分页
  • 带条件查询
    实际开发中,一般都是模糊查询才需要传递条件,虽然mapper封装了容器查询的方法,但有时候要求比较特别,example查询比较单一难以满足要求,所以上例中采用了手写接口进行自定义分页查询的实现。

版权声明:本文为qq_43820523原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。