很多网站都需要对于某些关键字或者某些敏感词汇进行过滤替换的功能。比如在输入框中输入些js 脚本,或者输入些政府类型的词汇等都是不允许的,但是你不能限制用户的自由。所以对于网站的过滤功能就显得很有必要了。对于一般的网站使用来说,不需要非常复杂的过滤算法等比较高端的实现。简单的用 filter 和 HttpServletRequestWrapper 就可以实现。
HttpServletRequestWrapper 的实现采用了包装模式,具体介绍请另找资料。直接切入正题。实现思路:首先定义一个 properties文件,在文件中存放需要替换的文字和替换后的文字,比如替换 fuck=** ,政府 =** ,替换 <=< 和 >=> (这样就可以避免文本输入的 js 脚本)。然后定义一个类来继承 HttpServletRequestWrapper 达到包装 request对象的作用,最后用一个 filter 使用包装后的 request 对象(即已经经过了过滤作用)。
keyword.properties文件:
CNM=**
fuck=**
<=<
>=>
然后写一个操作properties文件的工具类,PropertiesUtil.java
package com.lhwl.elt.filter;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
public class PropertiesUtil{
public static Map readProperties(String src) {
Properties props = new Properties();
Map map = new HashMap();
try {
File file=new File(src);
InputStream in=new FileInputStream(file);
props.load(in);
Enumeration en = props.propertyNames();
while (en.hasMoreElements()) {
String key = (String) en.nextElement();
String value = props.getProperty(key);
map.put(key, value);//把properties文件中的key-value存放到一个map中
}
return map;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static String replaceCheck(Map map,String name) {
Set<String> keys = map.keySet();
Iterator<String> iter = keys.iterator();
while (iter.hasNext()) {
String key = iter.next();
String value = (String) map.get(key);
if (name.contains(key)) {
name=name.replace(key, value);//对于符合map中的key值实现替换功能
}
}
return name;
}
}
这里我把从properties文件中读取的key--value的形式都存放到一个map对象中,方法都用static关键字,方便调用。
然后写了个KeyWordRequestWrapper来继承HttpServletRequestWrapper,实现包装request对象的作用。
package com.lhwl.elt.filter;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
public final class KeyWordRequestWrapper extends HttpServletRequestWrapper{
public Map keyMap;
public KeyWordRequestWrapper(HttpServletRequest servletRequest,Map keyMap){
super(servletRequest);
this.keyMap = keyMap;
}
@Override
public Map getParameterMap() {
super.getContextPath();
Map<String,String[]> map = super.getParameterMap();
if(!map.isEmpty()){
Set<String> keySet = map.keySet();
Iterator<String> keyIt = keySet.iterator();
while(keyIt.hasNext()){
String key = keyIt.next();
// String value = map.get(key)[0];
// map.get(key)[0] = this.replaceParam(value);
//这边实现对整个数组的判断。
String[] values=map.get(key);
for(int i=0;i<values.length;i++){
map.get(key)[i]=this.replaceParam(values[i]);
}
}
}
return map;
}
/* @Override
public String[] getParameterValues(String name) {
// TODO Auto-generated method stub
String[] resources = super.getParameterValues(name);
if (resources == null)
return null;
int count = resources.length;
String[] results = new String[count];
for (int i = 0; i < count; i++) {
results[i] = this.replaceParam(resources[i]);
}
return results;
}*/
public String replaceParam(String name){
return PropertiesUtil.replaceCheck(keyMap,name);
}
}
这里由于本人项目的框架原因,框架的request都是使用的getParameterMap来获取的,经过处理了,所以没有使用getParameterValues,可以看到代码中注释掉的方法。覆写了ServletRequestWrapper中的getParameterMap方法来实现包装功能,一般情况下,提交的value数组都只有一个,String value = map.get(key)[0];map.get(key)[0] = this.replaceParam(value);即可满足要求,但为了不出情况,还是实现了对整个数组的过滤替换功能。</div>
还剩个filter来实现了,先看具体的filter代码:
package com.lhwl.elt.filter;
import java.io.IOException;
import java.util.HashMap;
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;
public class KeyWordFilter implements Filter{
private FilterConfig filterConfig;
public static HashMap keyMap = null;
public static String path;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig=filterConfig;
String keyWordPath = filterConfig.getInitParameter("key");
path = filterConfig.getServletContext().getRealPath(keyWordPath);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest)request;
if(keyMap == null){
keyMap = (HashMap)PropertiesUtil.readProperties(path);
}
if(req.getMethod().equals("POST")){
chain.doFilter(new KeyWordRequestWrapper(req,keyMap), response);
}else{
chain.doFilter(request, response);
}
}
@Override
public void destroy() {
this.filterConfig = null;
}
}
这里在filter初始化的时候,就获得项目的真实路径,然后把最先定义的keyword.properties文件放到WEB-INF目录下,定义一个keyWordPath,然后就可以通过在web.xml文件中配置init-param来注入。这里把keyMap和path都定义为static,这样只需要在加载的时候一次初始化就好了。chain.doFilter(new KeyWordRequestWrapper(req,keyMap), response);对于需要过滤的内容进行处理关键字,敏感字等,其他的则正常chain.doFilter(request, response); 最后再web.xml中配置这个filter就可以,注意配置的顺序不要和其他filter冲突就行。web.xml配置:</div>
<!-- 配置过滤关键字 --> <filter> <filter-name>keyWordFilter</filter-name> <filter-class>com.lhwl.elt.filter.KeyWordFilter</filter-class> <init-param> <param-name>key</param-name> <param-value>/WEB-INF/keyword.properties</param-value> </init-param> </filter> <filter-mapping> <filter-name>keyWordFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
OK,现在只要输入些properties文件中定义好要替换的内容,则自动的实现了替换功能。比如输入fuck,提交显示出来的就变成了**,对输入的一些js脚本也能够当成文本显示出来了。。。