目录
4.1.1 @SpringBootConfiguration
4.1.3 @EnableAutoConfiguration
8.1.2 编写一个controller,返回一些用户数据,放入模型中,等会在页面渲染
一、SpringBoot概念
1.1 什么是SpringBoot
1.2 为什么要学习SpringBoot
spring的缺点:
1,复杂的配置
2,混乱的依赖管理。
1.3 SpringBoot的特点
Spring Boot 特点:
1.4 总结
二、入门案例
需求:创建HelloController,在页面中打印hello spring boot...
2.1 创建工程
2.1.1 创建一个空工程

2.1.2 工程名为project_test:

2.1.3 设置jdk版本为1.8

2.1.4 新建一个module

2.1.5 填写项目坐标

2.2 添加依赖
2.2.1 添加父工程坐标
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.0.RELEASE</version>
    </parent> 
2.2.2 添加web启动器
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies> 
需要注意的是,我们并没有在这里指定版本信息。因为SpringBoot的父工程已经对版本进行了管理了。这个时候,我们会发现项目中多出了大量的依赖:
 
这些都是SpringBoot根据spring-boot-starter-web这个依赖自动引入的,而且所有的版本都已经管理好,不会出现冲突。
2.2.3 管理jdk版本
默认情况下,maven工程的jdk版本是1.5,而我们开发使用的是1.8,因此这里我们需要修改jdk版本,只需要简单的添加以下属性即可:
    <properties>
        <java.version>1.8</java.version>
    </properties> 
2.2.4 完整的pom文件
<?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.lxy</groupId>
    <artifactId>spring-boot-demo-test</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.0.RELEASE</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
</project> 
2.3 启动类
Spring Boot项目通过main函数即可启动,我们需要创建一个启动类:

然后编写main函数:
package com.lxy;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }
}
 
2.4 编写controller
接下来,我们就可以像以前那样开发SpringMVC的项目了!
 我们编写一个controller:
package com.lxy.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello(){
        return "hello, spring boot!";
    }
}
 
2.5 启动测试
接下来,我们运行main函数,查看控制台:

并且可以看到监听的端口信息:

打开页面访问:http://localhost:8080/hello

测试成功了!
三、全注解配置和属性注入
<!-- 配置连接池 -->
<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.1 回顾历史
事实上,在Spring3.0开始,Spring官方就已经开始推荐使用java配置来代替传统的xml配置了,我们不妨来回顾一下Spring的历史:
3.2 spring全注解配置
spring全注解配置主要靠java类和一些注解,比较常用的注解有:
我们接下来用java配置来尝试实现连接池配置:
首先引入Druid连接池依赖:
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency> 
创建一个jdbc.properties文件,编写jdbc属性(可以拷贝):
jdbc.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT
jdbc.usernam=root
jdbc.passwor=linda198721 
然后编写代码: 创建一个JdbcConfig类
package com.lxy.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import javax.sql.DataSource;
@Configuration
@PropertySource("classpath:jdbc.properties")
public class JdbcConfig {
    @Value("${jdbc.url}")
    String url;
    @Value("${jdbc.driverClassName}")
    String driverClassName;
    @Value("${jdbc.username}")
    String username;
    @Value("${jdbc.password}")
    String password;
    @Bean
    public DataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(url);
        dataSource.setDriverClassName(driverClassName);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }
}
 
解读:
然后我们就可以在任意位置通过 @Autowired 注入DataSource了!
我们在 HelloController 中测试:
package com.lxy.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.sql.DataSource;
@RestController
public class HelloController {
    @Autowired
    private DataSource dataSource;
    @GetMapping("/hello")
    public String hello(){
        return "hello, spring boot!"+dataSource;
    }
}
 
然后Debug运行并查看:

属性注入成功了!
3.3 SpringBoot的属性注入
1)我们新建一个类,用来进行属性注入:
package com.lxy.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "jdbc")
public class JdbcProperties {
    private String url;
    private String driverClassName;
    private String username;
    private String password;
    public String getUrl() {
        return url;
    }
    public void setUrl(String url) {
        this.url = url;
    }
    public String getDriverClassName() {
        return driverClassName;
    }
    public void setDriverClassName(String driverClassName) {
        this.driverClassName = driverClassName;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
}
 
 
2)在JdbcConfig中使用这个属性:
package com.lxy.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import javax.sql.DataSource;
@Configuration
@EnableConfigurationProperties(JdbcProperties.class)
public class JdbcConfig {
    @Bean
    public DataSource dataSource(JdbcProperties jdbc) {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(jdbc.getUrl());
        dataSource.setDriverClassName(jdbc.getDriverClassName());
        dataSource.setUsername(jdbc.getUsername());
        dataSource.setPassword(jdbc.getPassword());
        return dataSource;
    }
}
 
