快速开发架构Spring Boot 从入门到精通 附源码

导读#

  篇幅较长,干货十足,阅读需花费点时间。珍惜原创,转载请注明出处,谢谢!

Spring Boot 基础#

Spring Boot 简介#

  Spring Boot由 Pivotal 团队提供的全新框架,其设计目的是用来简化新 Spring 应用初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring Boot致力于在蓬勃发展的快速应用开发领域(rapid application development) 成为领导者。

  简单来说,SpringBoot可以简化应用程序的开发,使我们再需要spring 配置文件及 web.xml

SpringBoot 工程和创建#

IDEA 中的创建#

工程编辑#

  系统会在前面设置的包中自动生成一个启动类

  在启动类所在的包下创建一个子包,在其中编写 SpringMvc 的处理器类。

  注意,要求代码所在的包必须启动类所在的包的子孙宝不能是同级包。 

启动#

ide 方式#

mac 控制台方式 (需 maven 打包)#

官网创建#

地址:https://start.spring.io/

配置及生成#

  配置项配置完成后,点击Generate按钮后,即可打开一个下载对话框。官网将配置好的Spring Boot工程生成一个 zip压缩文件,只要我们将下载后的文件解压并添加到工程即可使用

基于 war 的 Spring Boot 工程#

  前面 2 种方式创建的 Spring Boot 工程最终被打为了 jar 包,是以可执行文件的形式出现的,他们都使用了 Spring Boot 内嵌的 Tomcat 作为 web 服务器来运行 web 应用的。新版的 Dubbo 的监控中心工程就是典型的应用。但在实际生产环境下,对于 web 工程,很多时候我们需要的是 war 包,然后部署到企业级 web 服务器中。下面来演示如何使用 Spring Boot 将工程打为 war 包。

工程创建#

我们看一下 pom.xml 文件,可以知道,Tomcat 打包的时候不打进去

将项目打包后,仍到 Tomcat 的 wabapps 目录下

启动 Tomcat#

接下来我们查看 Tomcat 目录

打开网页,注意加上项目名

 

注:mac 启动 Tomcat 过程中遇到点麻烦,1、需要赋予文件夹权限;2、执行 shell 脚本报错:Operation not permitted,博主参考了下面 2 个链接配成成功哒

大概配置步骤#

1、切换 Tomcat 的 bin 目录下
    sudo chmod 755 *.sh

