0
点赞
收藏
分享

微信扫一扫

SpirngBoot<读完包你更上一层楼>

西风白羽 2022-12-07 阅读 138

目录

一、SpringBoot概念 

1.1 什么是SpringBoot

1.2 为什么要学习SpringBoot

1.3 SpringBoot的特点

1.4 总结

二、入门案例

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 添加父工程坐标

2.2.2 添加web启动器

2.2.3 管理jdk版本

2.2.4 完整的pom文件 

2.3 启动类

2.4 编写controller

2.5 启动测试

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

3.1 回顾历史 

3.2 spring全注解配置

3.3 SpringBoot的属性注入

3.4 更优雅的注入

四、自动配置原理

4.1 @SpringBootApplication

4.1.1 @SpringBootConfiguration

4.1.2 @ComponentScan

4.1.3 @EnableAutoConfiguration

4.2 默认配置原理

4.3 总结

五、整合SpringMVC

5.1 修改端口

5.2 访问静态资源

5.3 添加拦截器

六、整合jdbc

七、整合mybatis

7.1 mybatis整合

7.1.1 测试案例 

7.1.2 Mapper的加载接口代理对象方式有2种

7.2 通用mapper

7.2.1 概念

7.2.2 案例测试 

7.2.3 tk.mybatis中Mapper的内置方法 

 八、thymeleaf

8.1 入门案例

8.1.1 编写接口

8.1.2 编写一个controller,返回一些用户数据,放入模型中,等会在页面渲染 

8.1.3 引入启动器

8.1.4 静态页面

8.1.5 测试

8.1.6 模板缓存

8.2 thymeleaf详解

8.2.1 表达式

8.2.2 表达式常见用法

8.2.3 常用th标签

8.2.4 基本用法

8.3 使用thymeleaf布局

九、Mybatis Plus 

9.1 简介

9.2 快速入门

9.2.1 创建工程,引入依赖

9.2.2 配置文件application.yml

9.2.3 实体类

9.2.4 dao

9.2.5 启动类

9.2.6 测试

​9.3 常用注解

​9.3.1 mybatis plus注解策略配置

9.3.2 排除实体类中非表字段

9.4 内置增删改查

 9.4.1 增加

 9.4.2 删除

 9.4.3 更新

 9.4.4 查询

9.5 分页

9.5.1 内置分页 

9.5.2 自定义xml分页

9.5.3 pageHelper分页 


一、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)">
    &copy; 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>
    &copy; 2020 lxy版权所有<br>
    <span>lxy</span>
</footer></div>
<footer>
    &copy; 2020 lxy版权所有<br>
    <span>lxy</span>
</footer>
<div>
    &copy; 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的知识点及其源码就全部结束了,如果您看到了这里,我相信一定对您有很大的帮助,如果方便的话还请给博主三连,谢谢观看!!!

举报

相关推荐

0 条评论