过滤器

过滤器

场景1: request.getParameter("参数名"); 遇到参数内容中文乱码问题,解决方法:
- post提交: request.setCharacterEncoding("utf-8");
- get提交: 手动解码 name = new String(name.getBytes("iso-8859-1"),"utf-8");

问题: 每个请求都需要servlet进行上面代码的填写,如何把这些重复的操作抽取出来呢?
  使用过滤器,将重复的操作代码写在过滤器中

场景2: 登录页面=>输入用户名或密码=>后台检查是否成功=>登录成功,看到用户首页
  (用户名:xxx)登录数据放在session域对象中,如果用户不登录,用户首页看不到:

//判断用户登录权限代码:
HttpSession session = request.getSession(false);
if(session == null){
    跳转到登陆页面
}else{
    String user = (String)sessin.getAttribute("user");
    if(user == null){
        跳转到登录页面
    }
}
//////////////////////////////////////////////////////
//用户资源修改页面(需要用户登录才能访问),同样需要上面的代码进行判断

问题: 如何把这些登录权限代码抽取出?
  使用过滤器,把这些登录权限代码写在过滤器中

过滤器简介

1)过滤器就是一个Filter接口,在javax.servlet.Filter
2)过滤器是servlet的三大组件之一.servlet的三大组件:
  (servlet)servlet接口:javax.servlet.Servlet;作用:用于开发动态网页
  (过滤器)Filter接口:javax.servlet.Filter;作用:
  (监听器)Listener接口:javax.servlet.*
servlet组件的特点:
- 把组件配置到web.xml文件中
- 组件就可以交给tomcat服务器运行

3)作用:
  过滤器的作用,就是一个实现了Filter接口的对象,这个对象可以在请求资源(可能是动态网页或者静态网页)时,或者在响应资源时,或者在请求和响应资源时,执行过滤任务.

过滤器图解

过滤器的生命周期

构造方法: 创建过滤器对象的时候调用,在加载当前项目时加载过滤器,只调用一次.单例的多线程.
init方法: 创建完过滤器对象后调用,只调用一次.
doFilter方法: 过滤任务方法.会调用n次,每次访问目标资源时被调用
destory方法: 在销毁过滤器对象的时候调用,在web项目重新部署或tomcat服务器停止的时候销毁过滤器对象.

映射配置

精确过滤: /xxx
模糊过滤: /* *.后缀名

FilterConfig对象

  和servletConfig对象类似,这个FilterConfig对象加载初始化参数内容

FilterChain

  过滤器链: 当一个资源被多个过滤器所过滤,那么就形成了一个过滤器链

下面通过代码进行说明以上的一些问题:

过滤器的编写

/*输出语句中的序号代表发生顺序*/
//需要执行的servlet,需要被过滤的servlet
import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class TargetServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        System.out.println("4执行了servlet");
        response.getWriter().write("6用户看到响应内容");
    }
}
//过滤器的编写
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 FirstFilter implements Filter {
    public FirstFilter() {
        System.out.println("1过滤器创建了");
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("2过滤器初始化");
        // filterConfig对象封装了所有的当前过滤器配置的初始化参数
        System.out.println(filterConfig.getInitParameter("AAA"));
        Enumeration<String> enums = filterConfig.getInitParameterNames();
        while (enums.hasMoreElements()) {
            String paramName = enums.nextElement();
            String paramValue = filterConfig.getInitParameter(paramName);
            System.out.println(paramName + "=" + paramValue);
        }
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        System.out.println("3过滤器正在执行过滤任务");
        // 放行
        chain.doFilter(request, response);
        System.out.println("5过滤器正在执行任务--过滤响应");
    }

    // 过滤器对象销毁的时候才会调用;web项目重新部署或者tomcat服务器停止了才会销毁过滤器对象
    @Override
    public void destroy() {
        System.out.println("过滤器被销毁了");
    }
}
//web.xml的部分内容
<!-- 配置一个过滤器 -->
<!-- 过滤器配置 -->
<filter>
    <filter-name>FirstFilter</filter-name>
    <filter-class>cn.itcast.filter.FirstFilter</filter-class>
    <!-- 初始化参数 -->
    <init-param>
        <param-name>AAA</param-name>
        <param-value>AAA' value</param-value>
    </init-param>
    <init-param>
        <param-name>BBB</param-name>
        <param-value>BBB' value</param-value>
    </init-param>
