JavaWeb 后端 <十二> 之 过滤器 filter 乱码、不缓存、脏话、标记、自动登录、全站压缩过滤器

简介:

一、过滤器是什么?有什么?

1、过滤器属于Servlet规范,从2.3版本就开始有了。

2、过滤器就是对访问的内容进行筛选(拦截)。利用过滤器对请求和响应进行过滤

二、编写步骤和执行过程

1、编码步骤:

a、编写一个类:实现javax.servlet.Filter接口


public class FilterDemo1 implements Filter {
     
    public FilterDemo1(){
        System.out.println("调用了默认的构造方法");
    }
     
    //用户每次访问被过滤的资源,都会由服务器调用该方法实现过滤
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        System.out.println("FilterDemo1执行过滤前");
        //对请求进行拦截,代码写在这
        chain.doFilter(request, response);//放行
        //对响应进行拦截,代码写在这
        System.out.println("FilterDemo1执行过滤后");
    }
 
    public void destroy() {
        System.out.println("调用了销毁方法");
    }
 
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("调用初始化方法");
    }
 
}

 b、配置web.xml,指定需要过滤的资源。(和Servlet的配置相当类似)

2、过滤器的执行过程(生命周期)

生命周期:

诞生:过滤器的实例是在应用被加载时就完成的实例化,并初始化的。

存活:和应用的生命周期一致的。在内存中是单例的。针对拦截范围内的资源访问,每次访问都会调用void doFIlter(request,response.chain)进行拦截。

死亡:应用被卸载。

 

三、串联过滤器

一个过滤器接着另外一个过滤器。执行的顺序  按照web.xml的先后顺序

随意 访问  会先直接FilterDemo2 的 再执行 FilterDemo3的

会输出 :

FilterDemo2前

FilterDemo3前

执行内容

FilterDemo3后

FilterDemo2后

四、案例:

1、解决请求参数(POST)和响应输出的乱码过滤器


//解决post方式请求参数和响应编码问题的过滤器
public class SetCharacterEncodingFilter implements Filter {
    private FilterConfig filterConfig;
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
    }
 
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
         
        String encoding = filterConfig.getInitParameter("encoding");//用户可能忘记了配置该参数
        if(encoding==null){
            encoding = "UTF-8";//默认编码
        }
         
        request.setCharacterEncoding(encoding);//只能解决POST请求参数的中文问题
        response.setCharacterEncoding(encoding);//输出流编码
        response.setContentType("text/html;charset="+encoding);//输出流编码,通知了客户端应该使用的编码
        chain.doFilter(request, response);
    }
 
    public void destroy() {
 
    }
 
}

将 编码类型写在 Filter参数中

 

 

2、动态资源不要缓存的过滤器

Servlet/JSP:动态资源不要缓存。

 

这里 将 Servletrequest 和 ServletResponse 转换为 HttpServlet 的方法 避免发生错误


HttpServletRequest request = null;
HttpServletResponse response = null;
try{
  request  = (HttpServletRequest)req;
  response = (HttpServletResponse)resp;<br>}catch(Exception e){
  throw new RuntimeException("not-http request or response");
}

//控制动态资源不要缓存过滤器
public class NoCacheFilter implements Filter {
 
    public void init(FilterConfig filterConfig) throws ServletException {
 
    }
 
    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {
         
//      HttpServletRequest request = (HttpServletRequest)req;
//      HttpServletResponse response = (HttpServletResponse)resp;   不使用该方法
         
        HttpServletRequest request = null;
        HttpServletResponse response = null;
        try{
            request  = (HttpServletRequest)req;
            response = (HttpServletResponse)resp;
        }catch(Exception e){
            throw new RuntimeException("not-http request or response");
        }
        response.setHeader("Expires", "-1");
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Pragma", "no-cache");
        chain.doFilter(request, response);
    }
 
    public void destroy() {
 
    }
 
}

动态过滤掉 Servlet 和Jsp

