SpringBoot

SpringBoot-day01

01_SpringBoot概述

目标

  • 理解SpringBoot存在的意义是什么

路径

  1. SpringBoot是什么
  2. 什么是约定优于配置

SpringBoot是什么

官网参考:https://spring.io/projects/spring-boot

image-20210728164716295

SpringBoot可以非常简单的快速构建独立的、基于Spring应用的生产级应用程序。

SpringBoot基于约定优于配置的思想,可以让开发人员不必在配置与逻辑业务之间进行思维的切换,使我们可以全身心的投入到业务代码开发中,从而大大提高了开发的效率。

SpringBoot主要特点:

  • SpringBoot可以快速创建独立的Spring应用程序
  • SpringBoot直接嵌入Tomcat、Jetty或Undertow(不需要部署WAR文件)
  • SpringBoot提供了大量可供选择的场景依赖starter,大大简化工程配置的工作量
  • SpringBoot提供了Spring应用的自动化配置和常见第三方库的自动化配置
  • SpringBoot提供了大量生产级的特性,比如健康检查、外部化配置等
  • SpringBoot在简化配置的过程中不会生成代码,也不需要XML繁杂的配置

可以先初步认为:使用SpringBoot可以简化及快速开发SSM框架程序

什么是约定优于配置

约定优于配置(convention over configuration),也称按约定编程,是一种软件设计范式,旨在减少软件开发人员需做决定的数量,简化开发流程,说白了就是按照开发人员的通用习惯(约定)进行开发,尽量减少程序员做决策带来的时间成本的开销

日常开发中有哪些基于约定的配置习惯?

配置 说明
系统环境变量:JAVA_HOME 基于约定,方便维护
maven工程结构 main包下:
java包存放项目源码
resource包存放项目配置等公用资环
test包:
存放项目测试源码
target包:
存放编译后文件、打包后文件等
默认打包方式:jar
Tomcat配置 默认开启端口8080
SpringBoot配置文件 默认application.properties 或 application.yml文件;
Redis 默认端口6379,默认可以不使用密码登录,默认配置文件名称为redis.conf等

小结

问题:SpringBoot是对Spring功能上的增强么?

答案 Spring Boot 并不是Spring功能上的增强,而是提供了一种快速使用Spring的方式

问题:做为程序员我们选择SpringBoot的原因是什么?

答案 使用Spring Boot可以提高开发效率(简化SSM框架开发)

02_SpringBoot快速入门

目标

  • 能够基于SpringBoot快速开发web程序

路径

  1. 使用SpringMVC开发web程序
  2. 使用SpringBoot开发web程序步骤
  3. 使用SpringBoot开发web程序

使用SpringMVC开发web程序

pom.xml:

<!--依赖管理-->
<dependencies>
    <!-- SpringMV-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.2.10.RELEASE</version>
    </dependency>
    <!-- Servlet -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
    </dependency>
</dependencies>

Web容器配置类

public class ServletInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[0];
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        //加载SpringMVC配置类
        return new Class[]{SpringmvcConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        //配置SpringMVC控制器处理所有请求
        return new String[]{"/"};
    }
}

SpringMVC配置类

@Configurable
@ComponentScan("com.itheima.controller")
public class SpringmvcConfig {
}

Controller控制器

@RestController
@RequestMapping("/user")
public class UserController {
    @GetMapping("/{id}")
    public String getById(@PathVariable Integer id){
        System.out.println("id => "+id);
        return "Spring MVC";
    }
}

image-20220508202000680

使用SpringBoot开发web程序步骤

开发步骤:

  1. 创建Maven项目
  2. 导入SpringBoot起步依赖
  3. 编写SpringBoot引导类
  4. 编写UserController类及请求方法
  5. 启动测试

使用SpringBoot开发web程序

  1. 创建Maven项目

image-20220508203529385

  1. 导入SpringBoot起步依赖
    <!-- springboot工程需要继承的父工程 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.10.RELEASE</version>
    </parent>


    <dependencies>
        <!-- web开发的起步依赖:场景启动器依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
  1. 编写SpringBoot引导类
//SpringBoot引导类
@SpringBootApplication
public class SpringBootHelloApplication {
        public static void main(String[] args) {
            // 启动引导类,搭建相关环境
            SpringApplication.run(SpringBootHelloApplication.class, args);
        }
}
  1. 编写UserController类及请求方法
@RestController
@RequestMapping("/user")
public class UserController {
    @GetMapping("/{id}")
    public String getById(@PathVariable Integer id){
        System.out.println("id => "+id);
        return "Spring Boot";
    }
}
  1. 启动测试

image-20220508203950415

image-20220508204030686

03_IDEA快速构建SpringBoot

目标

  • 使用idea快速构建SpringBoot

路径

  1. IDEA快速构建SpringBoot

IDEA快速构建SpringBoot

第1步:选择Spring初始化,并配置相关基础信息

image-20220508205247052

第2步:选择要使用的技术集

image-20220508205646108

第3步:创建Controller类,编写请求方法

image-20220508210640535

@RestController
@RequestMapping("/user")
public class UserController {
    @GetMapping("/{id}")
    public String getById(@PathVariable Integer id){
        System.out.println("id => "+id);
        return "Hello Spring Boot";
    }
}

第4步:启动SpringBoot引导类

@SpringBootApplication
public class SpringbootHelloApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootHelloApplication.class, args);
    }
}

image-20220508210430826

04_SpringBoot入门案例分析

目标

  • 理解SpringBoot项目的pom依赖

路径

  1. SpringBoot工程pom依赖关系
  2. SpringBoot场景依赖starter介绍
  3. Spring-boot-starter-web场景依赖说明

去除pom.xml文件中不必要的内容后,保留的核心内容:

image-20220508211628686

SpringBoot工程pom依赖关系

点击查看spring-boot-starter-parent工程

image-20220508214015248

整体来看,spring-boot-starter-parent父工程仅仅定义了工程相关的描述信息,至于依赖资源配置方面,没有做过多参与,不过我们发现spring-boot-starter-parent工程也有自己的父工程

image-20220508213341704

进入到 spring-boot-dependencies 工程中发现:

  • 工程中声明了几乎所有开发中常用的依赖版本号并通过dependencyManagement进行版本控制

image-20220508214756013

SpringBoot场景依赖starter介绍

在spring-boot-dependencies父工程中,发现大量以 spring-boot-starter-开头的依赖:

这是SpringBoot已经封装好的场景启动器:

image-20220508215401377

由于父工程中已经存在web场景启动器,子工程中可以直接引用(不用添加版本号)

image-20220508220811049

Spring-boot-starter-web场景依赖说明

Spring-boot-starter-web场景依赖:

<!-- 依赖 -->
<dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
      <version>2.6.7</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-json</artifactId>
      <version>2.6.7</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-tomcat</artifactId>
      <version>2.6.7</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.3.19</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.3.19</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>

