JavaWeb-过滤器Filter学习(五)全站压缩

简介: 全站压缩,最大的好久就是帮客户端节省流量。 数据压缩,我们需要用到二个Java类,也就是java.util.zip 中的 类 GZIPOutputStream 此类为使用 GZIP 文件格式写入压缩数据实现流过滤器。

全站压缩,最大的好久就是帮客户端节省流量。
数据压缩,我们需要用到二个Java类,也就是java.util.zip 中的
类 GZIPOutputStream
此类为使用 GZIP 文件格式写入压缩数据实现流过滤器。

java.io
类 ByteArrayOutputStream
此类实现了一个输出流,其中的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。可使用 toByteArray() 和 toString() 获取数据。

我们利用GZIPOutputStream(OutputStream out) 使用默认缓冲区大小创建新的输出流。
再用write(byte[] b)将 b.length 个字节写入此输出流。
也就是把数据压缩后写入ByteArrayOutputStream。

然后通过内存流输出到客户端。

简单演示:

也就是在一个servlet这样写:

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

        response.setContentType("text/html;charset=utf-8");

        String str = "网页压缩数据hncuhdncu网页压缩数据hncuh数据hncuhdncu网页压缩数据hncuh数据hncuhdncu网页压缩数据hncuhdncu网页压缩数据hncuhdncu";

        System.out.println("原大小:" + str.getBytes("utf-8").length);

        // 压缩输出--把源数据压缩输出到baout内存流中
        ByteArrayOutputStream baout = new ByteArrayOutputStream();

        GZIPOutputStream gout = new GZIPOutputStream(baout);
        gout.write(str.getBytes("utf-8"));
        gout.close();

        // 从baout内存流中把压缩后的数据取出来,输出到客户端
        byte dest[] = baout.toByteArray();
        System.out.println("压缩后的大小:" + dest.length);

        //输出之前告诉客户端:我们的数据是gzip格式,然后输出
        response.setHeader("Content-Encoding", "gzip");
        response.setContentLength(dest.length);
        OutputStream out = response.getOutputStream();
        out.write(dest);
        out.close();
    }

这样可以实现压缩,但是每次我们有一个servlet就要写一大长串的代码,很臃肿,也很麻烦,毕竟代码是一样的。而且还无法压缩jsp和html字符文件。

这个时候,我们就需要用到过滤器了。只要拦截所有的servlet和jsp/html就ok。只要写一次!很方便。

全站压缩实例:

index.jsp:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>过滤器应用示例---全站压缩</title>
  </head>

  <body>
    <h2>过滤器应用示例---全站压缩</h2>
    <a href="<c:url value='/servlet/SecondServlet'/>">请求第二个servlet--用过滤器压缩输出字节流数据</a><br/><br/>
    <a href="<c:url value='/servlet/ThirdServlet'/>">请求第三个servlet--用过滤器压缩输出字符流数据</a><br/><br/>
  </body>
</html>

SecondServlet.java

package cn.hncu.servlets;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;

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

public class SecondServlet 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 {

        response.setContentType("text/html;charset=utf-8");
        String str = "网页压缩数据hncuhdncu网页压缩数据hncuh数据hncuhdncu网页压缩数据hncuh数据hncuhdncu网页压缩数据hncuhdncu网页压缩数据hncuhdncu";
        System.out.println("原大小:" + str.getBytes("utf-8").length);

        OutputStream out = response.getOutputStream();
        out.write(str.getBytes("utf-8"));
        //注意,虽然MyEclipse环境设置的是utf-8编码,但本句“str.getBytes()”却是以gbk方式编码---应该是Tomcat中的JVM采用的方式
    }
}

ThirdServlet.java

package cn.hncu.servlets;

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;

public class ThirdServlet 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 {

        response.setContentType("text/html;charset=utf-8");
        String str="网页压缩数据hncuhdncu网页压缩数据hncuh数据hncuhdncu网页压缩数据hncuh数据hncuhdncu网页压缩数据hncuhdncu网页压缩数据hncuhdncu";
        System.out.println("原大小:"+ str.getBytes("utf-8").length);

        PrintWriter out = response.getWriter();
        //out.write(str);
        out.println(str);
        out.close();
    }

}

GzipFilter.java