通过 @EnableConfigurationProperties(JdbcProperties.class) 来声明要使用 JdbcProperties 这个类的对象 .
3)可以通过以下方式注入JdbcProperties:
@Autowired注入:
@Autowired
private JdbcProperties prop; 
构造函数注入
private JdbcProperties prop;
public JdbcConfig(Jdbcproperties prop){
    this.prop = prop;
}
 
声明有@Bean的方法参数注入
@Bean
public Datasource dataSource(JdbcProperties prop){
    // ...
} 
本例中,我们采用第三种方式。
4)测试结果

5)这种方法的优势
大家会觉得这种方式似乎更麻烦了,事实上这种方式有更强大的功能,也是SpringBoot推荐的注入方式。两者对比关系: 
优势:
3.4 更优雅的注入
事实上,如果一段属性只有一个Bean需要使用,我们无需将其注入到一个类(JdbcProperties)中。而是直接在需要的地方声明即可:
(可删除之前创建的JdbcProperties类)在JdbcConfig中修改
package com.lxy.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
@Configuration
public class JdbcConfig {
    @Bean
    // 声明要注入的属性前缀,SpringBoot会自动把相关属性通过set方法注入到DataSource中
    @ConfigurationProperties(prefix = "jdbc")
    public DataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        return dataSource;
    }
}
 
 
四、自动配置原理
通过刚才的案例看到,一个整合了SpringMVC的WEB工程开发,变的无比简单,那些繁杂的配置都消失不见了,这是如何做到的?
 这些都是从springboot启动器开始的:

我们重点关注@SpringBootApplication注解
4.1 @SpringBootApplication
点击进入,查看源码:

这里重点的注解有3个:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
 
4.1.1 @SpringBootConfiguration
我们继续点击查看源码:
通过这段我们可以看出,在这个注解上面,又有一个 @Configuration 注解。这个注解的作用就是声明当前类是一个配置类,然后Spring会自动扫描到添加了 @Configuration 的类,并且读取其中的配置信息。
4.1.2 @ComponentScan
我们跟进源码:
并没有看到什么特殊的地方。我们查看注释:
 
大概的意思:
而我们的@SpringBootApplication注解声明的类就是main函数所在的启动类,因此扫描的包是该类所在包及其子包。因此,一般启动类会放在一个比较前的包目录中。
4.1.3 @EnableAutoConfiguration
关于这个注解,官网上有一段说明:
简单翻译一下:
4.2 默认配置原理
@EnableAutoConfiguration会开启SpringBoot的自动配置,并且根据你引入的依赖来生效对应的默认配置,springboot如何做到的?
 其实在我们的项目中,已经引入了一个依赖:spring-boot-autoconfigure,其中定义了大量自动配置类:
 

非常多,几乎涵盖了现在主流的开源框架,例如:
我们来看一个我们熟悉的,例如SpringMVC,查看mvc 的自动配置类:
 
打开WebMvcAutoConfiguration:
 
我们看到这个类上的4个注解:
接着,我们查看该类中定义了什么:
视图解析器:
 
处理器适配器(HandlerAdapter):
 
还有很多,这里就不一一截图了。
4.3 总结
SpringBoot为我们提供了默认配置,而默认配置生效的条件一般有两个:
五、整合SpringMVC
刚才案例已经能实现mvc自动配置,这里我们主要解决以下3个问题
5.1 修改端口
查看SpringBoot的全局属性可知,端口通过以下方式配置:
# 映射端口
server.port=80 
重启服务后测试:
5.2 访问静态资源
ResourceProperties的类,里面就定义了静态资源的默认查找路径:

默认的静态资源路径为:
只要静态资源放在这些目录中任何一个,SpringMVC都会帮我们处理。
 我们习惯会把静态资源放在 classpath:/static/ 目录下。我们创建目录,并且添加一些静态资源:

重启项目后测试:

5.3 添加拦截器
拦截器也是我们经常需要使用的,在SpringBoot中该如何配置呢?
首先我们定义一个拦截器:
package com.lxy.interceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoginInterceptor implements HandlerInterceptor {
    private Logger logger = LoggerFactory.getLogger(LoginInterceptor.class);
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        logger.debug("处理器执行前执行!");
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
        logger.debug("处理器执行后执行!");
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        logger.debug("跳转后执行!");
    }
}
 