3、静态资源控制缓存时间的过滤器


//控制静态资源的缓存时间
public class StaticResourcesNeedCacheFilter implements Filter {
    private FilterConfig filterConfig;
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
    }
 
    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = null;
        HttpServletResponse response = null;
        try{
            request  = (HttpServletRequest)req;
            response = (HttpServletResponse)resp;
        }catch(Exception e){
            throw new RuntimeException("not-http request or response");
        }
        long time = 0;//缓存的时间
         
        //根据用户请求的uri地址的后缀:/day19_00_filter/1.html
        String uri  = request.getRequestURI();
        String exName = uri.substring(uri.lastIndexOf(".")+1);
        if("html".equals(exName)){
            String value = filterConfig.getInitParameter("html");//小时
            time = Long.parseLong(value)*60*60*1000;
        }
        if("css".equals(exName)){
            String value = filterConfig.getInitParameter("css");//小时
            time = Long.parseLong(value)*60*60*1000;
        }
        if("js".equals(exName)){
            String value = filterConfig.getInitParameter("js");//小时
            time = Long.parseLong(value)*60*60*1000;
        }
         
        response.setDateHeader("Expires", System.currentTimeMillis()+time);  //Expires 控制时间
        chain.doFilter(request, response);
    }
 
    public void destroy() {
 
    }
 
}

 

4、//*用户自动登录过滤器:

使用了Md5 加密

Base64编码:很重要

编写


//自动登录过滤器
public class AutoLoginFilter implements Filter {
    private  BusinessService s = new BusinessServiceImpl();
    public void init(FilterConfig filterConfig) throws ServletException {
 
    }
 
    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {
         
        HttpServletRequest request = null;
        HttpServletResponse response = null;
        try{
            request  = (HttpServletRequest)req;
            response = (HttpServletResponse)resp;
        }catch(Exception e){
            throw new RuntimeException("not-http request or response");
        }
        HttpSession session = request.getSession();
        //判断用户有没有登录:只管没有登录的
        User sUser = (User)session.getAttribute("user");
        if(sUser==null){
            //找loginInfo的cookie:只管找到的
            Cookie cs[] = request.getCookies();
            for(int i=0;cs!=null&&i<cs.length;i++){
                if("loginInfo".equals(cs[i].getName())){
                    //解出用户名(Base64)和密码(MD5)
                    String usernamePassword = cs[i].getValue();
                    String username = usernamePassword.split("_")[0];//base64编码后的
                    String password = usernamePassword.split("_")[1];//MD5加密后的
                    //调用Service再次验证正确性
                    User user = s.login(SecurityUtil.base64decode(username), password);
                    //通过:登录。在HttpSession中设置登录标记
                    if(user!=null){
                        session.setAttribute("user", user);
                    }
                }
            }
        }
        chain.doFilter(request, response);
    }
 
    public void destroy() {
 
    }
 
}

五、过滤器配置的细节

 

六、巩固装饰设计模式

一、装饰

1、编写一个类,实现与被包装类(数据库驱动对Connection的实现)相同的接口。(使这个类和数据库的驱动实现有着相同的行为)

2、定义一个变量,引用被包装类的实例。

3、定义构造方法,传入被包装类的实例。

4、对于要改写的方法,编写自己的代码即可。

5、对于不需要改写的方法,调用原有对象的对应方法。

二、装饰变体(BufferedReader本身就是包装类,对Reader的包装。LineNumberReader,对BufferedReader的包装,还是他的子类)

1、编写一个类,继承已经是包装类的类。

2、定义一个变量,引用被包装类的实例。

3、定义构造方法,传入被包装类的实例。

4、覆盖掉需要改写的方法

七、案例:

1、解决全站中文乱码过滤器

之前解决了 post 的乱码 问题 这里 添加 get的 解决问题

1.定义一个类 EncodingHttpServletRequest 继承 HttpServletRequestWrapper  前对 后 的 包装 得到自己想要的 方法

