概述
在开发中,我们经常要考虑一些问题,对敏感词进行过滤,用户是否已经登录,是否需要对他的请求进行拦截,或者领导问现在在线人数有多少人?我们如何实现这些功能哪
@WebFilter
package com.xmlxy.firstspringbootproject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import java.io.IOException; @WebFilter(filterName = "customFilter",urlPatterns = "/*") public class CustomFilter implements Filter { private static final Logger log = LoggerFactory.getLogger(CustomFilter.class); @Override public void init(FilterConfig filterConfig) throws ServletException { log.info("===========拦截器初始化=========="); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { servletRequest.setCharacterEncoding("utf-8"); servletResponse.setCharacterEncoding("utf-8"); log.info("doFilter请求处理"); } @Override public void destroy() { log.info("fifter销毁"); } }
在application类中添加@ServletComponentScan注解
package com;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.ServletComponentScan; import org.springframework.context.annotation.PropertySource; @SpringBootApplication @ServletComponentScan @PropertySource(value = "classpath:jdbc.properties",encoding = "utf-8") public class FirstSpringbootProjectApplication { public static void main(String[] args) { SpringApplication.run(FirstSpringbootProjectApplication.class, args); } }
运行结果
(笔误,应该是过滤器初始化)过滤器已经生效,但若有多个过滤器,无法指定执行顺序,我们可以通过Java类的名称,从A-L,按顺序执行。但这种方式毕竟不大靠谱,所以,有第二种写法,它提供setOrder函数,为filter设置排序值。
package com.xmlxy.service;
import com.xmlxy.firstspringbootproject.CustomFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class WebFilterConfig { @Bean public FilterRegistrationBean someFilterRegistration1() { FilterRegistrationBean registration = new FilterRegistrationBean<>(); System.out.println("我执行了。。。。。。。"); registration.setFilter(new CustomFilter()); registration.addUrlPatterns("/*");
registration.setOrder(1);
return registration; } }
我们尝试写个demo,验证一下过滤器是否执行。
用户登录对象
User.java
package com.xmlxy.bean;
import lombok.Data;
import org.springframework.stereotype.Component; @Data @Component public class User { private String user; private String pwd; }
登录控制
LoginController.java
package com.xmlxy.firstspringbootproject;
import com.xmlxy.bean.User;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; @RestController public class LoginController { @RequestMapping(value = "login",method = RequestMethod.GET) public String login(HttpServletRequest request) { String user = request.getParameter("user"); String pwd = request.getParameter("pwd"); HttpSession session = request.getSession(); if ("admin".equals(user) && "admin".equals(pwd)) { User user1 = new User(); user1.setUser(user); user1.setPwd(pwd); session.setAttribute("user",user1); return "登录成功"; } return "密码错误,登录失败"; }
@RequestMapping(value = "test",method = RequestMethod.GET)
public String test()
{
return "test接口";
}
}
过滤器
CustomFilter.java
package com.xmlxy.firstspringbootproject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; //@WebFilter(filterName = "customFilter",urlPatterns = "/*") public class CustomFilter implements Filter { private static final Logger log = LoggerFactory.getLogger(CustomFilter.class); String includes[] = {"/login","register"}; @Override public void init(FilterConfig filterConfig) throws ServletException { log.info("===========过滤器初始化=========="); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; servletRequest.setCharacterEncoding("utf-8"); servletResponse.setCharacterEncoding("utf-8"); HttpSession session = request.getSession(false); String uri = request.getRequestURI(); boolean flag = isNeedFilter(uri); if (!flag) { filterChain.doFilter(servletRequest,servletResponse); System.err.printf("登录成功"); }else { if (session != null && session.getAttribute("user") != null) { filterChain.doFilter(servletRequest,servletResponse); }else { System.err.printf("暂时未登录"); } } log.info("doFilter请求处理"); } public boolean isNeedFilter(String uri) { for (String include:includes) { if (include.equals(uri)) { return false; } } return true; } @Override public void destroy() { log.info("fifter销毁"); } }
过滤器配置
WebFilterConfig
package com.xmlxy.service;
import com.xmlxy.firstspringbootproject.CustomFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class WebFilterConfig { @Bean public FilterRegistrationBean someFilterRegistration1() { FilterRegistrationBean registration = new FilterRegistrationBean<>(); System.out.println("我执行了。。。。。。。"); registration.setFilter(new CustomFilter()); registration.addUrlPatterns("/*"); return registration; } }
运行测试。。访问 127.0.0.1/test 控制台
访问 http://127.0.0.1:8080/login?user=admin&pwd=admin,可以看到登录成功
在次访问 127.0.0.1/test 页面显示
所以,我们的过滤器成功过滤未登录的用户
监听器
正在你为自己会了过滤用户自鸣得意时,你的组长过来了,小明,你看下我们平台的在线用户有多少人。如果不知道监听器童鞋,是否会在登录接口处每次登录成功都+1,然而这种统计结果是不准确的,因为用户如果反复登录退出,那这个在值就远远大于实际值,最后就面临着,加班在加班的悲惨下场。
CustomLister.java
package com.xmlxy.firstspringbootproject;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; @WebFilter public class CustomLister implements HttpSessionListener { public static int online = 0; @Override public void sessionCreated(HttpSessionEvent sessionEvent) { System.out.println("创建session,统计在线人数"); online ++; } @Override public void sessionDestroyed(HttpSessionEvent sessionEvent) { System.out.println("session已经销毁"); } }
配置监听器配置,在刚才的WebFilterConfig.java添加
@Bean
public ServletListenerRegistrationBean listenerRegistrationBean()
{
ServletListenerRegistrationBean srb = new ServletListenerRegistrationBean();
srb.setListener(new CustomLister()); System.out.println(""); return srb; }
添加一个访问在线人数的接口
@RequestMapping(value = "onLinePerson",method = RequestMethod.GET)
public String onLinePerson()
{
StringBuffer stringBuffer = new StringBuffer("");
stringBuffer.append(" 在线人数 "); stringBuffer.append(CustomLister.online); stringBuffer.append(" 个人 "); return stringBuffer.toString(); }
访问127.0.0.1/onLinePerson,发现被拦截器拦截了,我们先登录。在查看接口
换个浏览器,调用下login接口,在查看
拦截器
拦截器,个人理解,在web上有些像是过滤器的补充,它能更精确的控制拦截哪些函数或者字段,在拦截之前或之后做一些操作。我们现在做一个敏感词的拦截,其实这个操作放在过滤器操作也是可以的,但lz因为刚才把拦截用户的操作放在过滤器了,在大规模更改,lz觉得没必要,因为都是大同小异。
CustomInterceptor.java
package com.xmlxy.firstspringbootproject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.PrintWriter; public class CustomInterceptor implements HandlerInterceptor { private static final Logger log = LoggerFactory.getLogger(CustomInterceptor.class); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response,Object handler) throws Exception { log.info("=======拦截器被调用====="); String url = request.getRequestURI(); if (url != null && url.indexOf("seqing") != -1) { PrintWriter printWriter = response.getWriter(); printWriter.write("ming gan ci"); return false; } log.info("返回false 则中断请求"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { log.info("请求后调用"); } @Override public void afterCompletion(HttpServletRequest request,HttpServletResponse response,Object handler,Exception e) { log.info("视图渲染完回调"); } }
配置拦截
package com.xmlxy.service;
import com.xmlxy.firstspringbootproject.CustomFilter;
import com.xmlxy.firstspringbootproject.CustomInterceptor; import com.xmlxy.firstspringbootproject.CustomLister; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.ServletListenerRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebFilterConfig implements WebMvcConfigurer { @Bean public FilterRegistrationBean someFilterRegistration1() { FilterRegistrationBean registration = new FilterRegistrationBean<>(); System.out.println("我执行了。。。。。。。"); registration.setFilter(new CustomFilter()); registration.addUrlPatterns("/*"); return registration; } @Bean public ServletListenerRegistrationBean listenerRegistrationBean() { ServletListenerRegistrationBean srb = new ServletListenerRegistrationBean(); srb.setListener(new CustomLister()); return srb; } @Override public void addInterceptors(InterceptorRegistry registry) { /*拦截规则*/ registry.addInterceptor(new CustomInterceptor()).addPathPatterns("/*"); } }
现在测试访问127.0.0.1/seqing,被过滤,要求先登录。我们调用登录接口后,再次调用,发现被拦截了
看下日志调用,可以发现,拦截器是在访问接口前被调用的
过滤器,拦截器区别
这里主要说下拦截器和过滤器的区别和使用场景,通过demo可以发现,它们都能实现权限的检查,日志记录这些功能,主要说下它们的区别
- 过滤器和拦截器触发的时机是不同的,在进入servlet之前,过滤器就进行预处理了。而拦截器是在调用Controller之前才触发执行,过滤器的范围较广,对所有的请求都起作用,而拦截起只 对action起作用
2.拦截器可以获取IOC容器的各个bean,而过滤器就不行。因为拦截器是spring提供管理的,也因此拦截器可以使用spring的任何资源。
3.拦截器是利用Java反射机制实现,过滤器是函数的回调。因此实现方式是不同的。
三者使用场景
监听器:常用统计在线用户,统计网站的访问量,记录用户的访问路径
过滤器:过滤敏感词,权限访问控制
拦截器:权限验证,判断用户是否登录等