2、解决 Operation not permitted
xattr
-d com.apple.quarantine ./*

3、启动 Tomcat
sudo sh ./startup.sh
4、停止 Tomcat
  sudo sh ./shutdown.sh

参考链接: 注:第一、二链接,赋权限,第三个链接解决 Operation not permitted
https://blog.csdn.net/caoxiaohong1005/article/details/53463443
https://blog.csdn.net/F_Feng0628/article/details/60583250
https://blog.csdn.net/default7/article/details/80172340

工程解析#

   创建Spring Boot工程后,会自动生成工程的启动类 Application

   跟踪@SpringBootApplication注解源码可以看到,可以完成 Spring Boot 的自动配置

   继续跟踪@SpringBootConfiguration源码可以看到,其本质是一个@Configuration,使用Java 类充当 Spring 配置文件

 src/main/resources 目录#

  1. static:存放静态资源,如:css,js,images 等 
  2. templates目录:存放动态资源。Spring Boot不建议使用 jsp 作为动态数据展示页面,而是建议使用 ThymeleafThymeleaf 是一种 Java模板引擎,可以显示动态数据。Thymeleaf 文件的扩展名为 html,是对 html 的扩展。该目录用于存放 Thymeleaf 文件。
  3. 两个目录中存放的资源相当于存放当前web应用的根下。一般不适用他们存放资源。
  4. application.properties:SpringBoot 的主配置文件

查看当前工程#

  在pom.xml文件中包含 SpringBoot两个核心依赖一个核心插件一个是 SpringBoot 的Web 启动依赖一个是 SpringBoot 的测试启动依赖;而这个核心插件是用于完成对 SpringBoot工程打包结果的再打包

  注:他们都没有版本号,这是为什么呢?

   虽然他们都没有版本号,打开 maven 可以看到,他们版本均为 2.2.2

   他们的版本号均继承自父工程。从 pom 文件中可以看到,其父工程spring-boot-starter-parent

更换默认 springframework 的版本 (视生产环境降默认版本)#

查看 spring-boot-starter-parent 工程#

  打开 Maven 本地仓库,在 org.springframework 中找到工程 spring-boot-starter-parent。

打开 spring-boot-starter-parent-2.2.2.RELEASE.pom 文件,发现该工程的 <pluginManagement> 中有对该插件的配置信息。

注:<pluginManagement> 中声明的插件是选择性继承插件,而非全部继承插件。

    从该插件的配置信息可以得出,其执行的目标是 repackage,即对工程进行重新打包。

  首次打包是由 Maven 的 package 插件完成,其打包的结果仅仅是将当前工程中自定义的类打包成了一个普通的 jar 包,没有 Spring Boot 的相关资源,无法直接运行。当然,其打包的结果是.jar 文件。

  重新打包是由 spring-boot-maven-plugin 插件完成的,其实将前面打成的 jar 包进行了二次打包,将原来的软件包变为了 Spring Boot 可执行包,在其中不仅添加了 Spring Boot 依赖,还添加了很多其他配置。同时,其还将原来的.jar 文件扩展名变为了.orininal,而而二次打包后的文件扩展名成为了.jar。

  可以打开 01-primary-0.0.1-SNAPSHOT.jar

BOOT-INF目录:存的是当前应用程序的类及其所依赖的类

META-INF目录:存的是Maven相关的配置文件

org目录:存的是 SpringBoot启动所需的类

  打开 META-INF/MANIFEST.MF,不仅可以看到主类 Main-Class,还可以看到当前工程的启动类 Start-Class。

maven 打包#

Spring Boot 热部署#

  idea 中的 Spring Boot 工程若要使用热部署,需要 2 不操作:

  1. 导入 devtools 依赖
  2. 编辑工程的配置信息

  注:Spring Boot 工程在 idea 和 Eclipse 中的重启时机不同。Eclipse 只要修改的文件保存过了,工程会立马重新部署。而 idea 则对文件修改后的保存是自动的,所以其重新部署的时机是 idea 整个 ide 窗口被钝化时,即窗口切换到其他窗口时,工程会重新部署。

添加依赖#

pom.xml#

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

配置#

  当 idea 被钝化时,即当 idea 窗口被切换时,更新类与资源。

  在开发调试过程中,已经启动了工程的运行。此时又修改了代码或配置文件,若要使修改生效,则需要重新启动工程。这种方式降低了开发效率。

  热部署,即修改了代码或配置文件后,一旦保存,系统马上对工程进行自动重启,无需手工重启。若要实现热部署,只需要在 pom.xml 中添加一个依赖即可。

  热部署的使用有利有弊。利:无需手动重启工程;弊:在修改代码或配置后,只要保存系统就会重启工程,即使这个修改还未完毕,其他的会重启,从而导致代码重启后报错。

1、添加依赖

pom.xml

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

2、设置自动生成项目

3、Ctrl+Shift+A, 打开搜索框,输入:Registry

4、勾选即可 

Spring Boot 主配置文件#

配置文件形式一#

  Spring Boot 的主配置文件是 src/main/resources 中默认创建的 application.properties 文件。

 

  编辑配置文件

  启动

注意事项#

   注:这里指定的 Tomcat 端口号,仅仅只针对内置 Tomcat 的,是测试时使用的。将工程打为 war 包后部署到真正的 Tomcat,这些配置是不起作用的。

配置文件形式二#

  Spring Boot 的主配置文件也可以使用application.yml文件。.yml 也可以写成.yaml

  在开发之初 YAML 的本意是 Yet Another Markup Language( 仍是一种标记语言)。后来为了强调这种语言是以数据为中心,而不是以标记为中心,所以将标记为中心,所以将 YAML 解释为 Yaml Ain't Markup Language(Yaml 不是一种标记语言)。它是一种直观的能够被电脑识别的数据序列化格式,是一个可读性高并且容易被人阅读,容易和脚本语言交互,用来表达多级资源序列的编程语言。

  yml 与 properties 文件的主要区别是对于多级属性,即 key 的显示方式不同。yml 文件在输入时,只需按照点 (.) 的方式输出 key 既可,输入完毕后回车即出现了如下形式。该形式要求冒号后与值之间有一个空格(语法格式)。

 注意事项#

  注:application.properties 与 application.yml 这两个文件只能有一个。要求文件名必须是:application。

Actuator#

  Actuator 是Spring Boot 提供的对应用系统的自省和监控的集成功能,可以对应用系统进行配置查看、相关功能统计等。在Spring Colud中主要是完成微服务的监控,完成监控治理。可以查看微服务间的数据处理和调用,当它们之间出现异常,就可以快速定位到出现问题的地方

  其功能与 Dubbo 的监控中心类似,不同的是,Dubbo 的监控中心是需要专门部署的,而 Spring Boot 的 Actuator 是存在于每个工程中。

环境搭建#

  随便一个 Spring Boot 工程中都可以使用 Actuator 对其进行监控。

添加依赖#

pom.xml

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

修改配置文件#

application.properties

# 当前应用的端口与上下文路径
server.port=8888
server.servlet.context-path=/cyb

Actuator 监控的端口号与上下文路径

management.server.port=9999
management.server.servlet.context
-path=/cyb2

指定监控终端的基本路径,默认为 actuator

management.endpoints.web.base-path=/base

启动项目并测试#

添加 Info 信息#

修改配置文件#

  在配置文件中添加如下 Info 信息,则可以通过 Info 控制终端查看到。

测试#

注:博主浏览器安装了 JSON 格式化工具,所以显示的是 JSON 格式化后的状态

开发其他监控终端#

  默认情况下,Actuator 仅开放了 health 与 Info 两个监控终端,但它还有很多终端可以监控,需手动开放。

修改配置文件#

mappings 终端#

  mappings可以看到当前工程中所有的URI 与处理器映射关系,及详细的处理器方法以及其映射规则。很实用!!!

beans 终端#

evn 终端#

  可以到当前应用程序运行主机的所有软硬件环境信息

单独关闭某些监控终端#

  在开放了所有监控终端的情况下,有些终端显示的信息并不想公开,此时可以单独关闭这些终端。

修改配置文件#

测试#

  其他的监控终端不受影响。

其他常用的监控终端如下#

  若没有你需要的,可以自行百度搜“springboot actuator”

Spring Boot 重要用法#

自定义异常页面#

  对于 404、405、500 等异常页面,而这些异常页面一般都是英文的,非常不友好。我们可以通过简单方式使用自定义异常页面,并将默认状态码页面进行替换

定义目录#

  在 src/main/resources目录下新建目录:public/error。

定义异常页面#

  在error 目录定义异常页面。这些异常页面的名称必须为相应的状态码,扩展名为 html。

单元测试#

添加依赖#

pom.xml

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>

接口类#

ISomeService.java

package com.cyb.webdemo.controller;

public interface ISomeService {
void doSome();
}

接口实现类#

SomeServiceImpl.java

package com.cyb.webdemo.controller;

import org.springframework.stereotype.Service;

@Service
public class SomeServiceImpl implements ISomeService{
@Override
public void doSome() {
System.out.println(
"执行 Service 的 doSome");
}
}

测试类#

  类上需添加两个注解:

    1、@RunWith(SpringRunner.class)

    2、@SpringBootTest(classes = Spring Boot 启动类.class)

多环境选择#

什么是多环境选择?#

  在开发应用时,通常同一套程序运行多个环境,例如,开发、测试、生产环境等。每个环境的数据库地址、服务器端口号等配置都会不同。若在不同环境下运行时将配置文件修改为不同内容。那么,这种做法不仅非常繁琐,而且很容易发生错误

  在开发应用时,有时不同的环境,其需要运行的接口的实现类也是不同的。例如,若要开发一个具有短信发送功能的应用,开发环境中要执行的 send()方法仅需要调用短信模拟器即可,而生产环境中要执行的 send() 则需要调用短信运营商所提供的短信发送接口。这种情况下,就需要开发两个相关接口的实现类去实现 send() 方法。

  不同的环境,需使用不同的配置文件执行不同的类。而这个选择只需要Spring Boot 的主配置文件中指定即可

  下面以不同环境使用配置有不同的端口号的配置文件,以及调用不同的接口实现类”为例演示多环境选择问题的解决。

Example#

1、创建几个配置文件,格式:application-xxxxx.properties

2、创建一个包,并创建一个接口,内容如下

2、创建 DevMsgServiceImpl 开发环境类

注:@Profile("xxx") 中的值要和 application-xxx.properties对应上

3、创建 ProMsgServiceImpl 生产环境

注:@Profile("xxx") 中的值要和 application-xxx.properties对应上

4、创建处理器:MsgController

5、测试

正确请求

错误请求

说明#

  在 Spring Boot 中多环境配置文件名需满足application-[profile].properties格式,其中 [profile] 为对应的环境标识,例如

  1. application-dev.properties:开发环境
  2. application-pro.properties:生产环境

  至于那个配置文件会被加载取决于 application.properties 中的 spring.profiles.active 属性来设置,其值对应 [profile]。例如 spring.profiles.active=dev 就会加载 application-dev.properties 配置文件内容

  在实现类上加 @Profile 注解,并在注解参数中指定前述配置文件中的 [profile] 值用于指定该实现类所使用的环境

  以上开发过程中碰到的问题都解决啦 ~~~~

6、在命令行下选择环境

  将工程打为 Jar 包后,在命令行运行。若要想切换运行环境,必须要修改主配置文件吗?答案是否定的。只需添加一个命令参数即可动态指定。

  例如,现在的主配置文件中指定的是 dev 环境

   将当前工程打为 Jar 包后,在命令行运行时添加如下参数

 

  此时执行的就是生产环境,调用的就是 ProduceServiceImpl 类

读取自定义配置#

  自定义配置,可以是定义在主配置文件:application.properties 中的自定义属性,也可以是自定义配置文件中的属性。

读取主配置文件中的属性#

application.properties

SomeController.java

实现

读取指定配置文件中的属性#

创建配置文件:cybApplication.properties

SomeController.java 

实现 

读取对象属性#

cybApplication.properties

实体类:cyb.java

说明#

  1. @PropertySource:用于指定要读取的配置文件。
  2. @ConfigurationProperties:用于指定要读取配置文件中的对象属性。
  3. @Component:当前从配置文件读取来的对象,由 Spring 容器创建。

SomeController.java

实现

读取 List 属性 1#

cybApplication.properties

实体类:UserName

SomeController.java

实现

读取 List 属性 2#

cybApplication.properties

Group.java

students.java

SomeController.java

实现

补充知识 (lombok)#

  lombok 方式配置实体类。没用过的小伙伴,可以参考Lombok 介绍、使用方法和总结进行脑补,这里只演示使用

1、idea 安装 lombok

2、添加依赖

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

3、实体类上加 @Data 即可

package com.cyb.webdemo.controller;

import lombok.Data;

@Data
public class studens {
private String name;
private int age;

// public String getName() {
// return name;
// }
//
// public void setName(String name) {
// this.name = name;
// }
//
// public int getAge() {
// return age;
// }
//
// public void setAge(int age) {
// this.age = age;
// }
}

注:lombok 省去了 get/set,让代码更简洁。

Spring Boot 下使用 JSP 页面#

添加 JSP 解析依赖#

pom.xml

        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
        </dependency>

创建 webapp 目录#

  在 src/main 下建 webapp 目录,用于存放 jsp文件。创建的是一个普通目录指定为 web 资源目录,然后才可以创建 jsp 文件。File->Project Structure

添加 JSP 注册资源目录#

pom.xml

    <build>
        <resources>
            <!--注册 dao 包下 mybatis 映射文件为资源目录-->
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
            <!--注册 webapp 目录为资源目录-->
            <resource>
                <directory>src/main/webapp</directory>
                <targetPath>META-INF/resources</targetPath>
                <includes>
                    <include>**/*.*</include>
                </includes>
            </resource>
        </resources>
    </build>

