ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

springboot随记速查

2021-11-08 22:04:01  阅读:172  来源: 互联网

标签:springboot 配置文件 Spring 配置 Boot spring 速查 日志 随记


springboot随记

参考自http://c.biancheng.net/spring_boot/

文章目录

父项目依赖管理

<!--SpringBoot父项目依赖管理,spring-boot-starter-parent是所有Spring Boot项目的父级依赖,它被称为 Spring Boot 的版本仲裁中心,可以对项目内的部分常用依赖进行统一管理。-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.5</version>
        <relativePath/>
    </parent>
在该项目中执行以下 mvn 命令查看器依赖树。
mvn dependency:tree

YAML

YAML语法:https://www.runoob.com/w3cnote/yaml-intro.html

Spring Boot配置绑定

把配置文件中指定的配置封装到 JavaBean(实体类)

SpringBoot 提供了以下 2 种方式进行配置绑定:

  • 使用 @ConfigurationProperties 注解:可以将全局配置文件中的配置数据绑定到 JavaBean 中
  • 使用 @Value 注解:只需要读取配置文件中的某一个配置时,可以通过 @Value 注解获取

例如:

@ConfigurationProperties

标注在 JavaBean 的类名上;支持松散绑定(松散语法)

//将类中的所有属性和配置文件进行绑定;prefix=":配置文件中哪个下面的所有属性进行一一映射
@ConfigurationProperties(prefix = "person")
@Component//注解来添加组件到容器中
public class Person {...}
@Controller
public class HelloController {
    @Autowired//自动装配,在浏览器中展示配置文件中各个属性值
    private Person person;
    @ResponseBody
    @RequestMapping("/hello")
    public Person hello(){
        return person;}
}
@Value:

标注在 JavaBean 的属性上。不支持松散绑定

@Component
public class Person {
    @Value("${person.lastName}")
    private String lastName;
    ...
  • @ConfigurationProperties:支持所有类型数据的封装,例如 Map、List、Set、以及对象等;
  • @Value:只支持基本数据类型的封装,例如字符串、布尔值、整数等类型。
@PropertySource

通常会将与 Spring Boot 无关的配置(例如自定义配置)提取出来,写在一个单独的配置文件中,并在对应的 JavaBean 上使用 @PropertySource 注解指向该配置文件

@PropertySource(value = "classpath:person.properties")//指向配置文件,person.properties
@Component
@ConfigurationProperties(prefix = "person")
public class Person {...

Spring Boot导入Spring配置

默认下,Spring Boot 中是不包含任何的 Spring 配置文件,Spring Boot 提供了 2 种方式来导入 Spring 配置:

  • 使用 @ImportResource 注解加载 Spring 配置文件
  • 使用全注解方式加载 Spring 配置
@ImportResource

主启动类上使用 @ImportResource 注解可以导入一个或多个 Spring 配置文件

@ImportResource(locations = {"classpath:/beans.xml"})//将beans.xml 加载到项目中
@SpringBootApplication
public class HelloworldApplication {
<!--beans.xml-->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"   ......>
  <bean id="persionService" class="net.biancheng.www.service.impl.PersonServiceImpl">  	 </bean> //IOC中注册personService
</beans>
@Configuration 与 @Bean

@Configuration :注解定义配置类,替换 Spring 的配置文件,注解方式加载 Spring 配置。

@Bean:配置类内可含有一个或多个 @Bean 注解的方法,这些方法会被 AnnotationConfigApplicationContext

或 AnnotationConfigWebApplicationContext 类扫描,构建 bean 定义。

(相当于 Spring 配置文件中的标签),方法的返回值会以组件的形式添加到ioc中,组件的 id 就是方法名。

/**
* @Configuration 注解用于定义一个配置类,相当于 Spring 的配置文件,配置类中包含一个或多个被 @Bean 注解的方法,该方法相当于 Spring 配置文件中的 <bean> 标签定义的组件。
*/
@Configuration
public class Config {
    /**
     * 与 <bean id="personService" class="PersonServiceImpl"></bean> 等价
     * 该方法返回值以组件的形式添加到容器中,方法名是组件 id(相当于 <bean> 标签的属性 id)
     */
    @Bean
    public PersonService personService() {
        System.out.println("在容器中添加了一个组件:peronService");
        return new PersonServiceImpl();}
}

Spring Boot Profile(多环境配置)

一个项目通常会存在多个环境,Profile为在不同环境下使用不同的配置提供支持,可以通过激活、指定参数等方式快速切换环境。

#通过文件名的命名形式区分出不同的环境的配置,文件命名格式为:
#{profile} 一般为各个环境的名称或简称,例如 dev、test 和 prod 等等
application-{profile}.properties/yml
  • application.properties:主配置文件
  • application-dev.properties:开发环境配置文件
  • application-test.properties:测试环境配置文件
  • application.prod-properties:生产环境配置文件
#properties文件
#在applcation.properties文件中,指定默认服务器端口号,并通过以下配置激活生产环境的 profile。
server.port=8080
#激活指定的profile
spring.profiles.active=prod
#applcation.yml 文件
#默认配置
server:
  port: 8080
#切换配置
spring:
  profiles:
    active: dev #激活开发环境配置

applcation.yml 文件:YAML 配置文件中,可以使用 “—” 把配置文件分割成了多个文档块,可以在不同的文档块中针对不同的环境进行不同的配置,并在第一个文档块内对配置进行切换。

#默认配置
server:
  port: 8080
#切换配置
spring:
  profiles:
    active: test
---
#开发环境
server:
  port: 8081
spring:
  config:
    activate:
      on-profile: dev
---
#测试环境
server:
  port: 8082
spring:
  config:
    activate:
      on-profile: test

Spring Boot默认配置文件

Spring Boot 项目中可以存在多个 application.properties 或 apllication.yml。

Spring Boot 启动时会扫描以下 5 个位置的 application.properties 或 .yml 文件,并将它们作为 Spring boot 的默认配置文件。( 注:file: 指当前项目根目录;classpath: 指当前项目的类路径,即 resources 目录。)

