Filter高级开发(二)——实现敏感字符过滤功能
来源:互联网 发布:毒药法术升级数据 编辑:程序博客网 时间:2024/05/21 18:50
在实际开发中,我们如果真正要做一个上线的网站,就要考虑到过滤敏感字符(敏感词)。
敏感词可分为三大类:
- 禁用词,我们用数字1来表示。
- 审核词,我们用数字2来表示。
- 替换词,我们用数字3来表示。
为了实现敏感字符过滤功能,首先在网上下载一个敏感词库,然后在Eclipse中新建一个动态Web项目——day19_words。
这里我们介绍一个新技术:在项目day19_words下新建一个文件夹——config,如下:
然后,右键文件夹config→Build Path→Use as Source Folder(源目录),如下所示:
此时文件夹config就会在类目录路径下,最终会发布到classes目录下。
接着在config目录下创建一个cn.itcast.words包,将敏感词库拷贝到此包下,如下:
至此,前期的准备工作我们已经做好了。下面我们正式写代码来实现这一功能。
我们先在cn.itcast.web.filter包下编写一个敏感字符过滤器——WordsFilter.java。
现在我们思考这个过滤器该怎么写。当tomcat服务器启动day19_words这个web应用时,程序就要从config目录下的cn.itcast.words包下将敏感词库加载到内存中。也就是说该web应用一启动时,首先要将敏感词库读到系统里面去,而且敏感词库只要读一遍就行了。我们可以在静态代码块里面做,但是我们还有一种方法,可以在init方法里面做,因为filter对象只会创建一次,init方法也只会执行一次。
此时WordsFilter过滤器可以写为:
public class WordsFilter implements Filter { private List<String> banWords = new ArrayList<String>(); // 禁用词 private List<String> auditWords = new ArrayList<String>(); // 审核词 private List<String> replaceWords = new ArrayList<String>(); // 替换词 // WordsFilter过滤器只要一装载,WordsFilter对象只要一创建出来,init方法就会执行,init方法一执行,就会往List集合里面装东西。 /* * 首先要将敏感词库读到系统里面去,而且敏感词库只要读一遍就行了。 * 我们可以在静态代码块里面做,但是我们还有一种方法,可以在init方法里面做, * 因为filter对象只会创建一次,init方法也只会执行一次。 */ @Override public void init(FilterConfig filterConfig) throws ServletException { try { String path = WordsFilter.class.getClassLoader().getResource("cn/itcast/words").getPath(); File[] files = new File(path).listFiles(); for (File file : files) { if (!file.getName().endsWith(".txt")) { continue; } BufferedReader br = new BufferedReader(new FileReader(file)); String line = null; while ((line=br.readLine()) != null) { String[] s = line.split("\\|"); if (s.length != 2) { continue; } if (s[1].trim().equals("1")) { banWords.add(s[0].trim()); } if (s[1].trim().equals("2")) { auditWords.add(s[0].trim()); } if (s[1].trim().equals("3")) { replaceWords.add(s[0].trim()); } } } System.out.println("hahaha"); // 作断点调试用 } catch (Exception e) { throw new RuntimeException(e); } } @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { } @Override public void destroy() { }}
WordsFilter过滤器只要一装载,WordsFilter对象只要一创建出来,init方法就会执行,init方法一执行,就会往List集合里面装东西。此时我们可以在代码System.out.println("hahaha");
处打一个断点进行调试,然后Watch三个List集合,会发现这三个List集合都装载了东西。
首先我们来检查提交数据中是否包含禁用词。
此刻我们是不知道客户机要提交过来的数据的,也即不知道客户机会以什么名称提交数据过来, 所以我们应得到客户机提交的所有数据,然后挨个检查,那怎么得到客户机提交的所有数据呢?——可得到客户机提交的所有数据的名称,然后挨个取出来检查即可。
此时WordsFilter过滤器的代码可以写为:
public class WordsFilter implements Filter { private List<String> banWords = new ArrayList<String>(); // 禁用词 private List<String> auditWords = new ArrayList<String>(); // 审核词 private List<String> replaceWords = new ArrayList<String>(); // 替换词 // WordsFilter过滤器只要一装载,WordsFilter对象只要一创建出来,init方法就会执行,init方法一执行,就会往List集合里面装东西。 /* * 首先要将敏感词库读到系统里面去,而且敏感词库只要读一遍就行了。 * 我们可以在静态代码块里面做,但是我们还有一种方法,可以在init方法里面做, * 因为filter对象只会创建一次,init方法也只会执行一次。 */ @Override public void init(FilterConfig filterConfig) throws ServletException { try { String path = WordsFilter.class.getClassLoader().getResource("cn/itcast/words").getPath(); File[] files = new File(path).listFiles(); for (File file : files) { if (!file.getName().endsWith(".txt")) { continue; } BufferedReader br = new BufferedReader(new FileReader(file)); String line = null; while ((line=br.readLine()) != null) { String[] s = line.split("\\|"); if (s.length != 2) { continue; } if (s[1].trim().equals("1")) { banWords.add(s[0].trim()); } if (s[1].trim().equals("2")) { auditWords.add(s[0].trim()); } if (s[1].trim().equals("3")) { replaceWords.add(s[0].trim()); } } } System.out.println("hahaha"); // 作断点调试用 } catch (Exception e) { throw new RuntimeException(e); } } @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; // 检查提交数据是否包含禁用词 /* * 此刻是不知道客户机要提交过来的数据的,也即不知道客户机会以什么名称提交数据过来, * 所以应得到客户机提交的所有数据,然后挨个检查,怎么得到客户机提交的所有数据呢? * 可得到客户机提交的所有数据的名称,然后挨个取出来检查即可。 */ Enumeration<String> e = request.getParameterNames(); while (e.hasMoreElements()) { String name = (String) e.nextElement(); String data = request.getParameter(name); // 乱码:82342949842934*76%,所以这里还要解决乱码 // String regexData = data.replaceAll(" +", ""); for (String regex : banWords) { Pattern pattern = Pattern.compile(regex); // 编译regex这个正则表达式,得到代表此正则表达式的对象 Matcher m = pattern.matcher(data); // 看data数据里面有没有和该正则表达式相匹配的内容 if (m.find()) { // 匹配器的find方法若返回true,则客户机提交的数据里面有和正则表达式相匹配的内容 request.setAttribute("message", "文章中包含非法词汇,请检查后再提交!!!"); request.getRequestDispatcher("/message.jsp").forward(request, response); return; } } } chain.doFilter(request, response); } @Override public void destroy() { }}
编写玩上述WordsFilter过滤器之后,就要在web.xml文件中配置该过滤器了,但是一定得记住在配置该过滤器之前,一定得要配置解决全站中文乱码的过滤器,关于如何编写该过滤器可以参考我的笔记Filter高级开发(一)——使用Decorator模式包装request对象解决get和post请求方式下的中文乱码问题。
<filter> <filter-name>CharacterEncodingFilter2</filter-name> <filter-class>cn.itcast.web.filter.CharacterEncodingFilter2</filter-class></filter><filter-mapping> <filter-name>CharacterEncodingFilter2</filter-name> <url-pattern>/*</url-pattern></filter-mapping><filter> <filter-name>WordsFilter</filter-name> <filter-class>cn.itcast.web.filter.WordsFilter</filter-class></filter><filter-mapping> <filter-name>WordsFilter</filter-name> <url-pattern>/*</url-pattern></filter-mapping>
接着在WebRoot根目录下新建一个测试页面——form.jsp,form.jsp页面的内容如下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Insert title here</title></head><body> <form action="/day19_words/ServletDemo1" method="post"> <textarea rows="5" cols="50" name="resume"></textarea> <br /> <input type="submit" value="提交"> </form></body></html>
再在WebRoot根目录下新建一个全局消息显示页面——message.jsp,message.jsp页面的内容如下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Insert title here</title></head><body> ${message }</body></html>
当有人在form.jsp页面中填写内容并提交时,交给一个Servlet处理,所以应在cn.itcast.web.servlet包下创建一个Servlet——ServletDemo1.java。
ServletDemo1类的具体代码如下:
public class ServletDemo1 extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String data = request.getParameter("resume"); response.getWriter().write(data); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }}
现在我们来测试提交数据中是否包含禁用词,测试结果为:
虽然以上简单的测试通过了,但是人是非常复杂的动物,我们看一下在disu.txt文件中的禁用词。
有些人不会按照规矩来输入生儿子没屁眼
这样的字符串,他更有可能输入生 儿 子 没 屁 眼
这样的字符串,那么WordsFilter过滤器是检查不出来提交的数据中是否包含禁用词的,为了能够检查出来这样的禁用词,我们可以将那些破坏者提交的数据中的空格全部替换为""
,然后用替换掉的数据去和生儿子没屁眼
这样的正则表达式相匹配,并且我们另外还要保存一份破坏者提交的原始数据。所以WordsFilter过滤器中的doFilter(…)方法要修改为:
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; // 检查提交数据是否包含禁用词 /* * 此刻是不知道客户机要提交过来的数据的,也即不知道客户机会以什么名称提交数据过来, * 所以应得到客户机提交的所有数据,然后挨个检查,怎么得到客户机提交的所有数据呢? * 可得到客户机提交的所有数据的名称,然后挨个取出来检查即可。 */ Enumeration<String> e = request.getParameterNames(); while (e.hasMoreElements()) { String name = (String) e.nextElement(); String data = request.getParameter(name); // 乱码:82342949842934*76%,所以还要解决乱码 String regexData = data.replaceAll(" +", ""); for (String regex : banWords) { Pattern pattern = Pattern.compile(regex); // 编译regex这个正则表达式,得到代表此正则表达式的对象 Matcher m = pattern.matcher(regexData); // 看regexData数据里面有没有和该正则表达式相匹配的内容 if (m.find()) { // 匹配器的find方法若返回true,则客户机提交的数据里面有和正则表达式相匹配的内容 request.setAttribute("message", "文章中包含非法词汇,请检查后再提交!!!"); request.getRequestDispatcher("/message.jsp").forward(request, response); return; } } } chain.doFilter(request, response); }
由于破坏者是人,他就会想方设法地进行破坏,他不会简单地输入生 儿 子 没 屁 眼
这样的字符串,他更加有可能会输入生*儿*子*没$屁#眼
等等等这样的字符串,总之,破坏者就一定会搞破坏,我们写代码去防他,实在是防不胜防!!!虽然我们的处境很恶劣,但是我们程序员还是要竭尽全力地去防住破坏者,这是我们的职责,即使防不住!我们可以修改disu.txt文件的内容,在一定程度上去防他们。
以上这只是在一定的程度上去防破坏者,并不是防守得水泄不通,如果非得防守得天衣无缝,那就对提交的数据进行审核,管理员审核通过才发表,只要管理员觉得有一点不符合正确政治思想的东西,就不给其发表。
我们在上面检查完提交数据中是否包含禁用词之后,接下来就要检查提交数据中是否包含审核词。
现在我们来思考一个问题:文章中包含审核词,一提交,那么系统会怎么处理呢?——过滤器检查,检查文章包含审核词,过滤器应该把审核词高亮,然后再存到数据库里面去,方便管理员去审核,你要是不高亮,一篇文章几千字,管理员从中找一个审核词,眼睛都要找瞎啊!
当有人在form.jsp页面中填写内容并提交时,要交给一个Servlet——ServletDemo1去处理。ServletDemo1的具体代码为:
public class ServletDemo1 extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String data = request.getParameter("resume"); response.getWriter().write(data); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }}
对于代码String data = request.getParameter("resume");
而言,获取到的是原始数据,而不是高亮之后的数据,所以可以说request的getParameter方法是不行的,所以我们使用Decorator模式包装request对象,增强其getParameter方法。
那么此时WordsFilter过滤器的代码应该修改为:
public class WordsFilter implements Filter { private List<String> banWords = new ArrayList<String>(); // 禁用词 private List<String> auditWords = new ArrayList<String>(); // 审核词 private List<String> replaceWords = new ArrayList<String>(); // 替换词 // WordsFilter过滤器只要一装载,WordsFilter对象只要一创建出来,init方法就会执行,init方法一执行,就会往List集合里面装东西。 /* * 首先要将敏感词库读到系统里面去,而且敏感词库只要读一遍就行了。 * 我们可以在静态代码块里面做,但是我们还有一种方法,可以在init方法里面做, * 因为filter对象只会创建一次,init方法也只会执行一次。 */ @Override public void init(FilterConfig filterConfig) throws ServletException { try { String path = WordsFilter.class.getClassLoader().getResource("cn/itcast/words").getPath(); File[] files = new File(path).listFiles(); for (File file : files) { if (!file.getName().endsWith(".txt")) { continue; } BufferedReader br = new BufferedReader(new FileReader(file)); String line = null; while ((line=br.readLine()) != null) { String[] s = line.split("\\|"); if (s.length != 2) { continue; } if (s[1].trim().equals("1")) { banWords.add(s[0].trim()); } if (s[1].trim().equals("2")) { auditWords.add(s[0].trim()); } if (s[1].trim().equals("3")) { replaceWords.add(s[0].trim()); } } } System.out.println("hahaha"); // 作断点调试用 } catch (Exception e) { throw new RuntimeException(e); } } @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; // 检查提交数据是否包含禁用词 /* * 此刻是不知道客户机要提交过来的数据的,也即不知道客户机会以什么名称提交数据过来, * 所以应得到客户机提交的所有数据,然后挨个检查,怎么得到客户机提交的所有数据呢? * 可得到客户机提交的所有数据的名称,然后挨个取出来检查即可。 */ Enumeration<String> e = request.getParameterNames(); while (e.hasMoreElements()) { String name = (String) e.nextElement(); String data = request.getParameter(name); // 乱码:82342949842934*76%,所以还要解决乱码 // String regexData = data.replaceAll(" +", ""); for (String regex : banWords) { Pattern pattern = Pattern.compile(regex); // 编译regex这个正则表达式,得到代表此正则表达式的对象 Matcher m = pattern.matcher(data); // 看data数据里面有没有和该正则表达式相匹配的内容 if (m.find()) { // 匹配器的find方法若返回true,则客户机提交的数据里面有和正则表达式相匹配的内容 request.setAttribute("message", "文章中包含非法词汇,请检查后再提交!!!"); request.getRequestDispatcher("/message.jsp").forward(request, response); return; } } } // 检查审核词 chain.doFilter(new MyRequset(request), response); } class MyRequset extends HttpServletRequestWrapper { private HttpServletRequest request; public MyRequset(HttpServletRequest request) { super(request); this.request = request; } @Override public String getParameter(String name) { String data = this.request.getParameter(name); if (data == null) { return null; } for (String regex : auditWords) { Pattern p = Pattern.compile(regex); Matcher m = p.matcher(data); if (m.find()) { // 我有一把仿真手枪,你要电鸡吗?? String value = m.group(); // 找出客户机提交的数据中和正则表达式相匹配的数据 data = data.replaceAll(regex, "<font color='red'>" + value + "</font>"); } } return data; } } @Override public void destroy() { }}
现在我们来测试提交数据中是否包含审核词,测试结果为:
我们在上面检查完提交数据中是否包含禁用词和审核词之后,最后就要检查提交数据中是否包含替换词了。
同检查提交数据中是否包含审核词一样,我们希望request的getParameter方法内部检查已提交的内容里面有没有替换词,如果包含替换词,直接替换返回,所以还要增强这个方法。所以,最终我们的WordsFilter过滤器就全部写好了,其具体代码为:
public class WordsFilter implements Filter { private List<String> banWords = new ArrayList<String>(); // 禁用词 private List<String> auditWords = new ArrayList<String>(); // 审核词 private List<String> replaceWords = new ArrayList<String>(); // 替换词 // WordsFilter过滤器只要一装载,WordsFilter对象只要一创建出来,init方法就会执行,init方法一执行,就会往List集合里面装东西。 /* * 首先要将敏感词库读到系统里面去,而且敏感词库只要读一遍就行了。 * 我们可以在静态代码块里面做,但是我们还有一种方法,可以在init方法里面做, * 因为filter对象只会创建一次,init方法也只会执行一次。 */ @Override public void init(FilterConfig filterConfig) throws ServletException { try { String path = WordsFilter.class.getClassLoader().getResource("cn/itcast/words").getPath(); File[] files = new File(path).listFiles(); for (File file : files) { if (!file.getName().endsWith(".txt")) { continue; } BufferedReader br = new BufferedReader(new FileReader(file)); String line = null; while ((line=br.readLine()) != null) { String[] s = line.split("\\|"); if (s.length != 2) { continue; } if (s[1].trim().equals("1")) { banWords.add(s[0].trim()); } if (s[1].trim().equals("2")) { auditWords.add(s[0].trim()); } if (s[1].trim().equals("3")) { replaceWords.add(s[0].trim()); } } } System.out.println("hahaha"); // 作断点调试用 } catch (Exception e) { throw new RuntimeException(e); } } @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; // 检查提交数据是否包含禁用词 /* * 此刻是不知道客户机要提交过来的数据的,也即不知道客户机会以什么名称提交数据过来, * 所以应得到客户机提交的所有数据,然后挨个检查,怎么得到客户机提交的所有数据呢? * 可得到客户机提交的所有数据的名称,然后挨个取出来检查即可。 */ Enumeration<String> e = request.getParameterNames(); while (e.hasMoreElements()) { String name = (String) e.nextElement(); String data = request.getParameter(name); // 乱码:82342949842934*76%,所以还要解决乱码 // String regexData = data.replaceAll(" +", ""); for (String regex : banWords) { Pattern pattern = Pattern.compile(regex); // 编译regex这个正则表达式,得到代表此正则表达式的对象 Matcher m = pattern.matcher(data); // 看data数据里面有没有和该正则表达式相匹配的内容 if (m.find()) { // 匹配器的find方法若返回true,则客户机提交的数据里面有和正则表达式相匹配的内容 request.setAttribute("message", "文章中包含非法词汇,请检查后再提交!!!"); request.getRequestDispatcher("/message.jsp").forward(request, response); return; } } } // 检查审核词 // 检查替换词 chain.doFilter(new MyRequset(request), response); } class MyRequset extends HttpServletRequestWrapper { private HttpServletRequest request; public MyRequset(HttpServletRequest request) { super(request); this.request = request; } @Override public String getParameter(String name) { String data = this.request.getParameter(name); if (data == null) { return null; } for (String regex : auditWords) { Pattern p = Pattern.compile(regex); Matcher m = p.matcher(data); if (m.find()) { // 我有一把仿真手枪,你要电鸡吗?? String value = m.group(); // 找出客户机提交的数据中和正则表达式相匹配的数据 data = data.replaceAll(regex, "<font color='red'>" + value + "</font>"); } } for (String regex : replaceWords) { Pattern p = Pattern.compile(regex); Matcher m = p.matcher(data); if (m.find()) { // 我有一把仿真手枪,你要电鸡和四大舰队吗?? data = data.replaceAll(regex, "*******"); } } return data; } } @Override public void destroy() { }}
现在我们来测试提交数据中是否包含替换词,测试结果为:
至此,实现敏感字符过滤功能的过滤器我们才算写完了。
- Filter高级开发(二)——实现敏感字符过滤功能
- Filter高级开发(二)——实现敏感字符过滤功能
- Filter过滤敏感字符
- Filter——实现敏感字拦截
- 自定义标签实现过滤敏感字符
- C++实现敏感词过滤(3) Filter类的实现
- SQL过滤敏感字符
- 敏感字符过滤
- 过滤敏感字符
- 敏感字符过滤
- angularjs过滤敏感字符
- angularjs过滤敏感字符
- angularJS实现查询/选择排序/添加/敏感字符过滤
- 【C#】敏感字过滤功能的实现代码
- java过滤敏感词实现字符串替换功能
- Java实现DFA算法对敏感词、广告词过滤功能
- javaEE之---------过滤敏感词(filter)
- Filter过滤非法字符
- android平台HttpGet、HttpPost请求实例
- zTree中checkbox的具体项目用法
- 15、KVC、KVO和谓词
- UITextField和UITextView限制字数
- C++ Oracle OCCI 编程
- Filter高级开发(二)——实现敏感字符过滤功能
- arcgis总结——地理信息服务的发布以及通过rest服务进行geocode相关操作
- ACache轻量级缓存框架
- 三列布局中间列宽度自适应
- windows 配置 git
- JavaScript操作cookie与localStorage
- 人件读书笔记(29)自我愈复系统
- libsvm交叉验证与网格搜索(参数选择)
- windows安装go-sqlite3失败,提示找不到gcc