JavaWeb-Filter

来源:互联网 发布:java高级工程师技能 编辑:程序博客网 时间:2024/05/22 18:42

话说:
Servlet之后,我们客串了一下数据连接池,这会总结一下过滤器——Filter。

What?

Flilter即过滤器,就是javax.servlet包下面的一个接口。实现这个接口可以帮我们做很多事情。它是向Web应用程序的请求和响应添加功能的Web服务组件;可以统一的集中处理请求和响应;实现对数据的过滤。
可是还是抽象,到底有什么卵用?

应用场合:
1、对请求和响应进行统一处理
2、对请求日志进行日志记录和审核
3、对数据进行屏蔽和替换
笔者猜测,屏蔽色情、论坛屏蔽敏感字段可能会用到这个
4、对数据进行加密和解密
近代的电报,和这个类似吧

Why?

貌似跟我们有毛线关系啊?有的。还记得前面,我们写了很多个Servlet,后来简化成了BaseServlet,在BaseServlet里面,写多个方法。方法里面实现调用。本质还是一个Servlet处理一个请求。然鹅,Filter就可以实现一个Filter处理按照正则表达式匹配后满足条件的所有请求。这里我们来3个案例,实践出真知嘛!


案例一:MyFilter(Filter的实现及生命周期)
案例二:Filter实现权限过滤
案例三:Filter字符编码过滤


案例一:MyFilter(Filter的实现及生命周期)

Filter是什么东东?如何用呢?建立一个Filter步骤:


1)建立实现Filter接口的类(javax.servlet.Filter)也就是Tomcat自带的lib
2)实现过滤行为
3)在web.xml中配置过滤器


1)建立实现Filter接口的类(javax.servlet.Filter)也就是Tomcat自带的lib
整体工程架构图如下:

这里写图片描述

MyFilter