分析spring-boot-starter-web依赖发现:内部把关于Web MVC开发所有的依赖都已经导入并且指定了版本,只需引入 spring-boot-starter-web 依赖就可以实现Web MVC的功能

小结

问题:在SpringBoot环境中引入通用依赖,是否需要自己维护依赖的版本?

答案 SpringBoot父工程对通用的依赖进行了版本锁定,开发人员引入依赖时则无需关注依赖冲突和版本兼容问题

问题:SpringBoot提供的场景启动器有什么好处?

提示 1、场景启动器可以快速引入指定场景下所依赖的资源(不必做资源冲突处理)
2、场景启动器简化资源环境配置,让开发人员将重点放在业务逻辑上

05_依赖示例:切换web服务器

目标

  • 能够使用pom父工程中已有依赖,切换web服务器

路径

  1. 修改pom文件切换web服务器

修改pom文件切换web服务器

我们理解了springboot之后,也可以不使用其默认配置的一些选项,改用我们想要的选项。

例如:排除Tomcat,引入jetty服务器组件

web应用需要在web容器中运行。web容器有:Tomcat、Jetty、WebSphere、WebLogic

Jetty比Tomcat更轻量级,可扩展性更强(相较于Tomcat),谷歌应用引擎(GAE)已经全面切换为Jetty

当然大型的应用还是tomcat为主

修改pom.xml文件:

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.7</version>
        <relativePath/>
    </parent>
    <groupId>com.itheima</groupId>
    <artifactId>springboot_hello</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <!--排除tomcat依赖-->
            <exclusions>
                <exclusion>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                    <groupId>org.springframework.boot</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <!--引入jetty的依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
        </dependency>
    </dependencies>
</project>

06_SpringBoot配置文件入门

目标

  • 掌握SpringBoot配置文件的基本使用

路径

  1. SpringBoot配置分类
  2. SpringBoot配置文件使用入门

SpringBoot配置分类

通过spring-boot-starter-parent依赖发现:

image-20220508230509330

SpringBoot配置文件分为:

  • yaml文件(简写:yml)
  • properties文件

SpringBoot配置文件使用入门

以修改Tomcat端口号为例:

  1. 在resources目录下新建application.properties 配置文件,添加端口号:

    server.port=8081   # 修改tomcat端口
    

    启动项目发现端口修改为 8081

  2. 在resources目录下新建application.yml配置文件(暂时注释掉application.properties中的端口设置)

    server:
      port: 8082  #语法规则:当冒号后面有指定配置参数时,必须在冒号后添加空格
    

    启动项目发现端口修改为 8082

测试验证:properties和yaml文件的优先级

  • 验证1:

    • 如果把application.properties中的注释取消,即两种配置文件同时存在,启动项目发现项目的端口是8081,说明是application.properties配置文件优先级更高
  • 验证2:

    • 分别在application.properties和application.yml 里添加:company1=itheima、company2: itcast

      image-20220508233151502

    • 通过 @value注解注入读取配置

      @RestController
      @RequestMapping("/hello")
      public class HelloController {
          //注入配置文件中属性值
          @Value("${company1}")
          private String company1;
      
          @Value("${company2}")
          private String company2;
      
          @GetMapping
          public String hello(){
              return "hello Spring Boot !" + company1 +"  " + company2;
          }
      }
      

      使用postman访问:

      image-20220508233019433

小结

问题1:SpringBoot配置文件有哪些?

答案 常见2种:properties文件和yml文件,实际开发中yml使用居多

问题2:在同级路径下SpringBoot两种类型的配置文件同时存在时,配置优先级如何处理?

答案 properties和yaml配置文件如果同时存在,若key相同则properties配置文件优先级高,若key不同则合并加载

07_YAML基本使用

目标

  • 掌握yaml语法的基本数据类型的配置

路径

  1. 基本介绍
  2. 语法规则
  3. 数据读取

基本介绍