2.重写  HttpServletRequestWrapper 的 getParameter 方法 。

3.将get传入的值使用 该 super.getCharacterEncoding()的编码 方式返回

如果 使用 get方法 就可以 得到 应有的编码方式


public class SetCharacterEncodingFilter implements Filter {
    private FilterConfig filterConfig;
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
    }
 
    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {
         
        HttpServletRequest request;
        HttpServletResponse response;
        try{
            request = (HttpServletRequest)req;
            response = (HttpServletResponse)resp;
        }catch(Exception e){
            throw new RuntimeException("non-http request or response");
        }
         
        String encoding = filterConfig.getInitParameter("encoding");//用户可能忘记了配置该参数
        if(encoding==null){
            encoding = "UTF-8";//默认编码
        }
         
        request.setCharacterEncoding(encoding);//只能解决POST请求参数的中文问题
        response.setCharacterEncoding(encoding);//输出流编码
        response.setContentType("text/html;charset="+encoding);//输出流编码,通知了客户端应该使用的编码
         
        EncodingHttpServletRequest erequest = new EncodingHttpServletRequest(request);
         
        chain.doFilter(erequest, response);
    }
 
    public void destroy() {
 
    }
 
}
class EncodingHttpServletRequest extends HttpServletRequestWrapper{
    public EncodingHttpServletRequest(HttpServletRequest request){
        super(request);
    }
 
