SpringBoot教程——检视阅读

参考

SpringBoot教程——一点——蓝本——springboot2.1.1

SpringBoot教程——易百——springboo2.0.5.RELEASE

SpringBoot教程——w3c——springboot1.3.3.RELEASE

SpringBoot教程——C语言网——springboot2.1.6

SpringBoot教程博客——纯洁的微笑

SpringBoot教程——javaschool

SpringBoot官网

Spring Boot参考指南——翻译

SpringBoot教程汇总——博客项目索引

SpringBoot教程汇总——博客项目中文索引

Spring Boot 基础——IBM

SpringBoot教程——极客——杂乱讲不好——springboo2.1.5.RELEASE

SpringBoot教程——jc2182——参考——springboo2.3.0.BUILD-SNAPSHOT

  • 基于Spring Boot框架:Spring Boot 2.1.11.RELEASE

略读

一点

基于spring的知识点基础上讲springboot,只说了最简单的使用和常用的与其他框架如redis、mybatis的整合。缺点是没有对springboot与spring原来的细节对比。

C语言中午网

讲得比较详细,有深入到springboot最重要的两点COC和spring-boot-starter 自动配置依赖模块常用的操作,以及springboot与dubbo构建微服务的操作。

W3C

不是很好,学习起来操作不够清晰。

javaschool

只有这个好点

spring-boot-starter 起步依赖模块枚举

SpringBoot2.02官方参考指南

没翻译完,质量一般,还不如直接看官网

易百

仔细讲解了springboot里的一些使用,还结合了些springcloud的东西,但比较少说与其他框架如redis、mybatis的整合。总体来说这个教程并不好,有点杂乱无章。

IBM

最简单的hello world。

Spring Boot starter 参考页面  :列出了其他许多 starter。

spring-boot-starter-web。基于这个 starter,Spring Boot 形成了该应用程序的以下依赖:

  • 使用 Tomcat 作为嵌入式 Web 服务器容器
  • 使用 Hibernate 进行对象-关系映射 (ORM)
  • 使用 Apache Jackson 绑定 JSON
  • 使用 Spring MVC 作为 REST 框架

如果我们不想用tomcat,可以更改 POM 来使用 Jetty 代替 Tomcat。如果不想用hibernate,改用mybatis,也可以这样操作。

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-web</artifactId>
  5. <exclusions>
  6. <exclusion>
  7. <groupId>org.springframework.boot</groupId>
  8. <artifactId>spring-boot-starter-tomcat</artifactId>
  9. </exclusion>
  10. </exclusions>
  11. </dependency>
  12. <dependency>
  13. <groupId>org.springframework.boot</groupId>
  14. <artifactId>spring-boot-starter-jetty</artifactId>
  15. </dependency>
  16. </dependencies>

Spring Boot基础入门

什么是Spring Boot

Spring Boot概述

Spring Boot 是所有基于 Spring Framework 5.0 开发的项目的起点。Spring Boot 的设计是为了让你尽可能快的跑起来 Spring 应用程序并且尽可能减少你的配置文件。

简化了使用Spring的难度,简省了繁重的配置,提供了各种启动器,开发者能快速上手。

Spring Boot的优点

  • 使用 Spring 项目引导页面可以在几秒构建一个项目
  • 方便对外输出各种形式的服务,如 REST API、WebSocket、Web、Streaming、Tasks
  • 非常简洁的安全策略集成
  • 支持关系数据库和非关系数据库
  • 支持运行期内嵌容器,如 Tomcat、Jetty
  • 强大的开发包,支持热启动
  • 自动管理依赖自带应用监控
  • 支持各种 IDE,如 IntelliJ IDEA 、NetBeans

Spring Boot核心功能

起步依赖

起步依赖本质上是一个Maven项目对象模型(Project Object Model,POM),定义了对其他库的传递依赖,这些东西加在一起即支持某项功能。

自动配置

Spring Boot的自动配置是一个运行时(更准确地说,是应用程序启动时)的过程,考虑了众多因素,才决定Spring配置应该用哪个,不该用哪个。该过程是Spring自动完成的。

Spring Boot快速入门

步骤:

  1. 创建一个普通的maven项目。
  2. pom.xml导入起步依赖 。
  3. 编写引导类

示例:

pom.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <modelVersion>4.0.0</modelVersion>
  6. <groupId>com.self</groupId>
  7. <artifactId>hellospringboot</artifactId>
  8. <version>1.0-SNAPSHOT</version>
  9. <!-- 导入springboot父工程. 注意:任何的SpringBoot工程都必须有的!!! -->
  10. <!-- 父工程的作用:锁定起步的依赖的版本号,并没有真正到依赖 -->
  11. <parent>
  12. <groupId>org.springframework.boot</groupId>
  13. <artifactId>spring-boot-starter-parent</artifactId>
  14. <version>2.1.11.RELEASE</version>
  15. </parent>
  16. <dependencies>
  17. <!--web起步依赖-->
  18. <dependency>
  19. <groupId>org.springframework.boot</groupId>
  20. <artifactId>spring-boot-starter-web</artifactId>
  21. </dependency>
  22. </dependencies>
  23. </project>

引导类,或者说叫启动类

  1. @SpringBootApplication
  2. public class MyBootApplication {
  3. public static void main(String[] args) {
  4. SpringApplication.run(MyBootApplication.class,args);
  5. }
  6. }
  7. @Controller
  8. public class HelloController {
  9. @RequestMapping("/hello")
  10. @ResponseBody
  11. public String sayHello(){
  12. return "Hello Spring Boot!";
  13. }
  14. }

请求:http://localhost:8080/hello

输出:

Spring Boot配置文件

Spring Boot的核心是自动配置(或者叫默认配置),通过自动配置大大减少Spring项目的配置编写。但是在实际开发中,我们仍然需要根据需求来适当修改某些必要的参数配置,这时Spring Boot提供了两种格式的配置方便开发者进行修改。

  • applicaiton*.properties
  • application.yml(或者application.yaml)

application*.properties

Spring Boot使用了一个全局的配置文件application.properties,放在src/main/resources目录下或者src/main/resources/config下。在 src/main/resources/config 下的优先级高 。Sping Boot的全局配置文件的作用是对一些默认配置的配置值进行修改。

Spring Boot内置属性

示例:

编写修改Tomcat端口属性 :

application.properties

  1. server.port=9000

Spring Boot内置属性参考

自定义属性

application.properties

  1. server.port=9000
  2. #自定义类型
  3. #基本类型
  4. name=Amy
  5. age=21
  6. #JavaBean类型
  7. user.name=Amy
  8. user.age=21
  9. #数组/List集合
  10. user.list=Amy,Jack,Roy
  11. #或者
  12. user.list[0]=Amy
  13. user.list[1]=Jack
  14. user.list[2]=Roy
  15. #Map集合
  16. user.map={name:"Amy",age:21}
  17. #或者
  18. user.map.name=Amy
  19. user.map.age=21

自定义配置怎么取值使用,什么场景使用?

Profile多环境配置

当应用程序需要部署到不同运行环境时,一些配置细节通常会有所不同,最简单的比如日志,生产日志会将日志级别设置为WARN或更高级别,并将日志写入日志文件,而开发的时候需要日志级别为DEBUG,日志输出到控制台即可。如果按照以前的做法,就是每次发布的时候替换掉配置文件,这样太麻烦了,Spring Boot的Profile就给我们提供了解决方案,命令带上参数就搞定。

步骤:

  • 建立不同环境的application.properties文件
  • 每个文件里面的环境配置变量不同

示例:

application.properties

  1. #启用prod生产环境
  2. spring.profiles.active= prod
  3. #当profiles不同环境变量文件里有配置值时,application.properties里配置的变量是会被启用的环境如application-prod.properties里的值所覆盖的。
  4. server.port=9000

application-prod.properties

  1. server.port=9004

输出:

application*.yml

YAML(/ˈjæməl/,尾音类似camel骆驼)是一个可读性高,用来表达数据序列化的格式。

yml或yaml所表示的YAML Ain’t Markup Language,YAML是一种简洁的非标记语言,文件名后缀为yml,java中经常用它描述配置文件application.yml。YAML以数据为中心,比json/xml等更适合做配置文件。使用空白,缩进,分行组织数据,从而使得表示更加简洁易读。

在yml之前使用最多的配置文件形式是xml和properties文件。xml文件太过繁琐,看过的人都知道,想要新加一个配置节点的话还需要包含在<>标签里;而properties配置文件没有了标签,不过当你的配置有很多层级的时候,写完之后你会发现会有大量重复的代码。而yml/yaml文件结合了两者的优势,当你新增节点配置的时候,不需要标签,在写多层级配置的时候也不会产生重复代码。

yml格式书写规则

  1. 大小写敏感
  2. 使用缩进表示层级关系
  3. 禁止使用tab缩进,只能使用空格键
  4. 缩进长度没有限制,只要元素对齐就表示这些元素属于一个层级。
  5. 使用#表示注释
  6. 字符串可以不用引号标注

Spring Boot内置属性

注意:

当application.properties和application.yml同时存在时,生效的是application.properties。

  1. #yml文件在写时有提示,友好,优先选择使用
  2. #修改端口
  3. server:
  4. port: 9090
  5. #基本类型 注意:属性值大小写敏感
  6. name: Bruce Wayne
  7. age: 29
  8. #JavaBean类型
  9. user:
  10. name: Bruce Wayne
  11. age: 29
  12. #数组/List集合
  13. #user:层级只能指定一个,后面的如果是在user层级下的只需要tab空格就可以了,再写user层级则会报错
  14. #user:
  15. list: eric,jack,rose
  16. #下面这种写法用@Value注解解析不了
  17. list:
  18. - Jack
  19. - Rose
  20. - Jerry
  21. #Map集合
  22. #user:
  23. #yml语法格式要求key如map: 后面对应的value值必需在冒号:后面空格,否则格式错误
  24. map: {name: Bruce Wayne,age: 29}

Profile多环境配置

application.yml

  1. #启用test测试环境
  2. #当profiles不同环境变量文件里有配置值时,application.yml里配置的变量是会被启用的环境如application-test.yml里的值所覆盖的。
  3. #还有一点需要特别注意的是当存在application-test.properties与application-test.yml两个并行时,生效的是application-test.properties
  4. spring:
  5. profiles:
  6. active: test

application-test.yml

  1. server:
  2. port: 9092

Spring Boot读取配置文件(properties和yml处理是一样的)

Spring Boot里面有两个注解可以读取application.properties或application.yml文件的属性值。

  1. @Value
  2. @ConfigurationProperties

注意:

1、不能配置user.name=Amy属性配置,因为取不到Amy的值,取到的是计算机的用户名,在这台电脑里我的用户名是Castamere。应该是个系统默认保留的取值配置,这里没有深入去研究。

2、不能配置userName=Amy这个key为userName或者username的基本类型配置,否则取到的是还是计算机的用户名。

@Value

基本类型

application.yml

  1. #基本类型
  2. firstName: Bruce Wayne1111
  3. age: 29

读取:

  1. @Controller
  2. public class ConfigController {
  3. @Value("${firstName}")
  4. private String name;
  5. @Value("${age}")
  6. private Integer age;
  7. @RequestMapping("/show")
  8. @ResponseBody
  9. public String showConfig() {
  10. return name + " : " + age;
  11. }
  12. }

JavaBean类型

  1. #JavaBean类型
  2. user:
  3. first: Bruce Wayne
  4. age: 31

读取:

  1. @Controller
  2. public class ConfigController {
  3. @Value("${user.firstName}")
  4. private String firstName;
  5. @Value("${user.age}")
  6. private Integer age;
  7. @RequestMapping("/show")
  8. @ResponseBody
  9. public String showConfig() {
  10. return firstName + " : " + age;
  11. }
  12. }

数组/List集合

  1. user:
  2. list: Jack,Rose,Jerry

读取:

  1. @Value("#{'${user.list}'.split(',')}")
  2. private List<String> list;
  3. @RequestMapping("/show")
  4. @ResponseBody
  5. public String showConfig() {
  6. return JSON.toJSONString(list);
  7. }

Map集合

  1. user:
  2. #yml语法格式要求key如map: 后面对应的value值必需在冒号:后面空格,否则格式错误
  3. #读取的时候要加引号""是给@Value注解用的么?
  4. # map: {nickname: erci,age: 20}
  5. map: "{name: 'SuperMan',age: 28}"

读取:

  1. @Value("#{${user.map}}")
  2. private Map<String,Object> map;
  3. @RequestMapping("/show")
  4. @ResponseBody
  5. public String showConfig() {
  6. return JSON.toJSONString(map);
  7. }

注意,不加引号会报错.

  1. #报错:Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'user.map' in value "#{${user.map}}"
  2. user:
  3. map: {name: 'SuperMan',age: 28}

@ConfigurationProperties

注意以下几点:

  • prefix:代表属性的前缀,如果user.nickname前缀就是user

  • 属性名称必须和properties文件的属性名保持一致

  • 属性必须提供setter方法来注入文件的属性值

    firstName: Bruce Wayne
    age: 30

读取:

  1. @Controller
  2. @ConfigurationProperties
  3. public class ConfigurationController {
  4. private String firstName;
  5. private Integer age;
  6. public void setFirstName(String firstName) {
  7. this.firstName = firstName;
  8. }
  9. public void setAge(Integer age) {
  10. this.age = age;
  11. }
  12. @RequestMapping("/show")
  13. @ResponseBody
  14. public String showConfig() {
  15. return firstName + " : " + age;
  16. }
  17. }

