JavaWeb-Filter

话说:
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!睡个午觉吧。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值