通过实现 WebMvcConfigurer 并添加 @Configuration 注解来实现自定义部分SpringMvc配置:
package com.lxy.config;
import com.lxy.interceptor.LoginInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MvcConfig implements WebMvcConfigurer {
    /**
     * 通过@Bean注解,将我们定义的拦截器注册到Spring容器
     * @return
     */
    @Bean
    public LoginInterceptor loginInterceptor(){
        return new LoginInterceptor();
    }
    /**
     * 重写接口中的addInterceptors方法,添加自定义拦截器
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 通过registry来注册拦截器,通过addPathPatterns来添加拦截路径
        registry.addInterceptor(this.loginInterceptor()).addPathPatterns("/**");
    }
}
 
 
结构如下:
接下来运行并查看日志:
你会发现日志中什么都没有,因为我们记录的log级别是debug,默认是显示info以上,我们需要进行配置。SpringBoot通过 logging.level.*=debug 来配置日志级别,*填写包名
# 设置com.lxy包的日志级别为debug
logging.level.com.lxy=debug 
再次运行查看:

六、整合jdbc
导入资料中的t_user.sql文件 如果你也想要这个资源请在下发评论,我会发给你

引入依赖
(引入依赖之前需要先把之前添加的德鲁伊连接池的依赖删除)
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>
 
当然,不要忘了数据库驱动,SpringBoot并不知道我们用的什么数据库,这里我们选择MySQL:
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.23</version>
        </dependency> 
配置连接池
其实,在刚才引入jdbc启动器的时候,SpringBoot已经自动帮我们引入了一个连接池:

HikariCP应该是目前速度最快的连接池了,我们看看它与c3p0的对比:

因此,我们只需要在application.properties中指定连接池参数即可:
# 连接四大参数
spring.datasource.url=jdbc:mysql://localhost:3306/springboot
spring.datasource.username=root
spring.datasource.password=linda198721
# 可省略,SpringBoot自动推断
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.hikari.idle-timeout=60000
spring.datasource.hikari.maximum-pool-size=30
spring.datasource.hikari.minimum-idle=10 
实体类创建:
package com.lxy.domain;
import java.util.Date;
public class User {
    private Long id;
    // 用户名
    //自动转换下换线到驼峰命名user_name -> userName
    private String userName;
    // 密码
    private String password;
    // 姓名
    private String name;
    // 年龄
    private Integer age;
    // 性别,1男性,2女性
    private Integer sex;
    // 出生日期
    private Date birthday;
    // 创建时间
    private Date created;
    // 更新时间
    private Date updated;
    // 备注
    private String note;
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", userName='" + userName + '\'' +
                ", name='" + name + '\'' +
                ", updated=" + updated +
                ", note='" + note + '\'' +
                '}';
    }
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public Integer getSex() {
        return sex;
    }
    public void setSex(Integer sex) {
        this.sex = sex;
    }
    public Date getBirthday() {
        return birthday;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
    public Date getCreated() {
        return created;
    }
    public void setCreated(Date created) {
        this.created = created;
    }
    public Date getUpdated() {
        return updated;
    }
    public void setUpdated(Date updated) {
        this.updated = updated;
    }
    public String getNote() {
        return note;
    }
    public void setNote(String note) {
        this.note = note;
    }
}
 
dao类创建:
package com.lxy.dao;
import com.lxy.domain.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public class JdbcDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    public List<User> findAll(){
        return jdbcTemplate.query("select * from tb_user",new BeanPropertyRowMapper<>(User.class));
    }
}
 
测试:
package com.lxy.dao;
import com.lxy.domain.User;
import junit.framework.TestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class JdbcDaoTest extends TestCase {
    @Autowired
    private JdbcDao jdbcDao;
    @Test
    public void findAll(){
       jdbcDao.findAll().forEach(user -> {
           System.out.println(user);
       });
    }
} 

这里可以看到SpringBoot支持下划线转驼峰的形式,成功取到userName。
七、整合mybatis
7.1 mybatis整合
7.1.1 测试案例
SpringBoot官方并没有提供Mybatis的启动器,不过Mybatis官网自己实现了:
<!--mybatis -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.2</version>
</dependency> 
配置,基本没有需要配置的:
# mybatis 别名扫描
mybatis.type-aliases-package=com.lxy.domain
# mapper.xml文件位置,如果没有映射文件,请注释掉
mybatis.mapper-locations=classpath:mappers/*.xml
 
实体类,直接使用jdbc用到的实体类
package com.lxy.domain;
import java.util.Date;
public class User {
    private Long id;
    // 用户名
    //自动转换下换线到驼峰命名user_name -> userName
    private String userName;
    // 密码
    private String password;
    // 姓名
    private String name;
    // 年龄
    private Integer age;
    // 性别,1男性,2女性
    private Integer sex;
    // 出生日期
    private Date birthday;
    // 创建时间
    private Date created;
    // 更新时间
    private Date updated;
    // 备注
    private String note;
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", userName='" + userName + '\'' +
                ", name='" + name + '\'' +
                ", updated=" + updated +
                ", note='" + note + '\'' +
                '}';
    }
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public Integer getSex() {
        return sex;
    }
    public void setSex(Integer sex) {
        this.sex = sex;
    }
    public Date getBirthday() {
        return birthday;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
    public Date getCreated() {
        return created;
    }
    public void setCreated(Date created) {
        this.created = created;
    }
    public Date getUpdated() {
        return updated;
    }
    public void setUpdated(Date updated) {
        this.updated = updated;
    }
    public String getNote() {
        return note;
    }
    public void setNote(String note) {
        this.note = note;
    }
}
 
创建接口:
package com.lxy.dao;
import com.lxy.domain.User;
import java.util.List;
public interface UserDao {
    public List<User> findAll();
}
 
创建UserDao.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.lxy.dao.UserDao">
    <select id="findAll" resultType="user">
        select * from tb_user
    </select>
</mapper>
 
7.1.2 Mapper的加载接口代理对象方式有2种
第一种:使用@Mapper注解(不推荐)
需要注意,这里没有配置mapper接口扫描包,因此我们需要给每一个Mapper接口添加 @Mapper 注解,才能被识别。
@Mapper
public interface UserMapper {
}
 
第二种设置MapperScan,注解扫描的包(推荐)
@MapperScan("dao所在的包"),自动搜索包中的接口,产生dao的代理对象
package com.lxy;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.lxy.dao")
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }
}
 
测试
 引入测试构建:(之前已经引入)
测试代码:
package com.lxy.dao;
import com.lxy.domain.User;
import junit.framework.TestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserDaoTest {
    @Autowired
    private UserDao userDao;
    @Test
    public void testFindAll() {
        List<User> list = userDao.findAll();
        System.out.println(list);
    }
}
 
测试结果:

这里可以看到mybatis是不支持下划线转驼峰的写法的
7.2 通用mapper
7.2.1 概念
使用Mybatis时,最大的问题是,要写大量的重复SQL语句在xml文件中,除了特殊的业务逻辑SQL语句之外,还有大量结构类似的增删改查SQL。而且,当数据库表结构改动时,对应的所有SQL以及实体类都需要更改。这大量增加了程序员的负担。避免重复书写CRUD映射的框架有两个
7.2.2 案例测试
(1)通用Mapper的作者也为自己的插件编写了启动器,我们直接引入即可:
因为tk mybatis中包含mybatis,所以我们可以把之前的mybatis删除

(2)实体类代码:
package com.lxy.domain;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;
@Table(name = "tb_user")
public class User {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    // 用户名
    //自动转换下换线到驼峰命名user_name -> userName
    private String userName;
    // 密码
    private String password;
    // 姓名
    private String name;
    // 年龄
    private Integer age;
    // 性别,1男性,2女性
    private Integer sex;
    // 出生日期
    private Date birthday;
    // 创建时间
    private Date created;
    // 更新时间
    private Date updated;
    // 备注
    private String note;
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", userName='" + userName + '\'' +
                ", name='" + name + '\'' +
                ", updated=" + updated +
                ", note='" + note + '\'' +
                '}';
    }
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public Integer getSex() {
        return sex;
    }
    public void setSex(Integer sex) {
        this.sex = sex;
    }
    public Date getBirthday() {
        return birthday;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
    public Date getCreated() {
        return created;
    }
    public void setCreated(Date created) {
        this.created = created;
    }
    public Date getUpdated() {
        return updated;
    }
    public void setUpdated(Date updated) {
        this.updated = updated;
    }
    public String getNote() {
        return note;
    }
    public void setNote(String note) {
        this.note = note;
    }
}
 
 
不需要做任何配置就可以使用了。
(3)定义mapper接口,不需要编写映射文件xxx.xml
package com.lxy.dao;
import com.lxy.domain.User;
import tk.mybatis.mapper.common.Mapper;
public interface UserMapper extends Mapper<User> {
}
 
(4) mapper接口扫描
注意要把Application.java中,MapperScan类改成tk-mybatis构件的类

(5)测试
package com.lxy.dao;
import com.lxy.domain.User;
import junit.framework.TestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import tk.mybatis.mapper.entity.Example;
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest extends TestCase {
    @Autowired
    private UserMapper userMapper;
    @Test
    public void testFindAll() {
        userMapper.selectAll().forEach(user -> {
            System.out.println(user);
        });
    }
    @Test
    public void testByExample () {
        Example example = new Example(User.class);
        example.createCriteria().andLike("name", "%a%");
        userMapper.selectByExample(example).forEach(user -> {
            System.out.println(user);
        });
    }
} 
(6)自定义映射方法
创建一个UserMapper.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.lxy.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>
</mapper> 
在UserMapper接口中添加方法:
package com.lxy.dao;
import com.lxy.domain.User;
import tk.mybatis.mapper.common.Mapper;
import java.util.List;
public interface UserMapper extends Mapper<User> {
    public List<User> findByUser(User user);
}
 
测试:
    @Test
    public void testFindByUser() {
        User user = new User();
        user.setName("a");
        user.setNote("c");
        userMapper.findByUser(user).forEach(user1 -> {
            System.out.println(user1);
        });
    } 
7.2.3 tk.mybatis中Mapper的内置方法
八、thymeleaf
概念:
8.1 入门案例
8.1.1 编写接口
编写UserService,调用UserMapper的查询所有方法
package com.lxy.service;
import com.lxy.dao.UserMapper;
import com.lxy.domain.User;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
public class UserService {
    @Autowired
    private UserMapper userMapper;
    public List<User> findAll(){
        return userMapper.selectAll();
    }
}
 
8.1.2 编写一个controller,返回一些用户数据,放入模型中,等会在页面渲染
package com.lxy.controller;
import com.lxy.domain.User;
import com.lxy.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import java.util.List;
@Controller
public class UserController {
    @Autowired
    private UserService userService;
    public String all(Model model){
        List<User> list = userService.findAll();
        model.addAttribute("users",list);
        // 返回模板名称(就是classpath:/templates/目录下的html文件名)
        return "users";
    }
}
 
8.1.3 引入启动器
直接引入启动器:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency> 
SpringBoot会自动为Thymeleaf注册一个视图解析器:

与解析JSP的InternalViewResolver类似,Thymeleaf也会根据前缀和后缀来确定模板文件的位置:

所以如果我们返回视图: users ,会指向到 classpath:/templates/users.html
 一般我们无需进行修改,默认即可。 
8.1.4 静态页面
根据上面的文档介绍,模板默认放在classpath下的templates文件夹,我们新建一个html文件放入其中:

编写html模板,渲染模型中的数据:
 注意,把html 的名称空间,改成: xmlns:th="http://www.thymeleaf.org" 会有语法提示
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="UTF-8">
  <title>首页</title>
  <style type="text/css">
    table {border-collapse: collapse; font-size: 14px; width: 80%; margin: auto}
    table, th, td {border: 1px solid darkslategray;padding: 10px}
  </style>
</head>
<body>
<div style="text-align: center">
  <span style="color: darkslategray; font-size: 30px">欢迎光临</span>
  <hr/>
  <table class="list">
    <tr>
      <th>序号</th>
      <th>id</th>
      <th>姓名</th>
      <th>用户名</th>
      <th>年龄</th>
      <th>性别</th>
      <th>生日</th>
      <th>备注</th>
      <th>操作</th>
    </tr>
    <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 href="#">删除</a>
        <a href="#">修改</a>
        <a href="#">审核</a>
      </td>
    </tr>
  </table>
</div>
</body>
</html> 
8.1.5 测试
接下来,我们打开页面测试一下:

8.1.6 模板缓存
Thymeleaf会在第一次对模板解析之后进行缓存,极大的提高了并发处理能力。但是这给我们开发带来了不便,修改页面后并不会立刻看到效果,我们开发阶段可以关掉缓存使用:
# 开发阶段关闭thymeleaf的模板缓存
spring.thymeleaf.cache=false 
注意:
 在Idea中,我们需要在修改页面后按快捷键: Ctrl + Shift + F9 对项目进行rebuild才可以。
 我们可以修改页面,测试一下。 
8.2 thymeleaf详解
8.2.1 表达式
(1) 变量表达式
变量表达式即OGNL表达式或Spring EL表达式(在Spring中用来获取model attribute的数据)。如下所示:
${session.user.name} 
它们将以HTML标签的一个属性来表示:
<h5>表达式</h5>
<span>${text}</span>
<span th:text="${text}">你好 thymleaf</span> 
(2) 选择(星号)表达式
选择表达式很像变量表达式,不过它们用一个预先选择的对象来代替上下文变量容器(map)来执行,如下: *{customer.name}
被指定的object由th:object属性定义:users.html
<tr th:each="user : ${users}" th:object="${user}">
    <td th:text="${user.id}">1</td>
    <td th:text="*{name}">张三</td>
    <td th:text="*{userName}">zhangsan</td>
    .... 
(3) URL表达式
让我们看这些表达式:
<form th:action="@{/createOrder}">
<a href="main.html" th:href="@{/main}"> 
url表达式:
<a th:href="@{/delete(id=${user.id}, userName=*{userName})}">删除</a>
 
文本替换:
<a th:href="|/update/${user.id}|">修改</a> 
字符串拼接
<a th:href="'/approve/' + ${user.id}">审核</a> 
8.2.2 表达式常见用法
(1) 字面(Literals)
(2) 文本操作(Text operations)
(3) 算术运算(Arithmetic operations)
(4) 布尔操作(Boolean operations)
(5) 比较和等价(Comparisons and equality)
(6) 条件运算符(Conditional operators)
8.2.3 常用th标签
 

还有非常多的标签,这里只列出最常用的几个
8.2.4 基本用法
(1) 赋值、字符串拼接
字符串拼接还有另外一种简洁的写法
<a th:href="|/update/${user.id}|">修改</a>
<a th:href="'/approve/' + ${user.id}">审核</a> 
(2) 条件判断 If/Unless
Thymeleaf中使用th:if和th:unless属性进行条件判断,下面的例子中, <a> 标签只有在 th:if 中条件成立时才显示:
<h5>if指令</h5>
<a th:if="${users.size() > 0}">查询结果存在</a><br>
<a th:if="${users.size() <= 0}">查询结果不存在</a><br>
<a th:unless="${session.user != null}" href="#">登录</a><br> 
th:unless于th:if恰好相反,只有表达式中的条件不成立,才会显示其内容。
 也可以使用 (if) ? (then) : (else) 这种语法来判断显示的内容
(3) for 循环
    <tr th:each="user,status:${users}" th:object="${user}" th:bgcolor="${status.even} ? 'gray'">
      <th th:text="${status.count}">1</th>
      <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},userName=*{userName})}">删除</a>
        <a th:href="|/update/${user.id}|">修改</a>
        <a th:href="'approve' + ${user.id}">审核</a>
      </td>
    </tr> 
 
(4) 内联文本
使用的是后台传过来的Model中的数据
在thymeleaf指令中显示:
<h6 th:text="${text}">静态内容</h6> 
使用内联文本显示model attribute:
<h5>内联文本</h5>
<div>
    <h6 th:inline="text">[[${text}]]</h6>
    <h6 th:inline="none">[[${text}]]</h6>
    <h6>[[${text}]]</h6>
</div>
 
原则能用指令就用th指令
(5) 内联js
<h5>内联js</h5>
<script th:inline="javascript">
    /*<![CDATA[*/
    var text = '[[${text}]]';
    alert(text);
    /*]]>*/
</script>
 
(6) 内嵌变量
为了模板更加易用,Thymeleaf还提供了一系列Utility对象(内置于Context中),可以通过#直接访问:
下面用一段代码来举例一些常用的方法:
1. dates
<h5>内置变量</h5>
<h6 th:text="${#dates.createNow()}">获取当前日期</h6> 
2.strings
<h5>内置变量</h5>
<h6 th:text="${#dates.createNow()}">获取当前日期</h6>
<h6 th:text="${#strings.substring(text, 6, 9)}">截取字符串</h6>
<h6 th:text="${#strings.length(text)}">获得长度</h6>
<h6 th:text="${#strings.randomAlphanumeric(6)}">随机字符串</h6>
<h6 th:text="${#strings.equals(text, 'hello text....')}"></h6> 
8.3 使用thymeleaf布局
使用thymeleaf布局非常的方便
 在/resources/templates/目录下创建footer.html,内容如下
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<footer th:fragment="copy(title)">
    © 2020 lxy版权所有<br>
    <span th:text="${title}">title footer</span>
</footer>
</body>
</html>
 
在页面任何地方引入:
<h5>thymeleaf布局</h5>
<div th:insert="footer :: copy('开课吧1')"></div>
<div th:replace="footer :: copy('开课吧2')"></div>
<div th:include="footer :: copy('开课吧3')"></div> 
 
返回的HTML如下:
<h5>thymeleaf布局</h5>
<div><footer>
    © 2020 lxy版权所有<br>
    <span>lxy</span>
</footer></div>
<footer>
    © 2020 lxy版权所有<br>
    <span>lxy</span>
</footer>
<div>
    © 2020 lxy版权所有<br>
    <span>lxy</span>
</div> 
九、Mybatis Plus
9.1 简介

9.2 快速入门
9.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.lxy</groupId>
    <artifactId>mybatis-plus-demo-quickstart-test</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>
        <!--简化开发 实体类不用写get set方法-->
        <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>
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>5.1.11</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project> 
9.2.2 配置文件application.yml
yml配置简介
先来看一个Springboot中的properties文件和对应YAML文件的对比:
#properties(示例来源于Springboot User guide):
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
 
application.yml :
# 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 
 
9.2.3 实体类
package com.lxy.quickstart.entity;
import lombok.Data;
@Data
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}
 