YAML(YAML Ain't Markup Language):是一种数据序列化格式

  • YAML在开发中又有另外一层意思:Yet Another Markup Language(仍是一种标记语言)
  • YAML非常适合用来做以数据为中心的配置文件
  • 扩展名:xxx.yaml 或 xxx.yml(主流)

image-20220509100849262

优点:

  • 容易阅读
  • 容易与脚本语言交互
  • 以数据为核心,重数据轻格式

语法规则

  • 大小写敏感(区分大小写)
  • 属性值前面必须有空格,作为分隔符(属性名与属性值之间使用冒号+空格作为分隔)
  • 属性层级关系使用多行描述,每行结尾使用冒号结束
  • 使用缩进表示层级关系,同层级左侧对齐,只允许使用空格(不允许使用Tab键)
  • 字符串无需加引号,如果要加,""''表示字符串内容会被转义/不转义
  • # 表示注释

核心规则:数据前面要加空格与冒号隔开

示例:

enterprise:
  name: itcast     # String
  age: 16          # int
  tel: 4006184000  # long
  subject:         # 数组/集合
    - Java
    - 前端
    - 大数据
    
msg1: 'hello \n world'  # 单引忽略转义字符
msg2: "hello \n world"  # 双引识别转义字符    

数据读取

使用@Value读取数据

  • 引用方式:
    ${一级属性名}
    ${一级属性名.二级属性名}
    

1638671960028

代码示例:

  • yaml配置文件
enterprise:
  name: itcast
  age: 16
  tel: 4006184000
  subject:
    - Java
    - 前端
    - 大数据

msg1: 'hello \n world'  # 单引忽略转义字符
msg2: "hello \n world"  # 双引识别转义字符
  • Controller
@RestController
@RequestMapping("/heima")
public class HeimaController {
    @Value("${enterprise.name}")
    private String name;
    @Value("${enterprise.age}")
    private Integer age;
    @Value("${enterprise.tel}")
    private Long tel;
    @Value("${enterprise.subject[0]}")
    private String subject;
    @Value("${msg1}")
    private String message1;
    @Value("${msg2}")
    private String message2;

    @GetMapping
    public void itheima(){
        System.out.println(name);
        System.out.println(age);
        System.out.println(tel);
        System.out.println(subject);
        System.out.println(message1);
        System.out.println(message2);
    }
}

08_YAML高级配置

目标

  • 掌握YAML配置参数映射对象属性功能

路径

  1. YAML配置参数映射到对象属性
  2. 配置文件自动提示

YAML配置参数映射到对象属性

代码示例:

  • 实体类
//老师类
public class Teacher {
    private String name;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}


//课程类
public class Course {
    private String name;
    private Double score;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Double getScore() {
        return score;
    }
    public void setScore(Double score) {
        this.score = score;
    }
}


//学生类
public class Student {
    private String name;
    private Integer age;
    private Date birthday;
    private String[] address;
    private Map<String, Object> hobbies;
    private Teacher teacher;
    private List<Course> courseList;

    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 Date getBirthday() {
        return birthday;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
    public String[] getAddress() {
        return address;
    }
    public void setAddress(String[] address) {
        this.address = address;
    }
    public Map<String, Object> getHobbies() {
        return hobbies;
    }
    public void setHobbies(Map<String, Object> hobbies) {
        this.hobbies = hobbies;
    }
    public Teacher getTeacher() {
        return teacher;
    }
    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }
    public List<Course> getCourseList() {
        return courseList;
    }
    public void setCourseList(List<Course> courseList) {
        this.courseList = courseList;
    }
}
  • yml配置文件
student:
  name: 张三
  age: 22
  birthday: 2000/09/09 01:01:01
  address: [上海,北京]
  hobbies:
    sports:
      - football
      - basketball
    musics:
      - dj
  teacher:
     name: Jackie
  courseList:
    - name: JavaSE
      score: 88
    - name: MySQL
      score: 99

image-20220509183722643

  • 依赖注入
@Component
@ConfigurationProperties(prefix = "student")
public class Student {
    private String name;
    private Integer age;
    private Date birthday;
    private String[] address;
    private Map<String, Object> hobbies;
    private Teacher teacher;
    private List<Course> courseList;
    
    /* 省略: setter()、getter()方法 */
}

/*
两种注入属性方式:
方式1:在实体类Student上添加@ConfigurationProperties(prefix = "student”)
	  然后在SpringBoot启动类上添加@EnableConfigurationProperties(student.class)
	  
方式2:在实体类Student上添加@ConfigurationProperties(prefix = "student”)
      在实体类Student上添加@Component      
*/
  • Controller类
@RestController
@RequestMapping("/student")
public class StudentController {
    @Autowired
    private Student student;

    @GetMapping
    private Student getStudent(){
        return  student;
    }
}

使用postman测试:

image-20220509183320266

配置文件自动提示

idea中存在的问题:

  • 如果idea提示以下警告,可以忽略它,不影响运行,也可以在pom文件添加依赖

image-20220509184351037

解决方案: 在pom.xml文件中添加依赖

<!-- 解决SpringBoot自定义配置提示问题 -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-configuration-processor</artifactId>
  <optional>true</optional>
</dependency>

<build>
  <plugins>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
      <configuration>
        <excludes>
          <!--插件运行时排除依赖-->  
          <exclude>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
          </exclude>
        </excludes>
      </configuration>
    </plugin>
  </plugins>
</build>

在pom.xml文件中添加以上依赖和插件后,在yaml文件书写配置参数时,就有了自动提示功能

image-20220509212259829

小结

问题:获取配置文件中数据方式?

答案 第1种:直接获取数据。 使用:@Value("${key}")
第2种:通过映射对象获取。 使用:@ConfigurationProperties(prefix="前缀")+@Component

09_YAML应用:多环境配置

目标

  • 能够使用yaml配置文件,解决企业开发中多环境配置问题

路径

  1. 应用场景介绍
  2. 多个profile文件实现环境配置切换(掌握)
  3. 单个 profile文件实现环境配置切换(了解)
  4. profile激活方式

应用场景介绍

在程序开发完成要进入到部署阶段的时候,往往就会遇到需要把程序发布到不同环境(多环境):

  1. 开发环境(windows) 。 俗称:development
  2. 测试环境(linux) 。 俗称:test
  3. 生产环境(linux) 。 俗称:produce

以上每个环境的数据库、服务器端口、密钥等信息可能会存在差异,这时开发人员需要频繁修改配置来切换不同的环境,维护性相当差。

在这种情况下,我们就可以使用SpringBoot多环境配置方案,解决上述出现的问题。

多个profile文件实现环境配置切换

profile配置方式:

  • 多个profile文件方式:提供多个配置文件,每个代表一种环境
    • application-dev.yml (开发环境) 也可以是:application-dev.properties
    • application-test.yml (测试环境) 也可以是:application-test.properties
    • application-pro.yml (生产环境) 也可以是:application-pro.properties

image-20220509220758150

image-20220509220450250

好处: 解耦

  • 不同的环境使用不同的文件,这样修改时,仅仅修改对应配置文件的数据,无需修改其他环境的配置文件

单个profile文件实现环境配置切换

profile配置方式:

  • 在application.yml文件中使用: --- 分隔不同配置

image-20220509221624373

profile激活方式

使用idea自带的maven打包工具,对项目工程进行打包

image-20220509223557821

进入DOS执行命令: 启动某个jar包

java -jar XXX.jar

image-20220509223803541

利用DOS启动某个jar包时,可能会遇到的问题:

image-20220516215619006

  • 说明:启动后报没有主清单属性问题

  • 解决方案:添加打包插件

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
    

小結

问题:SpringBoot多环境配置方式?

答案  配置多个yml环境文件
 使用:spring.profiles.active="环境标识" (eg:标识来自于yml文件dev中:application-dev.yml)

10_配置文件加载顺序

目标

  • 了解配置文件加载顺序

路径

  1. 项目外配置加载顺序
  2. 项目内配置加载顺序

项目外配置加载顺序

# 启动并读取dev环境
java -jar XXX.jar --spring.profiles.active=dev    

# 启动时使用端口9000
java -jar XXX.jar --server.port=9000 		

# 启动时使用端口9000,其余配置读取dev环境
java –jar XXX.jar --server.port=9000 --spring.profiles.active=dev	

加载优先级: jar包外 > jar包内

项目内配置加载顺序

SpringBoot中有4级配置文件: (配置优先级:由高到底)

  • 1级 ==> file:config/application.yml 【最高】
    • 当前项目project下的/config目录下
  • 2级 ==> file:application.yml
    • 当前项目project的根目录
  • 3级 ==> classpath:config/application.yml
    • classpath的/config目录
  • 4级 ==> classpath:application.yml 【最低】
    • classpath的根目录
file : 指的是当前project所在目录
classpath : 指的是maven模块的resources目录

小结

问题:SpringBoot配置文件的加载顺序?

答案 按文件类型:properties > yml > yaml
按路径分类:当前project/config > 当前project > classpath/config > classpath
按命令行设置:jar包外的参数 > jar包内的参数

11_SpringBoot整合Junit

目标

  • 能够完成SpringBoot整合Junit单元测试

路径

  1. 整合Junit4
  2. 整合Junit5

整合Junit4

之前我们编写spring整合Junit,首先要导入两个依赖(junit、spring-test),然后编写如下测试类:

1638635088366

而在springboot中整合junit的实现步骤:

  1. 引入场景(test)依赖
  2. 编写测试类,添加注解

pom.xml:

<!-- SpringBoot中test场景依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <scope>test</scope>
</dependency>

编写测试类,添加注解@SpringBootTest@RunWith(SpringRunner.class)

import com.itheima.domain.Student;
import com.itheima.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import org.junit.runner.RunWith;
import org.junit.Test;


@SpringBootTest //指定当前类为springboot环境下的测试类
@RunWith(SpringRunner.class) //指定加载容器上下文的加载类
//如果当前测试类与启动类不在同级或其子目录下,那么需要显式指定启动配置类
//@ContextConfiguration(classes = SpringJunitApp.class)
public class SpringBootJunit4Test {
    @Autowired
    private StudentService studentService;

    @BeforeClass
    public static void beforeClasRun(){
        System.out.println("beforeClasRun ...");
    }

    /**
     * 测试方法运行几次,就执行几次
     */
    @Before
    public void before01(){
        System.out.println("before01 run....");
    }

    @Test
    public void test1(){
       studentService.saveStudent();
    }

    @After
    public void after01(){
        System.out.println("after01 run....");
    }

    @AfterClass
    public static void afterClasRun(){
        System.out.println("afterClasRun ...");
    }
}

  • 注意事项:
    如果测试类不在启动类同级或者子目录下,则需要通过@ContextConfiguration(classes=xxx.class)注解指定启动类的位置

整合Junit5

Spring Boot 2.2.0 版本开始引入JUnit5作为单元测试默认版本,2.3.X版本还保留了Junit4版本测试,但是在2.4.X则不再支持Junit4

作为最新版本的JUnit框架,JUnit5与之前版本的Junit框架有很大的不同。

JUnit5由三个不同子项目的几个不同模块组成

  • JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage

image-20220510093350034

JUnit Platform:Junit Platform是在JVM上启动测试框架的基础,不仅支持Junit自制的测试引擎,其他测试引擎也都可以接入。

JUnit Jupiter:JUnit Jupiter提供了JUnit5的新的编程模型,是JUnit5新特性的核心。内部 包含了一个测试引擎*,用于在Junit Platform上运行。

JUnit Vintage:由于JUint已经发展多年,为了照顾老的项目,JUnit Vintage提供了兼容JUnit4.x、Junit3.x的测试引擎。

使用Springboot整合JUnit5的实现:

pom.xml:

<!-- SpringBoot的test场景依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>

测试类:

import com.itheima.domain.Student;
import com.itheima.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.junit.jupiter.api.Test;


@SpringBootTest //设置JUnit加载的SpringBoot启动类
//如果当前测试类与启动类不在同级或其子目录下,那么需要显式指定启动配置类
//@ContextConfiguration(classes = SpringJunitApp.class)
//@SpringBootTest(classes = SpringJunitApp.class)
public class SpringBootJunit5Test {
    @Autowired
    private StudentService studentService;

    @BeforeAll //等价于junit4:@BeforeClass
    public static void beforeClasRun(){
        System.out.println("beforeClasRun ...");
    }

    @BeforeEach //等价于junit4:@Before
    public void before01(){
        System.out.println("before01 run....");
    }

    @Test
    public void test1(){
       studentService.saveStudent(null);
    }

    @AfterEach //等价于junit4:@After
    public void after01(){
        System.out.println("after01 run....");
    }

    @AfterAll //等价于junit4:@AfterClass
    public static void afterClasRun(){
        System.out.println("afterClasRun ...");
    }
}

小结

问题1:SpringBoot中如何整合JUnit5?

答案 步骤1:导入springboot的test场景依赖
步骤2:设置JUnit加载的SpringBoot启动类 (在测试类上添加@SpringBootTest)

问题2:如果测试类与SpringBoot启动类不在同级或其子目录下怎么解决?

答案 方式1:在测试类上添加@ContextConfiguration(classes = 启动类.class)
方式2:使用@SpringBootTest(classes = 启动类.class)

12_SpringBoot静态资源访问

目标

  • 了解SpringBoot中静态资源的访问方式

路径

  1. SpringBoot整合SMM的思路
  2. SpringBoot中静态资源访问
  3. 自定义静态资源访问路径

SpringBoot整合SMM的思路

由于springboot跟和spring,springmvc出于同一团队,所以springboot中已经自动配置好spring和springmvc环境。

SpringBoot实现SSM整合的思路:

  • SpringBoot整合Spring(不需要)

  • SpringBoot整合SpringMVC(不需要)

  • SpringBoot整合MyBatis(需要)

在SpringBoot环境下,整合SSM框架只需要完成以下两点即可:

  1. 解决SpringBoot环境下静态资源访问
  2. 实现SpringBoot环境下Mybatis的整合

SpringBoot中静态资源访问

问题:SpringBoot工程中没有webapp目录,静态资源存放在哪里呢?

答案:在默认情况下,Spring Boot从类路径中名为/static/public/resources/META-INF/resources)的目录中提供静态内容

