使用Filter实现非法字符过滤
需求:用户在评论页面输入非法字符以后,需要将非法字符替换为*
需要考虑的问题
1.用户输入的非法字符可能会有很多种,如果想要校验用户输入的字符是否是非法字符,首先需要将非法字符存储起来,而不是写死,那么存储非法字符的存储位置
- 文件如果文件的内容有变更,需要重启服务器才生效,
- 数据库(开发项目的时候)如果数据库有变更,不需要重启服务器,因为是实时查询数据库看到的都是最新的数据,Ctrip Apollo。
将非法字符存储到文件中,服务器启动之后就应该读取文件中的内容并且存储到集合中,而不是等到请求过来之后再读,因为这样会影响体验,
2.由于可能会有很多的页面存在用户输入的数据(订单评价,商品搜索等等),因此这个事情应该交给Filter去做,而不是servlet,因为servlet是负责处理没有非法字符的请求,有非法字符的请求统一交给Filter去做,这样就是实现了非法字符的过滤。
模拟评论页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>评论页面</title>
</head>
<body>
<h1>评论页面处理非法字符</h1>
<form action="${pageContext.request.contentType}/comments" method="post">
评论内容:<input type="text" name="comments"><br>
<input type="submit">
</form>
</body>
</html>
在src下创建非法字符的文件
过滤器处理非法字符
package 过滤器;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
@WebFilter("/comments")
public class illegalCharcaterFilter implements Filter {
List<String> list;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//获取非法的字节输入流
InputStream resourceAsStream = illegalCharcaterFilter.class.getClassLoader().getResourceAsStream("illegal.txt");
InputStreamReader inputStreamReader = null;
try {
inputStreamReader = new InputStreamReader(resourceAsStream,"UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String line =null;
list = new ArrayList<>();
while(true){
try {
if (!((line=bufferedReader.readLine())!=null)) break;
} catch (IOException e) {
e.printStackTrace();
}
list.add(line);
}
System.out.println("当前的非法字符");
for (String s:list){
System.out.println(s);
}
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//进行非法字符的替换
//使用动态代理增强HttpServletRequest的getparameter()方法
HttpServletRequest req =(HttpServletRequest)servletRequest;
HttpServletRequest proxyHttpServletRequest=(HttpServletRequest) Proxy.newProxyInstance(HttpServletRequest.class.getClassLoader(), new Class[]{HttpServletRequest.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String returnValue=null;
String proxyMethodName="getParameter";
//增强getParameter的方法
if(method.getName().equals(proxyMethodName)){
//目的是改变getParameter的返回值
//执行原本的方法获取返回值
returnValue=(String)method.invoke(req,args);
//将返回值的结果替换为非法字符**
if(returnValue!=null){
if(list!=null){
//遍历所有的非法字符
for (String illegalCharacter:list){
if(returnValue.contains(illegalCharacter)){
String asterisk="";
//用* 号代表一个字符
for (int i=0;i<illegalCharacter.length();i++){
asterisk+="*";
}
//将非法字符替换成星号
returnValue=returnValue.replace(returnValue,asterisk);
System.out.println("替换之后的为:"+returnValue);
}
}
}
return returnValue;
}
}
//如果不是getParameter方法,则执行原来的方法,不增强
return method.invoke(req,args);
}
});
filterChain.doFilter(proxyHttpServletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
servlet处理请求
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/comments")
public class illegalServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;character=utf-8");
String comments = req.getParameter("comments");
System.out.println("接收到了客户请求"+comments);
resp.getWriter().write(comments);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
运行结果