package cn.hncu.filter;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.zip.GZIPOutputStream;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
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 {

        MyResponse resp = new MyResponse((HttpServletResponse) response);
        // 用增强版的resp放行到servlet中去用(让后台把数据 写到 baout中 )

        chain.doFilter(request, resp);// 放行--让后台去写

        // 从增强版的resp的baout中(存放的是源字节数据),把数据取出来进行压缩,
        // 然后再压缩后的数据用原生的response输出到客户端
        ByteArrayOutputStream baout = resp.getBaout();
        byte bs[] = baout.toByteArray();// 源字节数据
        System.out.println("压缩前大小:" + bs.length);

        ByteArrayOutputStream baout2 = new ByteArrayOutputStream();
        GZIPOutputStream gout = new GZIPOutputStream(baout2);
        gout.write(bs);// 把数据压缩到baout中
        gout.close();

        bs = baout2.toByteArray();
        System.out.println("压缩后大小:" + bs.length);
        // 输出之前告诉客户端:我们的数据是gzip格式,然后输出
        HttpServletResponse httpResp = (HttpServletResponse) response;
        httpResp.setHeader("Content-Encoding", "gzip");
        httpResp.setContentLength(bs.length);
        OutputStream out = httpResp.getOutputStream();
        out.write(bs);

    }

    @Override
    public void destroy() {
    }

}

class MyResponse extends HttpServletResponseWrapper {
    private ByteArrayOutputStream baout = new ByteArrayOutputStream();

    public MyResponse(HttpServletResponse response) {
        super(response);
    }

    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        return new MyOutputStream(baout);
    }

    public ByteArrayOutputStream getBaout() {
        if(pw!=null){
            pw.flush();
            //这里很重要,如果不flush或close,不把字符流刷出去,baout中是不会有数据的.
        }
        return baout;
    }

    private PrintWriter pw;
    @Override
    public PrintWriter getWriter() throws IOException {
        pw = new PrintWriter(new OutputStreamWriter(baout, "utf-8"),true);
        return pw;
    }

}

class MyOutputStream extends ServletOutputStream {
    private ByteArrayOutputStream baout = null;

    public MyOutputStream(ByteArrayOutputStream baout) {
        this.baout = baout;
    }

    @Override
    public void write(int b) throws IOException {
        baout.write(b);
    }
}

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
  <display-name></display-name>

  <filter>
    <filter-name>gzip</filter-name>
    <filter-class>cn.hncu.filter.GzipFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>gzip</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

  <servlet>
    <servlet-name>FirstGzipServlet</servlet-name>
    <servlet-class>cn.hncu.servlets.FirstGzipServlet</servlet-class>
  </servlet>
  <servlet>
    <servlet-name>SecondServlet</servlet-name>
    <servlet-class>cn.hncu.servlets.SecondServlet</servlet-class>
  </servlet>
  <servlet>
    <servlet-name>ThirdServlet</servlet-name>
    <servlet-class>cn.hncu.servlets.ThirdServlet</servlet-class>
  </servlet>



  <servlet-mapping>
    <servlet-name>FirstGzipServlet</servlet-name>
    <url-pattern>/FirstGzipServlet</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>SecondServlet</servlet-name>
    <url-pattern>/servlet/SecondServlet</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>ThirdServlet</servlet-name>
    <url-pattern>/servlet/ThirdServlet</url-pattern>
  </servlet-mapping>    
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

用过滤器来做全站压缩,无论你怎么增加servlet,jsp,html,还是照原来的写,不用你增加代码,我们只要在过滤器中对你的数据进行压缩发送到前台去就可以了!!!

注意,过滤器中用了装饰模式。

完整项目源码:

https://github.com/chenhaoxiang/Java/tree/master/myGzipWeb

myGzipWeb.zip

转载请附上原文博客链接:

http://blog.csdn.net/qq_26525215