image-20220510113008452

  • 注意:META-INF.resources是两级目录

SpringBoot环境下静态资源访问:

  1. 添加web场景依赖

     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
     </dependency>
    
  2. 静态资源存放到springboot工程默认目录下

    image-20220510113557144

浏览器访问:http://localhost:8080/4.jpg

自定义静态资源访问路径

在application.yml配置文件中修改默认配置:

spring:
  mvc:
    static-path-pattern: /imgs/**   #配置静态资源的映射路径

  web:
    resources:
      static-locations: [classpath:/images/] #自定义静态资源存放位置

image-20220510115014169

使用浏览器访问:

image-20220510115433596

13_SpringBoot整合Mybatis

目标

  • 能够使用SpringBoot整合Mybatis框架

路径

  1. SpringBoot整合Mybatis的步骤
  2. SpringBoot整合Mybatis
  3. 整合Mybatis的细节调整

SpringBoot整合Mybatis的步骤

整合Mybatis的步骤:

  1. 创建maven模块项目
  2. 配置数据源
  3. 编写Mapper接口
  4. 编写Mapper映射文件

1638636458145

1638636469803

SpringBoot整合Mybatis

代码示例:

  • pom.xml
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.7</version>
        <relativePath/>
    </parent>
    <groupId>com.itheima</groupId>
    <artifactId>springboot_mybatis</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <!-- web场景 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- Mybatis场景 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.2</version>
        </dependency>
        <!-- MySQL驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
        <!-- Druid数据源 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.24</version>
        </dependency>
        <!-- test场景 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
  • application.yml (配置数据源)

    • springboot整合的mybatis默认使用连接池HikariDataSource,这里切换为DruidDataSource

      • HikariDataSource:快

      • DruidDataSource:功能比较多

# 配置数据源
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource #Druid连接池
    driver-class-name: com.mysql.jdbc.Driver #驱动
    url: jdbc:mysql://127.0.0.1:3306/ssm_db  #URL连接字符串
    username: root     #登录名
    password: itheima  #密码
  • Book类
public class Book {
    private Integer id;
    private String type;
    private String name;
    private String description;

    public Book() {
    }
    public Book(Integer id, String type, String name, String description) {
        this.id = id;
        this.type = type;
        this.name = name;
        this.description = description;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    @Override
    public String toString() {
        return "Book{" +
                "id=" + id +
                ", type='" + type + '\'' +
                ", name='" + name + '\'' +
                ", description='" + description + '\'' +
                '}';
    }
}
  • 编写dao层
@Mapper //表示当前接口为Mybatis需要被代理的接口,可以被springboot扫描加载IoC
public interface BookDao {
    @Select("select id, type, name, description from tbl_book where id = #{id}")
    Book findBookById(Integer id);

    List<Book> findAllBook();
}
  • 测试类
@SpringBootTest
public class SpringBootMybatisTest {
    @Autowired
    private BookDao bookDao;

    @Test
    public void testFindBookById(){
        Book book = bookDao.findBookById(1);
        System.out.println(book);
    }
} 

//输出结果:
//Book{id=1, type='编程', name='Spring实战', description='spring入门经典教程'}

整合Mybatis的细节调整

细节1:添加Mapper映射文件

  • image-20220510130655422

细节2:改变Mapper映射文件存放位置

  • resources 路径下创建 mapper 文件夹,并且将BookDao.xml放在mapper文件夹下

  • #指定Mapper映射文件存放位置
    mybatis:
      mapper-locations: classpath:mapper/**Dao.xml  #mapper映射文件位置
    

    image-20220510133022643

细节3:省略@Mapper注解

  • public interface BookDao {
        @Select("select id, type, name, description from tbl_book where id = #{id}")
        Book findBookById(Integer id);
    
        List<Book> findAllBook();
    }
    

    如果接口上省略@Mapper注解,那么启动项目后出现异常错误

  • 解决方案:在引导类上添加 @MapperScan 注解

    @SpringBootApplication
    @MapperScan("com.itheima.dao") //批量加载Mapper接口 (推荐)
    public class SpringbootMybatisApplication {
        public static void main(String[] args) {
            SpringApplication.run(SpringbootMybatisApplication.class, args);
        }
    }
    

细节4:驼峰命名映射、别名

  • #Mybatis配置
    mybatis:
      type-aliases-package: com.itheima.domain  #扫描指定包下的类,并取别名
      
      configuration:
        map-underscore-to-camel-case: true  #开启驼峰命名映射( user_name => username )
    

14_整合Mybatis的分页插件

目标

  • 能够在SpringBoot环境下添加Mybatis分页插件,实现分页查询

路径

  1. 传统分页查询的弊端
  2. 整合Mybatis分页插件
  3. 使用Mybatis分页插件实现分页查询

传统分页查询的弊端

分页查询,是在企业开发中是最常用的技术之一

之前学习Mybatis时,使用的分页查询技术:limit

//SQL语句:
     select * from  表 ...  LIMIT 起始位置,查询条数
//要计算起始位置
     起始位置 = (页码-1)*查询条数

存在的弊端:

  • 如果更换数据库,就无法使用limit方式进行分页查询。 例:Oracle数据库中没有limit

解决方案:

  • 使用第三方组织已经封装好的分页组件(如:PageHelper)

整合Mybatis分页插件

整合Mybatis分页插件步骤:

  1. 添加mybatis页面插件依赖

    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper-spring-boot-starter</artifactId>
        <version>1.4.1</version>
    </dependency>
    
  2. 配置分页插件

    #配置分页插件
    pagehelper:
      # mysql支持的方言
      helperDialect: mysql
      # sql合理化
      reasonable: true
    

使用Mybatis分页插件实现分页查询

PageHelper:第三方分页助手。将复杂的分页操作进行封装,从而让分页功能变得非常简单

  • 需要明确当前是第几页,这一页中显示多少条结果

代码示例:

@SpringBootTest
public class SpringBootMybatisTest {
    @Autowired
    private BookDao bookDao;

    @Test
    public void testFindBookByPage(){
        //PageHelper:是mybatis的分页插件,简化mybatis的分页开发
        //设置分页: 页码 、 每页条数
        PageHelper.startPage(2,3);

        //执行:查询所有书籍功能
        List<Book> allBook = bookDao.findAllBook(); //切入点

        //实例化PageInfo对象
        PageInfo<Book> pageInfo = new PageInfo<>(allBook);
        //获取总记录数
        long total = pageInfo.getTotal();
        //获取总页数
        int pages = pageInfo.getPages();
        //获取当前页
        int pageNum = pageInfo.getPageNum();
        //获取当前页数据
        List<Book> bookList = pageInfo.getList();

        for (Book book : bookList) {
            System.out.println(book);
        }
    }
}

15_SpringBoot整合SSM小结

SpringBoot整合SSM的步骤:

  1. 在pom.xml文件中添加依赖

    web场景: spring和springmvc
    mybatis场景: mybatis
    mysql驱动
    druid连接池
    
  2. 在application.yml文件中设置数据源

  3. 编写dao层

    Mapper接口上添加@Mapper   或  在启动类上添加@MapperScan
    
  4. 静态资源

    放置在resources目录下的static目录中
    

SpringBoot应用

  1. springboot是快速构建spring应用的脚手架
  2. springboot提供了场景启动器 (场景启动器自己封装了配置,开发者可以少做配置)
    • 开发者导入场景依赖时,不需要关心有哪些jar包以及什么版本号
  3. springboot封装了一些常用的场景(50个左右)
    • spring-boot-stater-场景名
      • 场景名:web 、 test 、.....
  4. springboot也提供了开发场景启动器的规范
    • 场景名-spring-boot-starter
      • Mybatis参照规范自定义了自己的场景:mybatis-spring-boot-starter
      • Druid、PageHelper等场景
  5. springboot使用约定大于配置的理念
    • springboot帮开发者封装了常见的配置,让开发者省略很多默认的配置

我们之前使用SpringBoot整合SSM框架时,根本没有用到:Spring配置文件、SpringMVC配置文件

16_SpringBoot自动装配原理

目标

  • 了解SpringBoot自动装配原理

路径

  1. 什么是自动装配
  2. SpringBoot自动装配原理

什么是自动装配

问题:场景启动器starter的底层封装了配置,那么springboot是如何自动加载它们?

答案:Springboot的自动装配

SpringBoot定义了一套接口规范,这套规范规定:SpringBoot 在启动时会扫描外部引用 jar 包中的META-INF/spring.factories文件(类似于SPI机制),将文件中配置的类型信息加载到 Spring 容器,并执行类中定义的各种操作。

  • 对于外部jar来说,只需要按照SpringBoot定义的标准,就能将自己的功能装置进SpringBoot

image-20220510164603214

没有Spring Boot的情况下,如果我们需要引入第三方依赖,需要手动配置,非常麻烦。但是在SpringBoot 中,我们直接引入一个 starter 即可。

比如你想要在项目中使用 redis 的话,直接在项目中引入对应的 starter 即可

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

引入starter之后,通过少量注解和一些简单的配置就能使用第三方组件提供的功能了

自动装配可以简单理解为:通过注解或者一些简单的配置就能在Spring Boot的帮助下实现某块功能

SpringBoot自动装配原理

SpringBoot启动类:

@SpringBootApplication //SpringBootApplication是SpringBoot的核心注解(复合注解)
public class App {
    public static void main(String[] args) {
        /*
          run(Class cls , String[] args)
          参数1:有@SpringBootApplication注解的类的Class对象
                目的:为了让SpringBoot底层解析@@SpringBootApplication
          参数2:命令行启动时传入的参数。最终要给SpringBoot
        */
        SpringApplication.run(App.class, args);
    }
}