</filter>
<!-- 过滤器映射配置 -->
<filter-mapping>
    <filter-name>FirstFilter</filter-name>
    <!-- 代表的是要过滤的路径,而不是访问过滤器的路径 -->
    <url-pattern>/target</url-pattern>
</filter-mapping> 
<servlet>
    <servlet-name>TargetServlet</servlet-name>
    <servlet-class>cn.itcast.filter.TargetServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>TargetServlet</servlet-name>
    <url-pattern>/target</url-pattern>
</servlet-mapping>

过滤器链

过滤器链

/*过滤器链的说明*/
//被过滤的servlet
import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class FirstServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doPost(request, response);
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        System.out.println("3执行目标资源代码");
    }
}
//两个过滤器的编写
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 FirstFilter implements Filter {

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

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        System.out.println("1执行第一个过滤器的请求过滤");
        // 放行
        // FilterChain就是过滤器对象,其中doFilter就是把请求或响应交给下一个过滤器,如果没有下一个,就访问目标资源或返回给用户显示
        // 过滤器链的过滤执行顺序由web.xml文件中过滤器的filter-mapping的顺序所决定的,先配置的先访问
        chain.doFilter(request, response);
        System.out.println("5执行第一个过滤器的响应过滤");
    }

    @Override
    public void destroy() {

    }
}

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 SecondFilter implements Filter {

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

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        System.out.println("2执行第二个过滤器的请求过滤");
        chain.doFilter(request, response);
        System.out.println("4执行第二个过滤器的响应过滤");
    }

    @Override
    public void destroy() {

    }
}
//web.xml部分内容
<filter>
    <filter-name>First</filter-name>
    <filter-class>cn.itcast.chain.FirstFilter</filter-class>
 </filter>
 <filter-mapping>
    <filter-name>First</filter-name>
    <url-pattern>/First</url-pattern>
 </filter-mapping>


 <filter>
    <filter-name>Second</filter-name>
    <filter-class>cn.itcast.chain.SecondFilter</filter-class>
 </filter>
 <filter-mapping>
    <filter-name>Second</filter-name>
    <url-pattern>/First</url-pattern>
 </filter-mapping>
 <servlet>
    <servlet-name>FirstServlet</servlet-name>
    <servlet-class>cn.itcast.chain.FirstServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>FirstServlet</servlet-name>
    <url-pattern>/First</url-pattern>
</servlet-mapping>

post get乱码的解决方案

//参数中文乱码的过滤器
import java.io.IOException;
import java.io.UnsupportedEncodingException;

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.HttpServletRequestWrapper;

public class EncodingFilter implements Filter {

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

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {
        // 强制转换
        HttpServletRequest request = (HttpServletRequest) req;
        // post提交参数乱码解决方案
        request.setCharacterEncoding("utf-8");
        // 创建一个HttpServletRequest实现类的装饰者类,重写getParameter方法
        MyHttpRequest myRequest = new MyHttpRequest(request);
        // 放行,这里放行的应该是我们装饰后的对象
        chain.doFilter(myRequest, resp);
    }

    @Override
    public void destroy() {

    }
}

// 装饰者类
class MyHttpRequest extends HttpServletRequestWrapper {
    private HttpServletRequest request;// 多态

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

    @Override
    public String getParameter(String name) {
        // 对get提交参数乱码处理
        // 1得到原来的参数
        String value = request.getParameter(name);// iso-8859-1
        // 2手动解码
        if ("GET".equals(request.getMethod())) {
            try {
                value = new String(value.getBytes("iso-8859-1"), "utf-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }
        return value;
    }
}
//web.xml的配置信息这里省略

压缩网页内容的过滤器解决方案

用户浏览一个网页: 服务器=>发送一个网页的内容给用户(1k)
一个用户一天访问10页,服务器输出10kb内容
网站1天10万用户:
100 000 * 10kb = 1 000 000kb = 1GB 消耗网络带宽
要求:在不影响用户浏览效果前提下,减少服务器输出的数据.用到压缩网页的技术,gzip压缩技术
gzip技术

//需要被拦截的servlet
import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ContentServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doPost(request, response);
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 2
        // 准备内容
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i <= 3000; i++) {
            sb.append("abcd");
        }

        /*
         * 思路: response对象的getWriter()方法得到的是一个没有缓冲功能的PrintWriter(),
         * 直接调用write()方法,就是直接把内容输出到浏览器显示
         * 如果我们通过改造response对象的getWriter()方法,从而得到一个带有缓冲功能的PrintWriter()对象,
         * 那么write写出的网页内容就是写到缓冲区中,我们就可以从PrintWriter的缓冲区中得到网页内容
         */
        /* 每次写出的网页内容都是已经经过gzip压缩的内容 */
        response.getWriter().write(sb.toString());
    }
}
//编写的带有网页压缩技术的过滤器,这里也有一个装饰者模式,用来增强getWriter方法
import java.io.ByteArrayOutputStream;
import java.io.CharArrayWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.zip.GZIPOutputStream;