9.2.4 dao
package com.lxy.quickstart.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lxy.quickstart.entity.User;
public interface UserMapper extends BaseMapper<User> {
}
 
9.2.5 启动类
package com.lxy.quickstart;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.lxy.quickstart.mapper")
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
 
9.2.6 测试
package com.lxy.quickstart.mapper;
import com.lxy.quickstart.entity.User;
import junit.framework.TestCase;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest extends TestCase {
    @Autowired
    private UserMapper userMapper;
    @Test
    public void testSelect() {
        System.out.println(("----- selectAll method test ------"));
        List<User> userList = userMapper.selectList(null);
        //Assert.assertEquals(6, userList.size());
        userList.forEach(System.out::println);
    }
} 
测试结果:
9.3 常用注解
 
 
9.3.1 mybatis plus注解策略配置
 
如果mysql自增主键注解策略设置如下
默认主键策略:
9.3.2 排除实体类中非表字段
9.4 内置增删改查
9.4.1 增加
    @Test
    public void testInsert() {
        User user = new User();
        user.setName("aaa");
        user.setEmail("lxy@163.com");
        user.setAge(3);
        Assert.assertTrue(userMapper.insert(user) > 0);
        userMapper.selectList(null).forEach(System.out :: println);
    } 

9.4.2 删除
    @Test
    public void testDelete() {
//        //主键删除
//        userMapper.deleteById(3l);
//        userMapper.selectList(null).forEach(System.out :: println);
//        //批量删除:1
//        userMapper.delete(new QueryWrapper<User>().like("name", "J"));
//        userMapper.selectList(null).forEach(System.out :: println);
//        //批量删除:2
//        userMapper.delete(Wrappers.<User>query().like("name", "J"));
//        userMapper.selectList(null).forEach(System.out :: println);
        //批量删除:3
        userMapper.delete(Wrappers.<User>query().lambda().like(User::getName, "J"));
        userMapper.selectList(null).forEach(System.out :: println);
        
    } 