要搞清楚SpringBoot的自动装配原理,要从SpringBoot的核心注解@SpringBootApplication开始分析,下面有张图, 包含了这个注解的核心内容:

1646381118146

@SpringBootApplication注解属于复合注解,包含:

  • @SpringBootConfiguration:标识是一个配置类(是对@Configuration注解的包装)
  • 允许在上下文中注册额外的bean或导入其他配置类
  • @EnableAutoConfiguration:启用SpringBoot的自动配置机制
  • @ComponentScan:组件扫描
    • 默认扫描的规则:引导类所在的包及其子包所有带Spring注解的类
    • 扫描被@Component(@Service、@Controller)注解的 bean

@EnableAutoConfiguration是实现自动装配的重要注解,我们从这个注解入手分析:

  1. @EnableAutoConfiguration 只是一个简单地注解,自动装配核心功能的实现实际是通过AutoConfigurationImportSelector类

    image-20220510175950806

  2. AutoConfigurationImportSelector的selectImports()方法会读所有SpringBoot Starter下的META-INF/spring.factories文件(SPI机制)

    • selectImports()方法底层调用getAutoConfigurationEntry()方法

    image-20220510180551591

    • getAutoConfigurationEntry()方法调用getCandidateConfigurations(annotationMetadata, attributes)方法获取所有基于META-INF/spring.factories文件下的自动配置类的集合

    image-20220510180738996

    • getCandidateConfigurations方法底层利用Spring工厂加载器调用loadSpringFactories()方法扫描当前系统中所有META-INF/spring.factories文件,并加载获取自动配置类信息

    image-20220510181301810

    默认扫描当前系统里面所有META-INF/spring.factories位置的文件