创建 JSP 页面#

实现#

 

创建 welcome.jsp#

创建 home.jsp#

SomeController.java#

实现#

关于静态资源请求#

  Spring Boot 已经处理好了静态资源访问问题。

视图前 / 后缀#

Spring Boot 中使用 MyBatis#

添加依赖项#

MyBatis 与 Spring Boot 整合依赖#

pom.xml

        <!--Mybatis 与 Spring Boot 整合依赖,必须要版本号-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>

MySql 驱动依赖#

pom.xml

        <!--mysql 驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

Druid 连接池依赖#

pom.xml

        <!--Druid 连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency>

lombok 依赖 (可忽略,用于实体类)#

pom.xml

        <!--lombok 依赖-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

  注:若使用 lombok 需配置 ide。

注册资源目录文件#

pom.xml

    <build>
        <resources>
            <!--注册 dao 包下 mybatis 映射文件为资源目录-->
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
            <!--注册 webapp 目录为资源目录-->
            <resource>
                <directory>src/main/webapp</directory>
                <targetPath>META-INF/resources</targetPath>
                <includes>
                    <include>**/*.*</include>
                </includes>
            </resource>
        </resources>
    </build>

  注:若不注册 dao 包下的 mybatis 映射文件,需将 xxx.xml 文件放到:/resource,并且修改 application.properties 文件中的 mybatis.mapper-locations 映射路径!!!!!!!

资源文件#

application.properties

# 视图的前缀和后缀
spring.mvc.view.prefix=/
spring.mvc.view.suffix=.jsp

注册映射文件

mybatis.mapper-locations=classpath:com/cyb/webdemo/dao/EmployeeDao.xml

注册实体类别名

mybatis.type-aliases-package=com.cyb.webdemo.bean.EmployeePo

注册数据源类型

spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

数据库连接字符串

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/cyb
spring.datasource.username=root
spring.datasource.password=root

创建 jsp#

index.jsp#

实体类 (Po)#

EmployeePo.java#

注意#

  案例中使用了 lombok 依赖(idea 中需要配置,可以参考前面讲解 lombok 配置环境方法),所以实体类中可以不设置 get/set 方法

dao 层 (数据访问层)#

EmployeeDao.java#

EmployeeDao.xml#

  注:mybatis 映射文件的存放位置!!!!!

代码拷贝区#

package com.cyb.webdemo.dao;

import com.cyb.webdemo.bean.EmployeePo;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface EmployeeDao {
void insertEmployee(EmployeePo employeePo);
}

<?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.cyb.webdemo.dao.EmployeeDao">
<insert id="insertEmployee">
    insert into employee (name,age) values (#{name},#{age})
</insert>
</mapper>

service 层 (业务层)#

EmployeeService.java(接口)#

EmployeeServiceImpl.java(接口实现类)#

代码拷贝区#

package com.cyb.webdemo.service;

import com.cyb.webdemo.bean.EmployeePo;

public interface EmployeeService {
void addEmployee(EmployeePo employee);
}

package com.cyb.webdemo.service;

import com.cyb.webdemo.bean.EmployeePo;
import com.cyb.webdemo.dao.EmployeeDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class EmployeeServiceImpl implements EmployeeService{

@Autowired(required </span>= <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> EmployeeDao dao;
@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> addEmployee(EmployeePo employee) {
    dao.insertEmployee(employee);
}

}

Controller 层#

package com.cyb.webdemo.controller;

import com.cyb.webdemo.bean.EmployeePo;
import com.cyb.webdemo.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class RegisterHandler {
@Autowired(required
= false)
private EmployeeService service;
@PostMapping(
"register")
public String RegisterHandler(EmployeePo employee){
service.addEmployee(employee);
return "ok";
}
}

扫描 dao 层(可忽略#

数据库表结构#

实现#

项目源码#

直接下载

Spring Boot 事务支持#

步骤#

  1. 启动类上添加 @EnableTransactionManagement
    注解,开启事务
  2. Service 实现类方法上加 @Transactional
    注解

启动类#

 业务层接口实现类#

Spring Boot 对日志的控制 #

logback 日志技术#

  Spring Boot 中使用日志技术为 logback。其与 Log4J 都出自一人性能优于 Log4J,是Log4J 的替代者

  在 Spring Boot 中若要使用 logback,则需要具有 spring-boot-starter-logging 依赖,而该依赖被 spring-boot-starter-web 依赖,即不用直接导入 spring-boot-starter-logging 依赖(间接依赖)。

方式一#

xml 方式#

  必须放到 src/main/resources 类路径下!!!

代码拷贝区#

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <appender name="myConsole" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%-5level - %msg%n</pattern>
        </encoder>
    </appender>
    <root level="WARN">
        <appender-ref ref="myConsole"></appender-ref>
    </root>
    <logger name="com.cyb.webdemo.dao.EmployeeDao" level="DEBUG"></logger>
</configuration>

方式二#

application.properties#

 

代码拷贝区#

application.properties

# 控制日志显示格式
logging.pattern.console=%leven %msg%n
logging.level.root=warn
# 格式:logging.level.dao 层命名空间
logging.level.com.cyb.webdemo.dao.EmployeeDao=debug

实现#

Spring Boot 中使用 Redis(解决高并发,重点!!)#

注意#

  案例从头到尾,使用都是同一个项目,代码配置结构复杂,看红色圈中的代码,敲黑板划重点!!!!!

学前预习#

  Redis 还不会的小伙伴,请先预习:分布式架构 -Redis 从入门到精通 。

应用场景#

  使用 Redis 缓存的数据划分为两类:

  1. DB表中的数据更新后,Redis缓冲的相关数据要清除,要不然客户端获取的不是最新数据。
  2. 对数据准确性要求不高的数据,可以与 DB 表中的数据不一致,但差别不能太大,所以该类数据一般会设置过期 1 时效

启动 redis 服务器#

Spring Boot 与 Redis 整合依赖#

完整 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.2.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.cyb</groupId>
    <artifactId>webdemo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>webdemo</name>
    <description>Demo project for Spring Boot</description>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">properties</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">java.version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>13<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">java.version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">properties</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">dependencies</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)">Mybatis与Spring Boot整合依赖,必须要版本号</span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>org.mybatis.spring.boot<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>mybatis-spring-boot-starter<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>1.3.2<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)">mysql驱动</span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>mysql<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>mysql-connector-java<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)">Druid连接池</span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>com.alibaba<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>druid<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>1.1.10<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)">lombok依赖</span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>org.projectlombok<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>lombok<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)">Spring Boot与redis依赖</span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>org.springframework.boot<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>spring-boot-starter-data-redis<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>org.apache.tomcat.embed<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>tomcat-embed-jasper<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>org.springframework.boot<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>spring-boot-starter-web<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>org.springframework.boot<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>spring-boot-starter-tomcat<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">scope</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>provided<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">scope</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>org.springframework.boot<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>spring-boot-starter-test<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">scope</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>test<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">scope</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">exclusions</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
            <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">exclusion</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
                <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>org.junit.vintage<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
                <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>junit-vintage-engine<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
            <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">exclusion</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">exclusions</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>junit<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>junit<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">scope</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>test<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">scope</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">dependencies</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">build</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">resources</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)">注册dao包下mybatis映射文件为资源目录</span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">resource</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
            <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">directory</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>src/main/java<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">directory</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
            <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">includes</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
                <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">include</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>**/*.xml<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">include</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
            <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">includes</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">resource</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)">注册webapp目录为资源目录</span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">resource</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
            <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">directory</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>src/main/webapp<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">directory</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
            <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">targetPath</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>META-INF/resources<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">targetPath</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
            <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">includes</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
                <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">include</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>**/*.*<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">include</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
            <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">includes</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">resource</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">resources</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">plugins</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">plugin</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
            <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>org.springframework.boot<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
            <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>spring-boot-maven-plugin<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">plugin</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">plugins</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">build</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

