赞
踩
过滤器是一个基于Servlet的程序,它先于Servlet或JSP执行,因此常常被用作请求前的信息检查,修改编码,重定向请求路径等功能。
SpringBoot定义一个web过滤器只需要其继承HttpFilter
类,并在类上使用@WebFilter
注解声明过滤路径。
@Slf4j
@WebFilter("/*") // 过滤器路径
public class MessageFilter extends HttpFilter {
public void doFilter(HttpServletRequest request, HttpServletResponse response,
FilterChain chain) throws IOException, ServletException {
log.info("[MessageFilter] 请求地址:" + request.getRequestURI());
chain.doFilter(request, response);
}
}
由于SpringBoot默认采用内嵌的tomcat,所以需要在启动类上添加@ServletComponentScan
注解进行web组件的扫描。
@SpringBootApplication
@ServletComponentScan // 扫描Servlet组件
public class StartSpringBoot {
public static void main(String[] args) {
SpringApplication.run(StartSpringBoot.class, args);
}
}
通过浏览器访问:http://localhost:8080/hello
发现控制台打出过滤器日志,说明过滤器配置成功:
在实际的项目开发中,一个访问路径前可能存在多个过滤器组成的过滤链。传统的Java WEB项目会有一个web.xml
的配置文件,可以在其中配置过滤器的过滤路径,如果一个访问路径在多个过滤器的过滤路径下,那么过滤器的执行顺序就和配置文件的编写顺序有关了:
<!-- 过滤顺序:谁的写在上面,谁先被过滤 --> <filter> <filter-name>Filter1</filter-name> <filter-class>com.it.filter.Filter1</filter-class> </filter> <filter-mapping> <filter-name>Filter1</filter-name> <url-pattern>/*</url-pattern> <!-- 过滤所有 --> </filter-mapping> <filter> <filter-name>Filter2</filter-name> <filter-class>com.it.filter.Filter2</filter-class> </filter> <filter-mapping> <filter-name>Filter2</filter-name> <url-pattern>/*</url-pattern> <!-- 过滤所有 --> </filter-mapping>
以上面的配置为例,如果要访问:http://localhost:8080/hello
,那么一定会是以下的顺序:
而SpringBoot的目标就是减少传统java web项目繁杂的配置文件,配置信息可以在application.yml
中编写,也可以自定义配置类,通过代码的方式进行配置。
删除MessageFilter
类上的@WebFilter
注解:
@Slf4j
public class MessageFilter extends HttpFilter {
public void doFilter(HttpServletRequest request, HttpServletResponse response,
FilterChain chain) throws IOException, ServletException {
log.info("[MessageFilter] 请求地址:" + request.getRequestURI());
chain.doFilter(request, response);
}
}
再编写一个ValidateFilter
:
@Slf4j
public class ValidateFilter extends HttpFilter {
public void doFilter(HttpServletRequest request, HttpServletResponse response,
FilterChain chain) throws IOException, ServletException {
log.info("[ValidateFilter] 请求地址:" + request.getRequestURI());
chain.doFilter(request, response);
}
}
编写一个配置类控制Filter的执行顺序:
@Configuration public class WebFilterConfig { /** * 配置MessageFilter的执行顺序 * @return FilterRegistrationBean */ @Bean public FilterRegistrationBean getMessageRegistration() { FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); filterRegistrationBean.setFilter(new MessageFilter()); // 过滤器类实例对象 filterRegistrationBean.setName("MessageFilter"); // 过滤器名 filterRegistrationBean.addUrlPatterns("/*"); // 过滤路径 filterRegistrationBean.setOrder(2); // 执行顺序 return filterRegistrationBean; } @Bean public FilterRegistrationBean getValidateRegistration() { FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); filterRegistrationBean.setFilter(new ValidateFilter()); filterRegistrationBean.setName("ValidateFilter"); filterRegistrationBean.addUrlPatterns("/*"); filterRegistrationBean.setOrder(5); return filterRegistrationBean; } }
通过FilterRegistrationBean
类的order属性可以指定过滤器的执行顺序,order值越小则越先执行。
直接访问:http://localhost:8080/
发现ValidateFilter比MessageFilter先执行。
监听器就是监听某个对象的的状态变化的组件,按照被监听的对象可划分为:ServletRequest域 、HttpSession域、 ServletContext域。按照监听的内容可分为:域对象的创建与销毁、域对象的属性变化。
ServletRequest | ServletRequest | ServletRequest | |
---|---|---|---|
域对象的创建与销毁 | ServletContextListener | HttpSessionListener | ServletRequestListener |
域对象的属性变化 | ServletContextAttributeListener | HttpSessionAttributeListener | ServletRequestAttributeListener |
以监听Servlet初始化为例,定义一个监听器类并实现ServletContextListener
接口,在类上添加@WebListener
注解。
@Slf4j
@WebListener
public class DefaultServletListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
log.info("[DefaultServletListener] " + sce.getServletContext().getServerInfo());
log.info("[DefaultServletListener] " + sce.getServletContext().getRealPath("/"));
log.info("[DefaultServletListener] " + sce.getServletContext().getVirtualServerName());
}
}
由于使用了@WebListener
注解,所以需要在SpringBoot启动类上添加@ServletComponentScan
注解扫描Servlet组件。
@SpringBootApplication
@ServletComponentScan({"com.it.listener"})
public class StartSpringBoot {
public static void main(String[] args) {
SpringApplication.run(StartSpringBoot.class, args);
}
}
启动项目,发现Servlet初始化监听生效:
拦截器是基于java反射机制实现的java程序,其不依赖于Servlet 容器,通常用于service层方法调用前后的处理。
值得注意的是:
SpringBoot整合拦截器只需要实现HandlerInterceptor接口。
@Slf4j
public class DefaultInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
log.info("------------------------------ DefaultInterceptor ------------------------------");
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
log.info("[控制器实例]" + handlerMethod.getBean());
log.info("[控制器类型]" + handlerMethod.getBeanType());
log.info("[控制器方法]" + handlerMethod.getMethod());
}
log.info("------------------------------------------------------------------------------------");
return true;
}
}
定义好的拦截器需要在配置类中进行启用。
@Configuration public class InterceptorConfig implements WebMvcConfigurer { /** * 注册拦截器 * @param registry InterceptorRegistry */ public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(getDefaultInterceptor()) // 添加拦截器 .addPathPatterns("/**"); // 配置拦截器路径 } @Bean public HandlerInterceptor getDefaultInterceptor() { return new DefaultInterceptor(); } }
启动项目,访问任意Action类:
基于AspectJ切面表达式实现的AOP处理是Spring的一个重要特性,AOP拦截器可以直接进行指定类结构的拦截处理。
SpringBoot如果想要使用AOP,则需要添加依赖支持:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.5.5</version>
</dependency>
新建IMessageService
业务层接口和实现类:
public interface IMessageService {
String echo(String message);
}
public class MessageServiceImpl implements IMessageService {
@Override
public String echo(String message){
return "[echo] : " + message;
}
}
再aspect包下新建ServiceAspect
类并配置业务层环绕拦截。
@Slf4j @Aspect @Component public class ServiceAspect { // AOP切面管理 /** * service环绕切面 * @param point * @throws Throwable */ @Around("execution(* *..service..*.*(..))") // 配置所有service生效 public Object aroundInvoke(ProceedingJoinPoint point) throws Throwable { log.info("[invoke before] " + Arrays.toString(point.getArgs())); Object obj = point.proceed(point.getArgs()); // 调用真实业务 log.info("[invoke after] return: " + obj); return obj; // 业务执行的结果 } }
新建RestController测试AOP拦截结果:
@RestController
@RequestMapping("/message/*")
public class MessageAction {
private final IMessageService messageService;
public MessageAction(IMessageService messageService) {
this.messageService = messageService;
}
@RequestMapping("/get")
public String getMessage(String message) {
return messageService.echo(message);
}
}
访问:http://localhost:8080/message/get?message=hello
,查看控制台日志:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。