过滤器的概念
Servlet过滤器从表面的字意理解为经过一层层的过滤器处理才达到使用的要求,而其实Servlet过滤器就是服务器与客户端请求与响应的中间层组件。在实际项目开发中Servlet过滤器主要用于对浏览器的请求进行过滤处理,将过滤后的请求再转发给下一个资源。其实Servlet过滤器与Servlet十分相似,只是多了个具有拦截浏览器请求的功能。
过滤器的生命周期
实例化———————————————–web.xml
初始化———————————————–init()
执行过滤——————————————–doFilter()
销毁————————————————–destory()
配置
在web.xml中配置过滤器,关键代码如下:
<filter>
<filter-name></filter-name> <!--配置的过滤器名-->
<filter-class></filter-class> <!--过滤器类所在的路径-->
<init-param> <!--初始化参数,可有可无,最多不限-->
<description></description> <!--描述字段,可有可无,最多不限-->
<param-name></param-name> <!--初始化参数名-->
<param-value></param-value> <!--初始化参数值-->
</init-param>
</filter>
<filter-mapping> <!--可以配置多个-->
<filter-name></filter-name> <!--配置的过滤器名与上面的对应-->
<url-pattern></url-pattern>
<servlet-name></servlet-name> <!--和url-pattern至少配置一个,最多不限,匹配指定路径或者对应请求的Servlet-->
<dispatcher></dispatcher> <!--可有可无,最多配置4个-->
</filter-mapping>
The dispatcher has four legal values: FORWARD, REQUEST, INCLUDE, and ERROR.
A value of FORWARD means the Filter will be applied under RequestDispatcher.forward() calls.
如果目标资源是通过request.getRequestDisPatcher的forward方法进行访问,那么该过滤器将会被调用,其他情况下,不会被调用。
A value of REQUEST means the Filter will be applied under ordinary client calls to the path or servlet.
当用户直接访问页面时,web容器将会调用过滤器,如果目标资源是通过请求转发(request.getRequestDisPatcher)的include方法或forward方法进行访问,那么该过滤器就不会被调用,过滤器的拦截方式默认就是 REQUEST。
A value of INCLUDE means the Filter will be applied under RequestDispatcher.include() calls.
如果目标资源是通过request.getRequestDisPatcher的include方法进行访问,那么该过滤器将会被调用,其他情况下,不会被调用。
A value of ERROR means the Filter will be applied under the error page mechanism.
如果目标资源是通过声明或异常处理机制调用,那么该过滤器将会被调用,除此之外,不会被调用。
The absence of any dispatcher elements in a filter-mapping indicates a default of applying filters only under ordinary client calls to the path or servlet.
redirect与(include、forward)的区别在于是不是同一个Request,redirect会有两次交互。
include与forward的区别在于输出的内容,include包含本身servlet与跳转页面内容的结果,而forward不包含本身servlet的内容。
过滤器在web.xml配置时,<filter>
元素用来定义一个过滤器,<filter-mapping>
元素用于为过滤器映射特定的URL。注意:在配置多个Filter时执行有先有后,规定是<filter-mapping>
配置在前面的Filter执行要早于配置在后面的(但是过滤器的初始化顺序即init()方法的执行顺序却不是,它是按照过滤器名字排序的),另外注意多个Filter可能会互相影响。只有在web.xml中配置了的过滤器才会执行初始化过程。
自定义请求
public class CharFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("CharFilter过滤器初始化");
System.out.println("name: "+filterConfig.getInitParameter("name"));
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
System.out.println("before_charFilter");
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
HttpServletRequest charRequest = new CharRequest(request);
chain.doFilter(charRequest, response);
System.out.println("after_charFilter");
}
@Override
public void destroy() {
System.out.println("CharFilter过滤器销毁了");
}
class CharRequest extends HttpServletRequestWrapper {
/**
* 定义被增强的请求对象
*/
private HttpServletRequest request;
/**
* Constructs a request object wrapping the given request.
*
* @param request
* @throws IllegalArgumentException if the request is null
*/
public CharRequest(HttpServletRequest request) {
super(request);
this.request = request;
}
@Override
public String getParameter(String name) {
String value = request.getParameter(name);
if (value == null) {
return null;
}
return "我是你爸爸: " + value;
}
}
}
web.xml配置
<filter>
<filter-name>charFilter</filter-name>
<filter-class>com.filter.CharFilter</filter-class>
<init-param>
<param-name>name</param-name>
<param-value>ljh</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>charFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Controller层调用HttpServletRequest的getParameter方法:
@RequestMapping(method = RequestMethod.POST, value = "login")
@ResponseBody
public List loginHandle(HttpServletRequest request) {
System.out.println(request.getParameter("account"));
return null;
}
//output:
我是你爸爸: fuck
自定义响应
public class GzipFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
BufferResponse myresponse = new BufferResponse(response);
chain.doFilter(request, myresponse);
//拿出缓存中的数据,压缩后再打给浏览器
byte out[] = myresponse.getBuffer();
System.out.println("原始大小:" + out.length);
ByteArrayOutputStream bout = new ByteArrayOutputStream();
//压缩输出流中的数据
GZIPOutputStream gout = new GZIPOutputStream(bout);
gout.write(out);
gout.close();
byte gzip[] = bout.toByteArray();
System.out.println("压缩后的大小:" + gzip.length);
response.setHeader("content-encoding", "gzip");
response.setContentLength(gzip.length);
response.getOutputStream().write(gzip);
}
public void destroy() {
}
public void init(FilterConfig filterConfig) throws ServletException {
}
class BufferResponse extends HttpServletResponseWrapper {
private ByteArrayOutputStream bout = new ByteArrayOutputStream();
private PrintWriter pw;
private HttpServletResponse response;
public BufferResponse(HttpServletResponse response) {
super(response);
this.response = response;
}
/**
* servlet容器没有编码二进制数据,调用ServletOutputStream对象的flush()方法提交响应。
* Either this method or {@link #getWriter} may be called to write the body, not both.
* @return 响应的二进制数据的输出流
* @throws IOException
*/
@Override
public ServletOutputStream getOutputStream() throws IOException {
return new MyServletOutputStream(bout);
}
/**
* 如果响应字符编码没有指定,默认"ISO-8859-1",可以调用PrintWrite对象的flush()方法提交响应
* @return PrintWriter对象能够发送字符数据到客户端
* @throws IOException
*/
@Override
public PrintWriter getWriter() throws IOException {
pw = new PrintWriter(new OutputStreamWriter(bout, this.response.getCharacterEncoding()));
return pw;
}
public byte[] getBuffer() throws IOException {
if (pw != null) {
pw.close();
}
if (bout != null) {
bout.flush();
return bout.toByteArray();
}
return null;
}
class MyServletOutputStream extends ServletOutputStream{
private ByteArrayOutputStream bout;
public MyServletOutputStream(ByteArrayOutputStream bout){
this.bout = bout;
}
@Override
public void write(int b) throws IOException {
this.bout.write(b);
}
}
}
}
自定义过滤器链
在web.xml中配置的多个过滤器按照的定义顺序执行,由servlet容器的过滤器链控制。过滤器链FilterChain通过doFilter()方法进行过滤器的传递,自定义过滤器链需要实现FilterChain接口。
public class FirstFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String name = filterConfig.getInitParameter("username");
System.out.println("我是初始化方法"+name);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("你好啊");
List filters = new ArrayList<FilterChain>();
filters.add(new SecondFilter());
ConFilterChain con = new ConFilterChain(filters, chain);
con.doFilter(request,response);
System.out.println("我又回来了");
}
@Override
public void destroy() {
System.out.println("我被销毁了");
}
}
第二个过滤器(不需要在web.xml中配置就可执行):
public class SecondFilter implements Filter {
//不会执行
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("我是第二个初始化");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("SecondFilter的doFilter方法");
chain.doFilter(request,response);
System.out.println("SecondFilter的doFilter方法2");
}
@Override
public void destroy() {
}
}
过滤器链:
public class ConFilterChain implements FilterChain {
private List<Filter> filters; //自定义的过滤器
private FilterChain chain; //保存的servlet容器的过滤器链
private int currentPosition; //当前执行的过滤器在过滤器集合中的下标
public ConFilterChain(List<Filter> filters,FilterChain chain){
this.filters = filters;
this.chain = chain;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
if(currentPosition == filters.size()){
chain.doFilter(request,response); //如果过滤器集合都已经执行完毕,那么继续执行servlet容器中过滤器链的下一个处理
}else{
currentPosition++;
Filter nextFilter = filters.get(currentPosition - 1);
nextFilter.doFilter(request,response,this); //执行过滤器的doFilter方法
}
}
}
参考
https://blog.csdn.net/Evankaka/article/details/45480101
https://www.cnblogs.com/xdp-gacl/p/3952405.html