</project>

修改主配置文件#

application.properties#

代码拷贝区#

# 视图的前缀和后缀
spring.mvc.view.prefix=/
spring.mvc.view.suffix=.jsp

注册映射文件

mybatis.mapper-locations=classpath:com/cyb/webdemo/dao/EmployeeDao.xml

注册实体类别名

mybatis.type-aliases-package=com.cyb.webdemo.bean.EmployeePo

注册数据源类型

spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

数据库连接字符串

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/cyb
spring.datasource.username=root
spring.datasource.password=root

控制日志显示格式

logging.pattern.console=%leven %msg%n
logging.level.root=warn

格式:logging.level.dao 层命名空间

logging.level.com.cyb.webdemo.dao.EmployeeDao=debug

连接 redis

spring.redis.host=192.168.31.200
spring.redis.port=6379
spring.redis.password=root

连接 redis 集群,redis 利用哨兵机制实现高可用

spring.redis.sentinel.master=mymaster

spring.redis.sentinel.nodes=sentinel1:6370,sentinel2:6371,sentinel3:6372

指定缓存类型

spring.cache.type=redis

设置缓存名称

spring.cache.cache-names=realTimeCache

JSP 页面#

index.jsp#

代码拷贝区#

<%--
  Created by IntelliJ IDEA.
  User: chenyanbin
  Date: 2020/1/6
  Time: 7:13 下午
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="register" method="post">
    姓名:<input type="text" name="name"><br/>
    年龄:<input type="number" name="age"><br/>
    <input type="submit" value="注册">