9.4.3 更新
    @Test
    public void testUpdate() {
//        //基本修改
//        userMapper.updateById(new User().setId(1l).setName("慧科"));
//        userMapper.selectList(null).forEach(System.out :: println);
        // //批量修改:1
        // mapper.update(null, Wrappers.<User>update().set("email", "huike@163.com").like("name","J"));
        // mapper.selectList(null).forEach(System.out :: println);
        //批量修改:2
        userMapper.update(new User().setEmail("huike@163.com"), Wrappers.<User>update().like("name", "J"));
        userMapper.selectList(null).forEach(System.out :: println);
    } 
在更新时,使用的方法必须先在对应的实体类加上
@Accessors(chain = true)这个注解,此注解代表使用get set方法之后返回的是实体类的对象,而不是void,所以可以使用如上的更新方法便于操作。 
9.4.4 查询
    @Test
    public void testSelectTwo() {
        //基本查询
        // System.out.println(mapper.selectOne(Wrappers.<User>query().eq("name", "Tom")));
        //投影查询
        userMapper.selectList(new QueryWrapper<User>().select("id", "name")).forEach(user -> {
            System.out.println(user);
        });
    } 
映射查询只能查找到两列数据,其余列全部为null。
9.5 分页
9.5.1 内置分页
(1)添加分页插件
package com.lxy.quickstart.config;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
import org.springframework.context.annotation.Bean;
public class MybatisPlusConfig {
    /**
     * 分页插件
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        // 开启 count 的 join 优化,只针对 left join !!!
        return new PaginationInterceptor().setCountSqlParser(new JsqlParserCountOptimize(true));
    }
}
 
(2) 优化left join count场景
在一对一join操作时,也存在优化可能,看下面sql :
select u.id,ua.account from user u left join user_account ua on u.id=ua.uid
#本来生成的count语句像这样
select count(1) from (select u.id,ua.account from user u left join user_account ua on
u.id=ua.uid)
 
这时候分页查count时,其实可以去掉left join直查user,因为user与user_account是1对1关系,如下:
查count:
select count(1) from user u
查记录:
select u.id,ua.account from user u left join user_account ua on u.id=ua.uid limit 0,50
 
(3) 测试
    @Test
    public void testPage() {
        System.out.println("------ baseMapper 自带分页 ------");
        Page<User> page = new Page<>(1, 5);
        IPage<User> pageResult = userMapper.selectPage(page, new QueryWrapper<User>().eq("age", 331));
        System.out.println("总条数 ------> " + pageResult.getTotal());
        System.out.println("当前页数 ------> " + pageResult.getCurrent());
        System.out.println("当前每页显示数 ------> " + pageResult.getSize());
        pageResult.getRecords().forEach(System.out :: println);
    } 

9.5.2 自定义xml分页
application.yml配置文件
# 配置mybatis plus
mybatis-plus:
  type-aliases-package: com.lxy.quickstart.entity #别名搜索
  mapper-locations: classpath:/mappers/*.xml #加载映射文件 
UserMapper接口:
package com.lxy.quickstart.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.lxy.quickstart.entity.User;
import org.apache.ibatis.annotations.Param;
public interface UserMapper extends BaseMapper<User> {
    /**
     * 如果映射的接口方法有2个参数需要@Param定义参数名,定义参数名后,映射文件中使用p.属性 c.属性,具体访
     问
     *
     * @param page
     * @param condition
     * @return
     */
    public IPage<User> selectUserByPage(@Param("p") IPage<User> page, @Param("c") User condition);
}
 
