- filter、interceptor、AOP 执行顺序
- filter 是容器(常放在servlet)自带的,interceptor 是 Spring MVC 自带的,后者是一个 Web 应用,是放在容器里面的,所以请求会先进入容器,再进入到应用,所以 filter 会比 interceptor 先执行
- 结论: fileter — interceptor — aop
- 基本构成
- filter 基于 servlet
- Interceptor aop 基于 spring 的
- https://blog.csdn.net/testcs_dn/article/details/80279578
1. 过滤器(Filter)
1.1 基础认知
- 首先过滤器是 JavaWeb 阶段的知识,但是现在的项目都是 SpringBoot 的,Web 阶段如何配置的暂时忽略
- 过滤器(Filter)是 J2EE Servlet 模块下的组件
Filter 的作用是对 url 进行统一的拦截,常用于应用程序层面进行全局处理
1.2 实现一个过滤器
任何过滤器都要实现 javax.servlet.Filter 接口
- 在 Filter 接口的 doFilter() 方法编写过滤器的功能代码
配置过滤器
实现接口的代码就不写了,很简单,或者看看下面的版本
- 图一:如何在 web.xml 中对过滤器进行配置,说明拦截的 Url 范围
- 图二:注解如何配置
- 图三:配置化参数,可以提前设置一些设置,然后在初始化的时候取出来
- 图四:拦截支持正则匹配
1.4 SpringBoot版本
1.4.1 基础的Filter代码
package com.kong.wiki.filter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* 接口计时
*
* @author YiHua
* @date 2022/7/3
*/
public class InterfaceTimeFilter implements Filter {
private static final Logger log = LoggerFactory.getLogger(InterfaceTimeFilter.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 拿到请求,获取到想要的信息
HttpServletRequest request = (HttpServletRequest) servletRequest;
log.info("------------- 开始:接口开始被调用 -------------");
log.info("请求地址: {} {}", request.getRequestURL().toString(), request.getMethod());
log.info("远程地址: {}", request.getRemoteAddr());
long startTime = System.currentTimeMillis(); // 执行过滤器的链路,多个过滤器依次执行 ——> 执行业务代码,最后返回来,计算接口耗时
filterChain.doFilter(servletRequest, servletResponse);
log.info("------------- 结束:接口耗时:{} ms -------------", System.currentTimeMillis() - startTime);
}
@Override
public void destroy() {
Filter.super.destroy();
}
}
1.4.2 通过扫描注解完成Filter组件注册
- 在 Filter 实现类使用注解 @WebFilter,设置 filterName、urlPatterns、initParams 等参数
- 编写启动类:增加注解 @ServletComponentScan
- 如果有多个 Filter 可以用 @Order 注解指定执行顺序,序号越小,越早被执行,例如:@Order(1)
1.4.3 通过配置类完成Filter组件注册
```java package com.yihua.mall.common.config;
import com.yihua.mall.common.filter.InterfaceTimeFilter; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
/**
- Servlet级别的配置信息 *
- @author YiHua
- @date 2022/7/3
*/
@Configuration
public class ServletConfig {
@Bean
public FilterRegistrationBean getFilterRegistrationBean() {
} } ```FilterRegistrationBean filter = new FilterRegistrationBean();
filter.setFilter(new MyFilter());
filter.addUrlPatterns(new String[] {"*.do","*.jsp"});
filter.addUrlPatterns("/second");
return bean;
1.4.4 直接使用@Component注解完成注册
直接在实现的 xxxFilter 上新增 @Component 注解
1.5 过滤器的生命周期
1.6 过滤器的特性
过滤器对象在应用程序启动时候被创建,且全局唯一,所以 destory() 在程序关闭才会执行
唯一的过滤器对象在并发环境中采用“多线程”提供服务
拦截器是 Spring MVC 提供的
- 用于对 Url 请求进行前置/后置的拦截处理
- 拦截器和过滤器的用途类似,但是实现方式不同
拦截器的底层是基于Spring AOP切面编程实现的,所以换句话说也就是基于反射实现的
3.2 实现一个拦截器
继承和实现都可以
- 继承: HandlerInterceptorAdapter
- 实现: HandlerInterceptor
- 三个方法介绍
import com.kong.wiki.interceptor.InterfaceTimeInterceptor; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.beans.factory.annotation.Autowired;
@Configuration public class SpringMVCConfiguration implements WebMvcConfigurer {
/**
* 拦截器配置的两种方式
* 1. 直接配置Bean的方式,相当于在spring时代的配置xml文件
* 2. 注入方式,但是拦截器需要加上@Component注解交给spring管理
*/
// 注入这个拦截器
@Autowired
InterfaceTimeInterceptor interfaceTimeInterceptor;
// 配置bean的方式
@Bean
public UserTokenInterceptor interfaceTimeInterceptor() {
return new UserTokenInterceptor();
}
// 对拦截器进行一些配置,计算接口时间的直接默认权限路由
public void addInterceptors(InterceptorRegistry registry) {
// 这里添加的就是上面写的方法名称
registry.addInterceptor(interfaceTimeInterceptor)
// 那些接口需要经过这个拦截器
.addPathPatterns("/**")
// 排除某些接口:
.excludePathPatterns("/login");
}
}
<a name="Cm1NU"></a>
# 4. 监听器(Listener)
1. **监听器是 J2EE Servlet 模块下的组件**
1. **监听器的作用是对 Web 应用对象的行为进行监控**
1. **通过 Listener 监听自动触发指定的功能代码**
1. **内置对象监听接口,如下图所示**
1. **想要监听某个对象,只需要实现对应的监听器接口**
![image.png](https://cdn.nlark.com/yuque/0/2022/png/26687455/1656832624418-23cc8829-77ae-4218-89fe-d8827b92f428.png#clientId=ufbc61056-ae9a-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=341&id=ue8f90a4b&margin=%5Bobject%20Object%5D&name=image.png&originHeight=682&originWidth=1918&originalType=binary&ratio=1&rotation=0&showTitle=false&size=236502&status=done&style=none&taskId=uc5e2e87f-78a1-4e96-ba5c-1eec3374aee&title=&width=959)<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/26687455/1656832645132-a72ae62e-efaf-4ed5-b256-3d27661bb624.png#clientId=ufbc61056-ae9a-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=340&id=u111cb63c&margin=%5Bobject%20Object%5D&name=image.png&originHeight=680&originWidth=1918&originalType=binary&ratio=1&rotation=0&showTitle=false&size=236240&status=done&style=none&taskId=u986646a5-ddce-4487-9419-cc6f09e9c51&title=&width=959)
<a name="YDjT1"></a>
# 5. 参数校验
<a name="WWzsO"></a>
## 5.1 路径参数校验
1. **在类上新增 **`**org.springframework.validation.annotation.Validated**`** 注解**
1. **在对应的参数前面加上常用、定制化的校验注解**
1. **常见的注解**
1. `**javax.validation.constraints.Max**`
1. `**javax.validation.constraints.Min**`
1. `**javax.validation.constraints.Positive**`
4. **注意:路径参数一般不做非空判断,需要的话可以设置**`**required = false**`
<a name="aaZlY"></a>
## 5.2 请求对象参数校验
1. **使用 Spring 提供的**`**org.springframework.validation.annotation.Validated**`**注解**
1. **在类上新增该注解**
1. **在参数对象前面新增该注解**
2. **使用 Servlet 提供**`**javax.validation.Valid**`**注解**
1. **直接在参数对象前面新增该注解**
<a name="VbrSz"></a>
## 5.3 嵌套对象的参数校验
1. **嵌套对象:指一个 model 是另外一个 model 的成员属性**
1. **方式一**
1. **类上、参数对象上新增 @Validated 注解**
1. **参数对象中的,嵌套 model 属性上新增 @Valid 注解**
3. **方式二**
1. **参数对象上新增 @Valid 注解 **
1. **参数对象中的,嵌套 model 属性上新增 @Valid 注解**
<a name="tknWQ"></a>
## 5.4 常见的校验注解
<a name="nSfZD"></a>
### 5.4.1 常见注解
1. **长度校验:**`**@Length(min = 2, max = 20)**`
1. **定义参数的范围:**`**@Range(min = 1, max = 10, message = "1~10欧 ")**`
1. **字段必须是正整数:**`**@Positive**`
1. **字段不能为空**
1. `**@NotEmpty**`**:用在集合类上面**
1. `**@NotBlank**`**:用在 String上面**
1. `**@NotNull**`**:用在基本类型上**
<a name="J5RAs"></a>
### 5.4.2 自定义提示信息
1. **注解这边的操作**
1. `**@NotBlank(message = "{username.not-blank}")**`
1. `**@Positive(message = "{id.positive}")**`
2. **新增配置文件的操作**
1. `**ValidationMessages.properties**`
1. `**username.not-blank = 用户名不可为空**`
1. `**id.positive = id必须为正整数**`
<a name="zYnDa"></a>
## 5.5 自定义校验注解
1. **定义需要的注解,例如:**`**@PasswordEqual**`
1. **使用注解关联业务类,例如:**`**@Constraint(validatedBy = PasswordValidator.class )**`
1. **业务类需要实现指定接口:**`**ConstraintValidator<T,K>**`
1. **实际的操作**
1. `**@TokenPassword**`
1. `**@Enum**`
<a name="oHs8W"></a>
# 6. Spring Data Jpa
1. **VO对象解决的一个问题:如果双向配置导航属性,会产生循环序列化,可能会内存溢出的**
<a name="GuMPL"></a>
# 使用配置的方式配置数据源
1. `**架构师 - 分布式事务 - 基于XA的两阶段提交 - 使用Atomikos的分布式事务**`
1. `**架构师 - Rabbit MQ章节 - 基础组件的封装部分**`
1. **类似于如下的代码**
![image.png](https://cdn.nlark.com/yuque/0/2022/png/26687455/1654437265527-e3fd11aa-a271-42ed-9ef7-d1ae57b9fb1b.png#clientId=u65615064-4bc9-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=375&id=uc1cb55a2&margin=%5Bobject%20Object%5D&name=image.png&originHeight=750&originWidth=2178&originalType=binary&ratio=1&rotation=0&showTitle=false&size=218897&status=done&style=none&taskId=u6b176948-cba3-447f-894f-6fbb4d1d3f6&title=&width=1089)
<a name="LEYmu"></a>
# 事务问题
```sql
@Transactional(rollbackFor = Exception.class)
public Integer createOrder() throws Exception {
}
默认是RunTimeException才会回滚异常,上面的指定什么异常都回滚