</form>
<hr>
<form action="find" method="post">
    id:<input type="text" name="id">
    <input type="submit" value="查询">
</form>
<a href="count">查看员工总数</a>
</body>
</html>

实体类#

EmployeePo.java#

数据库表字段#

Dao 层 (数据访问层)#

EmployeeDao.java#

映射文件#

EmployeeDao.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.cyb.webdemo.dao.EmployeeDao">
    <insert id="insertEmployee">
    insert into employee (name,age) values (#{name},#{age})
</insert>
    <select id="selectEmployeeById" resultType="com.cyb.webdemo.bean.EmployeePo">
        select id,name,age from employee where id=#{id}
    </select>
    <select id="selectEmployeeCount" resultType="int">
        select count(1) from employee
    </select>
</mapper>

Service(业务层)#

EmployeeService.java(接口)#

EmployeeServiceImpl.java(接口实现类)#

  注:双重检测锁非常重要!!!!

代码拷贝区#

package com.cyb.webdemo.service;
import com.cyb.webdemo.bean.EmployeePo;
import com.cyb.webdemo.dao.EmployeeDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.concurrent.TimeUnit;
@Service
public class EmployeeServiceImpl implements EmployeeService {
    @Autowired(required = false)
    private EmployeeDao dao;
    @CacheEvict(value = "realTimeCache", allEntries = true)
    // 清除缓存, 实际生产环境就这样玩,因为每个实体类设置不同的缓存区空间,范围小,清除缓存好操作
    @Transactional
    @Override
    public void addEmployee(EmployeePo employee) {dao.insertEmployee(employee);
    }
    @Cacheable(value = "realTimeCache", key = "'employee_'+#id")
    // 先会去缓存中查下 key 是否存在,存在:则直接拿缓存中的数据;不存在:去数据库中查,查完将结果放入缓存中
    @Override
    public EmployeePo findEmployeeById(int id) {
        return dao.selectEmployeeById(id);
    }
    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;
    //使用双重检测锁,解决热点缓存问题
    //双重检测锁,解决了高并发下,对数据库访问的压力!!!!
    //热点缓存脑补,请参考:https://www.jianshu.com/p/6e37a1a9c160
    @Override
    public int findEmployeeCount() {
        //获取 Redis 操作对象
        BoundValueOperations<Object, Object> ops = redisTemplate.boundValueOps("count");
        //从缓存中读取数据
        Object count = ops.get();
        if (count == null) {
            synchronized (this) {
                count = ops.get();
                if (count == null) {
                    //从 DB 中查询
                    count = dao.selectEmployeeCount();
                    //将查询的数据,写入 Redis 缓存,并设置到期时限
                    ops.set(count,10, TimeUnit.SECONDS);}
            }
        }
        return (int)count;}
}

实现#

注:细心的小伙伴发现,一个问题,根据 id 查询数据库的时候,为什么控制台没有打印 sql 语句呢???对表进行增删改时,清除缓存,查询时设置缓存,因为之前演示的时候,已经将缓存写入到 redis 服务器中了,查询的时候,拿的是缓存数据!!

完整项目#

直接下载

Redis 自动生成 key(高级用法)#

自动生成类#

RedisCacheConfig.java

package com.cyb.webdemo.controller;

import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RedisCacheConfig extends CachingConfigurerSupport {
// 自定义生成 key 结构:类名 _ 方法名 _ 参数值
// 本例:EmployeeServiceImpl_findEmployeeById_1
public KeyGenerator keyGenerator() {
return (target, method, params) -> {
//获取注解所标的方法所在类的类名
String className = target.getClass().getName();
//获取注解所标注的方法的方法名
String methodName = method.getName();
return className + ""+ methodName +"" + params[0].toString();
};
}
}

实现#

Spring Boot 拦截器#

  在非 Spring Boot 工程中若要使用 Spring Mvc 的拦截器,在定义好拦截器后,需要在 Spring 配置文件中对其进行注册。但在 Spring Boot 工程中没有 Spring 的配置文件,那么如何使用拦截器呢?

  Spring Boot 对于原来在配置文件配置的内容,现在全部体现在一个类中,该要继承 WebMvcConfigurationSupport类,并使用@Configuration进行注册,表示该类为一个 JavaConfig/codeConfig 类,充当配置文件的角色。

定义拦截器#

SomeInterceptor.java#

package com.cyb.webdemo.controller;

import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class SomeInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println(
"拦截器:"+request.getRequestedSessionId());
return true;
}
}

  注:返回值 true:不拦截;false:拦截