UserMapper.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.lxy.quickstart.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> 
测试:
    @Test
    public void testXmlPage() {
        System.out.println("------ baseMapper 自定义xml分页 ------");
        Page<User> page = new Page<>(1, 5);
        User user = new User();
        user.setAge(331);
        user.setEmail("test");
        IPage<User> pr = userMapper.selectUserByPage(page, user);
        System.out.println("总条数 ------> " + pr.getTotal());
        System.out.println("当前页数 ------> " + pr.getCurrent());
        System.out.println("当前每页显示数 ------> " + pr.getSize());
        pr.getRecords().forEach(System.out :: println);
    } 

9.5.3 pageHelper分页
引入pageHelper依赖:
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.1.11</version>
</dependency>
 
mybatis plus 整合pageHelper的配置类 :
package com.lxy.quickstart.config;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
import com.github.pagehelper.PageInterceptor;
import org.springframework.context.annotation.Bean;
public class MybatisPlusConfig {
    /**
     * 分页插件
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        // 开启 count 的 join 优化,只针对 left join !!!
        return new PaginationInterceptor().setCountSqlParser(new JsqlParserCountOptimize(true));
    }
    /**
     * 两个分页插件都配置,不会冲突
     * pagehelper的分页插件
     */
    @Bean
    public PageInterceptor pageInterceptor() {
        return new PageInterceptor();
    }
}
 
