Servlet API 中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter。通过Filter技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截。简单说,就是可以实现web容器对某资源的访问前截获进行相关的处理,还可以在某资源向web容器返回响应前进行截获进行处理。
springBoot 配置通过bean的方式进行配置的,SpringBoot提供了BeanFilterRegistrationBean对应配置原生的Filter,下面提供的配置和方案采用的方式能够达到同一的效。
1.)自定义过滤器Filter类
验证是否登录,未登录则跳转登录页面
package com.ule.fenxiao;
import javax.servlet.*;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* Created by zongruibiao on 2017/3/14.
*/
public class DemoFilter extends HttpServlet implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("==>DemoFilter启动");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 将请求转换成HttpServletRequest 请求
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
String path = req.getContextPath();
String basePath = req.getScheme()+"://"+req.getServerName()+":"+req.getServerPort()+path;
HttpSession session = req.getSession(true);
String username = (String) session.getAttribute("username");
if (username == null || "".equals(username)) {
resp.setHeader("Cache-Control", "no-store");
resp.setDateHeader("Expires", 0);
resp.setHeader("Prama", "no-cache");
//此处设置了访问静态资源类
resp.sendRedirect(basePath+"/index.html");
} else {
// Filter 只是链式处理,请求依然转发到目的地址。
filterChain.doFilter(req, resp);
}
}
@Override
public void destroy() {
}
}
2.)注册过滤器类
package com.ule.fenxiao.config;
import com.ule.fenxiao.DemoFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.http.HttpRequest;
import org.springframework.web.servlet.DispatcherServlet;
/**
* Created by zongruibiao on 2017/3/14.
*/
@Configuration
public class FilterConfiguration {
@Bean
public FilterRegistrationBean filterDemo4Registration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
//注入过滤器
registration.setFilter(new DemoFilter());
//拦截规则
registration.addUrlPatterns("*.do");
//过滤器名称
registration.setName("DemoFilter");
//是否自动注册 false 取消Filter的自动注册
registration.setEnabled(false);
//过滤器顺序
registration.setOrder(1);
return registration;
}
}
4.) Filter的应用场景
通过对filter过滤器的了解,可以得知在以下三种情况下可以做些处理:
1> 通过控制对chain.doFilter的方法的调用,来决定是否需要访问目标资源。
比如,可以在用户权限验证等等。判断用户是否有访问某些资源的权限,有权限放行,没权限不执行chain.doFilter方法。
2> 通过在调用chain.doFilter方法之前,做些处理来达到某些目的。
比如,解决中文乱码的问题等等。可以在doFilter方法前,执行设置请求编码与响应的编码。甚至可以对request接口进行封装装饰来处理get请求方式的中文乱码问题(重写相应的request.getParameter方法)。
3> 通过在调用chain.doFilter方法之后,做些处理来达到某些目的。
比如对整个web网站进行压缩。在调用chain.doFilter方法之前用类A对response对象进行封装装饰,重写getOutputStream和重写getWriter方法。在类A内部中,将输出内容缓存进ByteArrayOutputStream流中,然后在chain.doFilter方法执行后,获取类A中ByteArrayOutputStream流缓存数据,用GZIPOutputStream流进行压缩下。
5.) Filter实现拦截的原理
Filter接口中有一个doFilter方法,当开发人员编写好Filter类实现doFilter方法,并配置对哪个web资源进行拦截后,WEB服务器每次在调用web资源的service方法之前(服务器内部对资源的访问机制决定的),都会先调用一下filter的doFilter方法。
6.)过滤规则
//过滤应用程序中所有资源,当前应用程序根下的所有文件包括多级子目录下的所有文件,注意这里*前有“/”
registration.addUrlPatterns("/*");
//过滤指定的类型文件资源, 当前应用程序根目录下的所有html文件,注意:*.html前没有“/”,否则错误
registration.addUrlPatterns(".html");
//过滤指定的目录下的所有文件,当前应用程序根目录下的folder_name子目录(可以是多级子目录)下所有文件
registration.addUrlPatterns("/folder_name/*");
//过滤指定文件
registration.addUrlPatterns("/index.html");