配置文件类#

MyMvcConfiguration.java#

package com.cyb.webdemo.controller;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

@Configuration //表示该类充当配置文件
public class MyMvcConfiguration extends WebMvcConfigurationSupport {
@Override
protected void addInterceptors(InterceptorRegistry registry) {
SomeInterceptor someInterceptor
= new SomeInterceptor();
registry.addInterceptor(someInterceptor)
.addPathPatterns(
"/one/") //拦截 one 开头请求
.excludePathPatterns("/two/
"); //允许 two 开头的请求
}
}

  注:**:代表多级目录;*:只有一级目录;

一般设置全部拦截addPathPatterns("/**");再设置局部的不拦截excludePathPatterns("/xx/**")

定义处理器#

package com.cyb.webdemo.controller;

import com.cyb.webdemo.bean.EmployeePo;
import com.cyb.webdemo.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

@Controller
public class SomeController {
@RequestMapping(
"/two/index")
public String RegisterHandler(){
return "two";
}
@RequestMapping(
"/one/index")
public String RegisterHandler2(){
return "one";
}
}

Spring Boot 中使用 Servlet#

  在Spring Boot使用 Servlet,根据 Servlet 注册方式的不同,有两种使用方式。若使用的是Servlet3.0+版本,则两种方式均可使用;若使用的是Servlet2.5版本,则只能使用配置类方式。

注解方式#

