Web---Filter---运用:敏感词过滤 、全站压缩

首先了解一下装饰模式

 

对一个类的增强,一般采取三种式

  • 继承被增强的类,即实现一个子类。
  • 使用动态代理处理需要增强的方法。
  • 使用包装设计模式。(Java中的IO基本上都是包装设计模式)

以下是使用包装设计模式增强一个类的步骤:

  1. 继承需要增强的类。
  2. 声明需要增强有的类为自己的成员变量。
  3. 书写一个构造方法接收需要增强的类。
  4. 实现需要增强的方法。
  5. 实现可扩展的其他方法。

包装(装饰)设计模式是指:

假定A类是B类的包装类,那么类A与类B有同样的接口,并且类A拥有类B的的实例,类A借助类B的实例来实现接口。

学习导航

运用三:敏感词汇过滤

运用场景:在论坛网址中,过虑非法语句,如脏话,和非法词组。

解决方案:在过虑器中。包装httpServletRequest类,修改getParameter方法。即可

过滤器

用户进行评论时,需要把数据提交给后台Servlet进行处理,这时还没到达Servlet时就把请求拦截,并且更换成MyRequest,然后采用敏感词汇替换工具进行敏感词汇替换。

package cn.hncu.filter;

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

import cn.hncu.pub.WordsUtils;

public class WordsFilter implements Filter {


	public void destroy() {
	}

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		//这里采用装饰模式,把HttpServletRequest改装成 MyRequest,然后用MyRequest进行方行
		MyRequest myRequest = new MyRequest((HttpServletRequest) request);
		chain.doFilter(myRequest, response); //放行
	}

	public void init(FilterConfig fConfig) throws ServletException {
	}

}
class MyRequest extends HttpServletRequestWrapper{

	public MyRequest(HttpServletRequest request) {
		super(request);
	}
	
	//改装 getParameter()方法,按理应该把重载的函数都改装了,这里就意思一下
	@Override 
	public String getParameter(String name) {
		String src = super.getParameter(name);
		//调用敏感词汇过滤工具进行过滤
		String dest = WordsUtils.wordsFilter(src);
		return dest;
	}
}

敏感词汇替换工具

从数据库中把敏感词汇加载出来,然后把用户评论中的敏感词汇进行替换。

package cn.hncu.pub;

import java.util.ArrayList;
import java.util.List;

/**
 *   处理敏感词的工具
 * <br/><br/><b>CreateTime:</b><br/>&emsp;&emsp;&emsp; 2018年9月26日 下午12:25:11	
 * @author 宋进宇&emsp;<a href='mailto:447441478@qq.com'>447441478@qq.com</a>
 */
public class WordsUtils {
	private static List<String> list;
	static {
		//按理这里应该是从数据库读取出所有敏感词汇,这里就模拟了
		list = new ArrayList<String>();
		list.add("SB");
		list.add("骂人");
		list.add("大大");
	}
	//对外关闭构造函数
	private WordsUtils() {
	}
	/**
	 * 获取敏感词汇集
	 * @return
	 */
	public static List<String> getWords(){
		return list;
	}
	/**
	 * 重新加载敏感词汇库
	 */
	public static void rebuild() {
		//按理这里应该访问service-->dao-->数据库,读取数据,这里模拟了
		System.out.println("敏感词汇加载完毕.");
	}
	/**
	 * 把敏感词汇进行过滤
	 * @param src 原数据
	 * @return 过滤过的数据
	 */
	public static String wordsFilter(String src) {
		for (String word : list) {
			src = src.replaceAll(word, "<font color='gray'>[和谐]</font>");
		}
		return src;
	}
	
}

完整代码链接

运用四:全站压缩

运用场景:现在的网络,流量就是钱。所以,如果能在很少的流量的情况下,查看相同的数据内容,那何乐而不为呢?

