SpringBoot手册学习(四)特性

SpringBoot 特性

  1. SpringApplication:

    SpringApplication类提供了快捷启动Spring应用的.run静态方法,默认启动项目打印日志级别为INFO

    启动失败,注册的失败分析器(FailureAnalyzers)会提供错误信息

  2. 启动Spring应用时输出的字符画称为Banner,设置Banner方法有三个

    1. 在classpath中添加banner.txt改变Banner样式

    2. 在application.properties设置Banner参数

    3. 在入口方法main函数中使用 setBannerMode或者setBanner方法设置Banner

      1
      2
      3
      SpringApplication app=new SpringApplication(App.class);
      app.setBannerMode(Banner.Mode.OFF);
      app.run(args);
  3. Logging:

    1. 日志格式解析:日期时间-日志级别-进程ID-[线程名]-日志名(源class类名)-日志信息

    2. 日志系统配置:可在application.properties中配置日志相关参数

      1. 日志级别:通过设置logging.level.*=“LEVEL”来配置不同模块的日志以不同的日志级别输出,一般日志级别从低到高有ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF

        1
        2
        3
        4
        5
        6
        #root日志以WARN级别输出
        logging.level.root=WARN
        #springframework.web日志以DEBUG级别输出
        logging.level.org.springframework.web=DEBUG
        #hibernate日志以ERROR级别输出
        logging.level.org.hibernate=ERROR
      2. 日志输出文件:可以通过设置logging.file或者logging.path属性默认记录ERROR+WARN+INFO级别的日志记录写入文件中

        | logging.file | logging.path | value | 描述 |
        | ———— | ———— | ———- | —————————— |
        | 无设置 | 无设置 | | 记录到控制台 |
        | 设置 | 无设置 | log/my.log | 写到特定目录的特定文件名中 |
        | 无设置 | 设置 | var/log | 写到特定目录的spring.log文件中 |

      3. 日志高级配置:若要设定更高级的日志配置需要使用logging.config指定相应的日志配置文件或者使用相应的*-spring.xml配置文件让SpringBoot帮我们自动配置,这里我们采用log4j2日志系统来进行系统日志配置

        1. 加载log4j2依赖:由于在spring-boot-starter中集成了logback日志系统依赖,我们需要先去除logback依赖再加载log4j2依赖

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter</artifactId>
          <!--去除logback依赖-->
          <exclusions>
          <exclusion>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-logging</artifactId>
          </exclusion>
          </exclusions>
          </dependency>
          <!--加载log4j2依赖-->
          <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-log4j2</artifactId>
          <version>2.0.0.RELEASE</version>
          </dependency>
        2. 配置log4j2配置文件:命名配置文件为log4j2-spring.xml(SpringBoot自动加载)或者自定义配置文件名称但是需要在application.properties里配置logging.config选项

          1
          logging.config=classpath:log4j2.xml
        3. 编写log4j2配置文件:

          简单的log4j2配置文件

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          <?xml version="1.0" encoding="UTF-8"?>
          <!--配置根节点 属性:status-打印日志级别 monitorinterval-监测自动重新配置时间 单位秒-->
          <Configuration>
          <!--日志输出方式组件-->
          <!--通常有Console File RollingFile节点-->
          <!--还有Socket远程服务器输出 Async中转输出至别的Appender-->
          <Appenders>
          <!--Console控制台输出节点-->
          <Console name="Console" target="SYSTEM_OUT">
          <!--输出消息规则-->
          <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
          </Console>
          </Appenders>
          <!--指定日志输出级别和输出方式的组件 通常有Root Logger节点-->
          <Loggers>
          <!--指定特定的包/类使用的日志级别-->
          <Logger name="com.example" level="INFO"/>
          <!--指定所有包/类默认使用的日志级别-->
          <Root level="WARN">
          <!--指定日志输出到哪个Appender-->
          <AppenderRef ref="Console"/>
          </Root>
          </Loggers>
          </Configuration>

          较完整的log4j2配置文件

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
          27
          28
          29
          30
          31
          32
          33
          34
          35
          36
          37
          38
          39
          40
          41
          42
          43
          44
          45
          46
          47
          48
          49
          50
          51
          52
          53
          54
          55
          56
          57
          58
          59
          60
          61
          62
          63
          64
          65
          66
          67
          <?xml version="1.0" encoding="UTF-8"?>
          <!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
          <!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出-->
          <!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数-->
          <configuration status="WARN" monitorInterval="30">
          <!--先定义所有的appender-->
          <appenders>
          <!--控制台输出配置-->
          <console name="Console" target="SYSTEM_OUT">
          <!--输出日志的格式-->
          <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
          </console>

          <!--文件输出,这个log每次运行程序会自动清空,由append属性决定,适合临时测试使用-->
          <File name="log" fileName="testLog/test.log" append="false">
          <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
          </File>

          <!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
          <RollingFile name="RollingFileInfo" fileName="infoLogs/info.log"
          filePattern="infoLogs/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log">
          <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
          <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
          <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
          <Policies>
          <TimeBasedTriggeringPolicy/>
          <SizeBasedTriggeringPolicy size="100 MB"/>
          </Policies>
          </RollingFile>

          <RollingFile name="RollingFileWarn" fileName="warnLogs/warn.log"
          filePattern="warnLogs/logs/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log">
          <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
          <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
          <Policies>
          <TimeBasedTriggeringPolicy/>
          <SizeBasedTriggeringPolicy size="100 MB"/>
          </Policies>
          <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件,这里设置了20 -->
          <DefaultRolloverStrategy max="20"/>
          </RollingFile>

          <RollingFile name="RollingFileError" fileName="errorLogs/error.log"
          filePattern="errorLogs/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log">
          <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
          <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
          <Policies>
          <TimeBasedTriggeringPolicy/>
          <SizeBasedTriggeringPolicy size="100 MB"/>
          </Policies>
          </RollingFile>
          </appenders>

          <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
          <loggers>
          <!--过滤掉spring和mybatis的一些无用的DEBUG信息-->
          <logger name="org.springframework" level="INFO"></logger>
          <!--<logger name="org.mybatis" level="INFO"></logger>-->
          <root level="all">
          <appender-ref ref="Console"/>
          <appender-ref ref="log"/>
          <appender-ref ref="RollingFileInfo"/>
          <appender-ref ref="RollingFileWarn"/>
          <appender-ref ref="RollingFileError"/>
          </root>
          </loggers>
          </configuration>
        4. 使用log自定义输出日志:

          1
          2
          3
          4
          5
          6
          7
          8
          //在类中定义log工具变量
          private static Logger log = LogManager.getLogger(DemoController.class);
          //在方法中可以使用log.日志level(String)输出对应级别的日志
          log.trace("trace");
          log.debug("debug");
          log.info("info");
          log.warn("warn");
          log.error("error");
  4. Lombok:

    Lombok是一种微型框架工具,有助于帮助减少模板代码使得开发更加快速,具体表现为可以使用注解生成Getter、Setter、toString、hashCode、constructor方法等,下面介绍在Spring Boot中使用Lombok

    1. 添加Lombok依赖:由于spring-boot-dependencies中已经配置了lombok依赖的参数,如version和scope,我们可以直接添加依赖

      1
      2
      3
      4
      5
      <!--lombok生成代码工具-->
      <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      </dependency>
  1. 在代码中使用Lombok:我们可以在需要使用生成Getter、Setter、Constructor的类中使用注解的方式而不是IDEA生成的方式生成相应的方法代码,常用的注解加粗,详细解释可查看Lombok官方文档

    | 注解 | 作用 |
    | ———————– | ————————————————– |
    | @Getter | 生成类属性的getter方法 |
    | @Setter | 生成类属性的setter方法 |
    | @ToString | 生成类所有属性的toString方法 |
    | @EqualsAndHashCode | 生成类的equal和hashCode方法 |
    | @NoArgsConstructor | 生成类的无参构造方法 |
    | @AllArgsConstructor | 生成类的全参数的构造方法 |
    | @Data | 相当于@Getter+@Setter+@ToString+@EqualsAndHashCode |
    | @Log4j | 为类生成一个名为log的log4j日志对象 |
    | @NonNull | 标识在实体对象上自动进行非空校验 |

  1. Hibernate Validator:

    后台经常需要校验所接收的参数,如是否为空、长度规定、正则判定等,spring-boot-starter-web 依赖中集成了hibernate validator 提供了一套较为完善、便捷的验证实现方式

    1. 简单参数的验证:在所需验证的参数的类(如controller)上添加@Validated注解,在需要验证传入参数的方法的参数列表中添加验证注解

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      @RestController
      @Validated
      public class DemoController{
      @RequestMapping("/")
      public void simpleParamsValidate(
      @Size(min=3,max=10,message="名字长度为3-10") @RequestParam("name") String name,
      @Range(min=1,max=99,message="年龄只能从1-99") @RequestParam("age") String age
      ){
      //toDo...
      }
      }
    2. 复杂的对象参数的验证:对于复杂的参数我们可以编写一个Model对象进行接收,这样直接在Model对象内部编写注解进行属性的验证,对于在Web开发中的POST请求我们可以直接使用@RequestBody注解将接收的json字符串注入到Model对象中进行验证,并利用BindingResult处理验证结果

      Person.java(Model对象)

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      @Data
      @NoArgsConstructor
      @AllArgsConstructor
      public class Person {
      @NotBlank(message = "姓名不能为空")
      @Size(min=3,max=10,message = "名字长度为3-10")
      private String name;

      @NotBlank(message = "年龄不能为空")
      @Range(min = 1, max = 99, message = "年龄只能从1-99")
      private String age;

      @Email
      private String email;

      @NotBlank(message = "密码不能为空")
      @Length(min=3,max=10,message = "密码长度为3-10")
      private String password;

      }

      DemoController中的validateModel方法

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      //用@RequestBody将JSON字符串直接注入至JAVA对象中需要HTTP方法使用POST
      //@Valid注解验证注入对象的数据是否符合注解规定
      //BindingResult存储错误消息
      @RequestMapping(value = "/validateModel",method = RequestMethod.POST)
      public Map validateModel(
      @RequestBody @Valid Person person,BindingResult result
      ){
      //BindingResult.hasErrors存储是否存在验证问题
      if(result.hasErrors()){
      ArrayList errorArray=new ArrayList();
      //BindingResult.getAllErrors()得到一个ObjectError对象的数组
      for (ObjectError error : result.getAllErrors()) {
      //ObjectError对象.getDefaultMessage()可得到错误消息
      errorArray.add(error.getDefaultMessage());
      }
      Map<String,Object> map=new HashMap<>();
      map.put("Error",errorArray);
      return map;
      }else{
      Map<String,Object> map=new HashMap<>();
      map.put("GetParams",person);
      return map;
      }

      }
    3. 设置失败快速返回:Hibernate Validator 有两种验证模式:

      • 普通模式(默认):校验完所有属性,返回所有验证失败信息
      • 快速失败返回模式:只要校验到一个失败,直接返回
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      @Configuration
      public class ValidatorConfig {

      @SuppressWarnings("unchecked")
      @Bean
      public Validator validator(){
      ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
      .configure()
      .failFast(true) //配置失败快速返回模式
      .buildValidatorFactory();
      Validator validator = validatorFactory.getValidator();

      return validator;
      }
      }
    4. 常见的验证注解:

    5. 其余校验技巧:详解可参考Mr.yang.localhost的博客文章

      • 级联校验:验证的对象A中有其他需要验证的对象B,需要在对象A中使用注解@Valid 标记对象B
      • 分组校验:在不同场景需要校验对象的不同属性,如注册中校验name、age等,但是用户操作要校验id等
      • 自定义验证器