学习笔记雷丰阳SpringBoot教程摘要
Posted 囚生CY
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了学习笔记雷丰阳SpringBoot教程摘要相关的知识,希望对你有一定的参考价值。
尝试在月底前更完, 之前看的那个教程虽然是2020年最新的, 但是感觉讲师有点半吊子, 慕名看了雷丰阳的SpringBoot教程https://www.bilibili.com/video/BV1Et411Y7tQ, 实在是精细而专业, 受益匪浅
认真要学还是亲自去看一遍网课, 本文主要是记录雷神授课时的笔记以及一些额外的细节, 相对较为详细, 可作参考
20201001更新: 都怪进巨太好看, 月底是更不玩了… 国庆再说吧…
最终还是做了个人, 赶在国庆假期最后一天把课程看完了. 后八章是进阶部分, 没有详细实践, 有些东西等要用再说吧
截至20201008, 更新完成16章111节的摘要
目录
- 1. Spring Boot入门
- 2. Spring Boot配置
- 3. Spring Boot日志
- 4. Spring Boot与Web开发
- 4.1 简介
- 4.2 webjars与静态资源映射资源
- 4.3 引入thymeleaf
- 4.4 thymeleaf语法
- 4.5 SpringMVC自动配置原理
- 4.6 扩展与全面接管SpringMVC
- 4.7 【实验】引入资源
- 4.8 【实验】国际化
- 4.9 【实验】登录和拦截器
- 4.10 【实验】Restful实验要求
- 4.11 【实验】员工列表: 公共页面抽取
- 4.12 【实验】员工列表: 链接高亮与列表完成
- 4.13 【实验】员工添加: 来到添加页面
- 4.14 【实验】员工添加: 添加完成
- 4.15 【实验】员工修改: 重用页面与修改完成
- 4.16 【实验】员工删除: 删除完成
- 4.17 错误处理原理与定制错误页面
- 4.18 定制错误数据
- 4.19 嵌入式Servlet容器配置修改
- 4.20 注册servlet三大组件
- 4.21 切换其他嵌入式Servlet容器
- 4.22 嵌入式Servlet容器自动配置原理
- 4.23 嵌入式Servlet容器自动启动原理
- 4.24 使用外部Servlet容器与JSP支持
- 4.25 外部Servlet容器启动SpringBoot应用原理
- 5. Spring Boot与Docker
- 6. Spring Boot数据访问
- 7. Spring Boot启动配置原理
- 8. Spring Boot自定义starters
- 9. Spring Boot缓存
- 10. Spring Boot消息
- 11. Spring Boot检索
- 12. Spring Boot任务
- 13. Spring Boot安全
- 14. Spring Boot分布式
- 15. Spring Boot开发热部署
- 16. Spring Boot监控管理
1. Spring Boot入门
-
Spring Boot来简化Spring应用开发, 约定大于配置, 去繁从简, just run就能创建一个独立的, 产品级别的应用
-
背景: J2EE笨重的开发, 繁多的配置, 低下的开发效率, 复杂的部署流程, 第三方技术集成难度大
-
Spring Boot问题解决: Spring全家桶时代
- Spring Boot: J2EE一站式解决方案
- Spring Cloud: 分布式整体解决方案
- Spring Boot优点:
- 快速创建独立运行的Spring项目以及主流框架的集成
- 使用嵌入式的Servlet容器, 应用无需打包成WAR包
- starters自动依赖与版本控制
- 大量的自动配置, 简化开发, 也可以修改默认值
- 无需配置XML, 无代码生成, 开箱即用
- 准生产环境的运行时应用监控
- 与云计算天然继集成
- Spring Boot与微服务: 区别于单体应用架构风格
- 2014年由Martin Fowler提出
- 一个应用应该是一组小型服务, 可以通过HTTP的方式进行互通
- 每一个功能元素欧式一个可独立替换和独立升级的软件单元
- 详细参考微服务文档: https://caoyang.blog.csdn.net/article/details/108700844
- Spring Boot前置环境约束:
jdk 1.7
版本及以上版本maven 3.x
版本spring tools suite 4.x.x
版本, 截至本文发布时spring-boot发行的最新版本是4.8.0
- 关于如何安装springboot及启动一个Helloworld项目详见https://caoyang.blog.csdn.net/article/details/108700844
- 因为笔者使用的是
sts4.8.0
, 而雷风阳使用的是sts1.5.9
, 因此上手时参考的是另一个视频教程, 后来感觉还是雷风阳的教程比较规整, 因此切换回来后跳过了入门部分的一些章节, 比如sts4从零开始创建Helloworld项目的流程以及注解器和日志等细节, 该链接中笔者较为详细地记录了这些跳过的内容, 两个版本区别可能不会太大; 下文中很多笔记都是基于链接中创建的Helloworld
项目继续完善的
2. Spring Boot配置
补充:
.properties
文件的注释是#
,.yml
文件不建议写注释
-
properties与yml配置文件详见https://caoyang.blog.csdn.net/article/details/108700844第二章内容
-
配置文件数据注入到javabean详见https://caoyang.blog.csdn.net/article/details/108700844第二章内容
-
除了使用
@ConfigurationProperties(prefix="student")
来实现配置文件数据注入外, 也可以使用@Value
注解来实现(以Student类)👇public class Student @Value("$student.id") private Integer id; // 在Value注解中使用SpEL表达式 @Value("#11*2") private Integer age;
-
@ConfigurationProperties
与@Value
注解在注入配置文件数据的区别- 前者写一个注解可以批量注入, 后者必须一个个写注解的注入
- 前者支持松散语法绑定, 后者不支持(如变量名为驼峰命名的studentId, 可以绑定到)
- 前者不支持SpEL表达式, 后者支持
#表达式
的写法, 关于SpEL表达式详见https://www.jianshu.com/p/e0b50053b5d3 - 前者支持数值校验, 后者不支持
- 如强者可以在
private Integer id
上方添加@Email
的注解来限定是邮箱格式的字段, 后者添加@Email
则无效(@Value
应该比@Email
更接近private Integer id
)
- 如强者可以在
- 前者可以用于复杂类型, 后者只能注入简单类型的数据(如数组, 字典无法注入)
- 两者在
.yml
和.properties
配置文件都可以获取到值- 若只是在某个业务逻辑中需要获取配置文件中的某项值, 一般使用
@Value
- 在javabean中一般使用
@ConfigurationProperties
- 若只是在某个业务逻辑中需要获取配置文件中的某项值, 一般使用
-
@PropertySource
与@ImportResource
注解@PropertySource
: 加载指定的配置文件- 不加该注解是默认从全局配置文件
application.properties
或application.yml
中读取 - 如果在
src/main/resources/
目录下新建了其他配置文件则需要在Student类上方添加注解@PropertySource(value="classpath:xxx.properties","classpath:xxx.yml")
, 即可以一次性引入多个配置文件
- 不加该注解是默认从全局配置文件
@ImportSource
: 导入Spring的xml配置文件, 让配置文件里面的内容生效- 在
src/main/resources/
目录下创建beans.xml
文件并写入
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"> <bean id="helloService" class="com.example.service.HelloService"></bean> </beans>
- 在
com.example.demo.service
包中创建HelloService.java
类 - 在用于junit test的文件里写入
@Autowired ApplicationContext ioc; boolean flag = ioc.containsBean("helloService"); // flag为false
- 这表明Spring Boot里面没有Spring的配置文件, 我们自己编写的配置文件, 也不能自动识别; 如果想让Spring的配置文件生效, 加载进来, 需要在主启动类上添加
@ImportResource(locations="classpath:beans.xml")
就会发现flag
输出为true
- Spring Boot并不推荐使用
@ImportSource
引入xml配置文件给容器中添加组件:- 配置类======Spring配置文件
- 推荐使用全注解的方式来给容器添加组件, 而无需在主启动类上添加
@ImportResource
注解也可以得到junit test测试结果返回true👇
// 在com.example.demo.config下新建的HelloworldConfig.java类 package com.example.demo.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.example.service.HelloService; /* * @Configuration: 指明当前类是一个配置类, 就是来替代之前的Spring的xml配置文件 * 在配置文件中是<bean></bean>标签添加组件 * */ @Configuration public class HelloworldConfig //将方法的返回值添加到容器中, 容i中这个组件默认的id就是方法名 @Bean public HelloService helloService() return new HelloService();
- 在
- 配置文件占位符
RandomValuePropertySource
配置文件中可以使用随机数$random.value
$random.int
$random.long
$random.int(10)
$random.int[1024,65536]
- 属性配置占位符
- 可以在配置文件中引用前面配置过的属性(优先级前面配置过的这里都能用)
$app.name:默认值
来指定找不到属性时的默认值
# application.properties文件 app.name=MyApp app.description=$app.name is a Spring Boot application app.owner=$app.user:caoyang
- Profile多环境支持
- Profile是Spring对不同环境提供不同配置功能的支持, 可以通过激活, 指定参数等方式快速切换环境
- properties多profile文件形式:
- 配置文件名可以是格式:
application-profile.properties
- 如新建
application-dev.properties
,application-prod.properties
配置文件 - 默认依然是使用
application.properties
配置文件 - 如果想要默认使用其他配置文件, 需要在
application.properties
中写入spring.profiles.active=dev
即可以使用application-dev.properties
- 如新建
- 配置文件名可以是格式:
- yml配置文件多profile文档块模式:
- 如果是
application-profile.yml
则更为容易, 在第一个文档块指定spring.profile.active
值来决定要激活prod
抑或dev
, 如下所示👇
server: port: 8081 spring: profiles: active: dev ---- server: port: 8082 spring: profile: dev ---- server: port: 8083 spring: profile: prod ----
- 如果是
- 激活dev的方式:
- 命令行带参数:
java -jar spring-boot-xx-config-x.x.x-SNAPSHOT.jar --spring.profiles.active=dev
, 可以在run的时候填写参数 - 配置文件中指定:
spring.profiles.active=dev
- jvm虚拟机带参数:
-Dspring.profiles.active=dev
- 命令行带参数:
- properties多profile文件形式:
- 配置文件加载位置
- Spring Boot启动会扫描以下位置的
application.properties
或者application.yml
文件作为Spring Boot的默认配置文件file: ./config/
file: ./
classpath: ./config/
classpath: ./
- 以上是按照优先级从高到低的顺序, 所有位置的文件都会被加载, 相同的内容高优先级配置内容将覆盖低优先级配置内容
classpath
指代/src/main/resources
目录file
指代项目工程目录, 即pom.xml
配置文件所在目录
- 我们也可以通过配置spring.config.location参数来改变默认位置
- 命令行启动jar包指令:
java -jar spring-boot-xx-config-x.x.x-SNAPSHOT.jar --spring.config.location=<绝对路径>
- 即可以在打包完成后再给个新的配置文件路径
- 命令行启动jar包指令:
- 外部配置加载顺序: 官方文档中有17个, 这里选取其中常用的11个, 优先级从高到低
- 命令行参数:
java -jar spring-boot-xx-config-x.x.x-SNAPSHOT.jar --<参数名>=<参数值>
- 来自
java:com[/env
的JNDI属性 - Java系统属性(
System.getProperties()
) - 操作系统环境变量
RandomValuePropertySource
配置的random.*
属性值- jar包外部的
application-profile.properties
或application.yml
(带spring.profile
)配置文件 - jar包内部的
application-profile.properties
或application.yml
(带spring.profile
)配置文件 - jar包外部的
application.properties
或application.yml
(不带spring.profile
)配置文件 - jar包内部的
application.properties
或application.yml
(不带spring.profile
)配置文件 @Configuration
注解类上的@PropertySource
- 通过
SpringApplication.setDefaultProperties
指定的默认属性
- 自动配置原理:
- 配置文件中可以写什么东西?配置文件能配置的属性参照文档
- 自动配置原理:
- SpringBoot启动时加载主配置类, 开启了自动配置功能
@EnableAutoConfiguration
@EnableAutoConfiguration
的作用- 利用
@EnableAutoConfigurationImportSelector
给容器中导入一些组件 - 可以参考
selectImports()
方法的内容 List<String> configuration = getCandidateConfigurations(annotationMetadata, attributes);
获取候选的配置- 将类路径下
META-INF/spring.factories
里面配置的所有EnableAutoConfiguration的值添加进来到容器中 - 每一个这样的
xxxAutoConfiguration
类都是容器中的一个组件, 加入到容器中, 用它们来做自动配置
- 利用
- 配一个自动配置类进行自动配置功能
- 以
HttpEncodingAutoConfiguration
为例解释自动配置原理
@Configuraion // 表明这是一个配置类 @EnableConfigurationProperties(HttpEncodingProperties.class) // 启动指定类ConfigurationProperties功能, 将配置文件中对应值和HttpEncodingProperties绑定起来 @ConditionalOnWebApplication // Spring底层@Conditional注解, 根据不同的条件, 如果满足指定的条件, 整个配置类里面的配置就会生效, 判断当前应用是否是web应用, 如果是则当前配置类生效 @ConditionalOnClass(CharacterEncodingFilter.class) // 判断当前项目有没有这个类, 用于乱码解决的过滤器 @ConditionalOnProperty(prefix="spring.http.encoding",value="enabled",matchIfMissing=true) // 判断配置文件中是否存在某个配置spring.http.encoding.enabled; 如果不存在, 判断也是成立, 即便我们配置文件中不配置spring.http.encoding.enabled, 也会默认生效(matchIfMissing=true) public class HttpEncodingAutoConfiguration private final HttpEncodingProperties properties; // 它已经和SpringBoot的配置文件映射了 //只有一个有参构造器的情况下, 参数的值就会从容器中拿 public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) this.properties = properties; @Bean // 给容器中添加一个组件, 这个组件的某些值需要从properties中获取 @ConditionalOnMissing
- 比如可以配置
spring.http.encoding.enabled=true
,spring.http.encoding.charset=utf-8
,spring.http.encoding.force=true
, 都是在预先设定好的
- 所有在配置文件中能配置的属性都是在
xxxProperties
类中封装着, 配置文件能配置什么就可以参照某个功能对应的属性类
- SpringBoot启动时加载主配置类, 开启了自动配置功能
- SpringBoot的精髓
- SpringBoot启动会加载大量的自动配置类
- 需要的功能有没有SpringBoot默认写好的自动配置类? 没有就需要自己写
- 我们再来看这个自动配置类中到底配置了哪些组件, 只要我们要用的组件有, 就不需要再来配置了
- 给容器中自动配置类添加组件的时候, 会从properties类中获取某些属性, 我们就可以在配置文件中指定这些属性的值
xxxAutoConfiguration
自动配置类给容器添加组件 -->xxxProperties
类封装配置文件中相关属性
- 一些细节:
@Conditional
派生注解- 作用: 必须是
@Conditional
指定的条件成立, 才给容器中添加组件, 配置文件中的所有内容才会生效 @ConditionalOnJava
: 系统的Java版本是否符合要求@ConditionalOnBean
: 容器中存在指定Bean@ConditionalOnMissingBean
: 容器中不存在指定Bean@ConditionalOnExpression
: 满足SpEL表达式指定@ConditionalOnClass
: 系统中有指定的类@ConditionalOnMissingClass
: 系统中没有指定的类@ConditionalOnSingleCandidate
: 容器中只有一个指定的Bean, 或者这个Bean是首选的Bean@ConditionalOnProperty
: 系统中指定的属性是否有指定的值@ConditionalOnResource
: 类路径下是否存在指定资源文件
- 作用: 必须是
- 在
application.properties
配置文件中首行写入debug=true
- 开启Spring调试模式: 控制台里打印自动配置报告, 哪些配置类使用, 哪些没有使用
3. Spring Boot日志
3.1 日志框架分类和选择
- 市面上的日志框架:
- 日志门面(日志的抽象层):
- JCL: Jakarta Commons Logging, 这个最后更新是2014年, 基本已经弃用了
- slf4j: Simple Logging Facade for java
- jboss-logging
- 日志实现:
- JUL:
java.util.logging
- logback
- log4j
- log4j2
- JUL:
- 选择日志门面中的一个作为框架(抽象层), 再选择日志实现中的一个来实现
SpringBoot底层是Spring框架, 默认使用的是JCL, 但SpringBoot选用的是slf4j呵呵logback
3.2 slf4j使用原理
- 如何在系统中使用slf4j
- 开发的时候, 日志记录方法的调用, 不应该直接调用体制的实现类, 而是调用日志抽象层里面的方法
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloWorld
public static void main(String[] args)
Logger logger = LoggerFactory.getLogger(HelloWorld.class);
logger.info("Hello World");
每一个日志的实现框架都有自己的配置文件, 使用slf4j以后, 配置文件还是做成日志实现框架自己本身的配置文件
3.3 其他日志框架统一转换为slf4j
- 遗留问题
- 开发A系统(slf4j+logback): Spring(commons-logging), Hibernate(jboss-logging), MyBatis等
- 统一日志记录, 即便是别的框架也一起使用slf4j来输出?
- 先排除其他的日志框架
- 用中间包替换原有的日志框架
- 引入slf4j其他的实现
- 详情可见: http://www.slf4j.org/images/legacy.png
3.4 SpringBoot日志关系
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
SpringBoot使用
spring-boot-starter-logging
依赖来实现日志功能
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
- SpringBoot底层也是使用slf4j+logback的方式进行日志记录
- SpringBoot也把其他的日志都替换成了slf4j
- SpringBoot使用了中间替换包
- 如果我们要引入其他框架, 一定要把这个框架的默认日志依赖移除
- Spring框架用的是commons-logging
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-core</artifactId> <exclusion> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </exclusion> </dependency>
- SpringBoot能自动适配所有的日志, 而且底层使用slf4j+logback的方式记录日志, 引入其他框架的时候, 只需要把这个框架依赖的日志框架排除掉
3.5 SpringBoot默认配置
- SpringBoot默认输出日志级别是
info
logger.level.com.example.demo = info
: 指定com.example.demo
包的输出级别为info及以上logging.file = F:/spring-boot-helloworld.log
: 指定日志输出位置(精确到文件)logging.path = /spring/log
: 在当前磁盘的根目录下创建spring文件夹和里面的log文件夹, 使用spring.log
作为默认的文件名logging.pattern.console = %dyyyy-MM-dd [%thread] %-5level %logger50 - %msg%n
: 在控制台输出的日志格式logging.pattern.file = %dyyyy-MM-dd === [%thread] === %-5level === %logger50 === %msg%n
: 指定文件中输出的格式- 日志输出格式:
%d
表示日期时间%thread
表示线程名%-5level
级别从左显示5个字符宽度%logger50
表示logger名字最长50个字符, 否则按照句点分割%msg
表示日志消息%n
表示换行符
- LoggerFactory的logger对象方法(级别从低到高)
- logger.trace()
- logger.debug()
- logger.info()
- logger.warn()
- logger.error()
3.6 指定日志文件和日志Profile功能
- 指定配置
- 给类路径下放上每个日志框架自己的配置文件即可, SpiringBoot就不适用默认配置了
- 不同日志系统的自定义配置文件
- logback:
logback-spring.xml
,logback-spring.groovy
,logback.xml
,logback.groovy
- log4j2:
log4j2-spring.xml
,log4j2.xml
- JDK(java util logging):
logging.properties
- 如果文件名为
logging.xml
: 直接就被日志框架识别了 - 如果文件名为
logback-spring.xml
: 日志框架就不直接加载日志的配置项, 由SpringBoot解析日志配置, 可以使用SpringBoot的高级Profile功能<springProfile name="staging"> <!-- configuration to be enabled when the "staging" profile is active --> 可以指定某段配置只在某个环境下生效 比如可以把staging改成dev即在开发环境生效, !dev则非开发环境生效 </springProfile>
- 如果文件名为
- logback:
- 举个logback-spring.xml配置文件的例子:
- 集成到springboot的yml格式配置文件的示例:
logging: config: classpath:logback-spring.xml level: dao: debug org: mybatis: debug
- 具体logback配置:
<?xml version="1.0" encoding="UTF-8"?> <!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 --> <!-- scan:当此属性设置为true时,配置文档如果发生改变,将会被重新加载,默认值为true --> <!-- scanPeriod:设置监测配置文档是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。 当scan为true时,此属性生效。默认的时间间隔为1分钟。 --> <!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 --> <configuration scan="true" scanPeriod="10 seconds"> <contextName>logback</contextName> <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义后,可以使“$”来使用变量。 --> <property name="log.path" value="G:/logs/pmp" /> <!--0. 日志格式和颜色渲染 --> <!-- 彩色日志依赖的渲染类 --> <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" /> <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" /> <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" /> <!-- 彩色日志格式 --> <property name="CONSOLE_LOG_PATTERN" value="$CONSOLE_LOG_PATTERN:-%clr(%dyyyy-MM-dd HH:mm:ss.SSS)faint %clr($LOG_LEVEL_PATTERN:-%5p) %clr($PID:- )magenta %clr(---)faint %clr([%15.15t])faint %clr(%-40.40logger39)cyan %clr(:)faint %m%n$LOG_EXCEPTION_CONVERSION_WORD:-%wEx"/> <!--1. 输出到控制台--> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息--> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>debug</level> </filter> <encoder> <Pattern>$CONSOLE_LOG_PATTERN</Pattern> <!-- 设置字符集 --> <charset>UTF-8</charset> </encoder> </appender> <!--2. 输出到文档--> <!-- 2.1 level为 DEBUG 日志,时间滚动输出 --> <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 正在记录的日志文档的路径及文档名 --> <file>$log.path/web_debug.log</file> <!--日志文档输出格式--> <encoder> <pattern>%dyyyy-MM-dd HH:mm:ss.SSS [%thread] %-5level %logger50 - %msg%n</pattern> <charset>UTF-8</charset> <!-- 设置字符集 --> </encoder> <!-- 日志记录器的滚动策略,按日期,按大小记录 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 日志归档 --> <fileNamePattern>$log.path/web-debug-%dyyyy-MM-dd.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <!--日志文档保留天数--> <maxHistory>15</maxHistory> </rollingPolicy> <!-- 此日志文档只记录debug级别的 --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>debug</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender> <!-- 2.2 level为 INFO 日志,时间滚动输出 --> <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 正在记录的日志文档的路径及文档名 --> <file>$log.path/web_info.log</file> <!--日志文档输出格式--> <encoder> <pattern>%dyyyy-MM-dd HH:mm:ss.SSS [%thread] %-5level %logger50 - %msg%n</pattern> <charset>UTF-8</charset> </encoder> <!-- 日志记录器的滚动策略,按日期,按大小记录 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 每天日志归档路径以及格式 --> <fileNamePattern>$log.path/web-info-%dyyyy-MM-dd.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <!--日志文档保留天数--> <maxHistory>15</maxHistory> </rollingPolicy> <!-- 此日志文档只记录info级别的 --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>info</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender> <!-- 2.3 level为 WARN 日志,时间滚动输出 --> <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 正在记录的日志文档的路径及文档名 --> <file>$log.path/web_warn.log</file> <!--日志文档输出格式--> <encoder> <pattern>%dyyyy-MM-dd HH:mm:ss.SSS [%thread] %-5level %logger50 - %msg%n</pattern> <charset>UTF-8</charset> <!-- 此处设置字符集 --> </encoder> <!-- 日志记录器的滚动策略,按日期,按大小记录 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>$log.path/web-warn-%dyyyy-MM-dd.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <!--日志文档保留天数--> <maxHistory>15</maxHistory> </rollingPolicy> <!-- 此日志文档只记录warn级别的 --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>warn</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender> <!-- 2.4 level为 ERROR 日志,时间滚动输出 --> <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 正在记录的日志文档的路径及文档名 --> <file>$log.path/web_error.log</file> <!--日志文档输出格式--> <encoder> <pattern>%dyyyy-MM-dd HH:mm:ss.SSS [%thread] %-5level %logger50 - %msg%n</pattern> <charset>UTF-8</charset> <!-- 此处设置字符集 --> </encoder> <!-- 日志记录器的滚动策略,按日期,按大小记录 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>$log.path/web-error-%dyyyy-MM-dd.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <!--日志文档保留天数--> <maxHistory>15</maxHistory> </rollingPolicy> <!-- 此日志文档只记录ERROR级别的 --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>ERROR</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender> <!-- <logger>用来设置某一个包或者具体的某一个类的日志打印级别、 以及指定<appender>。<logger>仅有一个name属性, 一个可选的level和一个可选的addtivity属性。 name:用来指定受此logger约束的某一个包或者具体的某一个类。 level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF, 还有一个特俗值INHERITED或者同义词NULL,代表强制执行上级的级别。 如果未设置此属性,那么当前logger将会继承上级的级别。 addtivity:是否向上级logger传递打印信息。默认是true。 <logger name="org.springframework.web" level="info"/> <logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/> --> <!-- 使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想要查看sql语句的话,有以下两种操作: 第一种把<root level="info">改成<root level="DEBUG">这样就会打印sql,不过这样日志那边会出现很多其他消息 第二种就是单独给dao下目录配置debug模式,代码如下,这样配置sql语句会打印,其他还是正常info级别: 【logging.level.org.mybatis=debug logging.level.dao=debug】 --> <!-- root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性 level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF, 不能设置为INHERITED或者同义词NULL。默认是DEBUG 可以包含零个或多个元素,标识这个appender将会添加到这个logger。 --> <!-- 4. 最终的策略 --> <!-- 4.1 开发环境:打印控制台--> <springProfile name="dev"> <logger name="com.sdcm.pmp" level="debug"/> </springProfile> <root level="info"> <appender-ref ref="CONSOLE" /> <appender-ref ref="DEBUG_FILE" /> <appender-ref ref="INFO_FILE" /> <appender-ref ref="WARN_FILE" /> <appender-ref ref="ERROR_FILE" /> </root> <!-- 4.2 生产环境:输出到文档 <springProfile name="pro"> <root level="info"> <appender-ref ref="CONSOLE" /> <appender-ref ref="DEBUG_FILE" /> <appender-ref ref="INFO_FILE" /> <appender-ref ref="ERROR_FILE" /> <appender-ref ref="WARN_FILE" /> </root> </springProfile> --> </configuration>
- 集成到springboot的yml格式配置文件的示例:
3.7 切换日志框架
- 可以按照slf4j的日志适配图, 进行相关的切换
- slf4j切换为log4j的方式:
<dependency>
<groupId>org.spring.framework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<artifactId>logback-classic</artifactId>
<groupId>ch.qos.logback</groupId>
</exclusion>
<exclusion>
<artifactId>log4j-over-slf4j</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
- slf4j切换为log4j2:
<dependency>
<groupId>org.spring.framework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-logging</artifactId>
<groupId>org.spring.framework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.spring.framework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
4. Spring Boot与Web开发
4.1 简介
- 使用SpringBoot进行Web开发的步骤
- 创建SpringBoot应用, 选中我们需要的模块
- 普通小项目只需要勾选Web下的Spring Web即可
- 需要连接MyBatis, Redis, mysql都是有对应的选项可以勾选
- Spring已经默认将这些场景配置好了, 只需要在配置文件中指定少量配置就可以运行起来
- 关于如何修改配置, 可以修改哪些配置详见第二章
- 可以自己在STS4编辑器左栏Package Explorer中Maven Denpendencies–>spring-boot-autoconfigure-x.x.x.RELEASE.jar中查看相关的源码配置
xxxxAutoConfiguration: 帮我们给容器中自动配置组件 xxxxProperties: 配置类来封装配置文件的内容
- 自己编写业务代码
- 目前sts4直接新建一个项目后在主启动类下写个简单的controller类就可以直接运行个helloworld出来了, 别的什么都不需要额外配置
//简单的controller类
package com.example.demo;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class Controller
/*
* 在这里使用@RequestMapping建立请求映射
*/
@RequestMapping(value="/helloworld",method=RequestMethod.GET)
public String helloworld()
return "<h1>Helloworld caoyang</h1>";
4.2 webjars与静态资源映射资源
- SpringBoot对静态资源的配置规则
@ConfigurationProperties(prefix="spring.resources",ignoreUnknownFields=false)
public class ResourceProperties implements ResourceLoaderAware
// 可以设置和静态资源有关的参数, 缓存时间等
- 所有
/webjars/**
的资源, 都去classpath:META-INF/resources/webjars
找资源- webjars: 以jar包的方式引入静态资源
- 如何引入webjars依赖可参考https://www.webjars.org/
- 引入jquery的webjars:
<!-- 引入jquery的webjars, 3.5.1是当时最新版本 --> <dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>3.5.1</version> </dependency>
- 访问
localhost:8080/webjars/jquery/3.5.1/jquery.js
即可看到已经引入的jquery依赖
- 访问
/**
访问当前项目的任何资源, 静态资源的文件夹(classpath
指代/src/main/resources
目录)classpath:/META-INF/resources/
classpath:/resources/
classpath:/static/
classpath:/public/
- 当前项目根路径
- 如访问
localhost:8080/xxx
就可以访问到自己的静态资源, 一般就是放在src/main/resources
目录下里面
- 欢迎页: 静态资源文件夹下的所有index.html页面, 被
/**
映射localhost:8080/
就是欢迎页
- 标签页的图标: 所有的**/favicon.ico都是在静态资源文件夹下查找
- 如在
/src/main/resources/static
里放一张图标文件favicon.ico
- 如在
4.3 引入thymeleaf
- 模板引擎:
- JSP
- Velocity
- Freemarket
- Thymeleaf: SpringBoot推荐, 语法简单, 功能强大
- 引入thymeleaf
<!-- 引入thymeleaf模板引擎 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
- 默认使用
2.1.6
版本, 这太低了, 需要自定义版本, 在properties节点下添加, 特别注意3.x.x
版本的thymeleaf需要2.x.x
版本的layout来支持, 后续可能会更新, 需要参考github上的版本<thymeleaf.version>3.0.2.RELEASE</thymeleaf.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <thymeleaf-layout-dialect.version>2.1.1</thymeleaf-layout-dialect.version>
- 这里插个题外话, properties节点下可以添加
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
4.4 thymeleaf语法
- 检查ThymeleafProperties源码可知
@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties
private static final Charset DEFAULT_ENCODING = Charset.forName("UTF-8");
private static final MimeType DEFAULT_CONTENT_TYPE = MimeType.valueOf("text/html");
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
- 可以在
application.yml
配置文件中做如下配置
spring:
thymeleaf:
cache: false
prefix: classpath:/templates/
suffix: .html
encoding: UTF-8
mode: HTML
- 只要我们把HTML页面放在
classpath:/templates
下, 以.html
结尾就可以自动被thymeleaf渲染 - 具体语法可以在官网下载官方文档PDF查看
- 编写controller类: 这里有个坑是Controller类的类注解不能是
@RestController
, 只能是@Controller
, 否则不能实现页面的绑定package com.example.demo; import java.util.Map; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.ModelAndView; @Controller // 此处不能是@RestController, 否则无法实现跳转页面 public class Web1Controller /* * 在这里使用@RequestMapping建立请求映射 */ @RequestMapping("/success") public String success(Map<String,Object> map) // classpath:/templates/thymeleaftest.html map.put("hello","你好"); return "success";
- 在
/src/main/resources/templates/
目录下编写success.html
文件<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>thymeleaf test</title> </head> <body> <h1>成功!</h1> <div th:text="$hello"></div> <!-- 如果div中有信息, 则会被替换成hello变量的值, 正常访问则显示div中的信息 --> </body> </html>
- 注意点: 导入thymeleaf的名称空间:
<html lang="en" xmlns:th="http://www.thymeleaf.org">
, 以获取语法提示 - 访问
localhost:8080/success
即可看到"成功!你好"的字样
- 注意点: 导入thymeleaf的名称空间:
- thymeleaf语法规则
th
标签: 官方文档PDF的第十章th:text
和th:utext
: 文本(前者转义后者不转义)th.each
: 循环th.if
: 条件th:attr
任意属性修改, attr可以是id, class这些原生的HTML属性, 都可以修改
- 表达式: 官方文档PDF第四章
$...
: 取变量值- 去自定义值
$person.name
$persons[0]
- 使用内置的基本对象
$ctx
: 上下文对象$var
: 上下文变量$locale
: 上下文位置$request
: 请求对象$session
: 会话对象$servletContext
: servletcontext对象
- 使用基本的工具对象: number, boolean, float等
- 去自定义值
*...
: 选择表达式, 和$...
功能基本相同, 在取字典型的对象值时在对象控制域内可以简写(下面的firstname等价于写session.user.firstname), 主要是配合th:object
使用<div th:object="$session.user"> <p>Name: <span th:text="*firstname">Sebastian</span></p> </div>
#...
: 取国际化内容@...
: 定义URL链接, 一般用于th:href
标签@localhost:8080/helloworld
或@/helloworld
~...
: 片段引用表达式- ...
- 字面量:
- 字符串
- 数字
- 布尔型
- null
- 字面量标记: one, sometext, main
- 文本操作:
- 字符串拼接: “+”
- 字面量替换:
|The name is $name|
- 算术运算符: …
- 逻辑运算符: …
- 比较运算符: 注意大于号和小于号因为在HTML里是特殊字符可以用gt, lt, ge, le替代, 等于和不等于是eq和ne
- 条件运算符:
- if-then: (if) ? (then)
- if-then-else: (if) ? (then) : (else)
- default: (value) ?: (defaultvalue)
- 特殊标记:
- No-operation:
- 简单的一个样例
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>thymeleaf test</title> </head> <body> <h1>成功!</h1> <div th:text="$hello">这是转义的信息</div> <div th:utext="$hello">这是不转义的信息</div> <br/> <h4 th:text="$user" th:each="user:$users"></h4> <span th:each="user:$users">[[$user]]</span><!-- 行内写法: [[...]]不转义 --> <br/> <span th:each="user:$users">[($user)]</span><!-- 行内写法: [(...)]将转义 --> </body> </html>
4.5 SpringMVC自动配置原理
- SpringBoot自动配置好了SpringMVC
- 以下是SpringBoot对SpringMVC的默认配置:
- 自动配置了```ViewResolver````: 视图解析器, 根据方法的返回值得到视图对象(View), 视图对象决定如何渲染(转发,重定向等)
- ContentNegotiatingViewResolver: 组合所有的视图解析器的
- 如何定制: 我们可以自己给容器中添加一个视图解析器, 自动将其组合进来
- 静态资源文件夹路径和webjars
- 静态首页访问:
index.html
- 标签页图标
favicon.icon
- 自动注册几个工具类:
- Converter: 转换器
- Fomatter: 格式化器
- GenericConverter: 总体转换器
- 支持
HttpMessageConverter
:HttpMessageConverter
是SpringMVC用来转换Http请求和响应的HttpMessageConverter
是从容器中确定, 获取所有的HttpMessageConverter
- 自己给容器中添加
HttpMessageConverter
, 只需要将自己的组件放在容器中
- 定义错误代码生成规则:
MeaageCodesResolver
类 - 我们可以配置一个ConfigurableWebBindingInitializer来替换默认的配置, 添加到容器
初始化WebDataBinder 请求数据=====JavaBean
- 如
org.springframework.boot.autoconfigure.web: web
的所有自动场景
- 如
- 如何修改SpringMVC的默认配置
- 模式:
- SpringBoot在自动配置很多组件的时候, 先看容器中有没有用户自己配置的(
@Bean
,@Component
), 如果有就用用户配置的, 如果没有才会自动配置, 如果有些组件可以有多个(如ViewResolver
), 则会将用户配置的和自己默认的组合起来 - 在SpringBoot中会有非常多的xxxWebMvcConfigurer, 需要多留心
- SpringBoot在自动配置很多组件的时候, 先看容器中有没有用户自己配置的(
4.6 扩展与全面接管SpringMVC
- 扩展SpringMVC:
<!-- springmvc.xml的一个示例, 一个控制器与一个拦截器 -->
<mvc:view-controller path="/hello" view-name="success">
<mvc:interceptors>
<mvc:interceptors>
<mvc:mapping path="/hello" />
<bean></bean>
</mvc:interceptors>
<mvc:interceptors>
- 编写一个配置类(@Configuration), 是WebMvcConfigurerAdapter类型, 不能标注
@EnableWebMvc
- 注意教程中提到的继承
WebMvcConfigurerAdapter
已经被弃用, 改成继承WebMvcConfigurationSupport
- 既保留了所有的自动配置也能用我们扩展的配置
package com.example.demo; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; @Configuration public class Web1Config extends WebMvcConfigurationSupport @Override public void addViewControllers(ViewControllerRegistry registry) registry.addViewController("/caoyang").setViewName("success");
- 此时直接访问
localhost:8080/caoyang
即可看到success页面的信息
- 注意教程中提到的继承
- 原理:
WebMvcConfigurerAdapter
类是SpringMVC的自动配置类- 在做其他自动配置时会导入,
@Import(EnableWebMvcConfiguration.class)
- 容器中所有的
WebMvcConfigurerAdapter
都会一起起作用 - 我们的配置类也会被调用
- 效果: SpringMVC的自动配置和我们的扩展配置都会起作用
- 全面接管SpringMVC配置
- SpringBoot对SpringMVC的自动配置不需要了, 所有都是我们自己配
- 只需要在配置类上添加
@EnableWebMvc
注解, 注意第1点里的配置文件是只能添加一个@Configuration
注解 - 一般不建议全面接管, 否则就连
index.html
也无法访问了 - 原理: 为什么
@EnableWebMvc
会使SpringMVC的默认配置都失效@EnableWebMvc
注解将WebMvcConfigurationSupport
组件导入进来- 导入的
WebMvcConfigurationSupport
组件只是SpringMVC的基本功能配置
4.7 【实验】引入资源
- 编写配置类实现路由映射
package com.example.demo;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.context.annotation.Bean;
@Configuration
public class Web1Config extends WebMvcConfigurationSupport
@Override
public void addViewControllers(ViewControllerRegistry registry)
registry.addViewController("/caoyang").setViewName("success"); // 可以通过访问/caoyang从而起到访问success的作用
registry.addViewController("/").setViewName("success");
registry.addViewController("/index.html").setViewName("success");
4.8 【实验】国际化
- 编写国际化配置文件
- 在
classpath
下新建i18n
文件夹, 其中新建三个配置文件login.properties
,login_en_US.properties
,login_zh_CN.properties
- 在里面分别填写一些默认配置数据(这是中文的模板, 还有英文的)
login.btn=登录 login.password=密码 login.remember=记住我 login.tip=请登录
- 在里面分别填写一些默认配置数据(这是中文的模板, 还有英文的)
- SpringBoot自动配置好了管理国际化资源的文件
- 在
application.properties
中进行国际化配置文件的路径配置:spring.messages.basename=i18n.login
- 去页面获取国际化的值:
- 官方文档第四章:
#...
获取国际化信息:<div th:text="#login.tip"></div>
即可 - 此时根据浏览器的语言或地区信息就可以实现中英文的切换
- 原理:
- 根据请求头中的
Accept-language
字段的语言排序来决定显示中文还是英文 - 当然可以重写
LocaleResolver
👇package com.example.demo; import java.util.Locale; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.util.StringUtils; import org.springframework.web.servlet.LocaleResolver; public class MyLocaleResolver implements LocaleResolver @Override public Locale resolveLocale(HttpServletRequest request) String l = request.getParameter("l"); Locale locale = Locale.getDefault(); // 获取操作系统的默认值 if(!StringUtils.isEmpty(l)) String[] split = l.split("_"); locale = new Locale(split[0],split[
以上是关于学习笔记雷丰阳SpringBoot教程摘要的主要内容,如果未能解决你的问题,请参考以下文章