package com.hmc.filter;import javax.servlet.*;import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.FilterConfig;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import java.io.IOException;/** * User:Meice * 2017/10/6 */public class MyFilter implements Filter{    @Override    public void init(FilterConfig config) throws ServletException {        System.out.println("Filter初始化....");    }    @Override    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {        System.out.println("请求来了...");        //执行过滤        chain.doFilter(req,resp);        System.out.println("处理响应...");    }    @Override    public void destroy() {        System.out.println("Filter销毁啦....");    }}

需要注意的是,一定要调用doFilter(request,response)方法,且在这个方法之前是过滤请求,此方法之后,过滤响应。那么以后如果写关于请求的操作,就要在该方法之后。

配置web.xml

  <!--配置MyFilter过滤器-->    <filter>        <filter-name>myFilter</filter-name>        <filter-class>com.hmc.filter.MyFilter</filter-class>    </filter>    <filter-mapping>        <filter-name>myFilter</filter-name>       <!-- <url-pattern>/*</url-pattern>--><!--对所有请求过滤;一般我们不同时写多个过滤条件-->       <!-- <url-pattern>/admin/*</url-pattern>--><!-- 对admin目录下的所有请求进行过滤-->        <url-pattern>*.do</url-pattern><!--对所有以.do结尾的请求过滤-->    </filter-mapping>

这里,我们开启猫,然后做各种测试即可。

总结:


1、Filter根据你的条件,对所有符合条件的请求进行过滤;如果是目录的话,目录下的任何请求也照样过滤;
2、对比Servlet,当年我们写Servlet的时候,每写一个Servlet都要处理编码,每一个请求最开始也要写对应的Servlet,好在后面我们用BaseServlet进行了优化。
4、Filter的生命周期和Servlet一模一样,不过Filter在一开始启动猫的时候就初始化了,然后执行请求,最后销毁。从此,我们又可以掌控Filter的生命啦,有木有感觉很有权力感?


*案例二:Filter实现权限过滤*

我们在web根目录下创建一个admin的目录,该目录下新建一个manager.jsp;代表后台管理界面。
按照案例一的过滤方法,如果我们知道这个目录,就可以直接访问的admin下的任何一个页面,这有点可怕。后台页面只允许管理员才能访问的,这就是案例二要解决的问题:如何通过过滤器来管理权限?

思路是这样的,我们把问题简化一下,如果在登录界面,用户没有输入用户名和密码,我们直接提示用户“未登录”,并且页面跳转到login.jsp;如果用户输入了用户名和密码,判断用户名是否等于admin,如果相等,ok,才允许跳转到admin目录下的manager.jsp页面(执行管理员操作);如果用户名不等于admin,跳转到noaccess.jsp页面,并给出权限不足提示。
页面整体架构图见案例一那张图。

1)用户在登录界面一旦登录,我们通过LoginSerlvet在后台获取用户名和密码,存到session里面,这里不做页面跳转。
登陆页面代码login.jsp

    <%--      User: Meice      Date: 2017/10/6      Time: 18:41    --%>    <%@ page contentType="text/html;charset=UTF-8" language="java" %>    <html>    <head>        <title>用户登陆</title>    </head>    <body>        <form action="login.do" method="post">            用户名:<input type="text" name="uname"><br/>            密码:<input type="password" name="pwd"><br/>            <input type="submit" value="登陆">        </form>    </body>    </html>

编写LoginServlet

package com.hmc.servlet;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;/** * User:Meice * 2017/10/6 */public class LoginServlet extends HttpServlet{    @Override    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {        doPost(req,resp);    }    @Override    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {        //接受参数        String uname = req.getParameter("uname");       String pwd = req.getParameter("pwd");        //存储session        req.getSession().setAttribute("curUser",uname);    }}

在web.xml中配置LoginServlet

<!--Login Servlet 配置-->    <servlet>        <servlet-name>login</servlet-name>        <servlet-class>com.hmc.servlet.LoginServlet</servlet-class>    </servlet>    <servlet-mapping>        <servlet-name>login</servlet-name>        <url-pattern>/login.do</url-pattern>    </servlet-mapping>

这样,一旦用户登陆,我们就把页面的参数存在了session里,便于下一步的权限判断。

2)用户一旦你在地址栏输入localhost://8080/JavaWeb_Filter/admin/manager.jsp;也就是用户企图访问后台管理员界面的时候,我们设置一个过滤器AuthFilter来做权限判断。

编写AuthFilter

package com.hmc.filter;import javax.servlet.*;import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.FilterConfig;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;/** * User:Meice * 2017/10/6 */public class AuthFilter implements Filter {    @Override    public void init(FilterConfig config) throws ServletException {    }    @Override    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {            chain.doFilter(req,resp);        //转换一下请求        HttpServletRequest request = (HttpServletRequest)req;        HttpServletResponse response = (HttpServletResponse)resp;        //设置编码;奇怪的是,未设置编码也没出现乱码啊!server.xml也没有改       // request.setCharacterEncoding("utf-8");       // response.setCharacterEncoding("utf-8");        //判断sessiion是否为空        String uname =(String) request.getSession().getAttribute("curUser");        System.out.println("uname:"+uname);        //如果不输入用户名,默认是"",而不是null值,以下是验证      /*  System.out.println("uname == null?"+uname==null);        System.out.println("uname== \"\" "+"".equals(uname));*/      //以下验证路径问题(相对路径、绝对路径)         System.out.println("=====================================");         System.out.println("我是Scheme:  "+request.getScheme());        System.out.println("我是ServerName :"+request.getServerName());        System.out.println("我是ServerPort:"+request.getServerPort());     System.out.println("我是ContextPath: "+request.getContextPath());     //所以把我们拼接在一起就是这样        System.out.println(request.getScheme()+"://"+request.getServerName()+":"+        request.getServerPort()+request.getContextPath()+"/"        );    //需要注意ContextPath自动带上半边/;为避免路径过长,一般我们这么写:        String path = request.getContextPath();        String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";        /**         * 页面获取路径用         * <%>=basePath</%>或者${basePath}即可;ContextPath就是项目路径         */    //获取上下文路径        String root = request.getContextPath();       if(uname !=null && !"".equals(uname)){           //判断session用户是否是管理员           if("admin".equals(uname)){           }else{               response.getWriter().write("<script>alert('权限不足');location.href='"+root+"/noaccess.jsp'</script>");           }       }else{           response.getWriter().write("<script>alert('尚未登录');location.href='"+root+"/login.jsp'</script> ");       }        chain.doFilter(request,response);    }    @Override    public void destroy() {    }}

这里需要注意一下路径的问题,上面root的作用就在此。为此,上面代码中间加入了以下这部分,仅仅作为路径的验证,读者可以忽略。

//以下验证路径问题(相对路径、绝对路径)         System.out.println("=====================================");         System.out.println("我是Scheme:  "+request.getScheme());        System.out.println("我是ServerName :"+request.getServerName());        System.out.println("我是ServerPort:"+request.getServerPort());     System.out.println("我是ContextPath: "+request.getContextPath());     //所以把我们拼接在一起就是这样        System.out.println(request.getScheme()+"://"+request.getServerName()+":"+        request.getServerPort()+request.getContextPath()+"/"        );    //需要注意ContextPath自动带上半边/;为避免路径过长,一般我们这么写:        String path = request.getContextPath();        String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";        /**         * 页面获取路径用         * <%>=basePath</%>或者${basePath}即可;ContextPath就是项目路径         */

同样,配置Web.xml中的过滤器

 <!--配置权限过滤器-->    <filter>        <filter-name>authFilter</filter-name>        <filter-class>com.hmc.filter.AuthFilter</filter-class>    </filter>    <filter-mapping>        <filter-name>authFilter</filter-name>        <url-pattern>/admin/*</url-pattern>    </filter-mapping>

这样用户访问的时候,如果没有填写用户名或者密码,就跳转到login.jsp;如果已经填写,不是admin,那么就会跳转到noaccess.jsp

noaccess.jsp代码如下:

<%--  User: Meice  Date: 2017/10/7  Time: 8:03--%><%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head>    <title>管理权限</title></head><body>    <h2>您没有访问权限,请联系管理员授权!</h2></body></html>

好了,到此为止,我们就实现了对后台权限页面的全面掌控!

案例三:Filter字符编码过滤

目的:我们希望,对web根目录下的所有请求在初始化的时候就处理掉编码,而不用每次在对应的Filter的doFilter()里面重复类似的代码
request.setCharacterEncoding(“utf-8”);
response.setCharacterEncoding(“utf-8”);

那么如何设置初始化参数呢?
跟Servlet一模一样,我们新建一个Filter叫做EncodingFilter专门处理字符编码,具体结构请参考上一张架构图。

EncodingFilter代码如下:

package com.hmc.filter;import javax.servlet.*;import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.FilterConfig;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;/** * User:Meice * 2017/10/7 */public class EncodingFilter implements Filter {    String encoding = null;    @Override    public void init(FilterConfig config) throws ServletException {        //初始化的时候就获取编码        encoding = config.getInitParameter("encoding");        //验证是否得到参数        System.out.println("初始化编码:"+encoding);        //判断字符编码值是否为空       if(encoding == null || "".equals(encoding)){           encoding="UTF-8";       }        System.out.println("初始化编码:"+encoding);    }    @Override    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {      //这里用到了向下转型,主要还是方便session的获取,因为session属于HttpSession        HttpServletRequest request = (HttpServletRequest)req;        HttpServletResponse response = (HttpServletResponse)resp;        request.setCharacterEncoding(encoding);        response.setCharacterEncoding(encoding);        //上面转换过来了,过滤当然也要过滤转化后的request,response        chain.doFilter(request,response);    }    @Override    public void destroy() {    }}

web.xml配置如下:

 <!--配置字符编码过滤器-->    <filter>        <filter-name>encoding</filter-name>        <filter-class>com.hmc.filter.EncodingFilter</filter-class>        <!--配置初始化参数encoding-->        <init-param>            <param-name>encoding</param-name>            <param-value></param-value>        </init-param>    </filter>    <filter-mapping>        <filter-name>encoding</filter-name>        <url-pattern>/*</url-pattern><!--字符编码,当然要对所有请求处理啦-->    </filter-mapping>

配置Filter的初始化参数和Servlet一模一样奥。如果读者对于Servlet不熟悉,请回看笔者关于Servlet相关的所有博客。哈哈。

到这里,我们的字符编码处理好啦!不论你是否给了字符编码的初始化参数,我们都设置为了再也亲切不过的UTF-8了。web目录下的所有请求都会经过这个字符编码过滤器!宝宝再也不用担心中文乱码的的问题啦!

还需要注意一下,我们到此为止,3个案例全部结束,整体的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">    <!--配置MyFilter过滤器-->    <filter>        <filter-name>myFilter</filter-name>        <filter-class>com.hmc.filter.MyFilter</filter-class>    </filter>    <filter-mapping>        <filter-name>myFilter</filter-name>       <!-- <url-pattern>/*</url-pattern>--><!--对所有请求过滤;一般我们不同时写多个过滤条件-->       <!-- <url-pattern>/admin/*</url-pattern>--><!-- 对admin目录下的所有请求进行过滤-->        <url-pattern>*.do</url-pattern><!--对所有以.do结尾的请求过滤-->    </filter-mapping>    <!--Login Servlet 配置-->    <servlet>        <servlet-name>login</servlet-name>        <servlet-class>com.hmc.servlet.LoginServlet</servlet-class>    </servlet>    <servlet-mapping>        <servlet-name>login</servlet-name>        <url-pattern>/login.do</url-pattern>    </servlet-mapping>    <!--配置权限过滤器-->    <filter>        <filter-name>authFilter</filter-name>        <filter-class>com.hmc.filter.AuthFilter</filter-class>    </filter>    <filter-mapping>        <filter-name>authFilter</filter-name>        <url-pattern>/admin/*</url-pattern>    </filter-mapping>    <!--配置字符编码过滤器-->    <filter>        <filter-name>encoding</filter-name>        <filter-class>com.hmc.filter.EncodingFilter</filter-class>        <!--配置初始化参数encoding-->        <init-param>            <param-name>encoding</param-name>            <param-value></param-value>        </init-param>    </filter>    <filter-mapping>        <filter-name>encoding</filter-name>        <url-pattern>/*</url-pattern><!--字符编码,当然要对所有请求处理啦-->    </filter-mapping></web-app>

以上总共有有3个过滤器:形成了一个过滤器链;这么多过滤器,那么执行顺序呢?所以,过滤器链按找注册先后顺序执行,也就是配置位置的先后顺序。
所以,字符编码应该放在权限配置之前奥。

Ok!睡个午觉吧。

原创粉丝点击