实现方案:

    •用户在调用response.getOutputStream()时让获取自己的输出流对像, 我们将信息写到事先准备好的缓存当中。

    •当用户书写完毕,我们再调用自己提供的方法,获取缓存中的数据流

    •然后接着对数据进行压缩,在过虑器中,将信息返回给用户,从而实现数据的压缩。

    •那么如何用户调用response.getWriter进行输出时,我们怎么办呢?

    •能不能也对jsp所有输出进行压缩呢?

    •可以处理中文乱码问题吗?

话不多说上代码

流压缩见Web---http协议---常用的参数文章

过程图解

压缩字节流

其实就是把原来的response改成包装类,并且把response.getOutputStream()获得流对象也改成包装类,这样在Servlet中进行字节流输出时,其实源数据输出的动向都是为我们所掌控。

package cn.hncu.filter;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
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.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

public class Gzip1Filter implements Filter{

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

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		//在这里需要把 response 换成MyResponse, response.getOutputStream 换成 MyOutputStream
		//这里我们知道 response 对象其实是 HttpServletResponse类对象,所有强转以便后面操作。
		HttpServletResponse resp = (HttpServletResponse) response;
		
		MyResponse myResponse = new MyResponse(resp);
		//放行参数的用myResponse
		chain.doFilter(request, myResponse); //放行
		//能到这里说明servlet 已经运行完 doGet/doPost 方法
		//这时候可以 通过 myResponse获取封装在它内部的 字节内存流对象,把原数据获取出来进行压缩
		 ByteArrayOutputStream baos = myResponse.getBaos();
		 byte[] src = baos.toByteArray();
		 
		 System.out.println( "压缩前长度:"+src.length );
		 
		 //下面开始进行字节数据压缩///
		 //1 创建一个字节内存流,用来存放压缩后的数据
		 ByteArrayOutputStream destBaos = new ByteArrayOutputStream();
		 //2 创建 GZIPOutputStream,并且把 创建的字节内存流传过去,接收压缩后的数据
		 GZIPOutputStream gzipOs = new GZIPOutputStream(destBaos);
		 //3 把 原字节数据写入 gzipOs 进行压缩
		 gzipOs.write(src);
		 //4 写完一定要刷缓存!!!!!!!!
		 gzipOs.close(); //gzipOs.flush(); //调close()内部自动刷缓存,而且还可以防止内存泄漏
		 //5 从存储 压缩完的数据的 destBaos中获取数据写给客户端
		 byte[] dest = destBaos.toByteArray();
		 System.out.println( "压缩后长度:"+dest.length );
		 //6 写给客户端前 一定要设置响应头 !!!  --- 注意 写给客户端时用的是:response对象
		 resp.setHeader("Content-Encoding", "gzip");
		 //7通过字节流输出给客户端.
		 resp.getOutputStream().write(dest);
	}

	@Override
	public void destroy() {
	}
	
	class MyResponse extends HttpServletResponseWrapper{
		//用来存储 servlet中 write时的原数据
		private ByteArrayOutputStream baos;
		public ByteArrayOutputStream getBaos() {
			return baos;
		}
		
		public MyResponse(HttpServletResponse response) {
			super(response);
			baos = new ByteArrayOutputStream();
		}
		
		//把原装的ServletOutputStream的类对象 改装成MyServletOutputStream类对象//
		@Override
		public ServletOutputStream getOutputStream() throws IOException {
			MyServletOutputStream myServletOutputStream = new MyServletOutputStream( super.getOutputStream(),baos);
			return myServletOutputStream;
		}
		//
	}
	class MyServletOutputStream extends ServletOutputStream{
		private ServletOutputStream sos;
		//用来存储 servlet中 write时的原数据
		private ByteArrayOutputStream baos;

		protected MyServletOutputStream(ServletOutputStream sos,ByteArrayOutputStream baos) {
			this.sos = sos;
			this.baos = baos;
		}

		@Override
		public boolean isReady() {
			return sos.isReady();
		}

		@Override
		public void setWriteListener(WriteListener arg0) {
			sos.setWriteListener(arg0);
		}
		
		//把write方法修改了
		@Override
		public void write(int b) throws IOException {
			baos.write(b);
		}
		///
		
	}
}