输出:

  1. //成功
  2. Bruce Wayne : 30
  3. //没有setter方法来注入文件的属性值,不会报错,但是没有赋值
  4. null : null

JavaBean类型

  1. #JavaBean类型
  2. user:
  3. firstName: Bruce
  4. age: 31

读取:

  1. @Controller
  2. //两种配置方式都可以
  3. @ConfigurationProperties("user")
  4. //@ConfigurationProperties(prefix = "user")
  5. public class ConfigurationController {
  6. private String firstName;
  7. private Integer age;
  8. public void setFirstName(String firstName) {
  9. this.firstName = firstName;
  10. }
  11. public void setAge(Integer age) {
  12. this.age = age;
  13. }
  14. @RequestMapping("/show")
  15. @ResponseBody
  16. public String showConfig() {
  17. return firstName + " : " + age;
  18. //return JSON.toJSONString(list);
  19. //return JSON.toJSONString(map);
  20. }
  21. }
  22. Bruce : 31

数组/List集合

  1. #数组/List集合
  2. #user:层级只能指定一个,后面的如果是在user层级下的只需要tab空格就可以了,再写user层级则会报错
  3. #user:
  4. #两种list表达方式都可以,倾下第一种
  5. list: Jack,Rose,Jerry
  6. list2:
  7. - Jack
  8. - Morty
  9. - Jerry

读取:

  1. @Controller
  2. //两种配置方式都可以
  3. @ConfigurationProperties("user")
  4. //@ConfigurationProperties(prefix = "user")
  5. public class ConfigurationController {
  6. private List<String> list;
  7. public void setList(List<String> list) {
  8. this.list = list;
  9. }
  10. @RequestMapping("/show")
  11. @ResponseBody
  12. public String showConfig() {
  13. return JSON.toJSONString(list);
  14. }
  15. }

Map集合

  1. #Map集合
  2. #yml语法格式要求key如map: 后面对应的value值必需在冒号:后面空格,否则格式错误
  3. #读取的时候要加引号""是给@Value注解用的么?@ConfigurationProperties("user")读取map不需要加引号,否则报错,说明两种读取方式不同
  4. #报错:Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'user.map' in value "#{${user.map}}"
  5. map: {name: 'SuperMan',age: 28}
  6. # map: "{name: 'SuperMan',age: 28}"

读取:

  1. @Controller
  2. //两种配置方式都可以
  3. @ConfigurationProperties("user")
  4. //@ConfigurationProperties(prefix = "user")
  5. public class ConfigurationController {
  6. private Map<String,Object> map;
  7. public void setMap(Map<String, Object> map) {
  8. this.map = map;
  9. }
  10. @RequestMapping("/show")
  11. @ResponseBody
  12. public String showConfig() {
  13. return JSON.toJSONString(map);
  14. }
  15. }
  16. {"name":"SuperMan","age":28}

Spring Boot热部署

什么是热部署

无法热部署的缺点:

  • 在实际开发过程中,每次修改代码就得将项目重启,重新部署,对于一些大型应用来说,重启时间需要花费大量的时间成本。
  • 程序员开发过程中重启缓慢影响开发。在 Java 开发领域,热部署一直是一个难以解决的问题,目前的 Java 虚拟机只能实现方法体的修改热部署,对于整个类的结构修改,仍然需要重启虚拟机,对类重新加载才能完成更新操作。

热部署原理

深层原理是使用了两个ClassLoader,一个Classloader加载那些不会改变的类(第三方Jar包),另一个ClassLoader加载会更改的类,称为restart ClassLoader,这样在有代码更改的时候,原来的restart ClassLoader 被丢弃,重新创建一个restart ClassLoader,由于需要加载的类相比较少,所以实现了较快的重启时间。

Spring Boot热部署实现方式

Spring Boot有3种热部署方式:

  1. 使用springloaded配置pom.xml文件,使用mvn spring-boot:run启动
  2. 使用springloaded本地加载启动,配置jvm参数
  3. 使用devtools工具包,操作简单,但是每次需要重新部署

Spring Boot使用devtools工具包实现热部署

需要说明以下4点:

  1. devtools可以实现页面热部署(即页面修改后会立即生效,这个可以直接在application.properties文件中配置spring.thymeleaf.cache=false来实现)
  2. 实现类文件热部署(类文件修改后不会立即生效,过会儿生效)
  3. 实现对属性文件的热部署。即devtools会监听classpath下的文件变动,并且会立即重启应用(发生在保存的时候)。这里可能有疑问,为什么还要重启?这样就不是热部署啦!注意:因为其采用的虚拟机机制,该项重启比正常重启会快非常多!
  4. scope配置为true,在修改java文件后就立即热启动,而且会清空Session中的数据。如果有用户登陆的话,项目重启后需要重新登陆。

示例:

pom.xml添加依赖:

  1. <!--devtools热部署-->
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-devtools</artifactId>
  5. <optional>true</optional>
  6. <scope>true</scope>
  7. </dependency>

application.yml添加devtools的配置 :

  1. spring:
  2. devtools:
  3. restart:
  4. enabled: true #设置开启热部署
  5. additional-paths: src/main/java #重启目录
  6. exclude: WEB-INF/**
  7. freemarker:
  8. cache: false #页面不加载缓存,修改即时生效

修改了类文件后,IDEA不会自动编译,必须修改IDEA设置。

  1. 1
  2. File-Settings-Compiler-Build Project automatically
  3. 2
  4. ctrl + shift + alt + / ,选择Registry,勾上 Compiler autoMake allow when app running

Spring Boot访问静态资源

Spring Boot默认静态资源目录

在Spring Boot应用启动过程中,会读取加载一个静态资源文件加载路径这个属性

  1. # 默认值为
  2. spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/

这个属性的默认值代表静态资源扫描目录:

  1. classpath:/META-INF/resources/
  2. classpath:/resources/
  3. classpath:/static/
  4. classpath:/public/
  5. /:当前项目的根路径

这意味着我们可以只要把静态资源文件存放在以上目录,即可以被访问到!

需注意优先级问题:根据前后关系确定优先级,配置路径在前面会优先访问前面的静态资源。也就是说如果classpath:/resources/目录和classpath:/public/都有一个test.html,那么根据默认的优先级,会去访问classpath:/resources/下的资源。

示例:分别建立了public、resources、static目录,在目录下建立html静态页面。项目启动后,我们都可以直接访问这些页面 。

  1. //请求
  2. http://localhost:8080/index.html
  3. http://localhost:8080/img/test.gif
  4. http://localhost:8080/hello.html //在public和resources文件夹下都有,优先访问resources下的静态资源
  5. http://localhost:8080/success.jsp//jsp文件访问会直接下载,而不会去解析。

修改Spring Boot静态资源路径

我们可以在application.yml文件中修改静态资源路径,如:

  1. # 修改静态资源加载路径
  2. spring:
  3. resources:
  4. static-locations: classpath:/download,classpath:/static/,classpath:/public/

注意:

如果按照以上写法会覆盖Spring Boot的默认路径。如果希望保留默认路径,那就要先写上之前所有值,再最后加上新的路径。

Spring Boot进阶

Spring Boot异常处理

有5种处理方式:

  1. Spring Boot默认异常提示。
  2. 自定义error的错误页面。
  3. @ExceptionHandler注解(Controller中自定义)。
  4. @ControllerAdvice注解 加 @ExceptionHandler注解 抽取所以共用的异常处理方法。
  5. 实现HandlerExceptionResovler。

Spring Boot默认异常提示

在Spring Boot应用执行过程中难免会出现各种错误,默认情况下,只要出现异常,就会跳转到Spring Boot默认错误提示页面,如下:

为了给用户更好的体验,我们可以使用以下四种手段来优化异常捕获的情况。

自定义error的错误页面

SpringBoot应用默认已经提供一套错误处理机制:就是把所有后台错误统一交给error请求,然后跳转到了本身自己的错误提示页面。这时,我们利用springboot的错误处理机制,重新建立了一个新的error.html,该页面必须放在resources的templates目录下 。

示例:

pom.xml ——页面用到了Thymeleaf,所以项目中需要导入Thymeleaf的依赖。如果没有加依赖则页面加载失败继续调整到第一种springboot默认异常提示页面上。

error.html

  1. <head>
  2. <meta charset="UTF-8">
  3. <title th:text="${title}"></title>
  4. </head>
  5. <body>
  6. <div >
  7. <div>
  8. <div>
  9. <p><span>页面出现</span><span class="code" th:text="${status}"></span>错误,非常抱歉!</p>
  10. <a href="/" class="btn-back common-button">您可以点击返回首页</a>
  11. <div >
  12. <div th:text="${#dates.format(timestamp,'yyyy-MM-dd HH:mm:ss')}"></div>
  13. <div>错误原因:</div>
  14. <div th:text="${message}"></div>
  15. <div th:text="${error}"></div>
  16. </div>
  17. </div>
  18. </div>
  19. </div>
  20. </body>

异常展示:

@ExceptionHandler注解

  1. /**@ExceptionHandler 注解只能作用为对象的方法上,并且在运行时有效,value() 可以指定异常类。由该注解注*释的方法可以具有灵活的输入参数。
  2. */
  3. @Target({ElementType.METHOD})
  4. @Retention(RetentionPolicy.RUNTIME)
  5. @Documented
  6. public @interface ExceptionHandler {
  7. Class<? extends Throwable>[] value() default {};
  8. }

示例:

  1. @Controller
  2. public class HelloController {
  3. @Autowired
  4. private User user;
  5. @RequestMapping("/hello")
  6. @ResponseBody
  7. public String sayHello() {
  8. throw new NullPointerException();
  9. //return "Hello Spring Boot!";
  10. }
  11. @RequestMapping("/user")
  12. @ResponseBody
  13. public String helloUser() {
  14. int i = 10 / 0;
  15. return JSON.toJSONString(user);
  16. }
  17. // 处理java.lang.ArithmeticException
  18. @ExceptionHandler(ArithmeticException.class)
  19. @ResponseBody
  20. public String handlerArithmeticException(Exception e) {
  21. return "数学运算错误:" + e.getMessage();
  22. }
  23. // 处理java.lang.NullPointerException
  24. @ExceptionHandler(value = {NullPointerException.class})
  25. @ResponseBody
  26. public String handlerNullPointerException(Exception e) {
  27. // e:该对象包含错误信息
  28. return "空指针错误:" + e;
  29. }
  30. }

输出:

@ControllerAdvice注解

刚才的@ExceptionHandler注解是用在控制器类里面的,这样每个控制器都需要定义相关方法,比较繁琐。这时可以使用@ControllerAdvice来抽取所有共同的@ExceptionHandler方法,从而简化异常方法的定义。

注意:

当业务Controller有自己的@ExceptionHandler注解处理方法时,生效的是Controller上的异常处理方法,@ControllerAdvice里的不会生效。

示例:

  1. @ControllerAdvice
  2. public class CommonExceptionHandler {
  3. // 处理java.lang.ArithmeticException
  4. @ExceptionHandler(ArithmeticException.class)
  5. @ResponseBody
  6. public String handlerArithmeticException(Exception e) {
  7. return "数学运算错误1:" + e.getMessage();
  8. }
  9. // 处理java.lang.NullPointerException
  10. @ExceptionHandler(value = {NullPointerException.class})
  11. @ResponseBody
  12. public String handlerNullPointerException(Exception e) {
  13. // e:该对象包含错误信息
  14. return "空指针错误1:" + e;
  15. }
  16. }

输出:

HandlerExceptionResovler

注意:

异常处理优先级顺序:Controller层异常 > @ControllerAdvice > HandlerExceptionResovler

示例:

  1. @Configuration
  2. public class CommonHandlerExceptionResolver implements HandlerExceptionResolver {
  3. @Override
  4. public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
  5. ModelAndView mv = new ModelAndView();
  6. //判断不同异常类型,做不同处理
  7. if(e instanceof ArithmeticException){
  8. mv.setViewName("error1");
  9. }
  10. if(e instanceof NullPointerException){
  11. mv.setViewName("error2");
  12. }
  13. mv.addObject("error", e.toString());
  14. return mv;
  15. }
  16. }

输出:

Spring Boot表单数据验证

在Spring Boot中我们经常需要对表单数据进行合法性验证。下面讲解如何在Spring Boot中进行表单验证。

更多校验规则参考Spring,两者是一样的。

示例:

pom.xml

  1. <dependencies>
  2. <!--web起步依赖-->
  3. <dependency>
  4. <groupId>org.springframework.boot</groupId>
  5. <artifactId>spring-boot-starter-web</artifactId>
  6. </dependency>
  7. <!-- 导入thymeleaf坐标 -->
  8. <dependency>
  9. <groupId>org.springframework.boot</groupId>
  10. <artifactId>spring-boot-starter-thymeleaf</artifactId>
  11. </dependency>
  12. </dependencies>

