美文网首页
JavaWeb之 Filter

JavaWeb之 Filter

作者: 测试员 | 来源:发表于2019-09-28 20:35 被阅读0次

FIlter作用

过滤器JavaWeb三大组件之一,它与Servlet很相似!不它过滤器是用来拦截请求的,而不是处理请求的。
当用户请求某个Servlet时,会先执行部署在这个请求上的Filter,如果Filter“放行”,那么会继承执行用户请求的Servlet;如果Filter不“放行”,那么就不会执行用户请求的Servlet。
其实可以这样理解,当用户请求某个Servlet时,Tomcat会去执行注册在这个请求上的Filter,然后是否“放行”由Filter来决定。可以理解为,Filter来决定是否调用Servlet!当执行完成Servlet的代码后,还会执行Filter后面的代码。

FIlter实现步骤

1.创建AFilter类实现javax.servlet.Filter接口

2.添加@WebFilter("/*")注解或者添加web.xml配置

    <filter>
        <filter-name>AFilter</filter-name>
        <filter-class>com.yuan.web.filter.AFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>AFilter</filter-name>
        <url-pattern>/*<!--表示连接所有请求,剩下的就不说明啦,要学会自己看懂哦--></url-pattern>
    </filter-mapping>

3.已经完成了

4.@WebFilter参数说明

编写简单一个Filter

package com.yuan.web.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

@WebFilter("/*")
public class AFilter implements Filter {
    /**
     * 初始化 创建后立即执行
     *
     * @param filterConfig
     * @throws ServletException
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("AFilter出生啦");
    }

    /**
     * 每次过滤时都会执行
     *
     * @param request
     * @param response
     * @param chain
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        //访问时过滤
        System.out.println("拦截!留下买路财");
        //放行
        chain.doFilter(request,response);
        //响应时过滤
        System.out.println("你又~回来啦?");
    }

    /**
     * 销毁前立即执行
     */
    @Override
    public void destroy() {
        System.out.println("AFilter去世啦");
    }
}

FIlter说明

Filter是单例的!

void init(FilterConfig)
创建之后,马上执行;Filter会在服务器启动时就创建!
FilterConfig-->与ServletConfig相似

  • 获取初始化参数:getInitParameter()
  • 获取过滤器名称:getFilterName()
  • 获取appliction:getServletContext()

void destory()
销毁之前执行!在服务器关闭时销毁

void doFilter(ServletRequest,ServletResponse,FilterChain)
每次过滤时都会执行
FilterChain

  • doFilter(ServletRequest, ServletResponse):放行!

    执行目标资源就相当于调用了目标Servlet的service()方法!,或是执行下一个过滤器!如果没有下一个过滤器那么执行的是目标资源,如果有,那么就执行下一个过滤器!

多个过滤器执行顺序

1.<filter-mapping>的配置顺序决定了过滤器的执行顺序!

2.过滤时遵守先进先出

过滤器的N种拦截方式

  <dispatcher>REQUEST</dispatcher>默认的!
  <dispatcher>FORWARD</dispatcher>
  <dispatcher>INCLUDE</dispatcher>
  <dispatcher>ERROR</dispatcher>
@WebFilter(value = "/CServlet",
        dispatcherTypes = {
                DispatcherType.ASYNC,//异步
                DispatcherType.ERROR,//错误
                DispatcherType.FORWARD,//转发
                DispatcherType.INCLUDE,//包含
                DispatcherType.REQUEST})//请求
public class AFilter implements Filter {}

应用场景

执行目标资源之前做预处理工作,例如设置编码,这种试通常都会放行,只是在目标资源执行之前做一些准备工作
通过条件判断是否放行,例如校验当前用户是否已经登录,或者用户IP是否已经被禁用
在目标资源执行后,做一些后续的特殊处理工作,例如把目标资源输出的数据进行处理

设置目标资源

/:所有资源
/xx/xx/
:xx/xx/下的所有资源
/aaa/bbb/ccc/Servlet:具体AServlet

案例

案例一【分ip统计网站的访问次数】

分析

统计工作需要在所有资源之前都执行,那么就可以放到Filter中了。
我们这个过滤器不做拦截操作!因为我们只是用来做统计的。
用什么东西来装载统计的数据。Map<String,Integer>
整个网站只需要一个Map即可!
Map什么时候创建(使用ServletContextListener,在服务器启动时完成创建,并只在到ServletContext中),Map保存到哪里!(Map保存到ServletContext中!!!)
Map需要在Filter中用来保存数据
Map需要在页面使用,打印Map中的数据

