SpringBoot
- 0.SpringBoot模块汇总
- 1.Webjars是什么?有什么用?
- 2.SpringBoot 2.0监听器(ApplicationListener)的使用:ApplicationReadyEvent事件
- 3.热部署是什么?SpringBoot怎么开启热部署?
- 4.SpringBoot内置日志框架logback的详细配置和说明
- 5.SpringBoot自动配置原理?
- 6.SpringBoot实现全局异常拦截处理?
- 7.SpringBoot使用@ConfigurationProperties 配置模块
- 8.SpringBoot监视器actuator的使用
- 9.SpringBoot项目基础依赖
- 10.SpringBoot获取服务器信息
- 11.java -jar命令启动一个SpringBoot
- 12.SpringBoot内置Tomcat配置
- 13.EnvironmentAware
- 14.AopContext.getCurrentProxy
- 15.SpringBoot使用Hibernate Validate
- 16. bootstrap.yml优先application.yml(或properties)加载
0.SpringBoot模块汇总
1.Webjars是什么?有什么用?
- Webjars 是将web前端资源(例如jquery/BookStrap/等css和js文件)打成jar包文件,然后借助Maven工具,以jar包的形式对web前端资源进行统一管理,保证这些web资源的唯一性。Webjars的jar包部署在Maven中央仓库上。
- 用过SpringMVC的人都知道,静态的js、css等文件都需要配置静态资源的映射;但在SpringBoot中不需要进行此项的配置,因为SpringBoot已经内置对Webjars的支持。SpringBoot自动将 /webjars/ ** 请求 映射到classpath:/META-INF/resources/webjars/ 目录下。
<!--Webjar官网:https://www.webjars.org/-->
<!--Webjars版本定位工具:省略版本号-->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>webjars-locator-core</artifactId>
</dependency>
<!--Jquery3.3.1-->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.3.1</version>
</dependency>
<!--bootstrap3.3.7-1-->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>3.3.7-1</version>
</dependency>
<!--忽略版本号之前的URL请求-->
<script src="/webjars/jquery/3.1.1/jquery.min.js"></script>
<script src="/webjars/bootstrap/3.3.7-1/js/bootstrap.min.js"></script>
<title>WebJars</title>
<link rel="stylesheet" href="/webjars/bootstrap/3.3.7-1/css/bootstrap.min.css" />
<!--忽略版本号之后URL请求,忽略版本号有利于后续的版本升级,而不需要修改URL请求地址-->
<script src="/webjars/jquery/jquery.min.js"></script>
<script src="/webjars/bootstrap/js/bootstrap.min.js"></script>
<title>WebJars</title>
<link rel="stylesheet" href="/webjars/bootstrap/css/bootstrap.min.css" />
2.SpringBoot 2.0监听器(ApplicationListener)的使用:ApplicationReadyEvent事件
- 好处:该事件在SpringBoot程序启动后触发,配合日志在控制台打印Swagger2访问地址,项目访问地址,Druid监控地址。
- ① 编写监听器类,实现ApplicationListener<>接口,重写onApplicationEvent方法。
package com.wpq.listener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
@Slf4j
public class ApplicationInitListener implements ApplicationListener<ApplicationReadyEvent> {
@Override
public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
log.info(".......程序初始化成功,SpringBoot启动后执行......");
log.info("Swagger2接口文档查看:http://localhost:8080/swagger-ui.html");
log.info("角色页面访问:http://localhost:8080/role.html");
log.info("Druid监控页面:http://localhost:8080/druid/sql.html");
}
}
- ② SpringBoot启动类中添加监听器。
package com.wpq;
import com.wpq.config.EnableNetWorkServiceAutoConfiguration;
import com.wpq.listener.ApplicationInitListener;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import tk.mybatis.spring.annotation.MapperScan;
@SpringBootApplication
@MapperScan(basePackages ="com.wpq.mapper")
public class Application {
public static void main(String[] args) {
SpringApplication application =new SpringApplication(Application.class);
application.addListeners(new ApplicationInitListener());
application.run(args);
//SpringApplication.run(Application.class, args);
}
}
- ③ SpringBoot程序启动后,控制台打印访问地址,可直接访问。
2020-02-18 14:21:56.510 INFO 10052 --- [main] c.wpq.listener.ApplicationInitListener: .......程序初始化成功,SpringBoot启动后执行......
2020-02-18 14:21:56.510 INFO 10052 --- [main] c.wpq.listener.ApplicationInitListener: Swagger2接口文档查看:http://localhost:8080/swagger-ui.html
2020-02-18 14:21:56.510 INFO 10052 --- [main] c.wpq.listener.ApplicationInitListener: 角色页面访问:http://localhost:8080/role.html
2020-02-18 14:21:56.510 INFO 10052 --- [main] c.wpq.listener.ApplicationInitListener: Druid监控页面:http://localhost:8080/druid/sql.html
3.热部署是什么?SpringBoot怎么开启热部署?
- 概念: 项目启动之后,如果内容有更改,项目会自动地实现及时更新,而不需要从新手动启动这个项目。
- SpringBoot有几种方式开启热部署,下面推荐一种最为常用的方式。
- 方式:手动进行热部署的触发。
- ① 导包
<!--导包
下面的这个包是咋们开发的时候 需要的所有的工具 在这里面都是有的。
热部署的这个工具也是位于这个包里面
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
② pom.xml中配置plugin。
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
</configuration>
</plugin>
</plugins>
</build>
③ 配置触发。
4.SpringBoot内置日志框架logback的详细配置和说明
- ① application.yml文件中设置logback配置文件位置。
logging:
config: classpath:logback-spring.xml #指定logback配置文件的位置
- ② logback-spring.xml文件中进行细节配置(文件名以spring结尾可以享受SpringBoot的高级特性)
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false" scan="true" scanPeriod="60 seconds">
<!-- 1. scan :设置是否动态加载该配置,设置为true的时候,只要文件改变,该文件就会被重新加载-->
<!-- 2. scanPeriod :设置监听配置文件是否有修改的时间间隔,没有给定时间单位的话那么默认时间单位是毫秒。
当scan为true的时候,此属性生效。-->
<!-- 3. debug:当此属性设置为true的时候,将打印出logback内部日志信息,实时查看logback的运行状态。默认false-->
<!-- 4. contextName :设置上下文名称,默认上下文名称为"default",可自定义,
用于区分不同应用程序的记录,一旦设置,不能修改-->
<contextName>logback</contextName>
<!-- 5. property :设置变量,name是键,value是值,设置之后可以在其它标签中使用${name值}引用-->
<property name="log.path" value="./logs/spring.log"/>
<!-- 6. appender : 定义日志组件-->
<!-- 7. ConsoleAppender :输出日志到控制台的类 -->
<!-- 8. encoder:指定日志的输出格式(pattern)和编码格式(charset)-->
<!-- 9. springProfile: SpringBoot高级标签,用于多环境的配置,name属性指定环境名称-->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!--表示的是输出日志的格式
%d{yyyy-MM-dd-HH:mm:ss.SSS}:时间引用
%level:日志的级别
%contextName:上下文名称
[%thread]:线程名字
%class:打印对象的全类名
%logger{36}: 打印日志的类的全类名,并限定不能超过36个字符
%file:打印日志的类的.java文件 xxxController.java
%line:打印日志的代码的行号(一般不要)
%msg:日志记录的信息
%n:换行
-->
<!--默认环境-->
<pattern>%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>
<!--dev环境-->
<springProfile name="dev">
<pattern>%d{HH:mm:ss} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>
</springProfile>
<!--prod环境-->
<springProfile name="prod">
<pattern>%d{HH:mm:ss.SSS} ======= %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>
</springProfile>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 10. RollingFileAppender:滚动输出日志到文件夹的类,当达到一定条件的时候日志会输出到其它文件中 -->
<!-- 11. file标签:设置日志文件的生成路径和名称 -->
<!-- 12. rollingPolicy:设置滚动策略 -->
<!-- 13. TimeBasedRollingPolicy:(常用)时间滚动策略,根据时间进行滚动,当达到一定的时间后,
会自动开辟一个新的日志文件 ,最小的滚动单位是天,每天生成一个日志文件-->
<!-- 14. fileNamePattern:文件名匹配:滚动生成的日志文件,会按照这个格式命名,
引用时间来使文件名不重复-->
<!-- 15. maxHistory: 设置生成日志的最大保留时间,单位为天,过期删除-->
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}.%d{yyyy-MM-dd}.zip</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%date %level [%thread] %logger{36} [%file : %line] %msg%n </pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 16. FixedWindowRollingPolicy:索引滚动策略,定义文件名称的时候使用%i作为占位符,滚动后会用角标替换 -->
<!-- 17. minIndex:设置生成日志文件数量的最小值-->
<!-- 18. maxIndex:设置生成日志文件数量的最大值-->
<!-- 19. triggeringPolicy:滚动策略的触发器,可设置触发条件-->
<!-- 20. maxFileSize:设置单个日志文件占用硬盘空间的最大值-->
<appender name="fixedFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>./logs/spring-controller.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<!--%i:会调用索引,1>>2>>3循环-->
<fileNamePattern>./logs/spring-controller.log%i.log</fileNamePattern>
<minIndex>1</minIndex>
<!-- 21. 最多生成三个日志文件,当三个日志文件的大小都为5M的时候,新的日志信息会覆盖第一个日志的内容-->
<maxIndex>3</maxIndex>
</rollingPolicy>
<!-- 22. 触发器说明:单个日志文件的大小达到5M的时候会触发 索引滚动策略,生成新的日志文件继续记录-->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>5MB</maxFileSize>
</triggeringPolicy>
<encoder>
<pattern>%date %level [%thread] %logger{36} [%file : %line] %msg%n
</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!--23. appender整合过滤器,日志信息先经过过滤器的筛选,再交给logger或者root(调用者),
调用者再用level属性进行二次过滤-->
<appender name="fileFilter" class="ch.qos.logback.core.FileAppender">
<file>./logs/spring-mapper.log</file>
<!--append:设置新日志信息是否追加到旧日志信息,默认为true,false表示覆盖-->
<append>true</append>
<!-- 24. LevelFilter:日志级别过滤器。
如果日志信息的级别等于配置(level)的级别。那么则执行onMatch里面的配置
否则执行 onMismatch中的内容
-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<!--
ACCEPT:当前日志信息被保存,不再经过其它的过滤器了
DENY:当前日志信息被删除,不再经过其它的过滤器了
NEUTRAL:将当前日志信息抛给下一个过滤器、如果是最后一个过滤器的话那么日志信息将会被保存
-->
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<!-- 25. ThresholdFilter:临界值过滤器:如果日志信息的级别低于配置(level)级别,将被过滤掉-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>DEBUG</level>
</filter>
<encoder>
<pattern>%date %level [%thread] %logger{36} [%file : %line] %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 26. prudent:设置是否线程安全,推荐关闭,设置线程安全会影响日志信息输出的效率-->
<prudent>false</prudent>
</appender>
<!--27.
logger:代表一个日志输出对象
name: 指定包名
level:指定日志级别
appender-ref:表示对appender的引用
additivity:设置是否向root(根logger)传递日志信息,false不传递,true传递
默认为true,即默认子logger是向root传递日志信息的
-->
<!--局部logger(子logger):记录controller层日志信息-->
<logger name="com.wpq.controller" level="info" additivity="false">
<appender-ref ref="fixedFile"/>
</logger>
<!--局部logger(子logger):记录mapper层日志信息-->
<logger name="com.wpq.mapper" level="debug" additivity="false">
<appender-ref ref="fileFilter"/>
</logger>
<!-- 28. root:可以理解为一个根节点,而其他的logger都可以看做root的子节点-->
<!--全局logger(父logger):打印整个项目的所有日志信息-->
<root level="info">
<appender-ref ref="console"/>
<appender-ref ref="file"/>
</root>
</configuration>
5.SpringBoot自动配置原理?
-
① SpringBoot启动类中的@SpringBootApplication注解中包含了@EnableAutoConfiguration注解。
-
② @EnableAutoConfiguration注解中包含了@Import(AutoConfigurationImportSelector.class)。
-
③ AutoConfigurationImportSelector类中–>selectImports()方法。
-
④ selectImports()方法中–>getCandidateConfigurations方法。
-
④ getCandidateConfigurations方法中–>SpringFactoriesLoader.loadFactoryNames方法。
-
⑤ SpringFactoriesLoader.loadFactoryNames方法中–>loadSpringFactories方法。
-
⑥ loadSpringFactories方法中–classLoader.getResources(“META-INF/spring.factories”)
-
⑦ 扫描所有jar包路径下的spring.factories文件
-
⑧ 找到spring.factories文件,获取文件中列表清单,加载自动配置类。实现自动配置。
-
⑨ 自动配置类是否生效又取决于条件注解。如@ConditionalOnBean,@ConditionalOnMissingBean,@ConditionalOnClass, @ConditionalOnProperty
6.SpringBoot实现全局异常拦截处理?
- @RestControllerAdvice: 只能拦截Controller层的异常。
package com.wpq.excption;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wpq.dto.ResponseBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
*
* 全局Controller层异常拦截,统一返回数据格式
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
private static final String ERROR_INFO = "errorInfo";
/**
* 全局处理Controller层的业务异常
* @param e
* @return
* @throws JsonProcessingException
*/
@ExceptionHandler(value = BasicBusinessException.class)
public ResponseBean basicBusinessExceptionHandler(BasicBusinessException e) throws JsonProcessingException {
String errorInfo = "";
JSONObject data = null;
if (e.getStackTrace().length>0){
StackTraceElement element = e.getStackTrace()[0];
errorInfo= e.toString()+ " 错位位置:"+element.getFileName()+":"+element.getLineNumber();
data = new JSONObject();
data.put(ERROR_INFO,errorInfo);
}
ResponseBean result = ResponseBean.businessError(e.getCode(), e.getMessage()).putData(data);
log.error(new ObjectMapper().writeValueAsString(result));
return result;
}
/**
*全局捕获Controller层的系统异常
* @param e
* @return
* 完整异常信息= 异常类型 + 产生异常的类 +错误行号
*/
@ExceptionHandler(value = Exception.class)
public ResponseBean exceptionHandler(Exception e) {
String errorInfo = "";
if (e.getStackTrace().length > 0) {
StackTraceElement element = e.getStackTrace()[0];
errorInfo = StringUtils.isEmpty(element.getFileName())
? e.toString() + " 未找到错误文件"
: e.toString() + " 错误位置:" + element.getFileName() + ":" + element.getLineNumber();
}
JSONObject data = new JSONObject();
data.put(ERROR_INFO, errorInfo);
ResponseBean result = ResponseBean.businessError().putData(data);
log.error(JSON.toJSONString(result));
return result;
}
}
7.SpringBoot使用@ConfigurationProperties 配置模块
- 1.搭建SpringBoot项目,导入configuration-processor依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
- 2.编写配置类
@ConfigurationProperties(prefix = "config.properties")
//@Component 可以自己注入到IOC
@Data
public class MyConfig {
private String name;
private String password;
private Integer code;
}
@Configuration
@EnableConfigurationProperties(MyConfig.class)//讲Myconfig类注入到IOC容器
@Data
public class MyConfigSS {
private MyConfig myConfig;
private String configName;
private Integer code;
MyConfigSS(MyConfig config){
this.myConfig = config;
this.configName=config.getName();
this.code=config.getCode();
}
}
- 3.yml或者properties中配置MyConfig的属性值,实现自动注入
config.properties.code=200
config.properties.password=12345
config.properties.name=jack
8.SpringBoot监视器actuator的使用
- 1.搭建SpringBoot项目,导入actuator依赖
<!--actuator-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
- 2.application配置文件中配置
# 监视器运行端口
management.server.port=8090
# 激活所有的内置Endpoints
management.endpoints.web.exposure.include=*
# 开启shutdown这个endpoint
management.endpoint.shutdown.enabled=true
- 3.开启程序,浏览器地址栏输入http://localhost:8099/actuator/,后面可以加Endpoints
9.SpringBoot项目基础依赖
<!--spring boot parent-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath/>
</parent>
<!--properties-->
<properties>
<spring-boot.version>2.0.4.RELEASE</spring-boot.version>
</properties>
<!--dependencies-->
<dependencies>
<!--test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
<!--build-->
<build>
<!--指定jar包名为项目唯一ID加上项目版本号-->
<finalName>${project.artifactId}-${project.version}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<!--要和springboot版本号相匹配-->
<version>${spring-boot.version}</version>
<!--配置mvn package的时候执行springboot maven plugin
的repackage命令-->
<!--配置mvn install的时候执行springboot maven plugin
的repackage命令-->
<!--将项目重新打包成可运行的jar包-->
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<!--开启支持devtools 热部署-->
<configuration>
<fork>true</fork>
</configuration>
</plugin>
</plugins>
<!--编译的时候同时也把包下面的xml同时编译进去-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
</build>
10.SpringBoot获取服务器信息
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
@Slf4j
public class ServerConfig {
private static final String serverPort;
private static final String applicationName;
static {
Properties pro = new Properties();
InputStream in = ServerConfig.class
.getClassLoader().getResourceAsStream("application.properties");
try
{
pro.load(in);
}
catch (IOException e)
{
log.error(e.getMessage(),e);
}
serverPort = pro.getProperty("server.port");
applicationName = pro.getProperty("spring.application.name");
}
public static String getServerInfo(){
return applicationName+":"+serverPort;
}
}
11.java -jar命令启动一个SpringBoot
java -jar [jar包绝对路径] CMD启动一个SpringBoot项目
将JAR包放在指定文件下: java -jar [jar包相对路径]
12.SpringBoot内置Tomcat配置
#配置 Web 容器的端口号(默认为 8080)
server.port:
#配置当前项目出错时跳转去的页面
server.error.path:
#配置 session 失效时间。30m 表示 30 分钟,如果不写单位则默认单位是秒。(注意:由于 Tomcat 中配置 session 过期时间是以分钟为单位,如果我们这里设置是秒的话,那么会自动转换为一个不超过所配置秒数的最大分钟数。比如配置了 119 秒,那么实际 session 过期时间是 1 分钟)
server.servlet.session.timeout:
#配置项目名称(默认为 /),如果配置了项目名称,那么在访问路径中要加上配置的路径
server.servlet.context-path:
#配置 Tomcat 请求编码
server.tomcat.uri-encoding:
#配置 Tomcat 的最大线程数
server.tomcat.max-threads:
#配置 Tomcat 运行日志和临时文件的目录。若不配置,则默认使用系统的临时目录
server.tomcat.basedir:
13.EnvironmentAware
- 根据application.yml或者application.properties文件中spring.active.profiles环境参数变量,加载对应环境变量结尾的properties或者yml配置文件。
@Component
public class EnvObj implements EnvironmentAware {
private static Environment environment;//根据 spring.profile.active激活的环境,加载对应的yml和properties配置文件
@Override
public void setEnvironment(@NonNull Environment environment) {
EnvObj.environment = environment;
String property = environment.getProperty("APP.a");
System.out.println("property = " + property);
String property1 = environment.getProperty("APP.b");
System.out.println("property1 = " + property1);
}
}
14.AopContext.getCurrentProxy
- 拿到当前类的代理类的实例来调用该类中方法。如带有日志自定义注解方法,直接被本类其它方法调用会丢失日志打印功能。可用该API解决该问题。Spring boot启动类注解记得要加上 @EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true) 来暴露AOP的代理对象,否则会报异常。
- service层
@Service
public class TestLogService {
@Log
public Object test_a(){
return "test_a";
}
//本类中AOP增强方法b调用本类另外一个AOP增强方法a,要使用代理对象去调用,否则a的日志将不会打印
@Log
public Object test_b(){
TestLogService testLogService = (TestLogService) AopContext.currentProxy();
return testLogService.test_a()+"_for_"+"test_b";
}
}
- 自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
boolean printLog() default true;
}
- AOP切面
@Aspect
@Component
@Slf4j
@Order(1)
public class LogAspect {
@Pointcut("@annotation(com.wpq.hibernate.log.Log)")
public void pc(){}
@Around("pc()&& @annotation(lg)")
public Object around(ProceedingJoinPoint jp,Log lg) throws Throwable {
Object proceed = jp.proceed();
boolean printLog = lg.printLog();
if (printLog)
log.info("result = {}",proceed.toString());
return proceed;
}
}
- Controller层
@RequestMapping(value = "logTest",
method = {RequestMethod.POST,RequestMethod.GET})
public Object logT(Demo demo){
Object o = testLogService.test_b();
}
- 日志打印结果
LogAspect : result = test_a
LogAspect : result = test_a_for_test_b
15.SpringBoot使用Hibernate Validate
- 1.SpringBoot配置类
import org.hibernate.validator.HibernateValidator;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
@SpringBootConfiguration
public class HibernateValidateConfig {
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
MethodValidationPostProcessor postProcessor = new MethodValidationPostProcessor();
postProcessor.setValidator(validator()); //设置validator模式为快速失败返回
return postProcessor;
}
@Bean
public Validator validator(){
ValidatorFactory validatorFactory =
Validation.byProvider( HibernateValidator.class )
.configure()
.failFast(false)//快速失败:遇到一个错误就立马中断检测
.buildValidatorFactory();
return validatorFactory.getValidator();
}
}
- 2.创建组接口和定义组顺序
public interface GroupA {}
public interface GroupB {}
//指定组的验证顺序,前面组验证不通过的,后面组不进行验证:
//组的意义:比如插入和更新验证的字段不同,组的概念
@GroupSequence({GroupA.class, GroupB.class, javax.validation.groups.Default.class})
public interface GroupOrder {}
- 3.实体类
@Data
public static class Demo {
@Length(min = 5,
max = 17,
message = "length长度在[5,17]之间!!",
groups = {GroupA.class})
private String length;
@NotBlank(message="年龄不能为空!!"
,groups = GroupA.class)
@Pattern(regexp="^[0-9]{1,2}$",
message="年龄必须是0~99!!"
,groups = {GroupA.class})
private String age;
@Range(min = 150,
max = 250,
message = "高度在[150,250]之间",
groups = {Default.class})
private int high;
@NotNull(message = "list cannot be null!",
groups = {Default.class})
//@Size适用于String, 集合, Map ,数组
@Size(min = 3,
max = 5,
message = "list的Size在[3,5]",
groups = {Default.class})
private List<String> list;
//只有一个@Pattern得话,如果是空,则不校验,如果不为空,则校验
@Pattern(regexp="^[0-9]{4}-[0-9]{2}-[0-9]{2}$",
message="出生日期格式不正确",
groups = {GroupB.class})
@NotBlank(message = "出生日期必须填写!!",
groups = {GroupB.class})
private String birthday;
}
- 4.Controller层注入验证器,校验接口入参实体
@Autowired
Validator validator;//HibernateValidator 校验器
@RequestMapping(value = "logTest",
method = {RequestMethod.POST,RequestMethod.GET})
public Object logT(Demo demo){
Set<ConstraintViolation<Demo>> validate =
validator.validate(demo,GroupA.class);//也可以同时校验多个组
for (ConstraintViolation<Demo> demo2ConstraintViolation : validate) {
String message = demo2ConstraintViolation.getMessage();
System.out.println("message = " + message);
}
}