//集中对网页内容进行gzip压缩
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.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

public class GZIPFilter implements Filter {

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

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        // 1过滤请求
        // 创建一个response的装饰者对象
        MyHttpResponse myResponse = new MyHttpResponse(
                (HttpServletResponse) response);

        // 放行
        chain.doFilter(request, myResponse);

        // 3过滤响应
        // 得到压缩前的内容;然而response中没有方法获取实体内容
        // 从缓存容器对象得到压缩前的内容
        char[] content = myResponse.getCharArray();
        // gzip压缩
        // 创建一个临时缓存容器
        ByteArrayOutputStream buf = new ByteArrayOutputStream();
        // 创建对象
        GZIPOutputStream gzip = new GZIPOutputStream(buf);
        // 进行压缩
        gzip.write(new String(content).getBytes());
        // 调用结束方法,把缓存内容刷新
        gzip.finish();
        // 得到压缩后的内容
        byte[] result = buf.toByteArray();
        /* 现在的内容已经是经过gzip算法压缩,必须要告诉浏览器目前输出的内容是gzip压缩格式的内容 */
        // 告诉浏览器发送内容的压缩格式
        myResponse.setHeader("content-encoding", "gzip");
        // 输出
        response.getOutputStream().write(result);
    }

    @Override
    public void destroy() {

    }
}

/**
 * HttpServletResponse的装饰者模式
 */
class MyHttpResponse extends HttpServletResponseWrapper {
    private HttpServletResponse response;

    // 定义一个缓冲容器对象
    private CharArrayWriter charArray = new CharArrayWriter();

    // 提供一个获取charArray内容的方法(包含网页内容)
    public char[] getCharArray() {
        return charArray.toCharArray();
    }

    public MyHttpResponse(HttpServletResponse response) {
        super(response);
        this.response = response;
    }

    // 重写getWriter()方法,让其返回一个带缓存功能的PrintWriter
    @Override
    public PrintWriter getWriter() throws IOException {
        return new PrintWriter(charArray);
    }
}
//web.xml省略

登录权限的过滤问题

login.jsp登录界面省略
LoginServlet登录判断的代码

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class LoginServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doPost(request, response);
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String name = request.getParameter("userName");
        String pwd = request.getParameter("userPwd");
        if ("james".equals(name) && "12345".equals(pwd)) {
            HttpSession session = request.getSession(true);
            session.setAttribute("user", name);
            response.sendRedirect(request.getContextPath()
                    + "/user/indexuser.jsp");//欢迎界面
        } else {
            request.setAttribute("msg", "用户名或密码错误");
            request.getRequestDispatcher("/login.jsp").forward(request,
                    response);//
        }
    }
}

SecurityFilter登录权限过滤器

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;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class SecurityFilter implements Filter {

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

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {
        // 强制转换
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;

        // 是否登录判断逻辑
        // 先判断有无session对象存在
        HttpSession session = request.getSession(true);
        if (session == null) {
            // 没有登录
            response.sendRedirect(request.getContextPath() + "/noAuth.jsp");
            return;
        } else {
            String user = (String) session.getAttribute("user");
            if (user == null) {
                // 没有登录成功
                response.sendRedirect(request.getContextPath() + "/noAuth.jsp");
                return;
            }
        }
        // 如果已经登录成功了,则放行
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {

    }
}

web.xml的部分编写

<filter>
    <filter-name>SecurityFilter</filter-name>
    <filter-class>cn.itcast.cases.SecurityFilter</filter-class>
 </filter>
 <filter-mapping>
    <filter-name>SecurityFilter</filter-name>
    <!-- user文件夹下的都是和登录之后相关的页面,这里不需要将login.jsp和servlet放在过滤器拦截路径里 -->
    <url-pattern>/user/*</url-pattern>
 </filter-mapping>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值