代码实现

Listener

package com.yuan.web.listener;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import java.util.HashMap;
import java.util.LinkedHashMap;

@WebListener()
public class CListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        //1.创建ServletContext
        ServletContext application = sce.getServletContext();
        //2.Map
        HashMap<String, Integer> ipMap = new LinkedHashMap<>();
        //3.把Map保存到ServletContext中
        application.setAttribute("ipMap",ipMap);
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {

    }
}

Filter

package com.yuan.web.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
import java.util.LinkedHashMap;

/**
 * @author Yuan-9826
 */
@WebFilter("/*")
public class CFilter implements Filter {


    @Override
    public void init(FilterConfig config) throws ServletException {

    }


    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        //1.得到ServletContext中的IPMap
        ServletContext application = req.getServletContext();
        //2.获取客户端IP
        String IP = req.getRemoteAddr();
        //3.获得并操作Map
        LinkedHashMap<String, Integer> ipMap = (LinkedHashMap<String, Integer>) application.getAttribute("ipMap");
        if (ipMap.containsKey(IP)) {
            int ipValue = ipMap.get(IP);
            ipMap.put(IP, ++ipValue);
            System.out.println("添加了map IP = " + IP + "次数 = " + ipValue);
        } else {
            ipMap.put(IP, 1);
            System.out.println("添加了map IP = " + IP + "次数 = " + 1);
        }
        application.setAttribute("ipMap", ipMap);
        //4.放行
        chain.doFilter(req, resp);
    }

    @Override
    public void destroy() {
    }

}

jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<%@ taglib prefix="y" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="zh-CN">
<html>
<body>
<h1>显示IP</h1>
<h1>${applicationScope.ipMap }</h1>

<table border="1" align="center" width="60%">

    <tr>
        <th>IP地址</th>
        <th>次数</th>
    </tr>
    <c:forEach items="${applicationScope.ipMap }" var="entry">
    <tr>
        <td>${entry.key}</td><%--这里不知道为啥没显示出来--%>
        <td>${entry.value}</td><%--这里不知道为啥没显示出来--%>
    </tr>
    </c:forEach>
</table>
</body>
</html>

效果

image.png

案例二【粗粒度权限过滤】

只有文字描述步骤

游客、会员、管理员三个粒度

1.创建一个Fileter,过滤会员下的资源访问,这是保安1号 ,doFilter里检查session中权限标记,第一道检查工序,不是管理员=> 放行,第二道检查工序,不是会员=> 打回到登录/注册页面,如果是会员就放行!

2.创建一个Fileter,过滤管理员下的资源访问,这是保安2号 ,doFilter里检查session中权限标记,查看是不是管理员,不是管理员=>打回到登录/注册页面,如果是管理员就放行!

案例三【解决全站字符乱码(POST和GET中文编码问题)】

工具类

package com.yuan.encoding;

import java.io.UnsupportedEncodingException;

/**
 * 编码转换
 */
public class EncodeingUtils {
    /**
     * iso-8859-1 转成 utf-8
     *
     * @param code
     * @return
     */
    public static String i2u(String code) {
        try {
            return new String(code.getBytes("iso-8859-1"), "utf-8");
        } catch (UnsupportedEncodingException e) {
            new RuntimeException("转码失败");
            return null;
        }
    }

    /**
     * iso-8859-1 转成 gbk
     *
     * @param code
     * @return
     */
    public static String i2g(String code) {
        try {
            return new String(code.getBytes("iso-8859-1"), "gbk");
        } catch (UnsupportedEncodingException e) {
            new RuntimeException("转码失败");
            return null;
        }
    }

    /**
     * gbk 转成 iso-8859-1
     *
     * @param code
     * @return
     */
    public static String g2i(String code) {
        try {
            return new String(code.getBytes("gbk"), "iso-8859-1");
        } catch (UnsupportedEncodingException e) {
            new RuntimeException("转码失败");
            return null;
        }
    }

    /**
     * gbk 转成 utf-8
     *
     * @param code
     * @return
     */
    public static String g2u(String code) {
        try {
            return new String(code.getBytes("gbk"), "utf-8");
        } catch (UnsupportedEncodingException e) {
            new RuntimeException("转码失败");
            return null;
        }
    }


