前言
匆匆忙忙,我的5月份都已经走到了末尾。之所以很久没更新博客,是最近一直在赶项目。我一直都很喜欢狂神的那句,世上没有白走的路,因为每一步都算数。今天我跟大家分享的是如何编写过滤器和拦截器。
1. 拦截器和过滤器的根本区别
[1] 过滤器是servlet规范的,只能用于web程序中,而拦截器是在spring容器中,它不依赖servlet容器。
[2] 拦截器属于Spring中的概念,可以在拦截器中使用任何Spring中的Bean信息,而过滤器不属于Spring的概念店,所以过滤器不行。
[3] 过滤器可以拦截几乎所有的请求(包括静态资源的请求),而拦截器只能拦截Spring 中请求的处理器(不包括静态资源请求)
[4] 不管是过滤器还是拦截器都是AOP 编程思想的体现。
[5] 过滤器的执行顺序在拦截器之前
2. 过滤器的简单实现
[1] 基于SpringBoot配置 FilterRegistrationBean
[2] 使用servlet自带的注解 @WebFilter
我们这里以解决中文乱码为实例列举:
第一种方式:配置 FilterRegistrationBean
编写一个实现了Filter的类
package com.example.kcb02.component;
import javax.servlet.*;
import java.io.IOException;
//编写一个中文乱码过滤器
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding("utf-8");
servletResponse.setCharacterEncoding("utf-8");
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
这里的 filterChain.doFilter(servletRequest,servletResponse); 表示放行请求一定要加上
接着在FilterRegistrationBean 中对该过滤器进行注册,并把它注入到容器中
package com.example.kcb02.config;
import com.example.kcb02.component.MyFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyMvcConfig {
//过滤器
@Bean
public FilterRegistrationBean traceFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new MyFilter());
registration.addUrlPatterns("/*");
return registration;
}
}
编写这样两个方法就可实现简单的过滤器,我们要实现复杂的业务只需要在doFilter()方法进行添加即可;相关的还有垃圾信息的过滤等。
第二种方式: 使用Servlet内置的注解
还是和上面一样的类,这时在MyFilter 上加上注解
package com.example.kcb02.component;
import javax.servlet.*;
import java.io.IOException;
//编写一个中文乱码过滤器
@WebFilter(urlPatterns = "/*", filterName = "MyFilter")
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding("utf-8");
servletResponse.setCharacterEncoding("utf-8");
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
记得这里编写网还应该在SpringBoot的main方法中添加@ServletComponentScan开启扫描Servlet 注解,这样就可以实现和上面同样的效果
//添加ServletComponentScan开启扫描Servlet注解
@ServletComponentScan
@SpringBootApplication
public class WebApplication {
public static void main(String[] args) {
SpringApplication.run(WebApplication.class, args);
}
}
3. 拦截器的简单实现
[1] 编写一个实现了HandlerInterceptor的拦截器
业务需求:
这里我们对非法登录进行拦截,就是我们本来应该先通过登录才能进入主界面,但是我们不加拦截的话,我们直接输入网址也可以访问主页。
相关方法说明:
preHandle:在业务处理器处理请求之前被调用。预处理,可以进行编码、安全控制、权限校验等处理;(这里刚好符合我们的业务需求)
postHandle:在业务处理器处理请求执行完成后,生成视图之前执行。后处理(调用了Service并返回ModelAndView,但未进行页面渲染),有机会修改ModelAndView;(这个较少使用)
afterCompletion:在DispatcherServlet完全处理完请求后被调用,可用于清理资源等。返回处理(已经渲染了页面);
实现思路:
这里先说明一下设计的相关思路:由于我登录的时候用一个session存储了用户名,只要我在这边检测到用户名不为空的话就放行请求(就是所谓的return true), 如果用户名为空的话就拦截请求(就是所谓的访问false)
package com.example.kcb02.component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* @Auther: Gs
* @Date: 2020/5/30
* @Description: com.example.kcb02.component
* @version: 1.0
*/
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
StringBuffer requestURL = request.getRequestURL();
HttpSession session = request.getSession();
Object username = session.getAttribute("username");
//System.out.println("用户名为:"+username);
//用户名不为空则放行
if (username!=null){
return true;
}else{
System.out.println("进行了拦截");
return false;
}
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
在SpringBoot2.0中提倡关于SpringMvc的功能扩展都去实现一个WebMvcConfigurer的类,在这个类中我们可以添加视图解析器,拦截器,格式化器等,这里我们先对添加拦截器进行简单说明。
package com.example.kcb02.config;
import com.example.kcb02.component.MyInterceptor;
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;
import javax.servlet.Filter;
/**
* @Auther: Gs
* @Date: 2020/5/4
* @Description: com.example.kcb02.config
* @version: 1.0
*/
//实现WebMvcConfigurer对SpringMvc的功能进行扩展
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor()).
addPathPatterns("/courselists","/treeholes","/comments","/teachers","/students");
}
}
这里通过addInterceptor()添加自定义的拦截器,通过addPathPatterns()添加要进行拦截的路径,可以包括多个路径。(上面所写的是我项目中进行拦截的路径)
小结
还记得在JavaWeb中最习惯的就是实现完相应的过滤器和拦截器后就在web.xml进行配置,而在SpringBoot中很多东西都喜欢以注解的形式存在,把这种在web.xml进行的配置换成配置类的形式呈现。