目录
相关文章
|
4天前
|
Java 调度 开发者
Java线程池ExecutorService学习和使用
通过学习和使用Java中的 `ExecutorService`,可以显著提升并发编程的效率和代码的可维护性。合理配置线程池参数,结合实际应用场景,可以实现高效、可靠的并发处理。希望本文提供的示例和思路能够帮助开发者深入理解并应用 `ExecutorService`,实现更高效的并发程序。
28 10
|
6天前
|
Java 数据库连接 数据库
【潜意识Java】深度分析黑马项目《苍穹外卖》在Java学习中的重要性
《苍穹外卖》项目对Java学习至关重要。它涵盖了用户管理、商品查询、订单处理等模块,涉及Spring Boot、MyBatis、Redis等技术栈。
32 4
|
6天前
|
前端开发 Java 数据库连接
【潜意识Java】深度解读JavaWeb开发在Java学习中的重要性
深度解读JavaWeb开发在Java学习中的重要性
23 4
|
6天前
|
存储 移动开发 算法
【潜意识Java】Java基础教程:从零开始的学习之旅
本文介绍了 Java 编程语言的基础知识,涵盖从简介、程序结构到面向对象编程的核心概念。首先,Java 是一种高级、跨平台的面向对象语言,支持“一次编写,到处运行”。接着,文章详细讲解了 Java 程序的基本结构,包括包声明、导入语句、类声明和 main 方法。随后,深入探讨了基础语法,如数据类型、变量、控制结构、方法和数组。此外,还介绍了面向对象编程的关键概念,例如类与对象、继承和多态。最后,针对常见的编程错误提供了调试技巧,并总结了学习 Java 的重要性和方法。适合初学者逐步掌握 Java 编程。
23 1
|
2月前
|
Java 大数据 API
14天Java基础学习——第1天:Java入门和环境搭建
本文介绍了Java的基础知识,包括Java的简介、历史和应用领域。详细讲解了如何安装JDK并配置环境变量,以及如何使用IntelliJ IDEA创建和运行Java项目。通过示例代码“HelloWorld.java”,展示了从编写到运行的全过程。适合初学者快速入门Java编程。
|
2月前
|
监控 Java 数据管理
java会话跟踪和拦截器过滤器
本文介绍了Web开发中的会话跟踪技术——Cookie与Session,以及过滤器(Filter)和监听器(Listener)的概念和应用。Cookie通过在客户端记录信息来识别用户,而Session则在服务器端保存用户状态。过滤器用于拦截和处理请求及响应,监听器则监控域对象的状态变化。文章详细解释了这些技术的实现方式、应用场景和主要方法,帮助开发者更好地理解和使用这些工具。
53 1
|
2月前
|
JavaScript Java 项目管理
Java毕设学习 基于SpringBoot + Vue 的医院管理系统 持续给大家寻找Java毕设学习项目(附源码)
基于SpringBoot + Vue的医院管理系统,涵盖医院、患者、挂号、药物、检查、病床、排班管理和数据分析等功能。开发工具为IDEA和HBuilder X,环境需配置jdk8、Node.js14、MySQL8。文末提供源码下载链接。
|
消息中间件 前端开发 JavaScript
如何用Java实现文件压缩和解压缩?
PS:最近是跳槽的高峰期,我连日加班好多天,整理出了包含16000 多道面试题的面试宝典,并且指北君也会持续更新这份面试宝典中的题目,希望它能帮助大家找到自己心仪的工作!【文末有领取方式】
如何用Java实现文件压缩和解压缩?
|
21天前
|
监控 Java
java异步判断线程池所有任务是否执行完
通过上述步骤,您可以在Java中实现异步判断线程池所有任务是否执行完毕。这种方法使用了 `CompletionService`来监控任务的完成情况,并通过一个独立线程异步检查所有任务的执行状态。这种设计不仅简洁高效,还能确保在大量任务处理时程序的稳定性和可维护性。希望本文能为您的开发工作提供实用的指导和帮助。
82 17
|
1月前
|
Java
Java—多线程实现生产消费者
本文介绍了多线程实现生产消费者模式的三个版本。Version1包含四个类:`Producer`(生产者)、`Consumer`(消费者)、`Resource`(公共资源)和`TestMain`(测试类)。通过`synchronized`和`wait/notify`机制控制线程同步,但存在多个生产者或消费者时可能出现多次生产和消费的问题。 Version2将`if`改为`while`,解决了多次生产和消费的问题,但仍可能因`notify()`随机唤醒线程而导致死锁。因此,引入了`notifyAll()`来唤醒所有等待线程,但这会带来性能问题。
Java—多线程实现生产消费者