Pojo,添加验证注解

  1. public class User {
  2. private Integer id;
  3. @NotEmpty(message = "姓名不能为空")
  4. private String name;
  5. @Min(1)
  6. private Integer age;
  7. @Email(message = "邮箱地址不正确")
  8. private String email;
  9. @NotEmpty(message = "描述不能为空")
  10. @Length(min = 5, max = 100, message = "描述必须在5-100个字之间")
  11. private String desc;
  12. //...}
  13. @Controller
  14. @RequestMapping("/user")
  15. public class UserController {
  16. /**
  17. * 跳转到add.html
  18. * @return
  19. */
  20. @RequestMapping("/toAdd")
  21. public String toAdd() {
  22. return "add";
  23. }
  24. /**
  25. * 用户添加
  26. * BindingResult: 用于封装验证对象(user)里面的验证结果
  27. */
  28. @RequestMapping("/add")
  29. public String add(@Valid User user, BindingResult result) {
  30. if (result.hasErrors()) {
  31. return "add";
  32. }
  33. //save
  34. System.out.println("保存用户:" + JSON.toJSONString(user));
  35. return "success";
  36. }
  37. }

设计页面,回显错误信息

add.html

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>用户添加</title>
  6. </head>
  7. <body>
  8. <h3>用户添加</h3>
  9. <form action="/user/add" method="post">
  10. 用户名:<input type="text" name="name"/><font color="red" th:errors="${user.name}"></font><br/>
  11. 描述:<input type="text" name="desc"/><font color="red" th:errors="${user.desc}"></font><br/>
  12. 年龄:<input type="text" name="age"/><font color="red" th:errors="${user.age}"></font><br/>
  13. 邮箱:<input type="text" name="email"/><font color="red" th:errors="${user.email}"></font><br/>
  14. <input type="submit" value="保存"/>
  15. </form>
  16. </body>
  17. </html>

success.html

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>提示页面</title>
  6. </head>
  7. <body>
  8. 保存成功
  9. </body>
  10. </html>
  11. 保存用户:{"age":25,"desc":"黄金脑殿下","email":"roy@inc.com","name":"艾米"}

Spring Boot文件上传

示例:

\resources\static\upload.html——在静态资源文件夹下这样我们就可以直接访问静态资源。

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>文件上传页面</title>
  6. </head>
  7. <body>
  8. 文件上传页面
  9. <hr/>
  10. <form action="/upload" method="post" enctype="multipart/form-data">
  11. 请选择文件:<input type="file" name="fileName"/><br/>
  12. <input type="submit" value="开始上传"/>
  13. </form>
  14. </body>
  15. </html>
  16. @Controller
  17. public class UploadController {
  18. @RequestMapping("/upload")
  19. public String upload(MultipartFile fileName, HttpServletRequest request){
  20. //处理文件
  21. System.out.println("文件原名称:"+fileName.getOriginalFilename());
  22. System.out.println("文件类型:"+fileName.getContentType());
  23. String upload = UploadController.class.getResource("/").getFile()+"/upload";
  24. File file = new File(upload);
  25. if (!file.exists()) {
  26. file.mkdir();
  27. }
  28. //目标文件传入地址路径+名称
  29. try {
  30. fileName.transferTo(new File(upload + "/" + fileName.getOriginalFilename()));
  31. } catch (IOException e) {
  32. e.printStackTrace();
  33. }
  34. return "success";
  35. }
  36. }

Spring Boot文件下载

示例:

\resources\static\download.html

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>文件下载</title>
  6. </head>
  7. <body>
  8. <h3>文件下载</h3>
  9. <a href="/download">下载</a>
  10. </body>
  11. </html>
  12. @Controller
  13. public class DownloadController {
  14. @RequestMapping("/download")
  15. public void download(HttpServletResponse response) throws IOException {
  16. InputStream inputStream = new FileInputStream(DownloadController.class.getResource("/").getFile()+"/static/img/test.gif");
  17. //2.输出文件
  18. //设置响应头
  19. response.setHeader("Content-Disposition","attachment;filename=export.gif");
  20. OutputStream outputStream = response.getOutputStream();
  21. byte[] buff = new byte[1024];
  22. int lenth = 0;
  23. while ((lenth= inputStream.read(buff))!= -1){
  24. outputStream.write(buff,0,lenth);
  25. }
  26. //3.关闭资源
  27. outputStream.close();
  28. inputStream.close();
  29. }
  30. }

Spring Boot原理分析

@SpringBootApplication

首先,我从引导类开始:

  1. @SpringBootApplication
  2. public class MyBootApplication {
  3. public static void main(String[] args) {
  4. SpringApplication.run(MyBootApplication.class,args);
  5. }
  6. }

引导类代码很简单,但可以看出最关键的是@SpringBootApplication注解以及在main方法中运行的SpringAppliation.run()了,我们进去@SpringBootApplication的源码:

  1. @Target({ElementType.TYPE})
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Inherited
  5. @SpringBootConfiguration
  6. @EnableAutoConfiguration
  7. @ComponentScan(
  8. excludeFilters = {@Filter(
  9. type = FilterType.CUSTOM,
  10. classes = {TypeExcludeFilter.class}
  11. ), @Filter(
  12. type = FilterType.CUSTOM,
  13. classes = {AutoConfigurationExcludeFilter.class}
  14. )}
  15. )
  16. public @interface SpringBootApplication {
  17. ......
  18. }

我们看到@SpringBootApplication其实是一个复合的注解,它就是由@SpringBootConfiguration、@EnableAutoConfiguration以及@ComponentScan 三个注解组成,所以如果我们把SpringBoot启动类改写成如下方式,整个SpringBoot应用依然可以与之前的启动类功能一样:

  1. @SpringBootConfiguration
  2. @EnableAutoConfiguration
  3. @ComponentScan(excludeFilters = {
  4. @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
  5. @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
  6. public class MyBootApplication {
  7. public static void main(String[] args) {
  8. SpringApplication.run(MyBootApplication.class, args);
  9. }
  10. }

因为我们每次新建项目时都要写上三个注解来完成配置,这显然太繁琐了,SpringBoot就为我们提供了@SpringBootApplication这样注解来简化我们的操作。接着,我们重点分析这三个注解的作用。

@SpringBootConfiguration

我们来看@SpringBootConfiguration注解的源码:

  1. @Target({ElementType.TYPE})
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Configuration
  5. public @interface SpringBootConfiguration {
  6. }

我们可以看到,SpringBoot为了区别@Configuration而新提供的专属于SpringBoot的注解,功能其实和@Configuration一模一样。而这里的@Configuration注解对于我们来说并不陌生,它就是是个IoC容器的配置类。看到这里,我们其实可以把SpringBoot的启动类这样来看就清楚了:

  1. @Configuration
  2. @EnableAutoConfiguration
  3. @ComponentScan
  4. public class MyBootApplication {
  5. public static void main(String[] args) {
  6. SpringApplication.run(MyBootApplication.class, args);
  7. }
  8. }

启动类MyBootApplication其实就是一个标准的Spring纯注解下的启动类,也并没有什么特殊。

@EnableAutoConfiguration

看到这个注解,我们不禁联想出Spring 中很多以“@Enable”开头的注解,比如:@EnableScheduling、@EnableCaching以及@EnableMBeanExport等,@EnableAutoConfiguration注解的理念和工作原理和它们其实一脉相承。简单的来说,就是该注解借助@Import注解的支持,Spring的IoC容器收集和注册特定场景相关的Bean定义:

  • @EnableScheduling是通过@Import将Spring调度框架相关的bean都加载到IoC容器。
  • @EnableMBeanExport是通过@Import将JMX相关的bean定义加载到IoC容器。

而@EnableAutoConfiguration注解也是借助@Import将所有复合配置条件的bean定义加载到IoC容器,仅此而已!@EnableAutoConfiguration注解的源码如下:

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Inherited
  5. @AutoConfigurationPackage
  6. @Import(AutoConfigurationImportSelector.class)
  7. public @interface EnableAutoConfiguration {
  8. ...
  9. }

这其中最关键的就是@Import(AutoConfigurationImportSelector.class)了,它借助AutoConfigurationImportSelector.class可以帮助SpringBoot应用将所有符合条件的@Configuration配置类都加载到当前SpringBoot创建并使用的IoC容器,就像下图一样。

下面我们给出AutoConfigurationImportSelector.java的部分源码,来解释和验证上图:

  1. public class AutoConfigurationImportSelector
  2. implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
  3. BeanFactoryAware, EnvironmentAware, Ordered {
  4. protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
  5. return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class,
  6. this.beanClassLoader);
  7. }
  8. protected List<AutoConfigurationImportListener> getAutoConfigurationImportListeners() {
  9. return SpringFactoriesLoader.loadFactories(AutoConfigurationImportListener.class,
  10. this.beanClassLoader);
  11. }
  12. }

以上源码可以看出,@EnableAutoConfiguration正是借助SpringFactoriesLoader的支持,才能完成所有配置类的加载!

SpringFactoriesLoader

SpringFactoriesLoader属于Spring框架专属的一种扩展方案(其功能和使用方式类似于Java的SPI方案:java.util.ServiceLoader),它的主要功能就是从指定的配置文件META-INF/spring.factories中加载配置,spring.factories是一个非常经典的java properties文件,内容格式是Key=Value形式,只不过这Key以及Value都非常特殊,为Java类的完整类名(Fully Qualified Name),比如:

  1. org.springframework.context.ApplicationListener=org.springframework.boot.autoconfigure.BackgroundPreinitializer

然后Spring框架就可以根据某个类型作为Key来查找对应的类型名称列表了,SpringFactories源码如下:

  1. public abstract class SpringFactoriesLoader {
  2. private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class);
  3. public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
  4. public static <T> List<T> loadFactories(Class<T> factoryClass, ClassLoader classLoader){
  5. ...
  6. }
  7. public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
  8. ...
  9. }
  10. // ...
  11. }

对于@EnableAutoConfiguraion来说,SpringFactoriesLoader的用途和其本意稍微不同,它本意是为了提供SPI扩展,而在@EnableAutoConfiguration这个场景下,它更多的是提供了一种配置查找的功能的支持,也就是根据@EnableAutoConfiguration的完整类名org.springframework.boot.autoconfigure.EnableAutoConfiguration作为Key来获取一组对应的@Configuration类:

  1. # Auto Configure
  2. org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  3. org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
  4. org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
  5. org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
  6. org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
  7. org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
  8. org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
  9. org.springframework.boot.autoconfigure.cloud.CloudServiceConnectorsAutoConfiguration,\
  10. org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
  11. org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
  12. org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
  13. org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
  14. org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
  15. org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
  16. org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\
  17. org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\
  18. org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
  19. org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
  20. org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\
  21. org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\
  22. org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\
  23. org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\
  24. org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
  25. org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
  26. org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration,\
  27. org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
  28. org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
  29. org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
  30. org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\
  31. org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\
  32. org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
  33. org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
  34. org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
  35. org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
  36. org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
  37. org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\
  38. org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\
  39. org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\
  40. org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\
  41. org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\
  42. org.springframework.boot.autoconfigure.elasticsearch.rest.RestClientAutoConfiguration,\
  43. org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
  44. org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
  45. org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\
  46. org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\
  47. org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\
  48. org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\
  49. org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\
  50. org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration,\
  51. org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\
  52. org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\
  53. org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\
  54. org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\
  55. org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
  56. org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
  57. org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
  58. org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
  59. org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
  60. org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
  61. org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
  62. org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
  63. org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
  64. org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\
  65. org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\
  66. org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\
  67. org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
  68. org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
  69. org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\
  70. org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\
  71. org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\
  72. org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\
  73. org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
  74. org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\
  75. org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\
  76. org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\
  77. org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
  78. org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\
  79. org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
  80. org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
  81. org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\
  82. org.springframework.boot.autoconfigure.reactor.core.ReactorCoreAutoConfiguration,\
  83. org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
  84. org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
  85. org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
  86. org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\
  87. org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\
  88. org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
  89. org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
  90. org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\
  91. org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,\
  92. org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,\
  93. org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration,\
  94. org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
  95. org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration,\
  96. org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration,\
  97. org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
  98. org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\
  99. org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\
  100. org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\
  101. org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\
  102. org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\
  103. org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\
  104. org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\
  105. org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\
  106. org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\
  107. org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration,\
  108. org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\
  109. org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
  110. org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
  111. org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\
  112. org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
  113. org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\
  114. org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
  115. org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\
  116. org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\
  117. org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\
  118. org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,\
  119. org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration

在SpringBoot的autoconfigure依赖包中的META-INF文件下的spring.factories文件中,我们可以找到以上内容。

总结来说,@EnableAutoConfiguration能实现自动配置的原理就是:SpringFactoriesLoader从classpath中搜寻所有META-INF/spring.fatories文件,并将其中Key[org.springframework.boot.autoconfigure.EnableAutoConfiguration]对应的Value配置项通过反射的方式实例化为对应的标注了@Configuration的JavaConfig形式的IoC容器配置类,然后汇总到当前使用的IoC容器中。

@ComponentScan

@ComponentScan注解在Spring Boot启动的时候其实不是必需的!因为我们知道作为Spring框架里的老成员,@ComponentScan的功能就是自动扫描并加载复合条件的组件或Bean定义,最终将这些Bean定义加载到当前使用的容器中。这个过程,我们可以手工单个进行注册,不是一定要通过这个注解批量扫描和注册,所以说@ComponentScan是非必需的。

所以,如果我们当前应用没有任何Bean定义需要通过@ComponentScan加载到当前SpringBoot应用对应的IoC容器,那么,去掉@ComponentScan注解,当前的SpringBoot应用依旧可以完美运行!