    public String getParameter(String name) {
        String value = super.getParameter(name);
        if(value==null)
            return value;
        //只管get方式
        if("get".equalsIgnoreCase(super.getMethod())){
            try {
                value = new String(value.getBytes("ISO-8859-1"),super.getCharacterEncoding());
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        return value;
    }
     
}

2、过滤脏话过滤器

1.新建 DWHttpServletRequest 类 继承  HttpServletRequestWrapper ,

2.包装 getParameter 发方法  过滤 脏话

3.执行 内容  时 得到的是  DWHttpServletRequest 的 request 所以使用的方法是 DWHttpServletRequest的 getParameter。


public class DirtyWordsFilter implements Filter {
 
    public void init(FilterConfig filterConfig) throws ServletException {
    }
 
    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {
         
        HttpServletRequest request;
        HttpServletResponse response;
        try{
            request = (HttpServletRequest)req;
            response = (HttpServletResponse)resp;
        }catch(Exception e){
            throw new RuntimeException("non-http request or response");
        }
        DWHttpServletRequest dwrequest = new DWHttpServletRequest(request);
        chain.doFilter(dwrequest, response);
 
    }
 
    public void destroy() {
    }
 
}
class DWHttpServletRequest extends HttpServletRequestWrapper{
    private String[] strs = {"禽兽","畜生","傻B","张新鹏"};
    public DWHttpServletRequest(HttpServletRequest request){
        super(request);
    }
 
    public String getParameter(String name) {
        String value = super.getParameter(name);
        if(value==null)
            return value;
         
        for(String s:strs){
            value = value.replace(s, "**");
        }
        return value;
    }
}

3、html标记过滤器

方法和前2种类似


public class HtmlFilter implements Filter {
 
    public void init(FilterConfig filterConfig) throws ServletException {
    }
 
    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {
         
        HttpServletRequest request;
        HttpServletResponse response;
        try{
            request = (HttpServletRequest)req;
            response = (HttpServletResponse)resp;
        }catch(Exception e){
            throw new RuntimeException("non-http request or response");
        }
        HtmlHttpServletRequest hrequest = new HtmlHttpServletRequest(request);
        chain.doFilter(hrequest, response);
 
    }
 
    public void destroy() {
    }
 
}
class HtmlHttpServletRequest extends HttpServletRequestWrapper{
    public HtmlHttpServletRequest(HttpServletRequest request){
        super(request);
    }
 
    public String getParameter(String name) {
        String value = super.getParameter(name);
        if(value==null)
            return value;
         
        value = htmlFilter(value);//转义字符
        return value;
    }
 
    private String htmlFilter(String message) {
        if (message == null)
            return (null);
 
        char content[] = new char[message.length()];
        message.getChars(0, message.length(), content, 0);
        StringBuffer result = new StringBuffer(content.length + 50);
        for (int i = 0; i < content.length; i++) {
            switch (content[i]) {
            case '<':
                result.append("<");
                break;
            case '>':
                result.append(">");
                break;
            case '&':
                result.append("&");
                break;
            case '"':
                result.append(""");
                break;
            default:
                result.append(content[i]);
            }
        }
        return (result.toString());
    }
}

4、//*全站压缩过滤器(有难度)


public class GzipFilter implements Filter {
 
    public void init(FilterConfig filterConfig) throws ServletException {
 
    }
 
    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request;
        HttpServletResponse response;
        try{
            request = (HttpServletRequest)req;
            response = (HttpServletResponse)resp;
        }catch(Exception e){
            throw new RuntimeException("non-http request or response");
        }
        GzipHttpServletResponse gresponse = new GzipHttpServletResponse(response);
        chain.doFilter(request, gresponse);
        //目标资源执行完毕后执行:要压缩
        byte b[] = gresponse.getBytes();//得到原始的数据为编码的关键点
        System.out.println("压缩前大小:"+b.length);
        //判断客户是否支持gzip压缩
        String acceptEncoding = request.getHeader("Accept-Encoding");
        if(acceptEncoding!=null&&acceptEncoding.contains("gzip")){
            //支持
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            GZIPOutputStream gout = new GZIPOutputStream(out);
            gout.write(b);
            gout.close();
             
            b = out.toByteArray();//压缩后的数据
            System.out.println("压缩后大小:"+b.length);
            //告知浏览器压缩方式
            response.setHeader("Content-Encoding", "gzip");
            response.setContentLength(b.length);//告知客户端,正文的长度
        }
        response.getOutputStream().write(b);
    }
 
    public void destroy() {
 
    }
 
}
class GzipHttpServletResponse extends HttpServletResponseWrapper{
    private ByteArrayOutputStream baos = new ByteArrayOutputStream();//存放截获的数据
     
    private PrintWriter pw = null;
    public GzipHttpServletResponse(HttpServletResponse response){
        super(response);
    }
    //截获输出的数据:放到baos中
    public ServletOutputStream getOutputStream() throws IOException {
        return new MyServletOutputStream(baos);
    }
     
    //字符流:截获放到baos中
    public PrintWriter getWriter() throws IOException {
        pw = new PrintWriter(new OutputStreamWriter(baos, super.getCharacterEncoding()));
        return pw;
    }
    //获取截获的数据
    public byte[] getBytes(){
        try {
            if(pw!=null){
                pw.close();
            }
            baos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return baos.toByteArray();
    }
}
class MyServletOutputStream extends ServletOutputStream{
    private ByteArrayOutputStream baos;
    public MyServletOutputStream(ByteArrayOutputStream baos){
        this.baos = baos;
    }
    public void write(int b) throws IOException {
        baos.write(b);
    }
     
}

 
目录
相关文章
|
22天前
|
存储 缓存 监控
后端开发中的缓存机制:深度解析与最佳实践####
本文深入探讨了后端开发中不可或缺的一环——缓存机制,旨在为读者提供一份详尽的指南,涵盖缓存的基本原理、常见类型(如内存缓存、磁盘缓存、分布式缓存等)、主流技术选型(Redis、Memcached、Ehcache等),以及在实际项目中如何根据业务需求设计并实施高效的缓存策略。不同于常规摘要的概述性质,本摘要直接点明文章将围绕“深度解析”与“最佳实践”两大核心展开,既适合初学者构建基础认知框架,也为有经验的开发者提供优化建议与实战技巧。 ####
|
3月前
|
缓存 JavaScript 中间件
优化Express.js应用程序性能:缓存策略、请求压缩和路由匹配
在开发Express.js应用时,采用合理的缓存策略、请求压缩及优化路由匹配可大幅提升性能。本文介绍如何利用`express.static`实现缓存、`compression`中间件压缩响应数据,并通过精确匹配、模块化路由及参数化路由提高路由处理效率,从而打造高效应用。
192 14
|
2月前
|
存储 缓存 NoSQL
深入理解后端缓存机制的重要性与实践
本文将探讨在后端开发中缓存机制的应用及其重要性。缓存,作为提高系统性能和用户体验的关键技术,对于后端开发来说至关重要。通过减少数据库访问次数和缩短响应时间,缓存可以显著提升应用程序的性能。本文将从缓存的基本概念入手,介绍常见的缓存策略和实现方式,并通过实例展示如何在后端开发中有效应用缓存技术。最后,我们将讨论缓存带来的一些挑战及其解决方案,帮助您在实际项目中更好地利用缓存机制。
|
3月前
|
机器学习/深度学习 缓存 NoSQL
深度学习在图像识别中的应用与挑战后端开发中的数据缓存策略
本文深入探讨了深度学习技术在图像识别领域的应用,包括卷积神经网络(CNN)的原理、常见模型如ResNet和VGG的介绍,以及这些模型在实际应用中的表现。同时,文章也讨论了数据增强、模型集成等改进性能的方法,并指出了当前面临的计算资源需求高、数据隐私等挑战。通过综合分析,本文旨在为深度学习在图像识别中的进一步研究和应用提供参考。 本文探讨了后端开发中数据缓存的重要性和实现方法,通过具体案例解析Redis在实际应用中的使用。首先介绍了缓存的基本概念及其在后端系统性能优化中的作用;接着详细讲解了Redis的常见数据类型和应用场景;最后通过一个实际项目展示了如何在Django框架中集成Redis,
|
4月前
|
缓存 网络协议 API
【API管理 APIM】APIM中对后端API服务的DNS域名缓存问题
【API管理 APIM】APIM中对后端API服务的DNS域名缓存问题
|
4月前
|
存储 缓存 JavaScript
深入理解后端开发中的缓存机制
【8月更文挑战第31天】本文将通过一个实际的后端开发案例,介绍如何有效地使用缓存来提高应用性能。我们将从基础概念开始,逐步深入到缓存策略的实施,最后通过代码示例展示如何在Node.js环境中实现一个简单的缓存系统。无论你是缓存新手还是希望优化现有系统的开发者,这篇文章都将为你提供实用的指导和启示。
|
5月前
|
存储 缓存 前端开发
(三)Nginx一网打尽:动静分离、压缩、缓存、黑白名单、跨域、高可用、性能优化...想要的这都有!
早期的业务都是基于单体节点部署,由于前期访问流量不大,因此单体结构也可满足需求,但随着业务增长,流量也越来越大,那么最终单台服务器受到的访问压力也会逐步增高。时间一长,单台服务器性能无法跟上业务增长,就会造成线上频繁宕机的现象发生,最终导致系统瘫痪无法继续处理用户的请求。
179 1
|
4月前
|
存储 缓存 关系型数据库
Django后端架构开发:缓存机制,接口缓存、文件缓存、数据库缓存与Memcached缓存
Django后端架构开发:缓存机制,接口缓存、文件缓存、数据库缓存与Memcached缓存
89 0
|
4月前
|
存储 缓存 数据库
Django后端架构开发:信号与缓存架构开发
Django后端架构开发:信号与缓存架构开发
77 0
|
4月前
|
缓存 NoSQL 算法
【Azure Redis 缓存】Redis导出数据文件变小 / 在新的Redis复原后数据大小压缩近一倍问题分析
【Azure Redis 缓存】Redis导出数据文件变小 / 在新的Redis复原后数据大小压缩近一倍问题分析
下一篇
DataWorks