• 过滤器应用案例分析


    ----------------------------------------------------------------------------------------------
    [版权申明:本文系作者原创,转载请注明出处
    文章出处:http://blog.csdn.net/sdksdk0/article/details/52077359
    作者:朱培      ID:sdksdk0      邮箱: zhupei@tianfang1314.cn   

    --------------------------------------------------------------------------------------------


    本文主要分享的内容是通过使用过滤器解决全站乱码、Html过滤、脏话过滤、Gzip压缩过滤等主要内容,是一个切实解决网站实际问题的一套方案。

    一、过滤器简介


    Filter,对web服务器管理的所有web资源对请求和响应对象进行拦截。例如实现URL级别的权限访问控制、过滤敏感信息。


    下面来看一下过滤器的执行过程和生命周期

    生命周期


    初始化:当应用被加载时,由服务器调用默认的构造方法,并接着调用初始化方法。
    doFilter:一直伴随着应用程序而存在,用户每次访问被过滤的资源,都会调用doFilter方法。
    销毁:应用被卸载的时候。


    执行过程


    1、在javaweb服务器:服务器启动时加载应用,加载应用的配置文件web.xml,实例化过滤器并初始化。
    2、浏览器请求index.jsp。
    3、创建request和response,经过过滤器,调用request,response,FilterChain。
    4、通过FilterChain()处理。


    开发步骤

    1、写一个类,继承Filter接口
    2、配置web.xml。指定需要过滤的资源

        <!-- 定义过滤器 -->
    	<filter>
    		<filter-name>Demo1</filter-name>
    		<filter-class>cn.tf.filter.Demo1</filter-class>
    	</filter>
    	
    	<!-- 映射要过滤的资源 -->
    	<filter-mapping>
    		<filter-name>Demo1</filter-name>
    		<url-pattern>/index.jsp</url-pattern>
    	</filter-mapping>


    二、全站乱码


    我们以前对于网站乱码的问题大多数是直接在servlet中rerquest.setCharacterEncoder("UTF-8")这样来解决,但是对于多个servlet重复也的话就非常不好了,及其不方便,所以我们可以使用一个过滤器来对整站的编码进行设置。

    新建一个类SetCharacterEncodingFilter,使其继承Filter接口。然后实现其3个生命周期方法init()、doFilter()、destroy(),当然,我们需要对其doFilter方法进行操作了。在这里面设置编码就可以了

    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);
    	}
    使用chain.doFilter释放拦截。

    然后我们就到web.xml中去配置一个这个过滤器。这个找到你直接的类路径就可以了,/*是通配符,表示全站过滤,如果你只想要过滤某一种类型的文件,只需要修改相应的<url-pattern>就可以了,例如是想要jsp的格式改变,就改成*.jsp即可。


    <filter>
    	  	<filter-name>SetCharacterEncodingFilter</filter-name>
    	  	<filter-class>cn.tf.filter.SetCharacterEncodingFilter</filter-class>
    	  </filter>
    	  <filter-mapping>
    	  	<filter-name>SetCharacterEncodingFilter</filter-name>
    	  	<url-pattern>/*</url-pattern>
    	  </filter-mapping>



    三、Html过滤

    对于一个网站来说,进行html过滤是非常有必要的,因为在执行某些操作的时候,很有看通过html文件对你的网站注入html进行攻击,一方面防止攻击,一方面使用户体验度更好,所以我们常常需要进行html标签过滤。

    首先新建一个类HtmlFilter,使其继承Filter接口,在doFilter中进行操作。

    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(e);
    		}
    		
    		HttpServletRequest hrequest=new HtmlHttpServletRequest(request);
    		chain.doFilter(hrequest,response);
    		
    	}
    这里我们把HtmlHttpServletRequest写出来

    class HtmlHttpServletRequest extends HttpServletRequestWrapper{
    
    	public HtmlHttpServletRequest(HttpServletRequest request) {
    		super(request);
    		
    	}
    	
    	@Override
    	public String getParameter(String name) {
    		
    		String value=super.getParameter(name);
    		if(value==null)
    			return null;
    		value=filter(value);
    		return value;
    	}
    
    	private String filter(String message) {
    		 if (message == null)
    	            return (null);
    
    	        char content[] = new char[message.length()];
    	        message.getChars(0, message.length(), content, 0);
    	        StringBuilder result = new StringBuilder(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());
    	}
    	}
    	
    
    
    


    同样的,我们需要在web.xml中进行配置

     <!-- 过滤html -->
    	 <filter>
    	 <filter-name>HtmlFilter</filter-name>
    	  	<filter-class>cn.tf.filterHtml.HtmlFilter</filter-class>
    	  </filter>
    	  <filter-mapping>
    	  	<filter-name>HtmlFilter</filter-name>
    	  	<url-pattern>/*</url-pattern>
    	  </filter-mapping>

    处理前效果:


    处理后:




    四、脏话过滤

    对于脏话过滤在一些论坛网站等都是非常常见的功能,实现这个功能的方法非常多,你可以直接用js来做判断也是可以,这里我介绍的是另一种方法,就是通过过滤器来对脏话进行过滤,把脏话都替换为*号。

    同样的,新建一个类DirtyWordsFilter.java,实现其Filter接口。

    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(e);
    		}
    		
    		DWHttpServletRequest  dwrequest=new DWHttpServletRequest(request) ;
    		chain.doFilter(dwrequest, response);
    	}
    在这里对脏话进行处理。
    class DWHttpServletRequest extends HttpServletRequestWrapper{
    
    		private String[] strs={"傻逼","人妖","他妈的"};
    		
    		public DWHttpServletRequest(HttpServletRequest request) {
    			super(request);
    			
    		}
    		
    		@Override
    		public String getParameter(String name) {
    			String value=super.getParameter(name);
    			if(value==null)
    				return null;
    			
    			for(String s:strs){
    				value=value.replace(s, "**");
    			}
    			return value;
    		}
    		
    	}
    

    处理前效果:



    处理后效果:



    五、Gzip压缩

    在网站数据传输的时候,我们通常为了节省流量,加快传输速度等原因,通常需要把文件进行压缩,不但是用户请求的页面,例如当用户访问你的index.html页面的时候,从你的服务器传输到用户的客户端,如果直接传输整个人html页面是很耗资源的(当然是对于大量用户访问),所以我们需要把页面压缩之后再传输,这个我们就可以通过过滤器来实现了。

    新建GzipFilter.java,使其继承Filter接口。

     

    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(e);
    		}
    		
    		MyHttpServletResponse  mresponse=new MyHttpServletResponse(response);
    		chain.doFilter(request, mresponse);
    		
    		//获取原始数据
    		byte b[] = mresponse.getOldData();
    		System.out.println("压缩前:"+b.length);
    		//GZIP压缩
    		ByteArrayOutputStream out = new ByteArrayOutputStream();//内存字节缓存输出流
    		GZIPOutputStream gout = new GZIPOutputStream(out);
    		gout.write(b);
    		gout.close();//压缩后的数据写到了ByteArrayOutputStream中了
    		
    		b = out.toByteArray();//取出压缩后的数据
    		System.out.println("压缩后:"+b.length);
    		//告知客户端正文的压缩方式:gzip
    		response.setHeader("Content-Encoding", "gzip");
    		response.setContentLength(b.length);//响应消息头,告知客户端正文的长度
    		response.getOutputStream().write(b);	
    	}
    

    对字符流、字节流进行处理。

    class MyHttpServletResponse  extends HttpServletResponseWrapper{
    
    		private ByteArrayOutputStream baos=new ByteArrayOutputStream();
    		private PrintWriter pw = null;
    		public MyHttpServletResponse(HttpServletResponse response) {
    			super(response);
    			
    		}
    		
    		//截获数据:字符流
    		public PrintWriter getWriter() throws IOException {
    			pw = new PrintWriter(new OutputStreamWriter(baos, super.getCharacterEncoding()));
    			return pw;
    		}
    		
    		//截获数据:字节流
    		public ServletOutputStream getOutputStream() throws IOException {
    			return new MyServletOutputStream(baos);
    		}
    	
    		//返回截取的数据
    		public byte[] getOldData(){
    			try {
    				if(pw!=null){
    					pw.close();
    				}
    				baos.flush();
    			} catch (IOException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    			
    			return baos.toByteArray();
    		}
    		
    	}
    	
    		class MyServletOutputStream extends ServletOutputStream{
    
    			private ByteArrayOutputStream  baos;
    			
    			public MyServletOutputStream(ByteArrayOutputStream baos){
    				this.baos=baos;
    			}
    			
    			@Override
    			public void write(int b) throws IOException {
    				baos.write(b);
    				
    			}
    			
    		}

    当然,我们同样要在web.xml中配置。这里的话我们不需要全部过滤,只需要过滤jsp、html、js、css类型的即可。

    <!-- GZIP压缩 -->
     <filter>
    	 <filter-name>GzipFilter</filter-name>
    	  	<filter-class>cn.tf.filterHtml.GzipFilter</filter-class>
    	  </filter>
    	  <filter-mapping>
    	  	<filter-name>GzipFilter</filter-name>
    	  	<url-pattern>*.jsp</url-pattern>
    	  </filter-mapping>
    	  	  <filter-mapping>
    	  	<filter-name>GzipFilter</filter-name>
    	  	<url-pattern>*.html</url-pattern>
    	  </filter-mapping>
    	  	  <filter-mapping>
    	  	<filter-name>GzipFilter</filter-name>
    	  	<url-pattern>*.js</url-pattern>
    	  </filter-mapping>
    	  	  <filter-mapping>
    	  	<filter-name>GzipFilter</filter-name>
    	  	<url-pattern>*.css</url-pattern>
    	  </filter-mapping>
    在servlet中使用:

    public void doGet(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    
    		String data="你们好啊fyufbdljsbcjlksdnckdnjkdhjfbjcnjdjkdsnkklqispkxlndkehlfehihiohfdidsisildnckdnilfiefilefkkdhwgflkfnioufhyoinckdnckllhdefwvvewfefrvb54eqgdfbfdbgsfngfnhggfns";
    		PrintWriter out = response.getWriter();
    		out.write(data);
    	}


    使用Gzip压缩我们需要注意的是,数据量如果太小了的话,压缩之后会变更大了,数据量至少应该在150个字节以上的再压缩,否则会适得其反。


    总结:本文主要是通过四个常用的案例来说明了Filter过滤器的使用,都是一些非常简单易用的知识。对于一名合格的开发者来说,这些知识都是必须要掌握的。共勉!欢迎关注!



    源码下载:https://github.com/sdksdk0/FilterDemo




  • 相关阅读:
    P3396 哈希冲突
    P3295 [SCOI2016]萌萌哒
    P2585 [ZJOI2006]三色二叉树
    Leetcode 1546 和为目标值的最大数目不重叠非空子数组数目 贪心前缀和
    Leetcode 200 岛屿数量 压缩路径并查集与DFS
    Leetcode 递增子序列 回溯去重
    机器学习sklearn(76):算法实例(三十三)回归(五)线性回归大家族(三)回归类的模型评估指标
    机器学习sklearn(75):算法实例(三十二)回归(四)线性回归大家族(二)多元线性回归LinearRegression
    机器学习sklearn(74):算法实例(三十一)回归(三)线性回归大家族(一)概述
    机器学习sklearn(73):算法实例(三十)分类(十七)SVM(八)sklearn.svm.SVC(七) SVC真实数据案例:预测明天是否会下雨
  • 原文地址:https://www.cnblogs.com/xiaowangba/p/6314816.html
Copyright © 2020-2023  润新知