Spring Boot整合其他技术

Spring Boot整合Servlet

在Spring Boot应用如何我们需要编写Servlet相关组件(包括Servlet、Filter、Listener),需要怎么做呢?Spring Boot提供了两种使用Servlet组件的方式:

  1. 使用@ServletComponentScan注解注册
  2. 使用@Bean注解注解

@ServletComponentScan

注意:在引导类类必须添加@ServletComponentScan注解,该注解用于扫描应用中Servlet相关组件。

示例:

  1. /**
  2. * 等同于web.xml配置
  3. * <servlet>
  4. * <servlet-name>helloServlet</servlet-name>
  5. * <servlet-class>com.yiidian.controller.HelloServlet</servlet-class>
  6. * </servlet>
  7. * <servlet-mapping>
  8. * <servlet-name>helloServlet</servlet-name>
  9. * <url-pattern>/helloServlet</url-pattern>
  10. * </servlet-mapping>
  11. *
  12. */
  13. // @WebServlet:声明该类为Servlet程序
  14. @WebServlet("/hi")
  15. //@WebServlet(name="helloServlet",urlPatterns="/hi")
  16. public class HelloServlet extends HttpServlet {
  17. @Override
  18. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  19. System.out.println("HelloServlet");
  20. String docType = "<!DOCTYPE html> \n";
  21. String top = "Hello SpringBoot";
  22. resp.getWriter().println(docType +
  23. "<html>\n" +
  24. "<head><title>" + top + "</title></head>\n" +
  25. "<body bgcolor=\"#f0f0f0\">\n" +
  26. "<h1 align=\"center\">" + top + "</h1>\n" +
  27. "</body></html>");
  28. }
  29. @Override
  30. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  31. doGet(req,resp);
  32. }
  33. }
  34. //表示对所有servlet都执行过滤操作
  35. //@WebFilter
  36. //表示对路径为/ 的servlet执行过滤操作
  37. //@WebFilter("/")
  38. //表示对路径为/hi 的servlet执行过滤操作,两种写法都可以
  39. @WebFilter("/hi")
  40. //@WebFilter(filterName="HiFilter",urlPatterns="/hi")
  41. //定义Filter过滤器
  42. public class HiFilter implements Filter {
  43. @Override
  44. public void init(FilterConfig filterConfig) throws ServletException {
  45. System.out.println("HiFilter init");
  46. }
  47. @Override
  48. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
  49. System.out.println("do HiFilter before");
  50. //放行执行目标servlet资源
  51. filterChain.doFilter(servletRequest,servletResponse);
  52. System.out.println("do HiFilter after");
  53. }
  54. @Override
  55. public void destroy() {
  56. System.out.println("HiFilter destroy");
  57. }
  58. }
  59. //定义Listener监听器
  60. @WebListener
  61. public class HiListener implements ServletContextListener {
  62. @Override
  63. public void contextInitialized(ServletContextEvent sce) {
  64. System.out.println("ServletContext对象创建了");
  65. }
  66. @Override
  67. public void contextDestroyed(ServletContextEvent sce) {
  68. System.out.println("ServletContext对象消耗了");
  69. }
  70. }

引导类

  1. @SpringBootApplication
  2. @ServletComponentScan //注册Servlet组件
  3. public class MyBootApplication {
  4. public static void main(String[] args) {
  5. SpringApplication.run(MyBootApplication.class,args);
  6. }
  7. }

输出:

  1. ServletContext对象创建了
  2. HiFilter init
  3. do HiFilter before
  4. HelloServlet
  5. do HiFilter after

注意:在测试时发现按照正确配置去写代码但是一直访问不成功。可能的原因有两个:

  • IDEA的问题,一直重启却识别不了@ServletComponentScan去扫描servlet,导致失败。
  • 启动类的@ServletComponentScan扫描默认是扫描与该启动类同包以及其子包下的类。

@Bean

第二种方式的代码和第一种几乎一样,就是引导类的差别,引导类改为使用@Bean注解来注解Servlet、Filter和Listener。

示例:

  1. @SpringBootApplication
  2. public class MyBeanBootApplication {
  3. public static void main(String[] args) {
  4. SpringApplication.run(MyBeanBootApplication.class,args);
  5. }
  6. //注册Servlet程序
  7. @Bean
  8. public ServletRegistrationBean getServletRegistrationBean(){
  9. ServletRegistrationBean bean = new ServletRegistrationBean(new HelloServlet());
  10. bean.addUrlMappings("/hi");
  11. return bean;
  12. }
  13. //注册Filter
  14. @Bean
  15. public FilterRegistrationBean getFilterRegistrationBean(){
  16. FilterRegistrationBean bean = new FilterRegistrationBean(new HiFilter());
  17. bean.addUrlPatterns("/hi");
  18. return bean;
  19. }
  20. //注册Listener
  21. @Bean
  22. public ServletListenerRegistrationBean getServletListenerRegistrationBean(){
  23. return new ServletListenerRegistrationBean(new HiListener());
  24. }
  25. }

注意:如果两个都配置则filter和listener会执行两遍。当使用@Bean整合Servlet时,Servlet,Filter,Listener不需要加对应的注解,因为我们在@Bean中已经把new HelloServlet()创建出来了。

Spring Boot整合JSP

示例:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <modelVersion>4.0.0</modelVersion>
  6. <groupId>com.self</groupId>
  7. <artifactId>hellospringboot</artifactId>
  8. <version>1.0-SNAPSHOT</version>
  9. <!-- 导入springboot父工程. 注意:任何的SpringBoot工程都必须有的!!! -->
  10. <!-- 父工程的作用:锁定起步的依赖的版本号,并没有真正到依赖 -->
  11. <parent>
  12. <groupId>org.springframework.boot</groupId>
  13. <artifactId>spring-boot-starter-parent</artifactId>
  14. <version>2.1.11.RELEASE</version>
  15. </parent>
  16. <dependencies>
  17. <!--web起步依赖-->
  18. <dependency>
  19. <groupId>org.springframework.boot</groupId>
  20. <artifactId>spring-boot-starter-web</artifactId>
  21. </dependency>
  22. <dependency>
  23. <groupId>com.alibaba</groupId>
  24. <artifactId>fastjson</artifactId>
  25. <version>1.2.60</version>
  26. </dependency>
  27. <!--devtools热部署-->
  28. <dependency>
  29. <groupId>org.springframework.boot</groupId>
  30. <artifactId>spring-boot-devtools</artifactId>
  31. <optional>true</optional>
  32. <scope>true</scope>
  33. </dependency>
  34. <!-- jsp依赖 -->
  35. <dependency>
  36. <groupId>javax.servlet</groupId>
  37. <artifactId>jstl</artifactId>
  38. </dependency>
  39. <dependency>
  40. <groupId>org.apache.tomcat.embed</groupId>
  41. <artifactId>tomcat-embed-jasper</artifactId>
  42. </dependency>
  43. <!-- <dependency>
  44. <groupId>org.springframework.boot</groupId>
  45. <artifactId>spring-boot-starter-tomcat</artifactId>
  46. </dependency>-->
  47. </dependencies>
  48. </project>

注意:Error resolving template [userlist], template might not exist or might not be accessible by any of the configured Template Resolvers.这是因为整合jsp就不能依赖thymeleaf。

  1. org.thymeleaf.exceptions.TemplateInputException: Error resolving template [userlist], template might not exist or might not be accessible by any of the configured Template Resolvers
  2. at org.thymeleaf.engine.TemplateManager.resolveTemplate(TemplateManager.java:869) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE]
  3. at org.thymeleaf.engine.TemplateManager.parseAndProcess(TemplateManager.java:607) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE]
  4. <!-- 导入thymeleaf坐标 整合jsp就不能依赖thymeleaf,否则会因为请求不到页面而报错-->
  5. <!-- <dependency>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-thymeleaf</artifactId>
  8. </dependency>-->

起步依赖tomcat。因为spring-boot-starter-web已经有spring-boot-starter-tomcat依赖了,如下,因此不再需要再依赖tomcat。

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-tomcat</artifactId>
  4. <version>2.1.11.RELEASE</version>
  5. <scope>compile</scope>
  6. </dependency>

扩展:

  1. pom中<scope></scope>一些理解
  2. compile:默认值,表示当前依赖包,要参与当前项目的编译,后续测试,运行时,打包
  3. provided:代表在编译和测试的时候用,运行,打包的时候不会打包进去
  4. test:表示当前依赖包只参与测试时的工作:比如Junit
  5. runtime:表示当前依赖包只参与运行周期,其他跳过了
  6. system:从参与度和provided一致,不过被依赖项不会从maven远程仓库下载,而是从本地的系统拿。需要
  7. systemPath属性来定义路径

配置application.yml

  1. #springmvc视图解析器配置
  2. spring:
  3. mvc:
  4. view:
  5. prefix: /WEB-INF/jsp/ # 前缀,注意最后的文件夹jsp后面要加斜杠/
  6. suffix: .jsp # 后缀
  7. @Controller
  8. @RequestMapping("/user")
  9. public class UserController {
  10. @RequestMapping("/list")
  11. public String list(Model model) {
  12. //模拟用户数据
  13. List<User> list = new ArrayList<User>();
  14. for (int i = 0; i < 3; i++) {
  15. User user = new User();
  16. user.setId(ThreadLocalRandom.current().nextInt());
  17. user.setAge(ThreadLocalRandom.current().nextInt(100));
  18. user.setName(UUID.randomUUID().toString());
  19. list.add(user);
  20. }
  21. //把数据存入model
  22. model.addAttribute("list", list);
  23. //跳转到jsp页面: userlist.jsp
  24. return "userlist";
  25. }
  26. }

编写userlist.jsp页面

注意:Spring Boot项目并不会到templates目录查找JSP页面,它是到/src/main/webapp目录下查找。所以我们需要创建webapp目录,然后在里面创建我们需要的目录和JSP文件。

  1. <%@ page language="java" contentType="text/html; charset=utf-8"
  2. pageEncoding="utf-8"%>
  3. <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
  4. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
  5. <html>
  6. <head>
  7. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  8. <title>用户列表展示</title>
  9. </head>
  10. <body>
  11. <h3>用户列表展示</h3>
  12. <table border="1">
  13. <tr>
  14. <th>编号</th>
  15. <th>姓名</th>
  16. <th>年龄</th>
  17. </tr>
  18. <c:forEach items="${list}" var="user">
  19. <tr>
  20. <td>${user.id}</td>
  21. <td>${user.name}</td>
  22. <td>${user.age}</td>
  23. </tr>
  24. </c:forEach>
  25. </table>
  26. </body>
  27. </html>
  28. @SpringBootApplication
  29. public class MyBootApplication {
  30. public static void main(String[] args) {
  31. SpringApplication.run(MyBootApplication.class,args);
  32. }
  33. }

修改项目运行目录,经过测试,不修改也行,估计和IDEA版本有关。

Spring Boot应用默认情况下,会到应用的classes目录下加载内容,因为JSP页面并不在classes下面,所以需要把运行目录手动改为应用的根目录下,这样才能加载到JSP页面。 如下:

请求:http://localhost:8080/user/list

输出:

报错:

如下图,是因为application.yml配置jsp页面解析器路径名称弄错。

Spring Boot整合Thymeleaf

thymeleaf怎么读?英 [taim li:f] 美 [taɪm lif] 。百里香叶。

关于模板引擎

  1. 市面上主流的 Java 模板引擎有:JSP、Velocity、Freemarker、Thymeleaf。
  2. JSP本质也是模板引擎,Spring Boot官方推荐使用“Thymeleaf”模板引擎。

模板引擎的原理

模板引擎原理图如下,模板引擎的作用都是将模板(页面)和数据进行整合然后输出显示,区别在于不同的模板使用不同的语法,如 JSP 的JSTL表达式,以及J SP 自己的表达式和语法,同理 Thymeleaf 也有自己的语法。

Spring Boot整合Thymeleaf

示例:

pom.xml导入Thymeleaf的依赖.

  1. <dependencies>
  2. <!--web起步依赖-->
  3. <dependency>
  4. <groupId>org.springframework.boot</groupId>
  5. <artifactId>spring-boot-starter-web</artifactId>
  6. </dependency>
  7. <!-- thymeleaf -->
  8. <dependency>
  9. <groupId>org.springframework.boot</groupId>
  10. <artifactId>spring-boot-starter-thymeleaf</artifactId>
  11. </dependency>
  12. </dependencies>
  13. @Controller
  14. @RequestMapping("/user")
  15. public class UserController {
  16. @RequestMapping("/thyme")
  17. public String thymeLeaf(Model model){
  18. model.addAttribute("message","thymeLeaf show");
  19. //跳转到templates/show.html
  20. return "show";
  21. }
  22. }

注意以下几点:

  • 模板文件(即页面)必须放在/resources/templates目录下,否则无法渲染。
  • Thymeleaf标签都是以th开头的。

show.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>SpringBoot整合Thymeleaf</title>
  6. </head>
  7. <body>
  8. <span th:text="${message}"></span>
  9. </body>
  10. </html>

输出:

Thymeleaf基本语法

变量输出

方法代码

  1. //变量输出
  2. @RequestMapping("/demo2")
  3. public String demo2(Model model){
  4. model.addAttribute("name", "张三");
  5. return "demo2";
  6. }

