留言板程序可能遇到的问题:
输入HTML代码 破坏了留言板的正常显示 和安全隐患
输入了不雅的字句
不对现有的代码进行修改 可以考虑加入过滤器 过滤器可以截取到请求和响应对象 但是无法直接使用这两个对象对他们的数据进行替换 但是我们可以利用请求和响应的包装类来间接改变请求和响应的信息
利用过滤器和包装类就可以解决留言板程序中存在在的这两个问题
第一个问题 编写一个HttpServletRequestWrapper类的子类 然后重写getParameter()方法 在这个方法中 对请求参数的值进行过滤 将特殊字符转换成对应的实体引用或字符引用
第二个问题 编写一个HttpServletResponseWrapper类的子类 响应的内容是通过字符(PrintWrite)或者字节(ServletOutputStream)输出流对象向客户端输出的 而字符和字节输出流对象则是通过HttpServletResponse.getWriter()和HttpServletResponse.getOutputStream()方法得到的 正常情况下 响应的内容将被容器直接发送到客户端 要想得到响应的内容 就要替换默认的输出流对象 并且 新的输出流对象应该是内存输出流对象 也就是我们在调用输出流对象的write()方法时 数据被写到内存的缓冲区中 我们可以使用java.io包中的ByteArrayOutputStream类 让数据写到字节数组中 同时重写HttpServletResponse类的getWrite()和getOutputStream()方法 返回构建在ByteArrayOutputStream之上的PrintWriter对象和ServletOutputStream对象
实例开发步骤
1 MyRequestWrapper.java
从HttpServletRequestWrapper类继承 并重写getParameter()方法 对请求参数进行过滤 将特殊字符转换成对应的实体引用或者字符引用
- package filter;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletRequestWrapper;
- public final class MyRequestWrapper extends HttpServletRequestWrapper
- {
- public MyRequestWrapper(HttpServletRequest request)
- {
- super(request);
- }
-
- /**
- * 覆盖基类的getParameter()方法,对请求参数的值进行过滤。
- */
- public java.lang.String getParameter(java.lang.String name)
- {
- String value=super.getParameter(name);
- if(null!=value)
- return toHtml(value.trim());
- else
- return null;
- }
-
- /**
- * 将特殊字符转换为对应的实体引用或字符引用。
- */
- private String toHtml(String str)
- {
- if(str==null)
- return null;
- StringBuffer sb = new StringBuffer();
- int len = str.length();
- for (int i = 0; i < len; i++)
- {
- char c = str.charAt(i);
- switch(c)
- {
- case ' ':
- sb.append(" ");
- break;
- case '\n':
- sb.append("
");
- break;
- case '\r':
- break;
- case '\'':
- sb.append("'");
- break;
- case '<':
- sb.append("<");
- break;
- case '>':
- sb.append(">");
- break;
- case '&':
- sb.append("&");
- break;
- case '"':
- sb.append(""");
- break;
- case '\\':
- sb.append("\");
- break;
- default:
- sb.append(c);
- }
- }
- return sb.toString();
- }
- }
2 ByteArrayServletOutputStream.java
这个类从ServletOutputStream类继承 该类的对象用于替换HttpServletResponse.getOutputStream()方法返回的ServletOutputStream对象 其内部使用java.io.ByteArrayOutputStream的write(int b)方法实现ServletOutputStream类的write(int b)方法
- package filter;
- import java.io.ByteArrayOutputStream;
- import java.io.IOException;
- import javax.servlet.ServletOutputStream;
- public class ByteArrayServletOutputStream extends ServletOutputStream
- {
- ByteArrayOutputStream baos;
-
- ByteArrayServletOutputStream(ByteArrayOutputStream baos)
- {
- this.baos = baos;
- }
- public void write(int data) throws IOException
- {
- baos.write(data);
- }
- }
3 MyResponseWrapper.java
MyResponseWrapper类从HttpServletResponseWrapper类继承 并重写了getWriter() 和getOutputStream()方法 用构建在ByteArrayOutputStream之上的PrintWriter对象和ServletOutputStream对象替换Web容器创建的PrintWriter和ServletOutputStream对象
- package filter;
- import java.io.*;
- import javax.servlet.*;
- import javax.servlet.http.*;
- public class MyResponseWrapper extends HttpServletResponseWrapper
- {
- private ByteArrayOutputStream baos;
- private ByteArrayServletOutputStream basos;
- private PrintWriter pw;
-
- public MyResponseWrapper(HttpServletResponse response)
- {
- super(response);
- //创建ByteArrayOutputStream对象。
- baos=new ByteArrayOutputStream();
- //用ByteArrayOutputStream对象作为参数,
- //构造ByteArrayServletOutputStream对象。
- basos=new ByteArrayServletOutputStream(baos);
- //用ByteArrayOutputStream对象作为参数,
- //构造PrintWriter对象。
- pw=new PrintWriter(baos);
- }
-
- public PrintWriter getWriter()
- {
- return pw;
- }
-
- public ServletOutputStream getOutputStream()
- {
- return basos;
- }
-
- /**
- * 以字节数组的形式返回输出流缓冲区中的内容。
- */
- public byte[] toByteArray()
- {
- return baos.toByteArray();
- }
- }
4 GuestbookFilter.java
这个是过滤器类 利用MyRequestWrapper和MyPesponseWrapper类来替换请求中的特殊中的特殊字符和响应中的不雅字句不雅字句与替换的内容是以Java属性文件的格式保存到一个文件中 文件的路径名作为过滤器类的初始化参数在web.xml文件中进行配置。
- package filter;
- import java.io.*;
- import java.util.*;
- import javax.servlet.*;
- import javax.servlet.http.*;
- public class GuestbookFilter implements Filter
- {
- private static final String WORD_FILE="word_file";
-
- HashMap<String,String> hm=new HashMap<String,String>();
-
- /**
- * 在init()方法中,读取保存了不雅字句和替换内容的文件,
- * 并以不雅字句作为key,替换内容作为value,保存到Hashmap对象中。
- */
- public void init(FilterConfig filterConfig) throws ServletException
- {
- String configPath=filterConfig.getInitParameter(WORD_FILE);
-
- ServletContext sc=filterConfig.getServletContext();
- String filePath=sc.getRealPath(configPath);
-
- try
- {
- FileReader fr=new FileReader(filePath);
- BufferedReader br=new BufferedReader(fr);
-
- String line;
- while(null!=(line=br.readLine()))
- {
- String[] strTemp=line.split("=");
- hm.put(strTemp[0],strTemp[1]);
- }
- }
- catch(IOException ie)
- {
- throw new ServletException("读取过滤文件信息出错!");
- }
- }
-
- public void doFilter(ServletRequest request,
- ServletResponse response,
- FilterChain chain)
- throws IOException, ServletException
- {
-
- HttpServletRequest httpReq=(HttpServletRequest)request;
- HttpServletResponse httpResp=(HttpServletResponse)response;
-
- //得到请求和响应对象的封装类对象。
- MyRequestWrapper reqWrapper=new MyRequestWrapper(httpReq);
- MyResponseWrapper respWrapper=new MyResponseWrapper(httpResp);
-
- chain.doFilter(reqWrapper,respWrapper);
-
- String content = new String(respWrapper.toByteArray());
- String result=replaceText(content);
- httpResp.setContentType("text/html;charset=GB2312");
- PrintWriter out = httpResp.getWriter();
- out.println(result);
- out.close();
- }
-
- /**
- * 对内容中的不雅字句进行过滤。
- */
- public String replaceText(String content) throws IOException
- {
- StringBuffer sb=new StringBuffer(content);
- Set<String> keys=hm.keySet();
- Iterator<String> it=keys.iterator();
- while(it.hasNext())
- {
- String key=(String)it.next();
- int index=sb.indexOf(key);
- while(-1!=index)
- {
- sb.replace(index,index+key.length(),(String)hm.get(key));
- index=sb.indexOf(key);
- }
- }
- return sb.toString();
-
- }
- public void destroy(){}
- }
5 准备留言板程序
say.html
- <center>
- <form action="process.jsp" method="post">
- <table bgcolor="#B3B3FF">
- <caption>欢迎访问留言板</caption>
- <tr>
- <td>用户名:</td>
- <td><input type="text" name="name"></td>
- </tr>
- <tr>
- <td>主题:</td>
- <td><input type="text" name="title" size="40"></td>
- </tr>
- <tr>
- <td>内容:</td>
- <td>
- <textarea name="content" rows="10" cols="40"></textarea>
- </td>
- </tr>
- <tr>
- <td><input type="submit" value="提交"></td>
- <td><input type="reset" value="重填"></td>
- </tr>
- </table>
- </form>
- </center>
process.jsp
- <%@ page contentType="text/html;charset=gb2312" %>
- <%@ page import="java.sql.*,javax.sql.*,javax.naming.*" %>
- <%
- request.setCharacterEncoding("GBK");
-
- String name=request.getParameter("name");
- String title=request.getParameter("title");
- String content=request.getParameter("content");
-
- if(null==name || null==title || null==content)
- {
- response.sendRedirect("index.jsp");
- return;
- }
-
- if(name.equals("") || title.equals(""))
- {
- response.sendRedirect("say.html");
- return;
- }
-
- String fromIP=request.getRemoteAddr();
-
- Context ctx=new InitialContext();
- DataSource ds=(DataSource)ctx.lookup("java:comp/env/jdbc/bookstore");
- Connection conn=ds.getConnection();
-
- PreparedStatement pstmt=conn.prepareStatement(
- "insert into guestbook(gst_user,gst_title,gst_content,gst_ip) values(?,?,?,?)");
- pstmt.setString(1,name);
- pstmt.setString(2,title);
- pstmt.setString(3,content);
- pstmt.setString(4,fromIP);
-
- pstmt.executeUpdate();
- pstmt.close();
- conn.close();
- response.sendRedirect("index.jsp");
- %>
index.jsp
26-30行 最后一行 都用到 out.flush()语句的调用非常重要 否则 MyResponseWrapper类的toByteArray()方法将得不到缓冲区中的内容
6 配置JDBC数据源
http://blog.chinaunix.net/space.php?uid=26284395&do=blog&id=3038773
7 创建不雅字句与替换内容文件
文件word.txt存放在WEB-INF目录下
word.txt
8 配置web.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <web-app version="2.5"
- xmlns=""
- xmlns:xsi=""
- xsi:schemaLocation="
- /web-app_2_5.xsd">
- <filter>
- <filter-name>GuestbookFilter</filter-name>
- <filter-class>filter.GuestbookFilter</filter-class>
- <init-param>
- <param-name>word_file</param-name>
- <param-value>/WEB-INF/word.txt</param-value>
- </init-param>
- </filter>
-
- <filter-mapping>
- <filter-name>GuestbookFilter</filter-name>
- <url-pattern>/process.jsp</url-pattern>
- </filter-mapping>
-
- <filter-mapping>
- <filter-name>GuestbookFilter</filter-name>
- <url-pattern>/index.jsp</url-pattern>
- <dispatcher>REQUEST</dispatcher>
- <dispatcher>FORWARD</dispatcher>
- </filter-mapping>
-
- </web-app>
阅读(908) | 评论(0) | 转发(0) |