作者:朱培      ID:sdksdk0  

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


本文主要分享的内容是通过使用过滤器解决全站乱码、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>


处理前效果:


过滤器应用案例分析_zip压缩

处理后:

过滤器应用案例分析_html_02



四、脏话过滤

对于脏话过滤在一些论坛网站等都是非常常见的功能,实现这个功能的方法非常多,你可以直接用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;
}

}


处理前效果:


过滤器应用案例分析_zip压缩_03


处理后效果:

过滤器应用案例分析_数据_04


五、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">​​https://github.com/sdksdk0/FilterDemo​​​