1. 过滤器
我们常常在项目中会使用 filters 用于录调用日志、排除有 XSS 威胁的字符、执行权限验证等等。Spring Boot 自动添加了 OrderedCharacterEncodingFilter 和 HiddenHttpMethodFilter,并且我们可以自定义 Filter。
1). 注解式实现
三个步骤:
- 自定义过滤器类需要实现Filter接口,实现doFilter方法;
- 在过滤类上面需要添加@WebFilter注解,参数urlPatterns、filterName;添加@Order注解
- 在启动类上添加@ServletComponentScan注解或者在过滤类上面需要添加@Component注解
urlPatterns:配置过滤的请求路径;
filterName: 过滤器名称;
@Order:规定多个Filter的执行顺序,按照@Order()的值从小到大执行;
@ServletComponentScan:加了@ServletComponentScan,无论过滤器类不能加@Componment,单使用 @Component会默认过滤/*;
@Component:表示这个类是一个组件类,会交给spring管理;
//规定多个Filter的执行顺序,按照@Order()的值从小到大执行。
@Order(1)
//urlPatterns:配置过滤的请求路径 filterName:过滤器名称
@WebFilter(urlPatterns = "/*",filterName = "demoFilter")
@Component
public class DemoFilter implements Filter{
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
System.out.println("demoFilter...过滤器实现方式一");
filterChain.doFilter(servletRequest,servletResponse);
}
}
//加了@ServletComponentScan,无论过滤器类加不加@Componment都可以,单使用@Component会默认过滤/*,
//@ServletComponentScan
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
2). 注解式实现
两个步骤:
- 实现 Filter 接口,实现 Filter 方法
- 添加
@Configuration
注解,将自定义Filter加入过滤链
好吧,直接上代码
@Configuration
public class WebConfiguration {
@Bean
public FilterRegistrationBean<Filter> configFilter() {
FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<Filter>();
filterRegistrationBean.setFilter(new HelloFilter());
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.setName("helloFilter");
filterRegistrationBean.setOrder(2);
return filterRegistrationBean;
}
/**
* 过滤器
* @author Admin
*/
public class HelloFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse reServletResponse, FilterChain filterChain)
throws IOException, ServletException {
System.out.println("helloFilter....过滤器实现方式二");
filterChain.doFilter(servletRequest, reServletResponse);
}
}
}
2. 拦截器
两个步骤:
- 实现HandlerInterceptor接口,实现preHandle、postHandle、afterCompletion方法;
- 注册拦截器
@Component("demoInterceptor")
public class DemoInterceptor implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("在请求处理的方法之前执行");
System.out.println("demoInterceptor...拦截器实现方式一");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("在请求处理的方法执行后执行");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("在DispatcherServlet处理后执行---清理工作");
}
}
@Configuration
public class InterceptorConfig implements WebMvcConfigurer{
@Autowired
private DemoInterceptor demoInterceptor;
//@Autowired
//private LogInterceptor logInterceptor;
/**
* 拦截器的执行顺序和配置顺序有关系,即先配置顺序就在前
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册拦截器
registry.addInterceptor(demoInterceptor)
// 拦截的请求路径
.addPathPatterns("/back")
// 无需拦截的请求
.excludePathPatterns("/login");
//registry.addInterceptor(logInterceptor).addPathPatterns("/*");
}
}
3. 监听器
1). 注解方式实现
两个步骤:
- 编写监听器,需要在监听器类上加上@WebListener注解
- 扫描监听器,在spring boot启动类上加上@ServletComponentScan注解---扫描监听器
编写监听器
@WebListener
public class FirstListener implements ServletContextListener {
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("FirstListener---- 监听器实现方式一销毁");
}
/**
* 监听器实现方法一
* 1.需要在监听器上加上@WebListener注解
* 2.在spring boot启动类上加上@ServletComponentScan注解---扫描注册监听器
*/
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("FirstListener---- 监听器实现方式一");
}
}
扫描监听器
@ServletComponentScan
@SpringBootApplication
public class ReycoApplication {
public static void main(String[] args) {
SpringApplication.run(ReycoApplication.class, args);
}
}
2). 注册bean的方式实现
两个步骤:
- 编写监听器
- 编写一个配置类,对监听器进行bean注册
编写监听器
/**
* 监听器实现方法二:
* 1.创建监听器
* 2.编写一个配置类,对监听器进行bean注册
* @author reyco
*
*/
public class SecondListener implements ServletContextListener {
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("SecondListener---- 监听器实现方式二销毁");
}
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("SecondListener---- 监听器实现方式二");
}
}
注册监听器
@Configuration
public class ListenerConfig {
@Bean
public ServletListenerRegistrationBean<SecondListener> getServletListenerRegistrationBean(){
ServletListenerRegistrationBean<SecondListener> bean = new ServletListenerRegistrationBean<SecondListener>();
bean.setListener(new SecondListener());
return bean;
}
}
4. 事件机制
在实际项目中,我们往往需要自定义一些事件和监听器来满足业务场景,比如:支付系统:客户付款后需要发送邮件付款消息,平时我们在service中引入邮件服务,发送邮件服务也可能在一个事物内,这个时候第三方邮件服务器挂掉后,抛出异常整个逻辑都会回滚,这完全不符合逻辑。正常情况我的付款不需要依赖邮件服务,邮件发送成功与否都不应该影响我的付款操作。这个时候就需要这种事件监听。
1). 注解式
三个步骤:
- 编写自定义事件需要继承 ApplicationEvent 对象;
- 自定义监听器来监听自定义事件
- 在 Service 中注入 ApplicationContext,在业务代码处理完之后,通过 ApplicationContext 对象手动发布自定义事件,这样我们自定义的监听器就能监听到,然后处理监听器中写好的业务逻辑。
编写自定义事件
/**
* 登录记录日志自定义事件
* @author reyco
*
*/
public class LoginLogEvent extends ApplicationEvent{
/**
* 模拟登录信息
*/
private String logInfo;
public String getLogInfo() {
return logInfo;
}
public void setLogInfo(String logInfo) {
this.logInfo = logInfo;
}
public LoginLogEvent(Object source,String logInfo) {
super(source);
this.logInfo = logInfo;
}
}
自定义监听器
@Component
public class LoginLogListener {
/**
* 监听器
* @param loginLogEvent
*/
// @Async:异步执行,需要在入口类添加@EnableAsync注解,开启异步模式,异步执行不支持事物
@Async
@EventListener
public void save(LoginLogEvent loginLogEvent) {
String logInfo = loginLogEvent.getLogInfo();
System.out.println("insert登录日志,logInfo="+logInfo);
}
}
@EnableAsync
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
发布自定义事件
@Service
public class LoginService {
@Autowired
private ApplicationContext applicationContext;
public void login(){
LoginLogEvent loginLogEvent = new LoginLogEvent(this, "登录日志信息");
applicationContext.publishEvent(loginLogEvent);
}
}
1). 编程式
这里只需要修改监听器这一块,其他都一样。
/**
* 自定义监听器
* @author reyco
*
*/
@Component
public class LoginLogListener implements ApplicationListener<LoginLogEvent>{
@Override
public void onApplicationEvent(LoginLogEvent loginLogEvent) {
String logInfo = loginLogEvent.getLogInfo();
System.out.println("insert登录日志,logInfo="+logInfo);
}
}