- 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);@Overridepublic void init(FilterConfig filterConfig) throws ServletException {Filter.super.init(filterConfig);}@Overridepublic 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);}@Overridepublic 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管理*/// 注入这个拦截器@AutowiredInterfaceTimeInterceptor interfaceTimeInterceptor;// 配置bean的方式@Beanpublic 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. **想要监听某个对象,只需要实现对应的监听器接口**<br /><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 Jpa1. **VO对象解决的一个问题:如果双向配置导航属性,会产生循环序列化,可能会内存溢出的**<a name="GuMPL"></a># 使用配置的方式配置数据源1. `**架构师 - 分布式事务 - 基于XA的两阶段提交 - 使用Atomikos的分布式事务**`1. `**架构师 - Rabbit MQ章节 - 基础组件的封装部分**`1. **类似于如下的代码**<a name="LEYmu"></a># 事务问题```sql@Transactional(rollbackFor = Exception.class)public Integer createOrder() throws Exception {}默认是RunTimeException才会回滚异常,上面的指定什么异常都回滚



