学习笔记雷丰阳SpringBoot教程摘要

Posted 囚生CY

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了学习笔记雷丰阳SpringBoot教程摘要相关的知识,希望对你有一定的参考价值。

尝试在月底前更完, 之前看的那个教程虽然是2020年最新的, 但是感觉讲师有点半吊子, 慕名看了雷丰阳的SpringBoot教程https://www.bilibili.com/video/BV1Et411Y7tQ, 实在是精细而专业, 受益匪浅
认真要学还是亲自去看一遍网课, 本文主要是记录雷神授课时的笔记以及一些额外的细节, 相对较为详细, 可作参考
20201001更新: 都怪进巨太好看, 月底是更不玩了… 国庆再说吧…
最终还是做了个人, 赶在国庆假期最后一天把课程看完了. 后八章是进阶部分, 没有详细实践, 有些东西等要用再说吧
截至20201008, 更新完成16章111节的摘要

目录

1. Spring Boot入门

  1. Spring Boot来简化Spring应用开发, 约定大于配置, 去繁从简, just run就能创建一个独立的, 产品级别的应用

  2. 背景: J2EE笨重的开发, 繁多的配置, 低下的开发效率, 复杂的部署流程, 第三方技术集成难度大

  3. Spring Boot问题解决: Spring全家桶时代

  • Spring Boot: J2EE一站式解决方案
  • Spring Cloud: 分布式整体解决方案
  1. Spring Boot优点:
  • 快速创建独立运行的Spring项目以及主流框架的集成
  • 使用嵌入式的Servlet容器, 应用无需打包成WAR
  • starters自动依赖与版本控制
  • 大量的自动配置, 简化开发, 也可以修改默认值
  • 无需配置XML, 无代码生成, 开箱即用
  • 准生产环境的运行时应用监控
  • 与云计算天然继集成
  1. Spring Boot与微服务: 区别于单体应用架构风格
  1. Spring Boot前置环境约束:
  • jdk 1.7版本及以上版本
  • maven 3.x版本
  • spring tools suite 4.x.x版本, 截至本文发布时spring-boot发行的最新版本是4.8.0
  1. 关于如何安装springboot及启动一个Helloworld项目详见https://caoyang.blog.csdn.net/article/details/108700844
  • 因为笔者使用的是sts4.8.0, 而雷风阳使用的是sts1.5.9, 因此上手时参考的是另一个视频教程, 后来感觉还是雷风阳的教程比较规整, 因此切换回来后跳过了入门部分的一些章节, 比如sts4从零开始创建Helloworld项目的流程以及注解器和日志等细节, 该链接中笔者较为详细地记录了这些跳过的内容, 两个版本区别可能不会太大; 下文中很多笔记都是基于链接中创建的Helloworld项目继续完善的

2. Spring Boot配置