  1. file:./config/
  2. file:./config/*/
  3. file:./
  4. classpath:/config/
  5. classpath:/

以上所有位置的配置文件都会被加载,且它们优先级依次降低,序号越小优先级越高。其次,位于相同位置的 application.properties 的优先级高于 application.yml。

Spring Boot外部配置文件

可通过如下 2 个参数,命令行指定外部配置文件的路径:

  • spring.config.location : 指定外部配置文件的路径,使用该参数指定配置文件后,会使项目默认配置文件失效,Spring Boot 将只加载指定的外部配置文件。
  • spring.config.additional-location :与 spring.config.location 不同,spring.config.additional-location 不会使项目默认的配置文件失效,使用该命令行参数添加的外部配置文件会与项目默认的配置文件共同生效,形成互补配置,且其优先级是最高的,比所有默认配置文件的优先级都高。
java -jar {JAR}  --spring.config.additional-location={外部配置文件全路径}

Spring Boot简略自动配置原理

Spring Boot 的自动配置是基于 Spring Factories 机制实现的。

Spring Boot 会自动扫描所有 Jar 包类路径下 META-INF/spring.factories 文件,并读取其中的内容,进行实例化,这种机制也是 Spring Boot Starter 的基础

spring-core 包里定义了 SpringFactoriesLoader 类,这个类会扫描所有 Jar 包类路径下的 META-INF/spring.factories 文件,并获取指定接口的配置

SpringFactoriesLoader 类中定义了两个对外的方法:

返回值方法描述
ListloadFactories(Class factoryType, @Nullable ClassLoader classLoader)静态方法;根据接口获取其实现类的实例;该方法返回的是实现类对象列表。
ListloadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader)公共静态方法;根据接口l获取其实现类的名称;该方法返回的是实现类的类名的列表

loadFactories() 方法:获取指定接口的实现类对象。

loadFactoryNames() 方法:根据接口获取其实现类类名的集合。

loadSpringFactories() 方法:读取该项目中所有 Jar 包类路径下 META-INF/spring.factories 文件的配置内容,并以 Map 集合的形式返回。

Spring Boot 自动化配置也是基于 Spring Factories 机制实现的,在 spring-boot-autoconfigure-xxx.jar 类路径下的 META-INF/spring.factories 中设置了 Spring Boot 自动配置的内容。

@SpringBootApplication

@SpringBootApplication 是一个组合元注解,其主要包含两个注解:@SpringBootConfiguration@EnableAutoConfiguration,其中 @EnableAutoConfiguration 注解是 SpringBoot 自动化配置的核心所在。

@EnableAutoConfiguration 注解用于开启 Spring Boot 的自动配置功能, 它使用 Spring 框架提供的 @Import 注解通过 AutoConfigurationImportSelector类(选择器)给容器中导入自动配置组件。

Spring Boot统一日志框架

日志框架有很多,它们可以被分为两类:日志门面(日志抽象层)和日志实现

日志分类描述举例
日志门面(日志抽象层)为 Java 日志访问提供一套标准和规范的 API 框架,其主要意义在于提供接口。JCL(Jakarta Commons Logging)、SLF4j(Simple Logging Facade for Java)、jboss-logging
日志实现日志门面的具体的实现Log4j、JUL(java.util.logging)、Log4j2、Logback

日志由一个日志门面与一个日志实现组合搭建而成,Spring Boot 选用 SLF4J + Logback 的组合来搭建日志系统

SLF4J 的使用

记录日志时不应该直接调用日志实现层的方法,而应该调用日志门面(日志抽象层)的方法

Logger logger = LoggerFactory.getLogger(HelloWorld.class);
//调用 slf4j 的 info() 方法,而非调用 logback 的方法
logger.info("Hello World");

Log4j 没有直接实现 SLF4J,当应用使用 SLF4J+Log4j 的组合记录日志时,不但需要引入 SLF4J 和 Log4j 的 Jar 包,还必须引入它们之间的适配层(Adaptation layer)slf4j-log4j12.jarsss,它既要实现 SLF4J 的方法,还有调用 Log4j 的方法,以达到承上启下的作用。

每一个日志的实现框架都有自己的配置文件。使用 slf4j 记录日志时,配置文件应该使用日志实现框架(例如 logback、log4j 和 JUL 等等)自己本身的配置文件。

通常一个完整的应用下会依赖于多种不同的框架,而且它们记录日志使用的日志框架也不尽相同,例如,**Spring Boot(slf4j+logback),Spring(commons-logging)、Hibernate(jboss-logging)**等等。

统一日志框架

统一日志框架一共需要以下 3 步 :

(使用一个替换包来替换原来的日志框架,例如 log4j-over-slf4j 替换 Log4j(Commons Logging API)、jul-to-slf4j.jar 替换 JUL(java.util.logging API))

  1. 排除应用中的原来的日志框架;
  2. 引入替换包替换被排除的日志框架;
  3. 导入 SLF4J 实现。

Spring Boot 的核心启动器 spring-boot-starter 引入了 spring-boot-starter-logging

Spring Boot 依赖关系图

spring-boot-starter-logging 的 Maven 依赖不但引入了 logback-classic (包含了日志框架 SLF4J 的实现),还引入了 log4j-to-slf4j(log4j 的替换包),jul-to-slf4j (JUL 的替换包),即 Spring Boot 已经为我们完成了统一日志框架的 3 个步骤中的 2 步。

引入了依赖了其他日志框架的第三方框架(例如 Hibernate)时,只需要把这个框架所依赖的日志框架排除,即可实现日志框架的统一。

<dependency>
    <groupId>org.apache.activemq</groupId>
    <artifactId>activemq-console</artifactId>
    <version>${activemq.version}</version>
    <exclusions>
        <exclusion>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
        </exclusion>
    </exclusions>
</dependency>
日志级别
序号日志级别说明
1trace追踪,指明程序运行轨迹。
2debug调试,实际应用中一般将其作为最低级别,而 trace 则很少使用。
3info输出重要的信息,使用较多。
4warn警告,使用较多。
5error错误信息,使用较多。
日志输出格式
序号输出格式说明
1%d{yyyy-MM-dd HH:mm:ss, SSS}日志生产时间,输出到毫秒的时间
2%-5level输出日志级别,-5 表示左对齐并且固定输出 5 个字符,如果不足在右边补 0
3%logger 或 %clogger 的名称
4%thread 或 %t输出当前线程名称
5%p日志输出格式
6%message 或 %msg 或 %m日志内容,即 logger.info(“message”)
7%n换行符
8%class 或 %C输出 Java 类名
9%file 或 %F输出文件名
10%L输出错误行号
11%method 或 %M输出方法名
12%l输出语句所在的行数, 包括类名、方法名、文件名、行数
13hostName本地机器名
14hostAddress本地 ip 地址

Spring Boot 日志默认级别为 info,日志输出内容默认包含以下元素:

  • 时间日期
  • 日志级别
  • 进程 ID
  • 分隔符:—
  • 线程名:方括号括起来(可能会截断控制台输出)
  • Logger 名称
  • 日志内容
自定义日志配置

在 Spring Boot 的配置文件 application.porperties/yml 中,可以对日志的一些默认配置进行修改,但这种方式只能修改个别的日志配置,想修改更多配置或者使用更高级的功能,则需要通过日志实现框架自己的配置文件进行配置。

日志框架配置文件
Logbacklogback-spring.xml、logback-spring.groovy、logback.xml、logback.groovy
Log4j2log4j2-spring.xml、log4j2.xml
JUL (Java Util Logging)logging.properties

日志框架的配置文件基本上被分为 2 类:

  • 普通日志配置文件,即不带 spring 标识的配置文件,例如 logback.xml;
  • 带有 spring 表示的日志配置文件,例如 logback-spring.xml。

不带 spring 标识的普通日志配置文件,放在项目的类路径下后,会跳过 Spring Boot,直接被日志框架加载。通过这些配置文件,我们就可以达到自定义日志配置的目的。

带有 spring 标识的配置文件被放在项目类路径后,不会直接被日志框架加载,而是由 Spring Boot 对它们进行解析,这样就可以使用 Spring Boot 的高级功能 Profile,实现在不同的环境中使用不同的日志配置。

Spring Boot Web 快速开发

Spring Boot 为 Spring MVC 提供了自动配置,并在 Spring MVC 默认功能的基础上添加了以下特性:

  • 引入了 ContentNegotiatingViewResolver 和 BeanNameViewResolver(视图解析器)
  • 对包括 WebJars 在内的静态资源的支持
  • 自动注册 Converter、GenericConverter 和 Formatter (转换器和格式化器)
  • 对 HttpMessageConverters 的支持(Spring MVC 中用于转换 HTTP 请求和响应的消息转换器)
  • 自动注册 MessageCodesResolver(用于定义错误代码生成规则)
  • 支持对静态首页(index.html)的访问
  • 自动使用 ConfigurableWebBindingInitializer

spring-boot-starter-web 默认替我们引入了核心启动器 spring-boot-starter,因此,当 Spring Boot 项目中的 pom.xml 引入了 spring-boot-starter-web 的依赖后,就无须在引入 spring-boot-starter 核心启动器的依赖了

Spring Boot静态资源映射

Spring Boot 默认为我们提供了 3 种静态资源映射规则:

  • WebJars 映射:它可以 Jar 形式为 Web 项目提供资源文件。
  • 默认资源映射
  • 静态首页(欢迎页)映射
WebJars 映射

Spring Boot 项目是以 Jar 包的形式进行部署的,不存在 webapp 目录。WebJars 可以将 Web 前端资源(JS,CSS 等)打成一个个的 Jar 包,然后将这些 Jar 包部署到 Maven 中央仓库中进行统一管理,当 Spring Boot 项目中需要引入 Web 前端资源时,只需要访问 WebJars 官网,找到所需资源的 pom 依赖,将其导入到项目中即可。所有通过 WebJars 引入的前端资源都存放在当前项目类路径(classpath)下的 “/META-INF/resources/webjars/” 目录中。

WebJars 的映射路径为“/webjars/”,即所有访问“/webjars/”的请求,都会去**“classpath:/META-INF/resources/webjars/”**查找 WebJars 前端资源。

<dependency>
    <groupId>org.webjars</groupId>
    <artifactId>jquery</artifactId>
    <version>3.6.0</version>
</dependency>
默认资源映射

当访问项目中的任意资源(即“/**”)时,Spring Boot 会默认从以下路径中查找资源文件(优先级依次降低):

  1. classpath:/META-INF/resources/
  2. classpath:/resources/
  3. classpath:/static/
  4. classpath:/public/
静态首页(欢迎页)映射

静态资源文件夹下的所有 index.html 被称为静态首页或者欢迎页,它们会被被 /** 映射,换句话说就是,当我们访问“/”或者“/index.html”时,都会跳转到静态首页(欢迎页)。

访问静态首页或欢迎页时,其查找顺序也遵循默认静态资源的查找顺序,直到找到 index.html 为止。

Spring Boot定制Spring MVC

Spring Boot 对 Spring MVC 的自动配置可以满足我们的大部分需求,但是我们也可以通过自定义配置类(标注 @Configuration 的类)并实现 WebMvcConfigurer 接口来定制 Spring MVC 配置,例如拦截器、格式化程序、视图控制器等等。

WebMvcConfigurer 是一个基于 Java 8 的接口,该接口定义了许多与 Spring MVC 相关的方法,其中大部分方法都是 default 类型的,且都是空实现。因此我们只需要定义一个配置类实现 WebMvcConfigurer 接口,并重写相应的方法便可以定制 Spring MVC 的配置。

在 Spring Boot 项目中,我们可以通过以下 2 中形式定制 Spring MVC:

  • 扩展 Spring MVC
  • 全面接管 Spring MVC
扩展 Spring MVC
//实现WebMvcConfigurer接口可以来扩展 SpringMVC 的功能
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
    //重写 addViewControllers() 方法
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        //当访问 “/” 或 “/index.html” 时,都直接跳转到登陆页面
        registry.addViewController("/").setViewName("login");
        registry.addViewController("/index.html").setViewName("login");
    }
}
/*启动 Spring Boot,会发现“http://localhost:8080/login”、“http://localhost:8080/”
“http://localhost:8080/index.html” 3个URL都能跳转到登陆页 login.html  */
全面接管 Spring MVC

在特殊情况下,可能需要抛弃 Spring Boot 对 Spring MVC 的全部自动配置,完全接管 Spring MVC。此时我们可以自定义一个 WebMvcConfigurer 类型(实现 WebMvcConfigurer 接口)的配置类,并在该类上标注 @EnableWebMvc 注解,来实现完全接管 Spring MVC。(Spring Boot 对 Spring MVC 的自动配置将全部失效)

//实现 WebMvcConfigurer 接口可以来扩展 SpringMVC 的功能
@EnableWebMvc  // 完全接管SpringMVC,配置类上标注 @EnableWebMvc
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {...}

Spring Boot整合Thymeleaf

Thymeleaf 是一款用于渲染 XML/XHTML/HTML5 内容的模板引擎。特点:即使不启动 Web 应用,也可以直接在浏览器中打开并正确显示模板页面 。

Thymeleaf 支持 HTML 原型,其文件后缀为“.html”,因此可直接被浏览器打开,此时浏览器会忽略未定义的 Thymeleaf 标签属性,展示 thymeleaf 模板静态页面效果;当通过 Web 应用程序访问时,Thymeleaf 会动态地替换掉静态内容,使页面动态显示。

<!--Thymeleaf 通过在 html 标签中,增加额外属性来达到“模板+数据”的展示方式-->
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--th:text 为 Thymeleaf 属性,用于在展示文本-->
<h1 th:text="迎您来到Thymeleaf">欢迎您访问静态页面 HTML</h1>
</body>
</html>
欢迎您访问静态页面HTML   //当直接使用浏览器打开
迎您来到Thymeleaf	   //当通过 Web 应用程序访问

Thymeleaf 模板引擎具有以下特点:

