说明:当用户未经登录,直接访问后台网址时,为了避免可以直接访问后台内容,就需要使用过滤器或拦截器将此类请求在服务器响应数据之前做核对,如果未登录,则驳回请求,返回登录页面,如果登录,则放过该请求,允许访问。关于如何判断用户是否登录,参考JWT令牌。
过滤器
过滤器是Tomcat提供的一种对请求作拦截过滤的技术,使用流程如下:
第一步:创建过滤器类
过滤器类需要实现Filter类,实现doFilter()方法,即过滤方法,该方法可实现对设置的访问进行过滤判断,init()服务器启动需要执行代码,destroy()服务器关闭时需要执行代码可根据需求自行覆写。
过滤类上面加的@WebFilter()注解,括号内表明该过滤器类需要过滤的请求路径,有以下三种情况:
/*(所有请求都过滤)
/login(只过滤/login请求)
/login/ *(login路径下的所有请求都过滤)
我这里模拟拦截下/demo02请求,实际开发中的判断会更复杂,需要判断请求是否有token令牌,核对token令牌能否被正确解析
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* 过滤器
*/
@WebFilter("/*")
public class MyFilter implements Filter {
/**
* 执行过滤方法,每次在拦截范围内的请求都会被执行
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("<<<<<<<<MyFilter过滤器请求开始执行....>>>>>>>>");
// 如果请求为/demo02,就拦截下来
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
String requestURL = httpServletRequest.getRequestURL().toString();
if (requestURL.contains("demo02")){
return;
}
// 手动放行被拦截的所有方法,默认被过滤的请求是都不放行的
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("<<<<<<<<MyFilter过滤器响应开始执行...>>>>>>>>");
}
/**
* 初始化方法,服务器启动就会执行,且只执行一次
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("<<<<<<<<服务器启动执行的代码...>>>>>>>>");
}
/**
* 销毁方法,服务器关闭就会执行,且只执行一次
*/
@Override
public void destroy() {
System.out.println("<<<<<<<<服务器关闭执行的代码...>>>>>>>>");
}
}
controller层代码
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class FilterController {
@RequestMapping("/login")
public String login(){
System.out.println("login方法的执行内容...");
return "login....";
}
@RequestMapping("/demo02")
public String Demo02(){
System.out.println("demo02方法的执行内容...");
return "demo02...";
}
}
第二步:启动类加注解
启动类需要添加@ServletComponentScan注解,表示开启过滤扫码
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
@SpringBootApplication
@ServletComponentScan
public class Start {
public static void main(String[] args) {
SpringApplication.run(Start.class, args);
}
}
第三步:启动
服务器启动:init()方法开始执行
过滤器doFilter()方法开始执行,/login请求未被拦截,访问成功
过滤器doFilter()方法开始执行,/demo02被拦截,访问失败
服务器关闭,destroy()方法执行
小结
需要知道的是,过滤器放行后,并不是直接响应数据,而是执行下一个过滤器。当存在多个过滤器时,过滤器doFliter()方法执行的顺序是过滤器类排序的顺序,且为一个嵌套结构,即先执行MyFilter01,MyFilter01里面嵌套执行MyFilter02,而init()、destroy()方法执行的顺序是过滤器类排序的逆序。
拦截器
拦截器是SpringMVC提供的一种对请求作拦截过滤的技术,使用流程如下:
第一步:创建拦截类
与过滤器不同的是,该拦截方法是有返回值的,返回值为boolean类型,true表示放行,false表示拦截,另外,拦截器类和拦截器配置类需要加@Component注解,加入到IOC容器中,不然拦截器配置类无法使用拦截器类对象。当然,拦截器不需要给启动类加@ServletComponentScan注解。
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 拦截器
*/
@Component
public class MyIntercepor01 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("<<<<<<<<MyIntercepor01拦截器请求开始执行....>>>>>>>>");
// 如果请求为/demo02,就拦截下来
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String requestURL = httpServletRequest.getRequestURL().toString();
if (requestURL.contains("demo02")){
return false;
}
System.out.println("<<<<<<<<MyIntercepor01拦截器响应开始执行...>>>>>>>>");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("<<<<<<<<MyIntercepor01 postHandle()执行的代码...>>>>>>>>");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("<<<<<<<<MyIntercepor01 afterCompletion()执行的代码...>>>>>>>>");
}
}
controller层代码
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class InterceporController {
@RequestMapping("/login")
public String login(){
System.out.println("login方法的执行内容...");
return "login....";
}
@RequestMapping("/demo02")
public String Demo02(){
System.out.println("demo02方法的执行内容...");
return "demo02...";
}
@RequestMapping("/demo03")
public String Demo03(){
System.out.println("demo03方法的执行内容...");
return "demo03...";
}
}
第二步:创建配置类
addPathPatterns():设置拦截的请求;
excludePathPatterns():设置排除拦截的请求;
拦截路径设置,有以下四种情况:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 拦截器配置类
*/
@Component
public class MyConfig01 implements WebMvcConfigurer {
@Autowired
private MyIntercepor01 myIntercepor01;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 拦截所有除login的请求
registry.addInterceptor(myIntercepor01)
.addPathPatterns("/**")
.excludePathPatterns("/login");
}
}
第三步:启动
输入/login
输入/demo02
输入demo03
小结
如果存在多个拦截器,拦截器的执行顺序,是在拦截器配置类中添加的顺序,且是线性执行的,即先执MyIntercepor02的请求拦截、响应拦截,再执行MyIntercepor01的请求拦截、响应拦截……当所有的拦截器都执行完毕之后,才会放行请求。
值得一提的是,拦截器中的postHandle()和afterCompletion()方法的执行顺序,与配置顺序无关。关于这两个方法的作用,参考:http://t.csdn.cn/DktJv
总结
过滤器和拦截器的区别如下:
(1)技术支撑不同:过滤器由Tomcat提供、拦截器由SpringMVC提供;
(2)拦截的范围不同:过滤器处理的是Tomcat上的所有资源,拦截器只处理Spirng环境中的资源;
(3)两者的执行顺序不同:有过滤器,先执行过滤器;过滤器执行完了,再执行拦截器;
(4)具体的执行顺序不同:有多个过滤器,按照文件排序执行(doFliter()方法),为嵌套执行;有多个拦截器,按照配置类中的代码顺序执行,为线性执行;
(5)拦截路径标识稍有不同:拦截器可以设置拦截一级目录,过滤器没有;
因此,在过滤器和拦截器的选择上,应该视实际情况考虑