压缩字符流

同字节类似,但实现起来更简单,因为PrintWriter类可以封装一个字节流,正好可以 '字节内存输出流' 封装进去,这样servlet调用字符输出流的时候,其实是把数据输出到 '字节内存输出流' 中去,等servlet处理完后,把数据进行压缩再输出。

package cn.hncu.filter;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
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.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

public class Gzip2Filter implements Filter{

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

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		//在这里需要把 response 换成MyResponse, response.getOutputStream 换成 MyOutputStream
		//这里我们知道 response 对象其实是 HttpServletResponse类对象,所有强转以便后面操作。
		HttpServletResponse resp = (HttpServletResponse) response;
		
		MyResponse myResponse = new MyResponse(resp);
		//放行参数的用myResponse
		chain.doFilter(request, myResponse); //放行
		//能到这里说明servlet 已经运行完 doGet/doPost 方法
		//这时候可以 通过 myResponse获取封装在它内部的 字节内存流对象,把原数据获取出来进行压缩
		 ByteArrayOutputStream baos = myResponse.getBaos();
		 byte[] src = baos.toByteArray();
		 
		 System.out.println( "压缩前长度:"+src.length );
		 
		 //下面开始进行字节数据压缩///
		 //1 创建一个字节内存流,用来存放压缩后的数据
		 ByteArrayOutputStream destBaos = new ByteArrayOutputStream();
		 //2 创建 GZIPOutputStream,并且把 创建的字节内存流传过去,接收压缩后的数据
		 GZIPOutputStream gzipOs = new GZIPOutputStream(destBaos);
		 //3 把 原字节数据写入 gzipOs 进行压缩
		 gzipOs.write(src);
		 //4 写完一定要刷缓存!!!!!!!!
		 gzipOs.close(); //gzipOs.flush(); //调close()内部自动刷缓存,而且还可以防止内存泄漏
		 //5 从存储 压缩完的数据的 destBaos中获取数据写给客户端
		 byte[] dest = destBaos.toByteArray();
		 System.out.println( "压缩后长度:"+dest.length );
		 //6 写给客户端前 一定要设置响应头 !!!  --- 注意 写给客户端时用的是:response对象
		 resp.setHeader("Content-Encoding", "gzip");
		 //7通过字节流输出给客户端.
		 resp.getOutputStream().write(dest);
	}

	@Override
	public void destroy() {
	}
	
	class MyResponse extends HttpServletResponseWrapper{
		//用来存储 servlet中 write时的原数据
		private ByteArrayOutputStream baos;
		
		private PrintWriter writer;
		
		//有个细节 当访问的是 jsp文件时,需要把writer中的数据刷一下,因为jspWriter没有自带自动刷缓存///
		public ByteArrayOutputStream getBaos() {
			writer.close();
			return baos;
		}
		
		public MyResponse(HttpServletResponse response) {
			super(response);
			baos = new ByteArrayOutputStream();
		}

		
		//把原装的PrintWriter的类对象 替换掉//
		@Override
		public PrintWriter getWriter() throws IOException {
			//这里设置自带刷缓存只对Servlet中的字符输出流有效,对jsp的字符输出流是无法影响的。
			writer = new PrintWriter( baos,true);
			return writer;
		}
		/
	}
}

全站压缩:字节、字符都可以压缩

package cn.hncu.filter;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
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.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;


public class GzipAllFilter implements Filter {

	public void destroy() {
	}

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		/* 在这里需要把 response 换成MyResponse, 
		 * response.getOutputStream 换成 MyOutputStream,
		 * response.getWriter 换成   new PrintWirter(baos,true);
		 */
		//这里我们知道 response 对象其实是 HttpServletResponse类对象,所有强转以便后面操作。
		HttpServletResponse resp = (HttpServletResponse) response;
		