映射文件:
<?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.lxy.quickstart.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>
    <select id="selectUserByPage2" resultType="user">
        <include refid="selectSql"></include>
        <where>
            <if test="age !=null">
                age = #{age}
            </if>
            <if test="email !=null">
                and email like '%${email}%'
            </if>
        </where>
    </select>
</mapper> 
UserMapper添加代码:
package com.lxy.quickstart.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.lxy.quickstart.entity.User;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface UserMapper extends BaseMapper<User> {
    /**
     * 如果映射的接口方法有2个参数需要@Param定义参数名,定义参数名后,映射文件中使用p.属性 c.属性,具体访
     问
     *
     * @param page
     * @param condition
     * @return
     */
    public IPage<User> selectUserByPage(@Param("p") IPage<User> page, @Param("c") User condition);
    public List<User> selectUserByPage2(User condition);
}
 
测试类:
     @Test
    public void testPageHelper(){
        //条件对象
        User u = new User();
        u.setAge(331);
        u.setEmail("test");
        PageInfo<User> page = PageHelper.startPage(2,10).doSelectPageInfo(() ->{
            //自定义xml映射文件
            userMapper.selectUserByPage2(u);
//            //使用mp内置方法
//            userMapper.selectList(Wrappers.<User>query());
        });
        page.getList().forEach(System.out :: println);
        System.out.println("总行数=" + page.getTotal());
        System.out.println("当前页=" + page.getPageNum());
        System.out.println("每页行数=" + page.getPageSize());
        System.out.println("总页数=" + page.getPages());
        System.out.println("起始行数=" + page.getStartRow());
        System.out.println("是第一页=" + page.isIsFirstPage());
        System.out.println("是最后页=" + page.isIsLastPage());
        System.out.println("还有下一页=" + page.isHasNextPage());
        System.out.println("还有上一页=" + page.isHasPreviousPage());
        System.out.println("页码列表" + Arrays.toString(page.getNavigatepageNums()));
    } 

至此SpringBoot的知识点及其源码就全部结束了,如果您看到了这里,我相信一定对您有很大的帮助,如果方便的话还请给博主三连,谢谢观看!!!