    /**
     * utf-8 转成 iso-8859-1
     *
     * @param code
     * @return
     */
    public static String u2i(String code) {
        try {
            return new String(code.getBytes("utf-8"), "iso-8859-1");
        } catch (UnsupportedEncodingException e) {
            new RuntimeException("转码失败");
            return null;
        }
    }

    /**
     * utf-8 转成 gbk
     *
     * @param code
     * @return
     */
    public static String u2g(String code) {
        try {
            return new String(code.getBytes("utf-8"), "gbk");
        } catch (UnsupportedEncodingException e) {
            new RuntimeException("转码失败");
            return null;
        }
    }


}
package com.yuan.web.filter;

import com.yuan.encoding.EncodeingUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

/**
 * 被掉包了的Request
 */
public class HttpRequest extends HttpServletRequestWrapper {
    private HttpServletRequest request;

    public HttpRequest(HttpServletRequest request) {
        super(request);
        this.request = request;
    }

    /**
     * 处理编码问题
     * @param name
     * @return
     */
    @Override
    public String getParameter(String name) {

        String value = request.getParameter(name);
        return EncodeingUtils.i2u(value);

    }
}
package com.yuan.web.filter;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * 乱码过滤器
 */
public class EncodingFilter implements Filter {

    private String GET = "GET";
    private String POST = "POST";
    private Integer version = 8;


    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("编码过滤器执行");
        final String version = filterConfig.getInitParameter("tomcatVersion");
        this.version = Integer.valueOf(version);
        System.out.println(version);

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        //处理post请求编码问题
        req.setCharacterEncoding("utf-8");

        /**
         * tomcat1.8之后自己做了get请求的处理
         */
        if (version < 8) {
            System.out.println("Tomcat版本低于8 做GET请求处理");
            //掉包request 和 HttpServletRequest
            HttpServletRequest request = (HttpServletRequest) req;
            //放行时
            if (GET.equals(request.getMethod())) {
                HttpRequest hr = new HttpRequest(request);
                chain.doFilter(hr, res);
            } else if (POST.equals(request.getMethod())) {
                chain.doFilter(req, res);
            }
        }else {
            chain.doFilter(req, res);
            System.out.println("Tomcat版本不低于8 不做GET请求处理");
        }
    }

    @Override
    public void destroy() {

    }
}

只要配置了这个过滤器 即可使用

<filter>
    <filter-name>encoding</filter-name>
    <filter-class>com.yuan.web.filter.EncodingFilter</filter-class>
    <init-param>
        <param-name>tomcatVersion</param-name>
        <param-value>8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>encoding</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

案例四【页面静态化 改日补充】

相关文章

  • JavaWeb之 Filter

    FIlter作用 过滤器JavaWeb三大组件之一,它与Servlet很相似!不它过滤器是用来拦截请求的,而不是处...

  • Javaweb组件--Filter

    今天讲的是Javaweb的三大组件之:Filter Filter ,过滤器,主要是对web服务器管理的所有web资...

  • JavaWeb之Filter简介

    Filter: 作用:用于对用户请求(request)进行预处理(到达Servlet前),也可以对响应(respo...

  • JavaWeb基础之Filter

    编写一个过滤器 实现Filter接口 配置拦截的URL路径:在web.xml中填写 过滤器的常见应用 实现用户登录...

  • JavaWeb三大组件之过滤器(Filter)

    title: JavaWeb三大组件之过滤器(Filter)tags: JavaWeb 过滤器categories...

  • JavaWeb三大组件之Filter

    JavaWeb有三大组件,Servlet、Listener、Filter。本文将介绍Filter,主要从用处、种类...

  • Servlet、Filter、Listener

    JavaWeb三大组件指的是:Servlet、Filter、Listener,这三个组件在JavaWeb开发中分别...

  • JavaWeb三大组件(Servlet、Filter、Liste

    JavaWeb三大组件指的是:Servlet、Filter、Listener,这三个组件在JavaWeb开发中分别...

  • Filter

    过滤器(Filter) Servlet/Filter/Listener统称为JavaWeb的三大组件.其中Filt...

  • Filter&Listener

    Filter过滤器 概念 Filter表示过滤器,是JavaWeb的三大组件之一,Servlet、Filter、L...

网友评论

      本文标题:JavaWeb之 Filter

      本文链接:https://www.haomeiwen.com/subject/rqntpctx.html