  若使用 Servlet3.0+ 版本,可以使用注解方式,分两步。

  1. 在定义好的 Servlet 上使用 @WebServlet 注解
  2. 在入口类上添加 @ServletComponentScan 注解

cybServlet.java#

package com.cyb.webdemo.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name = "/cyb")
public class cybServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().println(
"hello spring boot servlet!");
}
}

入口类#

WebdemoApplication

 

实现#

 

配置类方式#

  若使用的是 Servlet2.5 版本,没有 Servlet 注解,此时只能使用配置类方式。其总步骤有两步,无需再入口类上添加 @ServletComponentScan 注解

定义 Servlet#

package com.cyb.webdemo.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class SomeServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().println(
"servlet");
}
}

定义配置类#

package com.cyb.webdemo.servlet;

import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration //表示其为配置类,相当于 applicationContext.xml 文件
public class MyApplicationContext {
@Bean
//表示该方法返回的对象即为 Spring 容器中的 Bean,方法名随意
public ServletRegistrationBean<SomeServlet> getServletBean(){
// 创建 Servlet
SomeServlet someServlet=new SomeServlet();
// 注册 Servlet
return new ServletRegistrationBean<SomeServlet>(someServlet,"/cyb");
}
}

实现#

 

 Spring Boot 中使用 Filter#

  在Spring Boot中使用Filter前面的使用Servlet 相似,根据 Filter 注册方式的不同,有两种使用方式。若使用的是Servlet3.0+版本,则两种方式均可使用;若使用的是Servlet2.5版本,则只能使用配置类方式

注解方式#

  若使用的是Servlet3.0+版本,可以直接使用 Filter 的注解对 Filter 进行注册。有两步

  1. 在定义好的 Filter 上使用 @WebFilter 注解
  2. 在入口类添加 @ServletComponentScan 注解

 

SomeFilter.java#

package com.cyb.webdemo.file;