说明:在spring.factories中有很多配置,但是只有满足一定条件的配置才会被自动装配

  • 举例:添加Mybatis场景依赖,查看底层装配信息

image-20220510164603214

小结

问题1:SpringBoot默认自动加载的配置文件路径是哪里?

答案 当前项目系统路径下的所有META-INF/spring.factories文件

问题2:简述SpringBoot自动装配流程?

答案 1. 通过@Import注解调用AutoConfigurationImportSelector类中的selectImports方法;
2. selectImports方法底层调用getAutoConfigurationEntry()方法获取可自动装配的配置类信息集合;
3. getAutoConfigurationEntry()方法调用getCandidateConfigurations(annotationMetadata, attributes)方法获取所有基于META-INF/spring.factories文件下的自动配置类的集合;
4. 底层利用Spring工厂加载器调用 loadSpringFactories()方法扫描当前系统中所有META-INF/spring.factories文件,并加载获取自动配置类信息;
5.根据@Conditional条件过滤,获取最终自动装配类,最后被IOC容器加载;

17_SpringBoot自定义starter

目标

  • 能够自定义starter场景启动依赖,并成功集成到新项目

路径

  1. 自定义starter场景步骤
  2. 自定义starter场景实现
  3. 测试使用自定义starter场景

自定义starter场景步骤

既然明白了SpringBoot自动装配的原理,那么我们可以自己写一个starter玩一玩

自定义starter场景的步骤:

  1. 创建starter场景工程
  2. 导入坐标:spring-boot-autoconfigure
  3. 编写自定义类
  4. 编写配置文件:spring.factories
    • 在resources下定义META-INF/spring.factories文件
  5. 安装到本地仓库
  6. 测试使用

自定义starter场景实现

步骤1:创建starter场景工程

  • 自定义starter的命名规则: xxx-spring-boot-starter

    • SpringBoot官方提供的starter以:spring-boot-starter-xxx 的方式命名
    • 官方建议自定义的starter使用:xxx-spring-boot-starter 命名规则
      • 用以区分SpringBoot生态提供的starter

    image-20220516211507747

步骤2:导入坐标

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-autoconfigure</artifactId>
        <version>2.6.7</version>
    </dependency>
</dependencies>

步骤3:编写自定义类

  • HeimaBean
//使用@ConfigurationProperties   注解的类生效
@EnableConfigurationProperties(HeimaBean.class)
@ConfigurationProperties(prefix ="heimabean") //prefix 在application.yml文件中体现
public class HeimaBean {
    private int id;
    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
  • HeimaAutoConfiguration
@Configuration
public class HeimaAutoConfiguration {
    @Bean
    public HeimaBean getHeimaBean(){
        return new HeimaBean();
    }
}

步骤4:编写配置文件(spring.factories)

  • 在resources下定义META-INF/spring.factories文件,并配置自动装配信息,让SpringBoot自动加载
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.mine.config.HeimaAutoConfiguration

步骤5:安装到本地库

  • 到步骤4为止,我们的自定义starter就算是写完了。接着就是使用maven安装到本地仓库,方便其它工程引用

image-20220516212506168

image-20220516213028426

测试使用自定义starter场景

新建一个springboot工程,来测试自定义的starter场景

image-20220516212643198

导入依赖:

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

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

        <!--导入自定义starter-->
        <dependency>
            <groupId>com.itheima</groupId>
            <artifactId>mine-spring-boot-starter</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

</dependencies>

编写配置文件:application.yml

heimabean:
  id: 1
  name: itheima

测试类:

@SpringBootTest
class TestMineStarterApplicationTests {

    @Autowired
    private HeimaBean heimaBean;

    @Test
    void contextLoads() {
        System.out.println(heimaBean.getName());
    }
}
//运行结果:
itheima

附录:MySQL 8.0的url连接字符串

在SpringBoot中,默认引入的MySQL驱动包是8版本

# 配置数据源
spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/ssm_db?serverTimezone=UTC  #mysql8.0字符串
    driver-class-name: com.mysql.cj.jdbc.Driver  #mysql8.0驱动

1638636610074

附录:Mybatis使用PageHelper实现分页查询

PageHelper

在企业级开发中,分页也是一种常见的技术。而目前使用的MyBatis是不带分页功能的,如果想实现分页的功能,需要我们手动编写LIMIT语句。但是不同的数据库实现分页的SQL语句也是不同的,所以手写分页成本较高。这个时候就可以借助分页插件来帮助我们实现分页功能。

PageHelper:第三方分页助手。将复杂的分页操作进行封装,从而让分页功能变得非常简单