页面代码

  1. <h3>变量输出</h3>
  2. <h4 th:text="${name}"></h4>
  3. <h4 th:text="李四"></h4>

条件判断及迭代遍历、域对象使用、超链接

show.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>SpringBoot整合Thymeleaf</title>
  6. </head>
  7. <body>
  8. <span th:text="${message}"></span>
  9. <h3>条件判断</h3>
  10. <div th:if="${gender} == '男'">
  11. 这是一位男性朋友
  12. </div>
  13. <div th:if="${gender} == '女'">
  14. 这是一位女性朋友
  15. </div>
  16. <br/>
  17. <div th:switch="${grade}">
  18. <span th:case="1">这是1的情况</span>
  19. <span th:case="2">这是2的情况</span>
  20. <span th:case="3">这是3的情况</span>
  21. </div>
  22. <h3>迭代遍历</h3>
  23. <table border="1">
  24. <tr>
  25. <td>编号</td>
  26. <td>姓名</td>
  27. <td>年龄</td>
  28. </tr>
  29. <tr th:each="user : ${list}">
  30. <td th:text="${user.id}"></td>
  31. <td th:text="${user.name}"></td>
  32. <td th:text="${user.age}"></td>
  33. </tr>
  34. </table>
  35. <h3>域对象数据的获取</h3>
  36. request: <span th:text="${#httpServletRequest.getAttribute('request')}"></span><br/>
  37. session: <span th:text="${session.session}"></span><br/>
  38. application: <span th:text="${application.application}"></span><br/>
  39. <h3>超链接的语法</h3>
  40. <a th:href="@{~/user/thyme}">访问demo1</a><br/>
  41. <a th:href="@{~/user/thyme(id=1,name=eric)}">访问demo1,传递参数</a>
  42. </body>
  43. </html>
  44. @Controller
  45. @RequestMapping("/user")
  46. public class UserController {
  47. @RequestMapping("/thyme")
  48. public String thymeLeaf(Model model, HttpServletRequest request){
  49. model.addAttribute("message","thymeLeaf show");
  50. model.addAttribute("gender","男");
  51. model.addAttribute("grade",2);
  52. List<User> list = new ArrayList<User>();
  53. for (int i = 0; i < 3; i++) {
  54. User user = new User();
  55. user.setId(ThreadLocalRandom.current().nextInt());
  56. user.setAge(ThreadLocalRandom.current().nextInt(100));
  57. user.setName(UUID.randomUUID().toString());
  58. list.add(user);
  59. }
  60. //把数据存入model
  61. model.addAttribute("list", list);
  62. //request
  63. request.setAttribute("request", "request's data");
  64. //session
  65. request.getSession().setAttribute("session", "session's data");
  66. //application
  67. request.getSession().getServletContext().setAttribute("application", "application's data");
  68. //跳转到templates/show.html
  69. return "show";
  70. }
  71. }

输出:

Spring Boot整合FreeMarker

//跳过

Spring Boot整合MyBatis

前置条件:

  1. CREATE TABLE `t_user` (
  2. `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
  3. `name` varchar(64) NOT NULL COMMENT '姓名',
  4. `dept` varchar(254) NOT NULL COMMENT '部门',
  5. `phone` varchar(16) NOT NULL COMMENT '电话',
  6. `height` decimal(10,2) DEFAULT NULL COMMENT '身高',
  7. `create_emp` bigint(20) NOT NULL COMMENT '创建人',
  8. `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  9. `modify_emp` bigint(20) DEFAULT NULL COMMENT '修改人',
  10. `modify_time` datetime DEFAULT NULL COMMENT '修改时间',
  11. PRIMARY KEY (`id`),
  12. KEY `idx_name` (`name`)
  13. ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COMMENT='用户表';

示例:

pom.xml——导入mybatis和mysql驱动程序

  1. <dependencies>
  2. <!--web起步依赖-->
  3. <dependency>
  4. <groupId>org.springframework.boot</groupId>
  5. <artifactId>spring-boot-starter-web</artifactId>
  6. </dependency>
  7. <!--mybatis 起步依赖-->
  8. <dependency>
  9. <groupId>org.mybatis.spring.boot</groupId>
  10. <artifactId>mybatis-spring-boot-starter</artifactId>
  11. <version>1.1.1</version>
  12. </dependency>
  13. <!-- MySQL 连接驱动 -->
  14. <dependency>
  15. <groupId>mysql</groupId>
  16. <artifactId>mysql-connector-java</artifactId>
  17. <version>5.1.46</version>
  18. </dependency>
  19. </dependencies>

application.yml——配置数据源连接参数,及mybatis相关配置。

  1. spring
  2. datasource: #修改数据库连接配置
  3. url: jdbc:mysql://localhost:3306/hello_mybatis?characterEncoding=UTF8
  4. driver-class-name: com.mysql.jdbc.Driver
  5. username: root
  6. password: 123456
  7. # mybatis配置
  8. mybatis:
  9. type-aliases-package: com.self.pojo # 别名目录
  10. public class User {
  11. private Integer id;
  12. @NotEmpty(message = "姓名不能为空")
  13. private String name;
  14. @Min(1)
  15. private Integer age;
  16. @Email(message = "邮箱地址不正确")
  17. private String email;
  18. @NotEmpty(message = "描述不能为空")
  19. @Length(min = 5, max = 100, message = "描述必须在5-100个字之间")
  20. private String desc;
  21. /**
  22. * 部门,帝国
  23. */
  24. private String dept;
  25. /**
  26. * 联系号码
  27. */
  28. private String phone;
  29. /**
  30. * 身高
  31. */
  32. private BigDecimal height;
  33. /**
  34. * 创建人
  35. */
  36. private Long createEmp;
  37. /**
  38. * 创建时间
  39. */
  40. private Date createTime;
  41. /**
  42. * 修改人
  43. */
  44. private Long modifyEmp;
  45. /**
  46. * 修改时间
  47. */
  48. private Date modifyTime;
  49. //...
  50. }
  51. //必须给Dao接口加上@Mapper,这样Spring Boot在启动时才能扫描到Dao接口,并为其生成代理对象。
  52. @Mapper
  53. //装饰用,告诉spring这是个dao注册bean,不加@Repository的话IDEA会提示这个bean无法@Autowired自动依赖
  54. @Repository
  55. public interface UserDao {
  56. public List<User> getUsers();
  57. }

UserDao.xml——Dao映射配置,在Dao接口相同目录下建立同名的XML文件。

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  3. "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
  4. <mapper namespace="com.self.dao.UserDao">
  5. <!-- 查询所有用户 -->
  6. <select id="getUsers" resultType="User">
  7. select * from t_user where 1=1
  8. </select>
  9. </mapper>
  10. @Controller
  11. @RequestMapping("/user")
  12. public class UserController {
  13. @Autowired
  14. private UserDao userDao;
  15. @RequestMapping("/showAll")
  16. @ResponseBody
  17. public List<User> list(){
  18. //模拟用户数据
  19. List<User> list = userDao.getUsers();
  20. return list;
  21. }
  22. }

启动类不变,输出:

整合Spring Data JPA

示例:

pom.xml——添加Spring Data JPA的依赖

  1. <dependencies>
  2. <!--web起步依赖-->
  3. <dependency>
  4. <groupId>org.springframework.boot</groupId>
  5. <artifactId>spring-boot-starter-web</artifactId>
  6. </dependency>
  7. <!-- springBoot JPA 的起步依赖 -->
  8. <dependency>
  9. <groupId>org.springframework.boot</groupId>
  10. <artifactId>spring-boot-starter-data-jpa</artifactId>
  11. </dependency>
  12. <!-- MySQL 连接驱动 -->
  13. <dependency>
  14. <groupId>mysql</groupId>
  15. <artifactId>mysql-connector-java</artifactId>
  16. <version>5.1.46</version>
  17. </dependency>
  18. </dependencies>

application.yml

  1. spring:
  2. datasource: #修改数据库连接配置
  3. url: jdbc:mysql://localhost:3306/mybatis?characterEncoding=UTF8
  4. driver-class-name: com.mysql.jdbc.Driver
  5. username: root
  6. password: root
  7. # jpa配置
  8. jpa:
  9. show-sql: true #控制台输出生成的SQL语句
  10. generate-ddl: true # 自动建表

项目使用Spring Data JPA,所以在Pojo实体中必须添加Jpa的映射注解,和数据库表进行一一映射。

如果pojo字段不是一一映射,比如比数据库多了字段,则会导致执行失败。

  1. import javax.persistence.*;
  2. @Entity
  3. @Table(name="t_user")
  4. public class User {
  5. @Id
  6. @GeneratedValue(strategy = GenerationType.IDENTITY)
  7. private Integer id;
  8. @NotEmpty(message = "姓名不能为空")
  9. private String name;
  10. /**
  11. * 部门,帝国
  12. */
  13. private String dept;
  14. /**
  15. * 联系号码
  16. */
  17. private String phone;
  18. /**
  19. * 身高
  20. */
  21. private BigDecimal height;
  22. /**
  23. * 创建人
  24. */
  25. private Long createEmp;
  26. /**
  27. * 创建时间
  28. */
  29. private Date createTime;
  30. /**
  31. * 修改人
  32. */
  33. private Long modifyEmp;
  34. /**
  35. * 修改时间
  36. */
  37. private Date modifyTime;
  38. //...
  39. }

Spring Data JPA提供了两个核心接口,我们项目中一般选择继承它们:

  • JpaRepository接口:拥有CRUD,分页,排序等方法

  • JpaSpecificationExecutor接口:拥有组合条件搜索方法

    public interface UserDao extends JpaRepository<User, Integer>, JpaSpecificationExecutor {

    }

    @Controller
    @RequestMapping(“/user”)
    public class UserController {

    1. @Autowired
    2. private UserDao userDao;
    3. @RequestMapping("/showAll")
    4. @ResponseBody
    5. public List<User> list(){
    6. //模拟用户数据
    7. List<User> list = userDao.findAll();
    8. return list;
    9. }
    10. }

输出:

Spring Boot整合Redis

前提: 需要Windows启动Redis Server 。

解压redis压缩包。

打开一个 cmd 窗口 使用 cd 命令切换安装目录如 E:\redis 运行:

  1. #启动redis服务器
  2. redis-server.exe redis.windows.conf

验证redis是否启动成功,另外打开一个 cmd 窗口 使用 cd 命令切换安装目录如 E:\redis 运行:

  1. #启动redis客户端
  2. redis-cli.exe -h 127.0.0.1 -p 6379
  3. #执行命令
  4. set name mike
  5. get name

示例:

pom.xml——导入Spring Data Redis依赖!

  1. <dependencies>
  2. <!--web起步依赖-->
  3. <dependency>
  4. <groupId>org.springframework.boot</groupId>
  5. <artifactId>spring-boot-starter-web</artifactId>
  6. </dependency>
  7. <!-- 配置使用 redis 启动器 -->
  8. <dependency>
  9. <groupId>org.springframework.boot</groupId>
  10. <artifactId>spring-boot-starter-data-redis</artifactId>
  11. </dependency>
  12. </dependencies>

application.yml——Spring Boot的Redis配置

  1. #host:代表Redis服务端地址
  2. #port:Java连接Redis的端口
  3. #database:操作的Redis的数据库索引
  4. spring:
  5. redis:
  6. host: localhost # 默认localhost,需要远程服务器需要修改
  7. port: 6379 # 默认6379,如果不一致需要修改
  8. database: 0 # 代表连接的数据库索引,默认为0,

在Controller注入RedisTemplate模板对象,利用它来操作Redis数据库,这里写一个put方法,用于往Redis存入数据,一个get方法,从Redis获取数据。但需要注意的时候,如果操作的Pojo对象,该Pojo必须实现java.io.Serializable接口 。

  1. @Controller
  2. @RequestMapping("/user")
  3. public class UserController {
  4. @Autowired
  5. private RedisTemplate redisTemplate;
  6. @RequestMapping("/load")
  7. @ResponseBody
  8. public String loadUsers(){
  9. List<User> list = userDao.findAll();
  10. for (User user : list) {
  11. redisTemplate.opsForValue().set(user.getName(),user);
  12. }
  13. return "success";
  14. }
  15. @RequestMapping(value = "/get",method = RequestMethod.GET)
  16. @ResponseBody
  17. public User getUser(String name){
  18. return (User) redisTemplate.opsForValue().get(name);
  19. }
  20. }
  21. public class User implements Serializable {
  22. //...
  23. }
  24. 请求:
  25. 先缓存redis
  26. http://localhost:8080/user/load
  27. redis获取缓存数据
  28. http://localhost:8080/user/get?name=艾米哈珀

输出:

报错:Failed to serialize object using DefaultSerializer。这是因为传输对象没有实现序列号接口,无法序列号。

  1. org.springframework.data.redis.serializer.SerializationException: Cannot serialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to serialize object using DefaultSerializer; nested exception is java.lang.IllegalArgumentException: DefaultSerializer requires a Serializable payload but received an object of type [com.self.pojo.User]

Spring Boot整合EhCache

EhCache简介

EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认CacheProvider。Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存,Java EE和轻量级容器。它具有内存和磁盘存储,缓存加载器,缓存扩展,缓存异常处理程序,一个gzip缓存servlet过滤器,支持REST和SOAP api等特点。

配置ehcache.xml——参数说明

参数名 说明
name 缓存名称
maxElementsInMemory 缓存最大个数
eternal 对象是否永久有效,一但设置了,timeout将不起作用
timeToIdleSeconds 设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大
timeToLiveSeconds 设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大
overflowToDisk 当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中
diskSpoolBufferSizeMB 这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区
maxElementsOnDisk 硬盘最大缓存个数
diskPersistent 是否缓存虚拟机重启期数据
diskExpiryThreadIntervalSeconds 磁盘失效线程运行时间间隔,默认是120秒。
memoryStoreEvictionPolicy 当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)
clearOnFlush 内存数量最大时是否清除