		MyResponse myResponse = new MyResponse(resp);
		
		//放行参数的用myResponse
		chain.doFilter(request, myResponse); //放行
		
		//能到这里说明servlet 已经运行完 doGet/doPost 方法
		//这时候可以 通过 myResponse获取封装在它内部的 字节内存流对象,把原数据获取出来进行压缩
		 ByteArrayOutputStream baos = myResponse.getBaos();
		 byte[] src = baos.toByteArray();
		 
		 System.out.println( "压缩前长度:"+src.length );
		 
		 //下面开始进行字节数据压缩///
		 //1 创建一个字节内存流,用来存放压缩后的数据
		 ByteArrayOutputStream destBaos = new ByteArrayOutputStream();
		 //2 创建 GZIPOutputStream,并且把 创建的字节内存流传过去,接收压缩后的数据
		 GZIPOutputStream gzipOs = new GZIPOutputStream(destBaos);
		 //3 把 原字节数据写入 gzipOs 进行压缩
		 gzipOs.write(src);
		 //4 写完一定要刷缓存!!!!!!!!
		 gzipOs.close(); //gzipOs.flush(); //调close()内部自动刷缓存,而且还可以防止内存泄漏
		 //5 从存储 压缩完的数据的 destBaos中获取数据写给客户端
		 byte[] dest = destBaos.toByteArray();
		 System.out.println( "压缩后长度:"+dest.length );
		 //6 写给客户端前 一定要设置响应头 !!!  --- 注意 写给客户端时用的是:response对象
		 resp.setHeader("Content-Encoding", "gzip");
		 //7通过字节流输出给客户端.
		 resp.getOutputStream().write(dest);
		
	}

	public void init(FilterConfig fConfig) throws ServletException {
	}

}
class MyResponse extends HttpServletResponseWrapper{
	//用来存储 servlet中 write时的原数据
	private ByteArrayOutputStream baos;
	
	//将数据输出到 baos 中去的打印流
	private PrintWriter writer;
	
	public ByteArrayOutputStream getBaos() {
		//两个流混用是 一定要注意:close 时要判断writer是否为空
		if( writer != null ) {
			writer.close();
		}
		return baos;
	}
	
	public MyResponse(HttpServletResponse response) {
		super(response);
		baos = new ByteArrayOutputStream();
	}
	********下面是把原有来的 getOutputStream和getWriter改掉*********
	//把原装的ServletOutputStream的类对象 改装成MyServletOutputStream类对象//
	@Override
	public ServletOutputStream getOutputStream() throws IOException {
		MyServletOutputStream myServletOutputStream = new MyServletOutputStream( super.getOutputStream(),baos);
		return myServletOutputStream;
	}
	//
	//把原装的PrintWriter的类对象 替换掉//
	@Override
	public PrintWriter getWriter() throws IOException {
		//这里设置自带刷缓存只对Servlet中的字符输出流有效,对jsp的字符输出流是无法影响的。
		writer = new PrintWriter( baos,true);
		return writer;
	}
	/
}
class MyServletOutputStream extends ServletOutputStream{
	private ServletOutputStream sos;
	//用来存储 servlet中 write时的原数据
	private ByteArrayOutputStream baos;

	protected MyServletOutputStream(ServletOutputStream sos,ByteArrayOutputStream baos) {
		this.sos = sos;
		this.baos = baos;
	}

	@Override
	public boolean isReady() {
		return sos.isReady();
	}

	@Override
	public void setWriteListener(WriteListener arg0) {
		sos.setWriteListener(arg0);
	}
	
	//把write方法修改了
	@Override
	public void write(int b) throws IOException {
		baos.write(b);
	}
	///
	
}

使用压缩流的一些细节:

配置只对部分和.jsp压缩,其他的不压缩, 还应配置对.js.css压缩。但决不能配置对所有请求都压缩,因为如果用户请求的是下载,那不但不能压缩,反而会让服务器因内存益处而崩溃。

完整代码链接

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值