  • 需要明确当前是第几页,这一页中显示多少条结果。

分页插件的使用

MyBatis可以使用第三方的插件来对功能进行扩展,分页助手PageHelper是将分页的复杂操作进行封装,使用简单的方式即可获得分页的相关数据

开发步骤:

1、导入与PageHelper的jar包 (第三方开发的)

2、在mybatis核心配置文件中配置PageHelper插件

<!-- 配置插件 -->
<plugins>
    <!-- 注意:分页助手的插件  配置在通用mapper之前 -->
    <plugin interceptor="com.github.pagehelper.PageInterceptor">
        <!-- 使用MySQL方言的分页 -->
        <property name="helperDialect" value="mysql"/><!--如果使用oracle,这里value为oracle-->
    </plugin>
</plugins>

3、分页数据获取

@Test
public void testPageHelper(){
    //设置分页参数
    PageHelper.startPage(1,3); //第1页, 每页显示3条数据

    //省略....
    
    //调用Mapper接口中的方法,查询所有用户信息
    List<User> userList = userMapper.queryAllUsers();
    
    
    for(User user : userList){
        System.out.println(user);
    }
}

分页插件的参数获取

//其他分页的数据
PageInfo<User> pageInfo = new PageInfo<User>(userList);
System.out.println("总条数:"+pageInfo.getTotal());
System.out.println("总页数:"+pageInfo.getPages());
System.out.println("当前页:"+pageInfo.getPageNum());
System.out.println("每页显示长度:"+pageInfo.getPageSize());
System.out.println("是否第一页:"+pageInfo.isIsFirstPage());
System.out.println("是否最后一页:"+pageInfo.isIsLastPage());
System.out.println("查询的数据:");
List<User> users = pageInfo.getList();
for(User user : users){
    System.out.println(user);
}

分页插件知识小结

​ 分页:可以将很多条结果进行分页显示

  • 分页插件jar包: pagehelper-5.1.10.jar、 jsqlparser-3.1.jar

  • 在MyBatis核心配置文件中使用标签集成PageHelper插件

  • 分页助手相关API

    1.PageHelper:分页助手功能类

    1. startPage():设置分页参数 (静态方法)
    2. PageInfo:分页相关参数功能类
    3. getTotal():获取总条数
    4. getPages():获取总页数
    5. getPageNum():获取当前页
    6. getPageSize():获取每页显示条数
    7. getPrePage():获取上一页
    8. getNextPage():获取下一页
    9. isIsFirstPage():获取是否是第一页
    10. isIsLastPage():获取是否是最后一页
    11. getList():获取查询的数据

使用PageHelper实现分页

前置操作

  • 导入PageHelper所需的jar文件到当前项目工程

  • 在mybatis核心配置文件中添加PageHelper插件

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <!--加载外部的配置文件-->
        <properties resource="db.properties"></properties>
        
        <!--别名-->
        <typeAliases>
            <package name="com.itheima.sh.domain"></package>
        </typeAliases>
        
        
        
        <!-- 配置插件 -->
        <plugins>
            <!-- 注意:分页助手的插件  配置在通用mapper之前 -->
            <plugin interceptor="com.github.pagehelper.PageInterceptor">
                <!-- 使用MySQL方言 
                     如果使用oracle,这里value为oracle
                -->
                <property name="helperDialect" value="mysql"/>
            </plugin>
        </plugins>
        
        
        
        
        
        <!--mybatis环境的配置
            一个核心配置文件,可以配置多个运行环境,default默认使用哪个运行环境
        -->
        <environments default="development">
            <!--id是环境的名字 -->
            <environment id="development">
                <!--事务管理器:由JDBC来管理-->
                <!--
                    事务管理器type的取值:
                    1. JDBC:由JDBC进行事务的管理
                    2. MANAGED:事务由容器来管理,后期学习Spring框架的时候,所有的事务由容器管理
                -->
                <transactionManager type="JDBC"/>
                <!--数据源的配置:mybatis自带的连接池-->
                <!--
                    数据源:
                    1. POOLED:使用mybatis创建的连接池
                    2. UNPOOLED:不使用连接池,每次自己创建连接
                    3. JNDI:由服务器提供连接池的资源,我们通过JNDI指定的名字去访问服务器中资源。
                -->
                <dataSource type="POOLED">
                    <property name="driver" value="${jdbc.driver}"/>
                    <property name="url" value="${jdbc.url}"/>
                    <property name="username" value="${jdbc.username}"/>
                    <property name="password" value="${jdbc.password}"/>
                </dataSource>
            </environment>
        </environments>
        
        <!--映射器-->
        <mappers>
            <package name="com.itheima.sh.dao"></package>
        </mappers>
    </configuration>
    

dao层:UserMapper

public interface UserMapper {
    //查询所有用户
    @Select("select id,name,sex,age,address,qq,email from t_user where isdelete=0")
    List<User> queryAllUsers();
}

service层:UserService

    /**
     * 功能: 分页查询用户数据
     * @param currentPage    页码
     * @return
     */
    public PageInfo<User> findUserByPage(int currentPage) {

        int pageSize = 5; //每页显示条数

        //获取UserMapper的代理类对象
        SqlSession session = SessionFactoryUtils.getSession();
        UserMapper userMapper = session.getMapper(UserMapper.class);

        //设置分页查询
        PageHelper.startPage(currentPage,pageSize);
        
        //执行UserMapper中的方法: 查询所有用户
        List<User> users = userMapper.queryAllUsers();
        
        //释放资源
        session.close();
        
        //实例化PageInfo对象 
        PageInfo<User> pageInfo = new PageInfo<>(users);
        //System.out.println("总记录数:"+ pageInfo.getTotal());
        //System.out.println("总页数:"+pageInfo.getPages());
        //System.out.println("当前页:"+pageInfo.getPageNum());
        //System.out.println("每页显示长度:"+pageInfo.getPageSize());
        //System.out.println("是否第一页:"+pageInfo.isIsFirstPage());
        //System.out.println("是否最后一页:"+pageInfo.isIsLastPage());
        //System.out.println("查询数据:");
        //List<User> userList = pageInfo.getList();
        //for(User user : userList){
        //    System.out.println(user);
        //}

        return pageInfo;//返回PageInfo对象
    }

web层 - 控制器:PageServlet

@WebServlet("/page")
public class PageServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //获取当前页码
        String currentPage = request.getParameter("currentPage");

        int curPage = 1;    //第一次获取用户数据时,没有发送当前页码 (初始化为1)

        //有获取到当前页码
        if (currentPage != null) {
            curPage = Integer.parseInt(currentPage);
        }

        //实例化service层
        UserService userService = new UserService();
        //调用业务层功能:分页查询用户数据
        PageInfo<User> pageInfo = userService.findUserByPage(curPage);