  • 动静结合:Thymeleaf 既可以直接使用浏览器打开,查看页面的静态效果,也可以通过 Web 应用程序进行访问,查看动态页面效果。
  • 开箱即用:Thymeleaf 提供了 Spring 标准方言以及一个与 SpringMVC 完美集成的可选模块,可以快速的实现表单绑定、属性编辑器、国际化等功能。
  • 多方言支持:它提供了 Thymeleaf 标准和 Spring 标准两种方言,可以直接套用模板实现 JSTL、 OGNL 表达式;必要时,开发人员也可以扩展和创建自定义的方言。
  • 与 SpringBoot 完美整合:SpringBoot 为 Thymeleaf 提供了的默认配置,并且还为 Thymeleaf 设置了视图解析器,因此 Thymeleaf 可以与 Spring Boot 完美整合。

Spring Boot 整合 Thymeleaf 模板引擎,需要以下步骤:

  1. 引入 Starter 依赖:spring-boot-starter-thymeleaf
  2. 创建模板文件,并放在在指定目录下

Thymeleaf 模板的默认位置在 resources/templates 目录下,默认的后缀是 html,即只要将 HTML 页面放在“classpath:/templates/”下,Thymeleaf 就能自动进行渲染。

<!--创建hello.html页面,并将该页面放在项目类路径(resources)下的templates目录中-->
<!DOCTYPE html>
<!--导入thymeleaf的名称空间-->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--th:text 为 Thymeleaf 属性,用于获取指定属性的值-->
<h1 th:text="'欢迎来到'+${name}"></h1>
</body>
</html>
@Controller
public class HelloController {
    @RequestMapping("/hello")
    public String hello(Map<String, Object> map) {
        //通过 map 向前台页面传递数据
        map.put("name", "koma_zhe页面");
        return "hello";
    }
}
//使用浏览器访问“http://localhost:8080/hello,出现欢迎来到koma_zhe页面

Spring Boot国际化(i18n)

在 Spring 项目中实现国际化,通常需要以下 3 步:

  1. 编写国际化资源(配置)文件
  2. 使用 ResourceBundleMessageSource 管理国际化资源文件
  3. 在页面获取国际化内容
编写国际化资源(配置)文件

在 Spring Boot 的类路径下创建国际化资源文件,文件名格式为:基本名_ 语言代码_国家或地区代码。

例如在 src/main/resources 下创建一个 i18n 的目录,并在该目录中按照国际化资源文件命名格式分别创建以下三个文件:

  • login.properties:无语言设置时生效
  • login_en_US.properties :英语时生效
  • login_zh_CN.properties:中文时生效

img

打开任意一个国际化资源文件,并切换为 Resource Bundle 模式,然后点击“+”号,创建所需的国际化属性。

国际化配置文件

使用 ResourceBundleMessageSource 管理国际化资源文件

Spring Boot 已经对 ResourceBundleMessageSource 提供了默认的自动配置。 Spring Boot 默认会获取类路径下的 message.properties 以及 message_XXX.properties 作为国际化资源文件。

Spring Boot拦截器

在 Spring Boot 项目中,使用拦截器功能通常需要以下 3 步:

  1. 定义拦截器;
  2. 注册拦截器;
  3. 指定拦截规则(如果是拦截所有,静态资源也会被拦截)。
定义拦截器

只需要创建一个拦截器类,并实现 HandlerInterceptor 接口,HandlerInterceptor 接口中定义以下 3 个方法

返回值类型方法声明描述
booleanpreHandle(HttpServletRequest request, HttpServletResponse response, Object handler)该方法在控制器处理请求方法前执行,其返回值表示是否中断后续操作,返回 true 表示继续向下执行,返回 false 表示中断后续操作。
voidpostHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)该方法在控制器处理请求方法调用之后、解析视图之前执行,可以通过此方法对请求域中的模型和视图做进一步修改。
voidafterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)该方法在视图渲染结束后执行,可以通过此方法实现资源清理、记录日志信息等工作。

例如:创建一个名为 LoginInterceptor 的拦截器类,对登陆进行拦截:

@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
    /**
     * 目标方法执行前
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Object loginUser = request.getSession().getAttribute("loginUser");
        if (loginUser == null) {
            //未登录,返回登陆页
            request.setAttribute("msg", "您没有权限进行此操作,请先登陆!");
            request.getRequestDispatcher("/index.html").forward(request, response);
            return false;
        } else {
            return true;//放行
        }
    }
    /**
     * 目标方法执行后
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("postHandle执行{}", modelAndView);
    }
    
    /**
     * 页面渲染后
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("afterCompletion执行异常{}", ex);
    }
}
注册拦截器

创建一个实现了 WebMvcConfigurer 接口的配置类(使用了 @Configuration 注解的类),重写 addInterceptors() 方法,并在该方法中调用 registry.addInterceptor() 方法将自定义的拦截器注册到容器中。

在配置类 MyMvcConfig 中,添加以下方法注册拦截器:

@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
    ......
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor());
    }
}
指定拦截规则

在使用 registry.addInterceptor() 方法将拦截器注册到容器中后,我们便可以继续指定拦截器的拦截规则

@Slf4j
@Configuration
public class MyConfig implements WebMvcConfigurer {
    ......
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        log.info("注册拦截器");
        
        registry.addInterceptor(new LoginInterceptor())
            	.addPathPatterns("/**") //拦截所有请求,包括静态资源文件
            	.excludePathPatterns("/", "/login", "/index.html", "/user/login", "/css/**", "/images/**", "/js/**", "/fonts/**"); //放行登录页,登陆操作,静态资源
    }
}
  • addPathPatterns:该方法指定拦截路径,例拦截路径为“/**”,表示拦截所有请求,包括对静态资源的请求。
  • excludePathPatterns:该方法用于排除拦截路径,即指定不需要被拦截器拦截的请求。

Spring Boot异常处理

默认异常处理机制

对于浏览器客户端而言,Spring Boot 会响应一个“ whitelabel”错误视图,以 HTML 格式呈现错误信息,对于机器客户端而言,Spring Boot 将生成 JSON 响应,来展示异常消息。

自定义异常处理

我们可以通过以下 3 种方式定制 Spring Boot 错误页面:

  • 自定义 error.html
  • 自定义动态错误页面
  • 自定义静态错误页面

自定义 error.html:直接在模板引擎文件夹(/resources/templates)下创建 error.html ,覆盖 Spring Boot 默认的错误视图页面(Whitelabel Error Page)。

自定义动态错误页面:如果 Sprng Boot 项目使用了模板引擎,当程序发生异常时,Spring Boot 的默认错误视图解析器(DefaultErrorViewResolver)就会解析模板引擎文件夹(resources/templates/)下 error 目录中的错误视图页面。还可以使用 4xx.html 和 5xx.html 作为动态错误页面的文件名(模糊匹配)

自定义静态错误页面: Sprng Boot 项目没有使用模板引擎,当程序发生异常时,Spring Boot 的默认错误视图解析器(DefaultErrorViewResolver)则会解析静态资源文件夹下 error 目录中的静态错误页面。

错误页面优先级

以上方式均可以定制 Spring Boot 错误页面,且它们的优先级顺序为:自定义动态错误页面(精确匹配)>自定义静态错误页面(精确匹配)>自定义动态错误页面(模糊匹配)>自定义静态错误页面(模糊匹配)>自定义 error.html。

定制 Spring Boot 的错误数据

@ControllerAdvice 注解的类可以用来实现全局异常处理,这是 Spring MVC 中提供的功能,在 Spring Boot 中可以直接使用

//自定义异常
public class UserNotExistException extends RuntimeException {
    public UserNotExistException() {
        super("用户不存在!");
    }
}
@Controller
public class IndexController {
    ......
    @GetMapping(value = {"/testException"})
    public String testException(String user) {
        if ("user".equals(user)) {
            throw new UserNotExistException();//触发 UserNotExistException 异常
        }
        //跳转到登录页 login.html
        return "login";
    }
}
//MyExceptionHandler 异常处理类
@ControllerAdvice
public class MyExceptionHandler {
    @ExceptionHandler(UserNotExistException.class)
    public String handleException(Exception e, HttpServletRequest request) {
        Map<String, Object> map = new HashMap<>();
        //向 request 对象传入错误状态码
        request.setAttribute("javax.servlet.error.status_code",500);
        //根据当前处理的异常,自定义的错误数据
        map.put("code", "user.notexist");
        map.put("message", e.getMessage());
        //将自定的错误数据传入 request 域中
        request.setAttribute("ext",map);
        return "forward:/error";
    }
}

Spring Boot注册Web原生组件(Servlet、Filter、Listener)

Spring Boot 默认以 Jar 包方式部署的,默认没有 web.xml,因此无法再像以前一样通过 web.xml 配置来使用 Servlet 、Filter、Listener,但 Spring Boot 提供了 2 种方式来注册这些 Web 原生组件。

  • 通过组件扫描注册

  • 使用 RegistrationBean 注册

通过组件扫描注册

Servlet 3.0 提供了以下 3 个注解:

  • @WebServlet:用于声明一个 Servlet;
  • @WebFilter:用于声明一个 Filter;
  • @WebListener:用于声明一个 Listener。

在 SpringBoot 中注册这些原生 Web 组件,可以使用 @ServletComponentScan 注解实现 ( 只能标记在启动类或配置类上),该注解可以扫描标记 @WebServlet、@WebFilter 和 @WebListener 三个注解的组件类,并将它们注册到容器中。

//使用 @WebServlet 注解声明一个 Servlet
@WebServlet(name = "myServlet", urlPatterns = "/myServlet")
public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws 							 ServletException, IOException {
        doPost(req, resp);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws 							  ServletException, IOException {
        resp.setContentType("text/html;charset=UTF-8");
        PrintWriter writer = resp.getWriter();
        writer.write("Spring Boot Servlet");
        writer.close();
    }
}
//使用 @WebFilter注解声明一个自定义的 Filter
@WebFilter(urlPatterns = ("/myServlet"))
public class MyFiler implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("MyFiler 初始化");
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("MyFiler doFilter");
        chain.doFilter(request, response);
    }
    @Override
    public void destroy() {
        System.out.println("MyFiler 销毁");
    }
}
//使用 @WebListener 注解声明一个自定义的 Listener
@WebListener
public class MyListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("MyListener 监听到 ServletContext 初始化");
    }
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("MyListener 监听到 ServletContext 销毁");
    }
}
使用 RegistrationBean 注册

还可以在配置类中使用 RegistrationBean 来注册原生 Web 组件,不过这种方式相较于注解方式要繁琐一些。使用这种方式注册的原生 Web 组件,不再需要使用 @WebServlet 、@WebListener 和 @WebListener 等注解。

RegistrationBean 是个抽象类,负责将组件注册到 Servlet 容器中,Spring 提供了三个它的实现类,分别用来注册 Servlet、Filter 和 Listener。

  • ServletRegistrationBean:Servlet 的注册类
  • FilterRegistrationBean:Filter 的注册类
  • ServletListenerRegistrationBean:Listener 的注册类

Spring Boot JDBC访问数据库

无论是 SQL 还是 NOSQL,Spring Boot 都默认采用整合 Spring Data 的方式进行统一处理。

导入 JDBC 场景启动器

导入 JDBC 场景启动器:spring-boot-starter-data-jdbc,该场景启动器默认引入了一个数据源:HikariCP

导入数据库驱动

Spring Boot 默认为数据库驱动程序做了版本仲裁,所以我们在导入数据库驱动时,可以不再声明版本。

配置数据源

在配置文件(application.properties/yml)中配置数据源

#数据源连接信息
spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/xxxx
    driver-class-name: com.mysql.cj.jdbc.Driver

Spring Boot 提供了一个名为 JdbcTemplate 的轻量级数据访问工具,它是对 JDBC 的封装。Spring Boot 对 JdbcTemplate 提供了默认自动配置,我们可以直接使用 @Autowired 或构造函数将它注入到 bean 中使用。

@SpringBootTest
class SpringBootJdbcApplicationTests {
    @Autowired
    DataSource dataSource;//数据源组件
    @Autowired
    JdbcTemplate jdbcTemplate; //用于访问数据库的组件
    @Test
    void contextLoads() throws SQLException {
        //class com.zaxxer.hikari.HikariDataSource
 		sout("默认数据源为:"+dataSource.getClass());
        sout("数据库连接实例:" + dataSource.getConnection());
        //访问数据库
        Integer i = jdbcTemplate.queryForObject("SELECT count(*) from `user`", 														Integer.class);
        sout("user 表中共有" + i + "条数据。");
    }
}

Spring Boot 数据源自动配置原理:

  • 在用户没有配置数据源的情况,若容器中存在 HikariDataSource 类,则 Spring Boot 就会自动实例化 Hikari,并将其作为其数据源。
  • Spring Boot 的 JDBC 场景启动器(spring-boot-starter-data-jdbc)通过 spring- boot-starter-jdbc 默认引入了 HikariCP 数据源(包含 HikariDataSource 类),因此 Spring Boot 默认使用 HikariCP 作为其数据源。

Spring Boot整合Druid数据源

Spring Boot 2.x 默认使用 HikariCP 作为数据源,我们只要在项目中导入了 Spring Boot 的 JDBC 场景启动器,便可以使用 HikariCP 数据源获取数据库连接,对数据库进行增删改查等操作。

Druid 是一款高性能数据源产品,支持所有 JDBC 兼容的数据库,包括 Oracle、MySQL、SQL Server 和 H2 等等。结合了 C3P0、DBCP 和 PROXOOL 等数据源产品的优点,还加入了强大的监控功能。通过 Druid 的监控功能,可以实时观察数据库连接池和 SQL 的运行情况。Druid 不是 Spring Boot 内部提供的技术,它属于第三方技术,我们可以通过以下两种方式进行整合:

  • 自定义整合 Druid
  • 通过 starter 整合 Druid
引入 Druid 依赖
<!--导入 JDBC 场景启动器-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<!--导入数据库驱动-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
<!--采用自定义方式整合 druid 数据源-->
<!--自定义整合需要编写一个与之相关的配置类-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.6</version>
</dependency>

Spring Boot 使用 HikariCP 作为其默认数据源,但其中有一个十分重要的条件

img

//创建一个名为 MyDataSourceConfig 的配置类,并将Druid数据源对象添加到容器
@Configuration
public class MyDataSourceConfig implements WebMvcConfigurer {
    /**
     * 当向容器中添加了 Druid 数据源
     * 使用@ConfigurationProperties 将配置文件中spring.datasource开头的配置与数据源中的属	   性进行绑定
     * @return
     */
    @ConfigurationPropserties("spring.datasource")
    @Bean
    public DataSource dataSource() throws SQLException {
        DruidDataSource druidDataSource = new DruidDataSource();
        return druidDataSource;
    }
}
@SpringBootTest
class SpringBootAdminexApplicationTests {
    //数据源组件
    @Autowired
    DataSource dataSource;
    //用于访问数据库的组件
    @Autowired
    JdbcTemplate jdbcTemplate;
    @Test
    void contextLoads() throws SQLException {
        //class com.alibaba.druid.pool.DruidDataSource
        sout("默认数据源为:" + dataSource.getClass());
        sout("数据库连接实例:" + dataSource.getConnection());
        //访问数据库
        Integer i = jdbcTemplate.queryForObject("SELECT count(*) from `user`", Integer.class);
        sout("user 表中共有" + i + "条数据。");
    }

开启 Druid 内置监控页面

Druid 内置提供了一个名为 StatViewServlet 的 Servlet,这个 Servlet 可以开启 Druid 的内置监控页面功能, 展示 Druid 的统计信息,它的主要用途如下:

  • 提供监控信息展示的 html 页面
  • 提供监控信息的 JSON API
开启 SQL 监控、开启防火墙、开启 Web-JDBC 关联监控
通过 starter 整合 Druid

在 Spring Boot 项目中,轻松地整合 Druid 的数据库连接池和监控功能。

Druid Spring Boot Starter 已经将 Druid 数据源中的所有模块都进行默认配置,我们也可以通过 Spring Boot 配置文件(application.properties/yml)来修改 Druid 各个模块的配置,否则将使用默认配置。

在 Spring Boot 配置文件中配置以下内容:

  • JDBC 通用配置
  • Druid 数据源连接池配置
  • Druid 监控配置
  • Druid 内置 Filter 配置
######### JDBC 通用配置 ####### 
spring:
  datasource:
    username: root                                                                   
    password: root                                                                   
    url: jdbc:mysql://127.0.0.1:3306/bianchengbang_jdbc                              
    driver-class-name: com.mysql.cj.jdbc.Driver
    
######### Druid连接池的配置 ######
spring:
  datasource:
    druid:
      initial-size: 5		#初始化连接大小
      min-idle: 5           #最小连接池数量
      max-active: 20        #最大连接池数量
      max-wait: 60000       #获取连接时最大等待时间,单位毫秒
      #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
      time-between-eviction-runs-millis: 60000
      #配置一个连接在池中最小生存的时间,单位是毫秒
      min-evictable-idle-time-millis: 300000                                         
      validation-query: SELECT 1 FROM DUAL 	#测试连接                                   
      test-while-idle: true    #申请连接的时候检测,建议配置为true,不影响性能,并且保证安全性 
      test-on-borrow: false    #获取连接时执行检测,建议关闭,影响性能                       
      test-on-return: false    #归还连接时执行检测,建议关闭,影响性能                       
      #是否开启PSCache,PSCache对支持游标的数据库性能提升巨大,oracle建议开启,mysql下建议关闭
      pool-prepared-statements: false                                                 
      #开启poolPreparedStatements后生效
      max-pool-prepared-statement-per-connection-size: 20                             
      #配置扩展插件,常用的插件有=>stat:监控统计  wall:防御sql注入
      filters: stat,wall             
      #通过connectProperties属性来打开mergeSql功能;慢SQL记录
      connection-properties: 'druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000'

######## Druid 监控配置信息  #############
spring:
  datasource:
    druid:
      # StatViewServlet配置,说明请参考Druid Wiki,配置_StatViewServlet配置
      stat-view-servlet:
        #是否开启内置监控页面,默认值为 false
        enabled: true     
        #StatViewServlet 的映射路径,即内置监控页面的访问地址
        url-pattern: '/druid/*'                                                       
         #是否启用重置按钮
        reset-enable: true                                                           
        #内置监控页面的登录页用户名 username
        login-username: admin                                                         
        #内置监控页面的登录页密码 password
        login-password: admin                                                         
      #WebStatFilter配置,说明请参考Druid Wiki,配置_配置WebStatFilter
      web-stat-filter:
      	#是否开启内置监控中的 Web-jdbc 关联监控的数据
        enabled: true                                                                 
        #匹配路径
        url-pattern: '/*'                                                             
        #排除路径
        exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*'                     
        #是否监控session
        session-stat-enable: true                                                     
      #Spring监控配置,说明请参考Druid Github Wiki,配置_Druid和Spring关联监控配置
      #Spring监控AOP切入点,如x.y.z.abc.*,配置多个英文逗号分隔
      aop-patterns: net.biancheng.www.*                                               

自定义整合还是通过 Druid Spring Boot Starter 整合,都能实现 Spring Boot 整合 Druid 数据源的目的,它们都各有利弊。