import javax.servlet.;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(
"/
")
public class SomeFilter implements Filter {

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> init(FilterConfig filterConfig) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> ServletException {

}

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> doFilter(ServletRequest request, ServletResponse response, FilterChain chain) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> IOException, ServletException {
    System.out.println(</span>"信息已被过滤"<span style="color: rgba(0, 0, 0, 1)">);
    chain.doFilter(request,response);
}

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> destroy() {

}

}

修改入口类#

package com.cyb.webdemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@SpringBootApplication
@EnableTransactionManagement //开启事务
@EnableCaching //开启缓存
@ServletComponentScan("com.cyb.webdemo.file") //注意是包名
public class WebdemoApplication {

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> main(String[] args) {

    SpringApplication.run(WebdemoApplication.</span><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">, args);
}

}

配置方式#

  若使用的是Servlet2.5版本,没有 Filter 注解,此时只能使用配置类方式。有两步,与 @ServletComponentScan 注解无关

定义 Filter#

package com.cyb.webdemo.file;

import javax.servlet.*;
import java.io.IOException;

public class SomeFilter implements Filter {

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> init(FilterConfig filterConfig) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> ServletException {

}

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> doFilter(ServletRequest request, ServletResponse response, FilterChain chain) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> IOException, ServletException {
    System.out.println(</span>"信息已被过滤"<span style="color: rgba(0, 0, 0, 1)">);
    chain.doFilter(request, response);
}

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> destroy() {

}

}

修改配置类#

package com.cyb.webdemo.file;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyFilter {
@Bean
public FilterRegistrationBean<SomeFilter> getFilterBean(){
FilterRegistrationBean
<SomeFilter> registrationBean=new FilterRegistrationBean<SomeFilter>(new SomeFilter());
registrationBean.addUrlPatterns(
"/*");
return registrationBean;
}
}

Thymeleaf#

  Thymeleaf,百里香叶。Thymeleaf 是一个流行的模板引擎,该模板引擎采用 Java 语言开发。模板引擎为了使用户界面与业务数据 (内容) 分离而产生,它可以生成特定格式的文档。例如,用于网站的模板引擎就会生成一个标准的 HTML 文档。不同的语言体系中都有自己的模板引擎,例如,Java 中常见的模板引擎有 Velocity、Freemaker、Thymeleaf 等。不同的模板引擎都会具有自己的特定的标签体系,而 Thymeleaf 以 HTML 标签为载体,在 HTML 的标签下实现对数据的展示。

  Thymeleaf 本身与 Spring Boot 没有关系,但Spring Boot 官方推荐使用 Thymeleaf 作为前端页面的数据展示技术,Spring Boot 很好地集成了这种模板技术。

  官网:https://www.thymeleaf.org/

Spring Boot 集成 Thymeleaf#

创建项目#

配置文件#

application.properties

处理器#

 

index.html#

  在页面的<html> 标签中添加 Thymeleaf 的命名空间属性:

<html lang="en" xmlns:th="https://www.thymeleaf.org/">

 

实现#

 

Thymeleaf 标准表达式#

  常用的 Thymeleaf标准表达式有三种。标准表达式都是用于获取代码中存放到Model中的属性值,只不过获取方式不同罢了

变量表达式:${...}#

  使用${...}的表达式,称为变量表达式。该表达式的内容会显示在 HTML标签体文本处

  该表达式一般都是通过 th:text 标签属性进行展示的。

实体类 (Po)#

 

处理器#

 

index.html#

方式一,直接使用实体类属性

 

方式二:使用实体类 get 方法获取值

 

  注:两种获取值的方式效果都是一样的。

实现#

 

选择表达式:*{...}#

  选择表达式,也称为星号表达式。一般用于展示对象的属性。该表达式的内容会显示在 HTML 标签体文本处。但其需要与 th:object 标签属性联用,先使用 th:object 标签选择了对象,再使用 *{...} 选择要展示的对象属性。该表达式可以有效降低页面中代码的冗余

  也可以不与 th:object 联用,在 *{...} 中直接使用“对象. 属性”方式,这种写法与变量表达式相同

  该表达式一般都是通过 th:text 标签属性进行展示

index.html 修改#

 

实现#

 

URL 表达式:@{...}#

  其中只能写一个绝对 URL 或相对 URL 地址的表达式,称为 URL 表达式。这个绝对 / 相对 URL 地址中一般包含有动态参数的需要结合变量表达式 ${...} 进行字符串拼接

  @{...} 中的 URL 地址有 3 种写法。

以 Http 协议开头的绝对地址#

  在进行字符串拼接时使用“+”连接,容易出错。但使用双竖线则无需字符串拼接,简单易读。但是,在 idea 中的问号会报错,不影响程序运行,可能是 idea 的 bug 吧。

index.html#

 

查看网页源码#

 

以 / 开头的相对地址#

  在 URL 表达式中,Thymeleaf 会将 / 解析为当前工程的上下文路径 ContextPath,而浏览器会自动为其添加 "http:// 主机名: 端口号",即为一个绝对路径

 

不以 / 开头的相对地址#

 

  查看页面源码可以看到解析结果是没有添加任何东西的,没有上下文路径,其实相对于当前请求路径的一个绝对地址。

自行学习#

  授人以鱼不如授人以渔,其他具体的使用用法,请参照官网 API:https://www.thymeleaf.org/documentation.html