        //请求域对象中存储:分页信息对象(含查询的用户数据)
        request.setAttribute("pageInfo", pageInfo);

        //转发
        request.getRequestDispatcher("/pageList.jsp").forward(request, response);
    }
}

web层 - 视图:pageList.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<!-- 网页使用的语言 -->
<html lang="zh-CN">
    <head>
        <!-- 指定字符集 -->
        <meta charset="utf-8">
        <!-- 使用Edge最新的浏览器的渲染方式 -->
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <!-- viewport视口:网页可以根据设置的宽度自动进行适配,在浏览器的内部虚拟一个容器,容器的宽度与设备的宽度相同。
        width: 默认宽度与设备的宽度相同
        initial-scale: 初始的缩放比,为1:1 -->
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
        <title>用户信息管理系统</title>

        <!-- 1. 导入CSS的全局样式 -->
        <link href="css/bootstrap.min.css" rel="stylesheet">
        <!-- 2. jQuery导入,建议使用1.9以上的版本 -->
        <script src="js/jquery-2.1.0.min.js"></script>
        <!-- 3. 导入bootstrap的js文件 -->
        <script src="js/bootstrap.min.js"></script>
        <style type="text/css">
            td, th {
                text-align: center;
            }
        </style>
    </head>
    <body>
        <div class="container">
            <h3 style="text-align: center">用户信息列表</h3>

            <div style="float: left;">
                <%-- 搜索 --%>
                <input id="keyword" type="text" name="keyword">
                <input class="btn btn-default btn-sm" type="button" value="搜索" onclick="searchKey()">

            </div>


            <div style="float: right;">
                <%-- 新增联系人 --%>
                <a class="btn btn-primary" href="add.jsp">添加联系人</a>
            </div>


            <table border="1" class="table table-bordered table-hover">
                <tr class="success">
                    <th>编号</th>
                    <th>姓名</th>
                    <th>性别</th>
                    <th>年龄</th>
                    <th>籍贯</th>
                    <th>QQ</th>
                    <th>邮箱</th>
                    <th>操作</th>
                </tr>


                <c:forEach items="${requestScope.pageInfo.list}" var="user">
                    <tr>
                        <td>${user.id}</td>
                        <td>${user.name}</td>
                        <td>${user.sex}</td>
                        <td>${user.age}</td>
                        <td>${user.address}</td>
                        <td>${user.qq}</td>
                        <td>${user.email}</td>
                        <td>
                            <a class="btn btn-default btn-sm" href="update.jsp">修改</a>
                            &nbsp;
                            <a class="btn btn-default btn-sm" href="">删除</a>
                        </td>
                    </tr>
                </c:forEach>


                <tr>
                    <td colspan="8" align="right">

                        <%--
                            分页栏
                        --%>
                        <nav>
                            <ul class="pagination">
                                <%-- 上一页 --%>
                                <c:if test="${requestScope.pageInfo.isFirstPage == true}">
                                    <li class="disabled">
                                        <a href="#">
                                            <span>&laquo;</span>
                                        </a>
                                    </li>
                                </c:if>
                                <c:if test="${requestScope.pageInfo.isFirstPage == false}">
                                    <li>
                                        <a href="/page?currentPage=${requestScope.pageInfo.prePage}">
                                            <span>&laquo;</span>
                                        </a>
                                    </li>
                                </c:if>

                                <%-- 页码显示区
                                     begin="1" 表示从第一页开始
                                     end="最后一页"
                                     var="num" 表示每一页
                                --%>
                                <c:forEach begin="1" end="${requestScope.pageInfo.pages}" var="num">
                                    <c:if test="${requestScope.pageInfo.pageNum == num}">
                                        <li class="active">
                                            <span style="background-color: blue">${num}</span>
                                        </li>
                                    </c:if>
                                    <c:if test="${requestScope.pageInfo.pageNum != num}">
                                        <li class="active">
                                            <a href="/page?currentPage=${num}">${num}</a>
                                        </li>
                                    </c:if>
                                </c:forEach>


                                <%-- 下一页 --%>
                                <c:if test="${requestScope.pageInfo.isLastPage==true}">
                                    <li class="disabled">
                                        <a href="#">
                                            <span>&raquo;</span>
                                        </a>
                                    </li>
                                </c:if>
                                <c:if test="${requestScope.pageInfo.isLastPage==false}">
                                    <li>
                                        <a href="/page?currentPage=${requestScope.pageInfo.nextPage}">
                                            <span>&raquo;</span>
                                        </a>
                                    </li>
                                </c:if>
                            </ul>
                        </nav>
                    </td>
                </tr>
            </table>

        </div>
    </body>
</html>
posted @   忘了鱼尾纱的猫  阅读(126)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
  1. 1 刘哈哈与大先生 刘心&大鹏
  2. 2 我们打着光脚在风车下跑,手上的狗尾巴草摇啊摇 等一下就回家 / -艾兜
  3. 3 哎呦 毛不易
  4. 4 夜、萤火虫和你 AniFace
刘哈哈与大先生 - 刘心&大鹏
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.

作词 : 刘心/大鹏

作曲 : 刘心

刘:我越来越没自信了

破头发还是不停的脱

那些快乐 快乐 不属于我

还剩下什么 一把吉他陪我唱歌

鹏:这不是我想的生活

鹏:这不是我想的生活

多希望有美眉爱看我

不是笑我 笑我 调侃着我

搞得像个失败者

其实我妈妈说我优点也很多

刘:这个世界开始变得越来越快了

刘:这个世界开始变得越来越快了

可是怎么却都不快乐

鹏:脱下你沉重的假面听我唱首歌

鹏:脱下你沉重的假面听我唱首歌

简单有时比复杂值得

刘:我想要点春风 我想要点感动

刘:我想要点春风 我想要点感动

鹏:我想要点香槟 我想要碟花生

沙滩 海风

刘:美女如云穿梭

这是我的美梦(合)白日梦

刘:这不是我想的生活

刘:这不是我想的生活

多希望有美眉爱看我

不是笑我 笑我 调侃着我

搞得像个失败者

其实我妈妈说我优点也很多

鹏:这个世界开始变得越来越快了

鹏:这个世界开始变得越来越快了

可是怎么却都不快乐

刘:脱下你沉重的假面听我唱首歌

刘:脱下你沉重的假面听我唱首歌

简单有时比复杂值得

鹏:这个世界开始变得越来越快了

鹏:这个世界开始变得越来越快了

可是怎么却都不快乐

刘:脱下你沉重的假面听我唱首歌

刘:脱下你沉重的假面听我唱首歌

简单有些时候都要比复杂值得

鹏:我想要点春风 我想要点感动

鹏:我想要点春风 我想要点感动

刘:我想要点香槟 我想要碟花生

沙滩 海风

鹏:美女如云穿梭

这是我的美梦(合)白日梦

点击右上角即可分享
微信分享提示