  • 根据官方文档,自定义整合 Druid 数据源能够更加清晰地了解 Druid 的各种功能及其实现方式,但整合过程繁琐。

  • 通过 Druid Spring Boot Starter 整合 Druid 数据源,则更加方便快捷,大大简化了整合过程,但无法清晰地了解 Druid 的功能内部的实现方式和原理。

Spring Boot整合MyBatis

starter:mybatis-spring-boot-starter

######## MyBatis 配置########
mybatis:
  #指定mapper.xml的位置
  mapper-locations: classpath:mybatis/mapper/*.xml
  #扫描实体类的位置,在此处指明扫描实体类的包,在 mapper.xml 中就可以不写实体类的全路径名
  type-aliases-package: com.xxx.bean
  configuration:
    #默认开启驼峰命名法,可以不用设置该属性
    map-underscore-to-camel-case: true  
创建 Mapper 接口
@Mapper
public interface UserMapper {
    //通过用户名密码查询用户数据
    User getByUserNameAndPassword(User user);
}
//当mapper接口较多时,我们可以在Spring Boot主启动类上使用@MapperScan注解扫描指定包下的mapper接口,而不再需要在每个mapper接口上都标注@Mapper注解。
创建 Mapper 映射文件
<!--在mybatis.mapper-locations 指定的位置中创建 UserMapper.xml-->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="xxxx对应上面mapper的路径xxx.UserMapper">
    <resultMap id="BaseResultMap" type="User">
        <id column="id" jdbcType="INTEGER" property="id"/>
        <result column="user_id" jdbcType="VARCHAR" property="userId"/>
        <result column="user_name" jdbcType="VARCHAR" property="userName"/>
        <result column="password" jdbcType="VARCHAR" property="password"/>
        <result column="email" jdbcType="VARCHAR" property="email"/>
    </resultMap>
    <sql id="Base_Column_List">
        id, user_id, user_name, password, email
    </sql>
    <!--根据用户名密码查询用户信息-->
    <!--application.yml 中通过 type-aliases-package 指定了实体类的为了,因此resultType-->
    <select id="getByUserNameAndPassword" resultType="User">
        select *
        from user
        where user_name = #{userName,jdbcType=VARCHAR}
          and password = #{password,jdbcType=VARCHAR}
    </select>
</mapper>

使用 Mapper 进行开发时,需要遵循以下规则:

  • mapper 映射文件中 namespace 必须与对应的 mapper 接口的完全限定名一致。
  • mapper 映射文件中 statement 的 id 必须与 mapper 接口中的方法的方法名一致
  • mapper 映射文件中 statement 的 parameterType 指定的类型必须与 mapper 接口中方法的参数类型一致。
  • mapper 映射文件中 statement 的 resultType 指定的类型必须与 mapper 接口中方法的返回值类型一致。

使用:

public interface UserService {
    public User getByUserNameAndPassword(User user);
}
@Service("userService")
public class UserServiceImpl implements UserService {
    @Autowired
    UserMapper userMapper;
    @Override
    public User getByUserNameAndPassword(User user) {
        User loginUser = userMapper.getByUserNameAndPassword(user);
        return loginUser;
    }
}
注解方式

MyBatis 针对实际实际业务中使用最多的“增伤改查”操作,分别提供了以下注解来替换 mapper 映射文件,简化配置:

  • @Select
  • @Insert
  • @Update
  • @Delete
@Mapper
public interface UserMapper {
    @Select("select * from user where user_name = #{userName,jdbcType=VARCHAR} and password = #{password,jdbcType=VARCHAR}")
    List<User> getByUserNameAndPassword(User user);
    
    @Delete("delete from user where id = #{id,jdbcType=INTEGER}")
    int deleteByPrimaryKey(Integer id);
    
    @Insert("insert into user ( user_id, user_name, password, email)" +
            "values ( #{userId,jdbcType=VARCHAR}, #{userName,jdbcType=VARCHAR}, #{password,jdbcType=VARCHAR}, #{email,jdbcType=VARCHAR})")
    int insert(User record);
    
    @Update(" update user" +
            "    set user_id = #{userId,jdbcType=VARCHAR},\n" +
            "      user_name = #{userName,jdbcType=VARCHAR},\n" +
            "      password = #{password,jdbcType=VARCHAR},\n" +
            "      email = #{email,jdbcType=VARCHAR}\n" +
            "    where id = #{id,jdbcType=INTEGER}")
    int updateByPrimaryKey(User record);
}

这两种方式则可以混合使用,可以根据 SQL 的复杂程度,选择不同的方式来提高开发效率。

  • 如果没有复杂的连接查询,可以使用注解的方式来简化配置;
  • 如果涉及 sql 较为复杂时,则使用 XML (mapper 映射文件)的方式更好

标签:springboot,配置文件,Spring,配置,Boot,spring,速查,日志,随记
来源: https://blog.csdn.net/qq_44033208/article/details/121217355

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有