补充: .properties文件的注释是#, .yml文件不建议写注释

  1. properties与yml配置文件详见https://caoyang.blog.csdn.net/article/details/108700844第二章内容

  2. 配置文件数据注入到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.propertiesapplication.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();
        	
        
        
  1. 配置文件占位符
  • 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
    
  1. 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
  1. 配置文件加载位置
  • 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=<绝对路径>
      • 即可以在打包完成后再给个新的配置文件路径
  1. 外部配置加载顺序: 官方文档中有17个, 这里选取其中常用的11个, 优先级从高到低
  • 命令行参数: java -jar spring-boot-xx-config-x.x.x-SNAPSHOT.jar --<参数名>=<参数值>
  • 来自java:com[/envJNDI属性
  • Java系统属性(System.getProperties())
  • 操作系统环境变量
  • RandomValuePropertySource配置的random.*属性值
  • jar包外部的application-profile.propertiesapplication.yml(带spring.profile)配置文件
  • jar包内部的application-profile.propertiesapplication.yml(带spring.profile)配置文件
  • jar包外部的application.propertiesapplication.yml(不带spring.profile)配置文件
  • jar包内部的application.propertiesapplication.yml(不带spring.profile)配置文件
  • @Configuration注解类上的@PropertySource
  • 通过SpringApplication.setDefaultProperties指定的默认属性
  1. 自动配置原理:
  • 配置文件中可以写什么东西?配置文件能配置的属性参照文档
  • 自动配置原理:
    • 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默认写好的自动配置类? 没有就需要自己写
    • 我们再来看这个自动配置类中到底配置了哪些组件, 只要我们要用的组件有, 就不需要再来配置了
    • 给容器中自动配置类添加组件的时候, 会从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 日志框架分类和选择

  1. 市面上的日志框架:
  • 日志门面(日志的抽象层):
    • JCL: Jakarta Commons Logging, 这个最后更新是2014年, 基本已经弃用了
    • slf4j: Simple Logging Facade for java
    • jboss-logging
  • 日志实现:
    • JUL: java.util.logging
    • logback
    • log4j
    • log4j2
  • 选择日志门面中的一个作为框架(抽象层), 再选择日志实现中的一个来实现

SpringBoot底层是Spring框架, 默认使用的是JCL, 但SpringBoot选用的是slf4j呵呵logback

3.2 slf4j使用原理

  1. 如何在系统中使用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

  1. 遗留问题
  • 开发A系统(slf4j+logback): Spring(commons-logging), Hibernate(jboss-logging), MyBatis等
  • 统一日志记录, 即便是别的框架也一起使用slf4j来输出?

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>
  1. SpringBoot底层也是使用slf4j+logback的方式进行日志记录
  2. SpringBoot也把其他的日志都替换成了slf4j
  3. SpringBoot使用了中间替换包
  4. 如果我们要引入其他框架, 一定要把这个框架的默认日志依赖移除
  • 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默认配置

  1. 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表示换行符
  1. LoggerFactory的logger对象方法(级别从低到高)
  • logger.trace()
  • logger.debug()
  • logger.info()
  • logger.warn()
  • logger.error()

3.6 指定日志文件和日志Profile功能

  1. 指定配置
  • 给类路径下放上每个日志框架自己的配置文件即可, 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-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>
      

3.7 切换日志框架

  1. 可以按照slf4j的日志适配图, 进行相关的切换
  2. 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>  
  1. 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 简介

  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: 配置类来封装配置文件的内容
      
  • 自己编写业务代码
  1. 目前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与静态资源映射资源

  1. 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

  1. 模板引擎:
  • JSP
  • Velocity
  • Freemarket
  • Thymeleaf: SpringBoot推荐, 语法简单, 功能强大
  1. 引入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语法

  1. 检查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即可看到"成功!你好"的字样
  1. thymeleaf语法规则
  • th标签: 官方文档PDF的第十章
    • th:textth: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自动配置原理

  1. SpringBoot自动配置好了SpringMVC
  2. 以下是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的所有自动场景
  1. 如何修改SpringMVC的默认配置
  • 模式:
    • SpringBoot在自动配置很多组件的时候, 先看容器中有没有用户自己配置的(@Bean,@Component), 如果有就用用户配置的, 如果没有才会自动配置, 如果有些组件可以有多个(如ViewResolver), 则会将用户配置的和自己默认的组合起来
    • 在SpringBoot中会有非常多的xxxWebMvcConfigurer, 需要多留心

4.6 扩展与全面接管SpringMVC

  1. 扩展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的自动配置和我们的扩展配置都会起作用
  1. 全面接管SpringMVC配置
  • SpringBoot对SpringMVC的自动配置不需要了, 所有都是我们自己配
  • 只需要在配置类上添加@EnableWebMvc注解, 注意第1点里的配置文件是只能添加一个@Configuration注解
  • 一般不建议全面接管, 否则就连index.html也无法访问了
  • 原理: 为什么@EnableWebMvc会使SpringMVC的默认配置都失效
    • @EnableWebMvc注解将WebMvcConfigurationSupport组件导入进来
    • 导入的WebMvcConfigurationSupport组件只是SpringMVC的基本功能配置

4.7 【实验】引入资源

  1. 编写配置类实现路由映射

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 【实验】国际化

  1. 编写国际化配置文件
  • classpath下新建i18n文件夹, 其中新建三个配置文件login.properties, login_en_US.properties, login_zh_CN.properties
    • 在里面分别填写一些默认配置数据(这是中文的模板, 还有英文的)
      login.btn=登录
      login.password=密码
      login.remember=记住我
      login.tip=请登录
      
  1. SpringBoot自动配置好了管理国际化资源的文件
  • application.properties中进行国际化配置文件的路径配置: spring.messages.basename=i18n.login
  1. 去页面获取国际化的值:
  • 官方文档第四章: #...获取国际化信息: <div th:text="#login.tip"></div>即可
  • 此时根据浏览器的语言或地区信息就可以实现中英文的切换
  1. 原理:
  • 根据请求头中的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教程摘要的主要内容,如果未能解决你的问题,请参考以下文章

    雷丰阳SpringSpring MVCMyBatis

    Docker基础用法

    Docker基础用法

    Docker基础用法

    学习笔记兄弟连Linux教程摘要

    动力节点Springboot教程学习笔记整理