示例:

pom.xml

  1. <!--web起步依赖-->
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-web</artifactId>
  5. </dependency>
  6. <!--springboot 集成 junit 起步依赖-->
  7. <dependency>
  8. <groupId>org.springframework.boot</groupId>
  9. <artifactId>spring-boot-starter-test</artifactId>
  10. <version>2.1.6.RELEASE</version>
  11. <scope>test</scope>
  12. </dependency>
  13. <!-- 缓存坐标 -->
  14. <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-cache -->
  15. <dependency>
  16. <groupId>org.springframework.boot</groupId>
  17. <artifactId>spring-boot-starter-cache</artifactId>
  18. <version>2.1.11.RELEASE</version>
  19. </dependency>
  20. <!-- Ehcache支持 -->
  21. <dependency>
  22. <groupId>net.sf.ehcache</groupId>
  23. <artifactId>ehcache</artifactId>
  24. <version>2.10.6</version>
  25. </dependency>

ehcache.xml

  1. <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
  2. <diskStore path="java.io.tmpdir"/>
  3. <!-- defaultCache: 默认配置 -->
  4. <defaultCache
  5. maxElementsInMemory="10000"
  6. eternal="false"
  7. timeToIdleSeconds="120"
  8. timeToLiveSeconds="120"
  9. maxElementsOnDisk="10000000"
  10. diskExpiryThreadIntervalSeconds="120"
  11. memoryStoreEvictionPolicy="LRU">
  12. <persistence strategy="localTempSwap"/>
  13. </defaultCache>
  14. <!-- 缓存名称为user的配置 -->
  15. <cache name="user"
  16. maxElementsInMemory="10000"
  17. eternal="false"
  18. timeToIdleSeconds="120"
  19. timeToLiveSeconds="120"
  20. maxElementsOnDisk="10000000"
  21. diskExpiryThreadIntervalSeconds="120"
  22. memoryStoreEvictionPolicy="LRU">
  23. <persistence strategy="localTempSwap"/>
  24. </cache>
  25. </ehcache>

application.yml

  1. #配置EhCache的配置spring:
  2. cache:
  3. ehcache:
  4. config: ehcache.xml

引导类中需要添加@EnableCaching注解,开启缓存功能 。

  1. @SpringBootApplication
  2. @EnableCaching // 开启缓存
  3. public class MyBootApplication {
  4. public static void main(String[] args) {
  5. SpringApplication.run(MyBootApplication.class,args);
  6. }
  7. }
  8. @Service
  9. public class UserService {
  10. @Cacheable(value = "user",key = "#id")
  11. public User findById(Integer id){
  12. System.out.println("执行了UserService获取User");
  13. User user = new User();
  14. user.setId(5);
  15. user.setName("林雨裳");
  16. user.setDept("艾米帝国");
  17. user.setPhone("911119");
  18. return user;
  19. }
  20. }

@Cacheable的属性:

  • value:对应ehcache.xml的缓存配置名称(name属性值)

  • key:给缓存值起个key,便于Spring内部检索不同的缓存数据。#id这个语法代表把方法形参作为key。

    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringBootTest(classes = MyBootApplication.class)
    public class EhCacheTest {

    1. @Autowired
    2. private UserService userService;
    3. @Test
    4. public void testCache(){
    5. //第一次
    6. System.out.println(JSON.toJSONString(userService.findById(5)));
    7. //第二次
    8. System.out.println(JSON.toJSONString(userService.findById(5)));
    9. }

    }

输出:

  1. 执行了UserService获取User
  2. {"dept":"艾米帝国","id":5,"name":"林雨裳","phone":"911119"}
  3. {"dept":"艾米帝国","id":5,"name":"林雨裳","phone":"911119"}

从结果可以看出,第一次调用Service的时候,到Service内部获取数据。但是第二次调用Service时已经不需要从Service获取数据,证明第一次查询的时候已经把Customer对象缓存到EhCache中。

EhCache常用注解

注解 说明
@Cacheable 主要针对方法配置,能够根据方法的请求参数对其进行缓存
@CacheConfig 统一配置本类的缓存注解的属性
@CachePut 保证方法被调用,又希望结果被缓存。与@Cacheable区别在于是否每次都调用方法,常用于更新
@CacheEvict 清空缓存

@Cacheable/@CachePut/@CacheEvict 主要的参数:

属性名 说明
value 缓存的名称,在 spring 配置文件中定义,必须指定至少一个 例如: @Cacheable(value=”mycache”) 或者 @Cacheable(value={”cache1”,”cache2”}
key 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写, 如果不指定,则缺省按照方法的所有参数进行组合 例如: @Cacheable(value=”testcache”,key=”#id”)
condition 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false, 只有为 true 才进行缓存/清除缓存 例如:@Cacheable(value=”testcache”,condition=”#userName.length()>2”)
unless 否定缓存。当条件结果为TRUE时,就不会缓存。 @Cacheable(value=”testcache”,unless=”#userName.length()>2”)
allEntries (@CacheEvict ) 是否清空所有缓存内容,缺省为 false,如果指定为 true, 则方法调用后将立即清空所有缓存 例如: @CachEvict(value=”testcache”,allEntries=true)
beforeInvocation (@CacheEvict) 是否在方法执行前就清空,缺省为 false,如果指定为 true, 则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法 执行抛出异常,则不会清空缓存 例如: @CachEvict(value=”testcache”,beforeInvocation=true)

具体参考一点

Spring Boot整合Junit

示例:

pom.xml

  1. <!--springboot 集成 junit 起步依赖-->
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-test</artifactId>
  5. <version>2.1.6.RELEASE</version>
  6. <scope>test</scope>
  7. </dependency>
  8. @RunWith(SpringJUnit4ClassRunner.class)
  9. //重点是加入@SpringBootTest注解,属性classes用于加载引导类
  10. @SpringBootTest(classes = MyBootApplication.class)
  11. public class JUnitTest {
  12. @Test
  13. public void test() {
  14. System.out.println("Hello JUnit");
  15. }
  16. }

输出:

  1. Hello JUnit

Spring Boot整合Quartz

Quartz(石英)简介

Quartz 是一个完全由Java 编写的开源任务调度的框架,通过触发器设置作业定时运行规则,控制作业的运行时间。Quartz 定时器作用很多,比如,定时发送信息和定时生成报表等。 Quartz 框架主要核心组件包括调度器、触发器和作业。调度器作为作业的总指挥,触发器 作为作业的操作者,作业为应用的功能模块。其关系如图:

示例:

pom.xml

  1. <!-- sping对schedule的支持 -->
  2. <dependency>
  3. <groupId>org.springframework</groupId>
  4. <artifactId>spring-context-support</artifactId>
  5. </dependency>
  6. <!--Quartz运行必须依赖到spring-tx包 注意:spring-boot-starter-web已经依赖了,所以不需要再依赖,只需要知道Quartz运行必须依赖到spring-tx包 -->
  7. <!-- <dependency>
  8. <groupId>org.springframework</groupId>
  9. <artifactId>spring-tx</artifactId>
  10. </dependency>-->
  11. <!-- Quartz支持 -->
  12. <dependency>
  13. <groupId>org.quartz-scheduler</groupId>
  14. <artifactId>quartz</artifactId>
  15. <version>2.2.1</version>
  16. <exclusions>
  17. <exclusion>
  18. <artifactId>slf4j-api</artifactId>
  19. <groupId>org.slf4j</groupId>
  20. </exclusion>
  21. </exclusions>
  22. </dependency>

Job任务类——我们想实现的定时任务业务代码写在这里。

  1. public class CheckJob {
  2. public void task() {
  3. System.out.println("校验任务被触发,当前时间为:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
  4. }
  5. }
  6. public class ReminderJob {
  7. //具体定时任务
  8. public void task(){
  9. System.out.println("呼吸提醒任务被触发,当前时间为:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
  10. }
  11. }

Quartz配置类——每个调度任务都对应一个配置类

  1. @Configuration
  2. public class CheckQuartzConfig {
  3. @Bean
  4. public CheckJob createCheckJob() {
  5. return new CheckJob();
  6. }
  7. /**
  8. * 创建任务
  9. */
  10. @Bean("checkJobDetail")
  11. public MethodInvokingJobDetailFactoryBean checkJobDetailFactoryBean(CheckJob job) {
  12. MethodInvokingJobDetailFactoryBean detailFactoryBean = new MethodInvokingJobDetailFactoryBean();
  13. //设置任务对象
  14. detailFactoryBean.setTargetObject(job);
  15. //设置任务方法
  16. detailFactoryBean.setTargetMethod("task");
  17. return detailFactoryBean;
  18. }
  19. /**
  20. * 触发器
  21. */
  22. @Bean("checkTrigger")
  23. public CronTriggerFactoryBean createTrigger(@Qualifier("checkJobDetail") MethodInvokingJobDetailFactoryBean bean) {
  24. CronTriggerFactoryBean triggerFactoryBean = new CronTriggerFactoryBean();
  25. triggerFactoryBean.setJobDetail(bean.getObject());
  26. // 每天11点30分触发执行一次
  27. triggerFactoryBean.setCronExpression("0 30 11 * * ? *");
  28. return triggerFactoryBean;
  29. }
  30. /**
  31. * 创建Schduler
  32. */
  33. @Bean("checkScheduler")
  34. public SchedulerFactoryBean createSchedulerFactoryBean(@Qualifier("checkTrigger") CronTriggerFactoryBean bean){
  35. SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
  36. //关联trigger
  37. schedulerFactoryBean.setTriggers(bean.getObject());
  38. return schedulerFactoryBean;
  39. }
  40. }
  41. @Configuration
  42. public class QuartzConfig {
  43. @Bean
  44. public ReminderJob createReminderJob() {
  45. return new ReminderJob();
  46. }
  47. @Bean("reminderJobDetail")
  48. public MethodInvokingJobDetailFactoryBean reminderJobDetailFactoryBean(ReminderJob job) {
  49. MethodInvokingJobDetailFactoryBean detailFactoryBean = new MethodInvokingJobDetailFactoryBean();
  50. detailFactoryBean.setTargetObject(job);
  51. detailFactoryBean.setTargetMethod("task");
  52. return detailFactoryBean;
  53. }
  54. @Bean("reminderTrigger")
  55. public CronTriggerFactoryBean createTrigger(@Qualifier("reminderJobDetail") MethodInvokingJobDetailFactoryBean bean) {
  56. CronTriggerFactoryBean triggerFactoryBean = new CronTriggerFactoryBean();
  57. triggerFactoryBean.setJobDetail(bean.getObject());
  58. //定时任务3秒执行一次
  59. triggerFactoryBean.setCronExpression("0/3 * * * * ? *");
  60. return triggerFactoryBean;
  61. }
  62. @Bean("reminderScheduler")
  63. public SchedulerFactoryBean createSchedulerFactoryBean(@Qualifier("reminderTrigger") CronTriggerFactoryBean bean){
  64. SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
  65. schedulerFactoryBean.setTriggers(bean.getObject());
  66. return schedulerFactoryBean;
  67. }
  68. }

运行引导类。

输出:

  1. 呼吸提醒任务被触发,当前时间为:2020-05-21 11:29:51
  2. 呼吸提醒任务被触发,当前时间为:2020-05-21 11:29:54
  3. 呼吸提醒任务被触发,当前时间为:2020-05-21 11:29:57
  4. 呼吸提醒任务被触发,当前时间为:2020-05-21 11:30:00
  5. 校验任务被触发,当前时间为:2020-05-21 11:30:00
  6. 呼吸提醒任务被触发,当前时间为:2020-05-21 11:30:03
  7. 呼吸提醒任务被触发,当前时间为:2020-05-21 11:30:06
  8. 呼吸提醒任务被触发,当前时间为:2020-05-21 11:30:09

Cron表达式扩展

Cron表达式在线工具

Cron表达式教程

CronTrigger

CronTriggers往往比SimpleTrigger更有用,如果您需要基于日历的概念,而非SimpleTrigger完全指定的时间间隔,复发的发射工作的时间表。 CronTrigger,你可以指定触发的时间表如“每星期五中午”,或“每个工作日9:30时”,甚至“每5分钟一班9:00和10:00逢星期一上午,星期三星期五“。 即便如此,SimpleTrigger一样,CronTrigger拥有的startTime指定的时间表时生效,指定的时间表时,应停止(可选)结束时间。

Cron表达式

cron的表达式被用来配置CronTrigger实例。 cron的表达式是字符串,实际上是由七子表达式,描述个别细节的时间表。这些子表达式是分开的空白,代表:

  1. Seconds
  2. Minutes
  3. Hours
  4. Day-of-Month
  5. Month
  6. Day-of-Week
  7. Year (可选字段)

例 “0 0 12 ? * WED” 在每星期三下午12:00 执行,

个别子表达式可以包含范围, 例如,在前面的例子里(“WED”)可以替换成 “MON-FRI”, “MON, WED, FRI”甚至”MON-WED,SAT”. “*” 代表整个时间段.

每一个字段都有一套可以指定有效值,如

Seconds (秒) :可以用数字0-59 表示,

Minutes(分) :可以用数字0-59 表示,

Hours(时) :可以用数字0-23表示,

Day-of-Month(天) :可以用数字1-31 中的任一一个值,但要注意一些特别的月份

Month(月) :可以用0-11 或用字符串 “JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV and DEC” 表示

Day-of-Week(每周):可以用数字1-7表示(1 = 星期日)或用字符口串“SUN, MON, TUE, WED, THU, FRI and SAT”表示

“/”:为特别单位,表示为“每”如“0/15”表示每隔15分钟执行一次,“0”表示为从“0”分开始, “3/20”表示表示每隔20分钟执行一次,“3”表示从第3分钟开始执行

“?”:表示每月的某一天,或第周的某一天

“L”:用于每月,或每周,表示为每月的最后一天,或每个月的最后星期几如“6L”表示“每月的最后一个星期五”

“W”:表示为最近工作日,如“15W”放在每月(day-of-month)字段上表示为“到本月15日最近的工作日”

““#”:是用来指定“的”每月第n个工作日,例 在每周(day-of-week)这个字段中内容为”6#3″ or “FRI#3” 则表示“每月第三个星期五”

常用Cron表达式

0 15 10 * * ? * 每天10点15分触发
0 15 10 * * ? 2017 2017年每天10点15分触发
0 * 14 * * ? 每天下午的 2点到2点59分每分触发
0 0/5 14 * * ? 每天下午的 2点到2点59分(整点开始,每隔5分触发)
0 0/5 14,18 * * ? 每天下午的 2点到2点59分、18点到18点59分(整点开始,每隔5分触发)
0 0-5 14 * * ? 每天下午的 2点到2点05分每分触发
0 15 10 ? * 6L 每月最后一周的星期五的10点15分触发
0 15 10 ? * 6#3 每月的第三周的星期五开始触发

Spring Boot整合Task

Spring自身有一个定时任务技术,叫Spring Task,本文讲解在Spring Boot应用中如何使用Spring Task。

cron表达式复习:

序号 说明 必填 允许值 通配符
1 秒 是 0-59 , – * /
2 分 是 0-59 , – * /
3 时 是 0-23 , – * /
4 日 是 1-31 , – * ? / L W
5 月 是 1-12 / JAN-DEC , – * /
6 周 是 1-7 or SUN-SAT , – * ? / L #
7 年 否 1970-2099 , – * /

  1. :表示匹配该域的任意值。假如在Minutes域使用, 即表示每分钟都会触发事件。
  2. ?:只能用在DayofMonth和DayofWeek两个域。它也匹配域的任意值,但实际不会。因为DayofMonth和DayofWeek会相互影响。例如想在每月的20日触发调度,不管20日到底是星期几,则只能使用如下写法: 13 13 15 20 * ?, 其中最后一位只能用?,而不能使用,如果使用表示不管星期几都会触发,实际上并不是这样。
  3. -:表示范围。例如在Minutes域使用5-20,表示从5分到20分钟每分钟触发一次
  4. /:斜杠前面值表示起始时间开始触发,后面值表示每隔固定时间触发一次。例如在Minutes域使用5/20,则意味着20分钟触发一次,从第5分钟开始,5,25,45等分别触发一次.
  5. ,:表示列出枚举值。例如:在Minutes域使用5,20,则意味着在5和20分每分钟触发一次。
  6. L:表示最后,只能出现在DayofWeek和DayofMonth域。如果在DayofWeek域使用5L,意味着在最后的一个星期四触发。
  7. W:表示有效工作日(周一到周五),只能出现在DayofMonth域,系统将在离指定日期的最近的有效工作日触发事件。例如:在 DayofMonth使用5W,如果5日是星期六,则将在最近的工作日:星期五,即4日触发。如果5日是星期天,则在6日(周一)触发;如果5日在星期一到星期五中的一天,则就在5日触发。另外一点,W的最近寻找不会跨过月份 。
  8. LW:这两个字符可以连用,表示在某个月最后一个工作日,即最后一个星期五。

示例:

pom.xml

  1. <dependencies>
  2. <!--web起步依赖-->
  3. <dependency>
  4. <groupId>org.springframework.boot</groupId>
  5. <artifactId>spring-boot-starter-web</artifactId>
  6. </dependency>
  7. <!-- sping对schedule的支持 -->
  8. <dependency>
  9. <groupId>org.springframework</groupId>
  10. <artifactId>spring-context-support</artifactId>
  11. </dependency>
  12. </dependencies>
  13. //引导类必须加上@EnableScheding注解启动SpringTask
  14. @SpringBootApplication
  15. @EnableScheduling // 开启Spring Task
  16. public class MyBootApplication {
  17. public static void main(String[] args) {
  18. SpringApplication.run(MyBootApplication.class,args);
  19. }
  20. }
  21. @Component
  22. public class WelcomeTask {
  23. //“5/20”表示每隔20秒执行一次,“5”表示为从“5”秒开始
  24. @Scheduled(cron = "5/20 * * * * ?")
  25. public void task(){
  26. System.out.println("欢迎任务被触发,当前时间为:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
  27. }
  28. }

输出:

  1. 2020-05-21 14:04:33.166 INFO 17100 --- [ restartedMain] com.self.MyBootApplication : Started MyBootApplication in 5.693 seconds (JVM running for 6.831)//启动成功时间33秒
  2. 欢迎任务被触发,当前时间为:2020-05-21 14:04:45
  3. 欢迎任务被触发,当前时间为:2020-05-21 14:05:05
  4. 欢迎任务被触发,当前时间为:2020-05-21 14:05:25
  5. 欢迎任务被触发,当前时间为:2020-05-21 14:05:45

spring-boot整合日志功能(logback、log4j2)

springboot为我们已经内置了log组件 。

springboot内置log组件

application.yml

  1. #在application.yml文件中修改springboot内置日志级别,默认是info
  2. #方式一:
  3. #debug: true
  4. #方式二:
  5. logging:
  6. level:
  7. root: debug

日志级别从低到高为TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF,级别越高,打印的日志越少。举例说明:说将日志级别设定为Debug,那么DEBUG, INFO, WARN, ERROR, FATAL, OFF这几类日志都会打印。

application.properties文件中日志key的第三级的含义为”路径”:

  • 填写root,能够指定整个项目(包含jdk源代码打印的日志)的日志级别;
  • 填写某个包名,能够指定该包下所有Java文件的日志级别,其余为被指定的Java文件的日志级别为默认级别:Info
  • 甚至可以指定任意Java文件

整合参考

日志框架选型——都log4J2或者logback都差不多

springboot整合logback

springboot整合log4J2


springboot整合logback

springboot默认依赖了logback,所以不需要添加依赖。

基本配置:

  1. #官方文档中有提到, SpringBoot 的 Logging 配置的级别有7个:TRACE , DEBUG , INFO , WARN , ERROR , FATAL , OFF
  2. #root日志以INFO级别输出
  3. logging.level.root=INFO
  4. #springframework.web日志以WARN级别输出
  5. logging.level.org.springframework.web=WARN
  6. #hibernate日志以ERROR级别输出
  7. logging.level.org.hibernate=ERROR

在resources下创建logback-spring.xml:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- scan 配置文件如果发生改变,将会被重新加载 scanPeriod 检测间隔时间-->
  3. <configuration scan="true" scanPeriod="60 seconds" debug="false">
  4. <contextName>spring-boot-log</contextName>
  5. <include resource="org/springframework/boot/logging/logback/base.xml"/>
  6. <!-- 普通日志 -->
  7. <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
  8. <file>log/spring-boot-log-info.log</file>
  9. <!-- 循环政策:基于时间创建日志文件 -->
  10. <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  11. <!-- 日志命名:单个文件大于128MB 按照时间+自增i 生成log文件 -->
  12. <fileNamePattern>log/spring-boot-log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
  13. <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
  14. <maxFileSize>128MB</maxFileSize>
  15. </timeBasedFileNamingAndTriggeringPolicy>
  16. <!-- 最大保存时间:30天-->
  17. <maxHistory>30</maxHistory>
  18. </rollingPolicy>
  19. <append>true</append>
  20. <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
  21. <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
  22. <charset>utf-8</charset>
  23. </encoder>
  24. <filter class="ch.qos.logback.classic.filter.LevelFilter">
  25. <level>info</level>
  26. <onMatch>ACCEPT</onMatch>
  27. <onMismatch>DENY</onMismatch>
  28. </filter>
  29. </appender>
  30. <!-- 错误日志 -->
  31. <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
  32. <file>log/spring-boot-log-error.log</file>
  33. <!-- 循环政策:基于时间创建日志文件 -->
  34. <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  35. <!-- 日志命名:单个文件大于2MB 按照时间+自增i 生成log文件 -->
  36. <fileNamePattern>log/spring-boot-log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
  37. <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
  38. <maxFileSize>2MB</maxFileSize>
  39. </timeBasedFileNamingAndTriggeringPolicy>
  40. <!-- 最大保存时间:180天-->
  41. <maxHistory>180</maxHistory>
  42. </rollingPolicy>
  43. <append>true</append>
  44. <!-- 日志格式 -->
  45. <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
  46. <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
  47. <charset>utf-8</charset>
  48. </encoder>
  49. <!-- 日志级别过滤器 -->
  50. <filter class="ch.qos.logback.classic.filter.LevelFilter">
  51. <!-- 过滤的级别 -->
  52. <level>ERROR</level>
  53. <!-- 匹配时的操作:接收(记录) -->
  54. <onMatch>ACCEPT</onMatch>
  55. <!-- 不匹配时的操作:拒绝(不记录) -->
  56. <onMismatch>DENY</onMismatch>
  57. </filter>
  58. </appender>
  59. <!-- 控制台 -->
  60. <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
  61. <!-- 日志格式 -->
  62. <encoder>
  63. <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
  64. <charset>utf-8</charset>
  65. </encoder>
  66. <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
  67. <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
  68. <level>INFO</level>
  69. </filter>
  70. </appender>
  71. <!-- additivity 避免执行2次 -->
  72. <logger name="com.itstyle" level="INFO" additivity="false">
  73. <appender-ref ref="STDOUT"/>
  74. <appender-ref ref="INFO_FILE"/>
  75. <appender-ref ref="ERROR_FILE"/>
  76. </logger>
  77. <root level="INFO">
  78. <appender-ref ref="STDOUT" />
  79. <appender-ref ref="INFO_FILE" />
  80. <appender-ref ref="ERROR_FILE" />
  81. </root>
  82. </configuration>

springboot整合log4J2

pom.xml

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-web</artifactId>
  4. <exclusions><!-- 去掉springboot默认配置 -->
  5. <exclusion>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-logging</artifactId>
  8. </exclusion>
  9. </exclusions>
  10. </dependency>
  11. <dependency> <!-- 引入log4j2依赖 -->
  12. <groupId>org.springframework.boot</groupId>
  13. <artifactId>spring-boot-starter-log4j2</artifactId>
  14. </dependency>

log4j2-spring.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出-->
  3. <!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数-->
  4. <configuration monitorInterval="5">
  5. <!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
  6. <!--变量配置-->
  7. <Properties>
  8. <!-- 格式化输出:%date表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符-->
  9. <!-- %logger{36} 表示 Logger 名字最长36个字符 -->
  10. <property name="LOG_PATTERN" value="%date{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" />
  11. <!-- 定义日志存储的路径 -->
  12. <property name="FILE_PATH" value="logs" />
  13. <property name="FILE_NAME" value="hellospringboot-log" />
  14. </Properties>
  15. <appenders>
  16. <console name="Console" target="SYSTEM_OUT">
  17. <!--输出日志的格式-->
  18. <PatternLayout pattern="${LOG_PATTERN}"/>
  19. <!--控制台只输出level及其以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
  20. <ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY"/>
  21. </console>
  22. <!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,适合临时测试用-->
  23. <File name="Filelog" fileName="${FILE_PATH}/test.log" append="false">
  24. <PatternLayout pattern="${LOG_PATTERN}"/>
  25. </File>
  26. <!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
  27. <RollingFile name="RollingFileInfo" fileName="${FILE_PATH}/info.log" filePattern="${FILE_PATH}/${FILE_NAME}-INFO-%d{yyyy-MM-dd}_%i.log.gz">
  28. <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
  29. <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
  30. <PatternLayout pattern="${LOG_PATTERN}"/>
  31. <Policies>
  32. <!--interval属性用来指定多久滚动一次,默认是1 hour-->
  33. <TimeBasedTriggeringPolicy interval="1"/>
  34. <SizeBasedTriggeringPolicy size="10MB"/>
  35. </Policies>
  36. <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
  37. <DefaultRolloverStrategy max="15"/>
  38. </RollingFile>
  39. <!-- 这个会打印出所有的warn及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
  40. <RollingFile name="RollingFileWarn" fileName="${FILE_PATH}/warn.log" filePattern="${FILE_PATH}/${FILE_NAME}-WARN-%d{yyyy-MM-dd}_%i.log.gz">
  41. <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
  42. <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
  43. <PatternLayout pattern="${LOG_PATTERN}"/>
  44. <Policies>
  45. <!--interval属性用来指定多久滚动一次,默认是1 hour-->
  46. <TimeBasedTriggeringPolicy interval="1"/>
  47. <SizeBasedTriggeringPolicy size="10MB"/>
  48. </Policies>
  49. <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
  50. <DefaultRolloverStrategy max="15"/>
  51. </RollingFile>
  52. <!-- 这个会打印出所有的error及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
  53. <RollingFile name="RollingFileError" fileName="${FILE_PATH}/error.log" filePattern="${FILE_PATH}/${FILE_NAME}-ERROR-%d{yyyy-MM-dd}_%i.log.gz">
  54. <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
  55. <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
  56. <PatternLayout pattern="${LOG_PATTERN}"/>
  57. <Policies>
  58. <!--interval属性用来指定多久滚动一次,默认是1 hour-->
  59. <TimeBasedTriggeringPolicy interval="1"/>
  60. <SizeBasedTriggeringPolicy size="10MB"/>
  61. </Policies>
  62. <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
  63. <DefaultRolloverStrategy max="15"/>
  64. </RollingFile>
  65. </appenders>
  66. <!--Logger节点用来单独指定日志的形式,比如要为指定包下的class指定不同的日志级别等。-->
  67. <!--然后定义loggers,只有定义了logger并引入的appender,appender才会生效-->
  68. <loggers>
  69. <!--过滤掉spring和mybatis的一些无用的DEBUG信息-->
  70. <logger name="org.mybatis" level="info" additivity="false">
  71. <AppenderRef ref="Console"/>
  72. </logger>
  73. <!--监控系统信息-->
  74. <!--若是additivity设为false,则 子Logger 只会在自己的appender里输出,而不会在 父Logger 的appender里输出。-->
  75. <Logger name="org.springframework" level="info" additivity="false">
  76. <AppenderRef ref="Console"/>
  77. </Logger>
  78. <root level="info">
  79. <appender-ref ref="Console"/>
  80. <appender-ref ref="Filelog"/>
  81. <appender-ref ref="RollingFileInfo"/>
  82. <appender-ref ref="RollingFileWarn"/>
  83. <appender-ref ref="RollingFileError"/>
  84. </root>
  85. </loggers>
  86. </configuration>

配置参数详解

日志级别

机制:如果一条日志信息的级别大于等于配置文件的级别,就记录。

  • trace:追踪,就是程序推进一下,可以写个trace输出
  • debug:调试,一般作为最低级别,trace基本不用。
  • info:输出重要的信息,使用较多
  • warn:警告,有些信息不是错误信息,但也要给程序员一些提示。
  • error:错误信息。用的也很多。
  • fatal:致命错误。

输出源

  • CONSOLE(输出到控制台)
  • FILE(输出到文件)

格式

  • SimpleLayout:以简单的形式显示
  • HTMLLayout:以HTML表格显示
  • PatternLayout:自定义形式显示

PatternLayout自定义日志布局:

  1. %d{yyyy-MM-dd HH:mm:ss, SSS} : 日志生产时间,输出到毫秒的时间
  2. %-5level : 输出日志级别,-5表示左对齐并且固定输出5个字符,如果不足在右边补0
  3. %c : logger的名称(%logger)
  4. %t : 输出当前线程名称
  5. %p : 日志输出格式
  6. %m : 日志内容,即 logger.info("message")
  7. %n : 换行符
  8. %C : Java类名(%F)
  9. %L : 行号
  10. %M : 方法名
  11. %l : 输出语句所在的行数, 包括类名、方法名、文件名、行数
  12. hostName : 本地机器名
  13. hostAddress : 本地ip地址

Log4j2配置详解

1、根节点Configuration

有两个属性:

  • status
  • monitorinterval

有两个子节点:

  • Appenders
  • Loggers(表明可以定义多个Appender和Logger).

status用来指定log4j本身的打印日志的级别.

monitorinterval用于指定log4j自动重新配置的监测间隔时间,单位是s,最小是5s.

2、Appenders节点

常见的有三种子节点:Console、RollingFile、File

Console节点用来定义输出到控制台的Appender.

  • name:指定Appender的名字.
  • target:SYSTEM_OUT 或 SYSTEM_ERR,一般只设置默认:SYSTEM_OUT.
  • PatternLayout:输出格式,不设置默认为:%m%n.

File节点用来定义输出到指定位置的文件的Appender.

  • name:指定Appender的名字.
  • fileName:指定输出日志的目的文件带全路径的文件名.
  • PatternLayout:输出格式,不设置默认为:%m%n.

RollingFile节点用来定义超过指定条件自动删除旧的创建新的Appender.

  • name:指定Appender的名字.
  • fileName:指定输出日志的目的文件带全路径的文件名.
  • PatternLayout:输出格式,不设置默认为:%m%n.
  • filePattern : 指定当发生Rolling时,文件的转移和重命名规则.
  • Policies:指定滚动日志的策略,就是什么时候进行新建日志文件输出日志.
  • TimeBasedTriggeringPolicy:Policies子节点,基于时间的滚动策略,interval属性用来指定多久滚动一次,默认是1 hour。modulate=true用来调整时间:比如现在是早上3am,interval是4,那么第一次滚动是在4am,接着是8am,12am…而不是7am.
  • SizeBasedTriggeringPolicy:Policies子节点,基于指定文件大小的滚动策略,size属性用来定义每个日志文件的大小.
  • DefaultRolloverStrategy:用来指定同一个文件夹下最多有几个日志文件时开始删除最旧的,创建新的(通过max属性)。

Loggers节点,常见的有两种:Root和Logger.

Root节点用来指定项目的根日志,如果没有单独指定Logger,那么就会默认使用该Root日志输出

  • level:日志输出级别,共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < AppenderRef:Root的子节点,用来指定该日志输出到哪个Appender.
  • Logger节点用来单独指定日志的形式,比如要为指定包下的class指定不同的日志级别等。
  • level:日志输出级别,共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF.
  • name:用来指定该Logger所适用的类或者类所在的包全路径,继承自Root节点.
  • AppenderRef:Logger的子节点,用来指定该日志输出到哪个Appender,如果没有指定,就会默认继承自Root.如果指定了,那么会在指定的这个Appender和Root的Appender中都会输出,此时我们可以设置Logger的additivity=”false”只在自定义的Appender中进行输出。

实例:

LoggerFactory创建Logger类。

  1. @Component
  2. public class WelcomeTask {
  3. private static final Logger logger = LoggerFactory.getLogger(UserController.class);
  4. //“5/20”表示每隔20秒执行一次,“5”表示为从“5”秒开始
  5. @Scheduled(cron = "5/5 * * * * ?")
  6. public void task(){
  7. logger.debug("进入WelcomeTask 定时任务!");
  8. System.out.println("欢迎任务被触发,当前时间为:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
  9. logger.error("完成WelcomeTask 定时任务!");
  10. }
  11. }

lombok工具简化创建Logger类。

  1. @Component
  2. @Slf4j
  3. public class WelcomeTask {
  4. //“5/20”表示每隔20秒执行一次,“5”表示为从“5”秒开始
  5. @Scheduled(cron = "5/5 * * * * ?")
  6. public void task(){
  7. log.debug("进入WelcomeTask 定时任务!");
  8. System.out.println("欢迎任务被触发,当前时间为:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
  9. log.error("完成WelcomeTask 定时任务!");
  10. }
  11. }

lombok使用参考教程。

lombok就是一个注解工具jar包,能帮助我们省略一繁杂的代码。

lombok使用实践

pom.xml依赖

  1. <dependency>
  2. <groupId>org.projectlombok</groupId>
  3. <artifactId>lombok</artifactId>
  4. <version>1.16.20</version>
  5. </dependency>

IDEA插件里搜索lombok插件安装,重启 。

常用注解

  1. @Setter 注解在类或字段,注解在类时为所有字段生成setter方法,注解在字段上时只为该字段生成setter方法。
  2. @Getter 使用方法同上,区别在于生成的是getter方法。
  3. @ToString 注解在类,添加toString方法。
  4. @EqualsAndHashCode 注解在类,生成hashCode和equals方法。
  5. @NoArgsConstructor 注解在类,生成无参的构造方法。
  6. @RequiredArgsConstructor 注解在类,为类中需要特殊处理的字段生成构造方法,比如final和被@NonNull注解的字段。
  7. @AllArgsConstructor 注解在类,生成包含类中所有字段的构造方法。
  8. @Data 注解在类,为类的所有字段注解@ToString、@EqualsAndHashCode、@Getter的便捷方法,同时为所有非final字段注解@Setter。

疑问:

1、Q:软件版本的GA 代表什么意思?

A:GA:General Availability,正式发布的版本,在国外都是用GA来说明release版本的 .

引申:

参考

Alpha:是内部测试版,一般不向外部发布,会有很多Bug.一般只有测试人员使用。

Beta:也是测试版,这个阶段的版本会一直加入新的功能。在Alpha版之后推出。

RC:(Release Candidate) 顾名思义么 ! 用在软件上就是候选版本。系统平台上就是发行候选版本。RC版不会再加入新的功能了,主要着重于除错。

GA:General Availability,正式发布的版本,在国外都是用GA来说明release版本的。

RTM:(Release to Manufacture)是给工厂大量压片的版本,内容跟正式版是一样的,不过RTM版也有出限制、评估版的。但是和正式版本的主要程序代码都是一样的。

OEM:是给计算机厂商随着计算机贩卖的,也就是随机版。只能随机器出货,不能零售。只能全新安装,不能从旧有操作系统升级。包装不像零售版精美,通常只有一面CD和说明书(授权书)。

RVL:号称是正式版,其实RVL根本不是版本的名称。它是中文版/英文版文档破解出来的。

EVAL:而流通在网络上的EVAL版,与“评估版”类似,功能上和零售版没有区别。

RTL:Retail(零售版)是真正的正式版,正式上架零售版。在安装盘的i386文件夹里有一个eula.txt,最后有一行EULAID,就是你的版本。比如简体中文正式版是EULAID:WX.4_PRO_RTL_CN,繁体中文正式版是WX.4_PRO_RTL_TW。其中:如果是WX.开头是正式版,WB.开头是测试版。PRE,代表家庭版;PRO,代表专业版。

α、β、λ常用来表示软件测试过程中的三个阶段,α是第一阶段,一般只供内部测试使用;β是第二个阶段,已经消除了软件中大部分的不完善之处,但仍有可能还存在缺陷和漏洞,一般只提供给特定的用户群来测试使用;λ是第三个阶段,此时产品已经相当成熟,只需在个别地方再做进一步的优化处理即可上市发行。

2、Q:springboot的核心功能起步依赖和自动配置详解?

3、Q: 自定义配置怎么取值使用,什么场景使用?

4、Q: 每次发布的时候替换掉配置文件,这样太麻烦了,Spring Boot的Profile就给我们提供了解决方案,命令带上参数就搞定。 是指打包命令带上参数就能自动加载不同的环境变量配置么?我们一般是如何打生产包或测试包部署的?怎么通过jekeins实现不同环境的打包部署?

5、Q: yml配置文件属性值是大小写敏感的么?教程里说是,可实际测试中并不是?怎么理解?

  1. #基本类型 注意:属性值大小写敏感
  2. firstName: Bruce Wayne1111
  3. age: 29
  4. @Controller
  5. public class ConfigController {
  6. @Value("${firstname}")
  7. private String name;
  8. @Value("${age}")
  9. private Integer age;
  10. @RequestMapping("/show")
  11. @ResponseBody
  12. public String showConfig() {
  13. return name + " : " + age;
  14. }
  15. }

输出:

  1. Bruce Wayne1111 : 29

6、Q: 下面@Value取值的表达式怎么理解符号#的作用?已经什么时候可以用split()方法?

  1. @Value("#{'${user.list}'.split(',')}")
  2. private List<String> list;

7、Q: Spring Boot3种热部署方式前两种如何实现?

Spring Boot有3种热部署方式:

  1. 使用springloaded配置pom.xml文件,使用mvn spring-boot:run启动
  2. 使用springloaded本地加载启动,配置jvm参数
  3. 使用devtools工具包,操作简单,但是每次需要重新部署

8、Q: 什么是Thymeleaf ?

9、Q: @Configuration注解的作用?对于下面这个异常处理类的作用?

  1. @Configuration
  2. public class CommonHandlerExceptionResolver implements HandlerExceptionResolver {
  3. }

10、Q: java注解和spring注解需要系统研究一遍。

11、Q: 启动类SpringbootDemoApplication其实就是一个标准的Spring纯注解下的启动类 。怎么理解Spring纯注解下的启动类?

12、Q: SPI 方案?

A:SPI 全称为 (Service Provider Interface),即服务提供商接口,是JDK内置的一种服务提供发现机制。目前有不少框架用它来做服务的扩展发现,简单来说,它就是一种动态替换发现服务实现者的机制。

Java扩展方法之SPI

其他:

1、COC:Convention over Configuration,即约定大于配置。

72法则

72法则指以1%的复利计息,72年后(72是约数,准确值是ln2/ln1.01),本金翻倍的规律。

版权声明:本文为castamere原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/castamere/p/12931675.html