• Servlet过滤器


    Servlet过滤器

    1.过滤器的基本概念

    1.1.基本概念

    过滤器(Filter)属于tomcat服务器中的Servlet功能。在普通的javaweb服务中,jsp中的请求要被Servlet来处理,但是很多对请求做一些操作或者判断,比如用户的每次请求都要判断是不是已经登录,这个时候就可以使用到过滤器,过滤器的作用就相当于Servlet的一个门,jsp的请求从这个门进来,也要从这个门出去

    通过过滤器Filter技术,对web服务器管理的所有web资源,例如:jsp,Servlet,静态图片或静态html进行拦截,从而实现一些功能。例如:实现URL级别的权限访问控制,过滤敏感词,压缩响应信息等一些高级功能

    1.2.过滤器的生命周期

    过滤器只有三个方法:init(),doFilter(),destory()。
    在tomcat在启动的就执行init()方法创建过滤器,
    当jsp有请求传进来的时候就会调用doFilter()方法来执行。doFilter()方法来中一定要有chain.doFilter()这个方法,这个是放行,使过滤器中的请求能进进入下一个过滤器或者Servlet
    在程序结束的时候调用destroy()方法来销毁过滤器实例

    1.3.过滤器的执行流程

    1.文字描述过滤器执行过程
    过滤器在程序中的执行流程是:
    1.用户访问服务器
    2.过滤器:对Servlet请求进行拦截
    3.请求先进入过滤器,过滤器处理请求
    4.过滤器处理完之后,再放行,此时请求到达下一个过滤器或Servlet/JSP
    5.下一个过滤器处理再传给Servlet,或者直接Servlet处理
    6.Servlet处理完后,再回到过滤器,最后再由tomcat服务器响应用户

    2.过滤器执行过程的时序图:

    3.代码描述过滤器的执行过程
    为了用代码说明过滤器的执行过程,这里用三个代码来说明,第一个脚本是第一个过滤器oneFilter.java;第二个脚本是第二个过滤器secFilter.java;第三个脚本是Servlet脚本,整个执行过程就是按照代码里面的序号来执行的
    第一个过滤器:

    
    
    import java.io.IOException;
    import java.util.Enumeration;
    
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    
    /**
     * 过滤器,测试
     *
     */
    public class oneFilter implements Filter{
    	
    	// 创建实例
    	public HelloFilter(){
    		System.out.println("1. 创建过滤器实例");
    	}
    
    	@Override
    	public void init(FilterConfig filterConfig) throws ServletException {
    		System.out.println("2. 执行过滤器初始化方法");
    		
    	}
    
    	// 过滤器业务处理方法: 在请求到达servlet之前先进入此方法处理公用的业务逻辑操作
    	@Override
    	public void doFilter(ServletRequest request, ServletResponse response,
    			FilterChain chain) throws IOException, ServletException {
    		System.out.println("3. 执行过滤器业务处理方法");
    		// 放行 (去到Servlet)
    		// 如果有下一个过滤器,进入下一个过滤器,否则就执行访问servlet
    		chain.doFilter(request, response);
    		
    		System.out.println("7. Servlet处理完成,又回到过滤器");
    	}
    
    	@Override
    	public void destroy() {
    		System.out.println("8. 销毁过滤器实例");
    	}
    
    }
    

    第二个过滤器

    
    
    import java.io.IOException;
    
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    
    public class secFilter implements Filter{
    
    
    	@Override
    	public void doFilter(ServletRequest request, ServletResponse response,
    			FilterChain chain) throws IOException, ServletException {
    		System.out.println("4.第二个过滤器开始执行");
    		// 放行,访问Servlet
    		chain.doFilter(request, response);
    		System.out.println("6.第二个过滤器执行结束");
    	}
    
    	
    	
    	
    	
    	@Override
    	public void init(FilterConfig filterConfig) throws ServletException {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public void destroy() {
    		// TODO Auto-generated method stub
    		
    	}
    
    }
    

    Servlet处理

    
    import java.io.IOException;
    import java.io.PrintWriter;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * Servlet:
     * 	 处理用户http request
     *
     */
    public class IndexServlet extends HttpServlet {
    
    	public void doGet(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    		
    
    		System.out.println("5.处理用户请求");
    
    	}
    
    }
    
    

    整个执行过程就是1->2->3->4->5->6->7->8;

    4.Filter开发步骤
    Filter开发要分为两步:
    1.编写java类实现Filter接口,并实现其doFilter方法,在web.xml文件中使用元素对编写的filter类进行注册,并设置它多能拦截的资源
    2.在一个web应用中,可以开发编写多个Filter,这些Filter组合起来称之为一个Filter链
    web服务器根据Filter在web.xml文件中的注册顺序,决定先调用那个Filter,当第一个Filter的doFilter方法被调用时,web服务器会创建一个Filter链的FilterChain对象传递给该方法

    2.过滤器的常用方法

    2.1.过滤器常用API

    interface Filter 过滤器核心接口

    void init(filterConfig);初始化方法,在服务器启动时调用
    Void doFilter(request,response,filterChain); 过滤器拦截的业务处理方法
    Void destroy(); 销毁过滤器实例时候调用

    在init中涉及到filterConfig接口,这个接口的作用是获取在web.xml中配置的Filter的初始化参数信息
    常用方法如下:

    getInitParameter(String name);指定参数名字来获取参数值
    getInitParameterNames();获取所有Filter的参数名

    在doFilter中使用到FilterChain接口,该接口的作用是,形成一个Filter执行链。

    void doFilter(request,response);执行下一个过滤器或放行

    代码示例如下:
    web.xml的配置文件,主要包括两个过滤器的配置和第一个过滤器的初始化参数

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
             version="3.1">
    
    
        <!--过滤器配置-->
        <filter>
            <!--配置初始化参数-->
            <init-param>
                <param-name>encoding</param-name>
                <param-value>UTF-8</param-value>
            </init-param>
            <init-param>
                <param-name>path</param-name>
                <param-value>/home/cenyu</param-value>
            </init-param>
    
    
            <!--内部名称-->
            <filter-name>oneFilter</filter-name>
            <!--过滤器类的全名-->
            <filter-class>d_filter.onrFilter</filter-class>
        </filter>
        <filter-mapping>
            <!--filter内部名-->
            <filter-name>oneFilter</filter-name>
            <!--拦截所有资源-->
            <url-pattern>/*</url-pattern>
            
        </filter-mapping>
    
        
        <!--配置第二个过滤器-->
        <filter>
            <filter-name>secFilter</filter-name>
            <filter-class>d_filter.secFilter</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>secFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    </web-app>
    

    三个接口的使用方式:

    package d_filter;
    
    import javax.servlet.*;
    import javax.servlet.annotation.WebFilter;
    import java.io.IOException;
    import java.util.Enumeration;
    
    
    @WebFilter(filterName = "onrFilter")
    public class onrFilter implements Filter {
        public onrFilter(){
            System.out.println("1.创建过滤器实例");
        }
        public void destroy() {
        }
    
        public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
            System.out.println("3.执行过滤器业务处理方法");
    
            chain.doFilter(req, resp);
    
            System.out.println("5.Servlet处理完成,又回到过滤器");
        }
    
        public void init(FilterConfig config) throws ServletException {
            System.out.println("2.执行过滤器初始化方法");
    
            //获取过滤器在web.xml中配置的初始化参数
            String encoding=config.getInitParameter("encoding");
            System.out.println(encoding);
    
            //获取过滤器在web.xml中配置的所有初始化参数的名称
            Enumeration<String> enums = config.getInitParameterNames();
            //遍历参数名称和值
            while (enums.hasMoreElements()){
                //获取国有参数名称:encoding, path
                String name = enums.nextElement();
                //获取名相应的值
                String value = config.getInitParameter(name);
                System.out.println(name+"	"+value);
    
            }
    
        }
    
    }
    
    

    2.2.xml配置文件中配置指定的请求拦截

      <filter-mapping>
            <!--filter内部名-->
            <filter-name>oneFilter</filter-name>
            <!--1.拦截所有资源-->
            <!--/*表示拦截多有的请求-->
            <url-pattern>/*</url-pattern>
    
            <!--2.拦截指定的jsp-->
            <!--拦截多个jsp时,可以直接在下面再写一个,也可以使用通用写法-->
            <url-pattern>/index.jsp</url-pattern>
            <url-pattern>/list.jsp</url-pattern>
    
            <!--连接所有jsp-->
            <url-pattern>*.jsp</url-pattern>
    
            <!--3.根据servlet的内存名连接-->
            <servlet-name>indexServlet</servlet-name>
            <!--或者这里放servlet的匹配url来拦截servlet-->
            <url-pattern>/index</url-pattern>
    
            <!--4.指定拦截指定的类型-->
            <!--拦截请求,默认拦截的类型-->
            <dispatcher>REQUEST</dispatcher>
            <!--拦截转发-->
            <dispatcher>FORWARD</dispatcher>
            <!--拦截包含的页面,例:(RequestDispatcher.include(/page.jsp));对page.jsp也进行拦截-->
            <dispatcher>INCLUDE</dispatcher>
            <!--拦截错误页面配置-->
            <dispatcher>ERROR</dispatcher>
        </filter-mapping>
    

    3.过滤器案例

    3.1.案例:处理中文编码

    问题来源
    在项目中,java默认是ISO-8859-1编码,而中文常用的是UTF-8或者gbk。于是几乎每一个Servlet都要设计编码处理,即处理请求中数据中文的问题!
    如果在每一个Servlet中写处理方法则过于繁琐,此时可以把公用代码抽取出来,然后写在过滤器中,就可以了。

    代码实现思路
    1.login.jsp:登录,输入“中文”
    2.loginServlet.java;直接处理登录请求
    3.EncodingFilter.java:过滤器处理请求数据编码:分GET/POST两种式的提交处理

    代码实现:
    本例中jsp写一个有POST和GET请求的表单,一个过滤器,一个Servlet处理程序
    jsp页面:

    <%--
      Created by IntelliJ IDEA.
      User: cenyu
      Date: 16-12-19
      Time: 下午3:12
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>登录页面</title>
    </head>
    <body>
    <form action="${pageContext.request.contextPath}/login" method="post">
        用户名:<input type="text" name="userName"><br/>
        <input type="submit" value="POST提交">
    </form>
        <hr/>
    <form action="${pageContext.request.contextPath}/login" method="get">
        用户名:<input type="text" name="userName"><br/>
        <input type="submit" value="GET提交">
    </form>
    
    </body>
    </html>
    
    

    过滤器

    package encodeFilter_demo;
    
    import javax.servlet.*;
    import javax.servlet.annotation.WebFilter;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /**
     * 编码处理统一写到这里(Servlet中不需要在处理编码)
     * Created by cenyu on 16-12-19.
     */
    @WebFilter(filterName = "EncodingFilter")
    public class EncodingFilter implements Filter {
        public void destroy() {
        }
    
    
        //过滤器业务处理方法:处理的公用的业务逻辑操作
        public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
           //转型
            HttpServletRequest request = (HttpServletRequest)req;
            HttpServletResponse response = (HttpServletResponse)resp;
    
            //1处理公用业务
            request.setCharacterEncoding("UTF-8"); //POST提交有效
            response.setContentType("text/html;chartset=UTF-8");
            //放行
            chain.doFilter(req, resp);
        }
    
        public void init(FilterConfig config) throws ServletException {
    
        }
    
    }
    
    

    Servlet程序;

    package encodeFilter_demo;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    /**
     *编码统一处理案例中的Servlet脚本
     * Created by cenyu on 16-12-19.
     */
    @WebServlet("/login")
    public class loginServlet extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            this.doGet(request,response);
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //获取请求数据
            String name = request.getParameter("userName");
            System.out.println("用户:"+name);
        }
    }
    
    

    过滤器的web.xml配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
             version="3.1">
    
        <!--编码处理过滤器配置-->
        <filter>
            <filter-name>EncodingFilter</filter-name>
            <filter-class>encodeFilter_demo.EncodingFilter</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>EncodingFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    </web-app>
    

    3.2.过滤敏感词汇

    效果:实现模拟过滤论坛过敏词汇

    实现思路:
    1.dis.jsp 讨论区页面
    2.disServlet.java 处理请求

    • 获取请求参数
    • 保存到request域
    • 跳转到dis.jsp(从request取数据显示(处理后))

    3.dataFilter.java 过滤器

    • 编码
    • 无效数据处理

    即:在上一个案例基础上,再添加无效数据过滤的相关代码
    代码示例:
    jsp的显示和接收页面:

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>无效数据过滤</title>
    </head>
    <body>
    ${requestScope.content}
    
    <form name="frmdis" action="${pageContext.request.contextPath}/disServlet" method="post">
        发表评论:<textarea   rows="6" cols="3" name="content"></textarea>
        <br/>
        <input type="submit" value="提交">
    </form>
    </body>
    </html>
    
    

    过滤器中的代码:

    package encodeFilter_demo;
    
    import javax.servlet.*;
    import javax.servlet.annotation.WebFilter;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 无效数据过滤
     */
    @WebFilter(filterName = "dataFilter")
    public class dataFilter implements Filter {
        //初始化无效数据
        private List<String> dirtyData;
    
        public void destroy() {
        }
    
        public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
    
            HttpServletRequest request = (HttpServletRequest)req;
            HttpServletResponse response = (HttpServletResponse)resp;
    
    
            request.setCharacterEncoding("UTF-8");
            response.setContentType("text/html;chartset=UTF-8");
    
    
            //中午数据已经处理完成,下面进行无效数据过滤
            String content = req.getParameter("content");
            //如果volue中出现dirtyData中数据,用****替换
            if (content != null && !"".equals(content)) {
                for (String data : dirtyData) {
                    //判断当前输入数据(value),是否包含无效数据
                    if (content.contains(data)) {
                        content = content.replace(data, "***");
                        request.setAttribute("content",content);
                        break;
                    }
                }
            }
            //放行
            chain.doFilter(req, resp);
        }
        public void init(FilterConfig config) throws ServletException {
            //模拟无效几个数据
            dirtyData = new ArrayList<String>();
            dirtyData.add("NND");
            dirtyData.add("三胖");
    
        }
    
    }
    
    

    Servlet中的代码:

    package encodeFilter_demo;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    /**
     * Created by cenyu on 16-12-19.
     */
    @WebServlet("/disServlet")
    public class DisServlet extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            this.doGet(request,response);
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //获取请求数据
            String content = (String) request.getAttribute("content");
            //保存到request
            request.setAttribute("content","Content: "+content);
            //转发
            request.getRequestDispatcher("/dis.jsp").forward(request,response);
        }
    }
    
    
  • 相关阅读:
    Java 概述
    vue组件事件
    小程序注册
    小程序基础知识梳理
    小程序简介
    公众号
    jeecg-boot
    小程序背景图
    bootstrap-select采坑
    存取cookie
  • 原文地址:https://www.cnblogs.com/cenyu/p/6200495.html
Copyright © 2020-2023  润新知