- 概念解释:
Servlet规范中的filter引入了一个功能强大的拦截模式。Filter能在request到达servlet的服务方法之前拦截HttpServletRequest对象,而在服务方法转移控制后又能拦截HttpServletResponse对象。
但是HttpServletRequest中的参数是无法改变的,若是手动执行修改request中的参数,则会抛出异常。且无法获取到HttpServletResponse中的输出流中的数据,因为HttpServletResponse中输出流的数据会写入到默认的输出端,你手动无法获取到数据。
我们可以利用HttpServletRequestWrapper包装HttpServletRequest,用HttpServletResponseWrapper包装HttpServletResponse,在Wrapper中实现参数的修改或者是response输出流的读取,然后用HttpServletRequestWrapper替换HttpServletRequest,HttpServletResponseWrapper替换HttpServletResponse。这样就实现了参数的修改设置和输出流的读取。
2.应用场景:
你可以使用filter来实现特定的任务,比如验证用户输入,以及压缩web内容。但HttpServletRequest对象的参数是不可改变的,这极大地缩减了filter的应用范围。至少在一半的时间里,你希望可以改变准备传送给 filter的对象。
幸运的是,尽管你不能改变不变对象本身,但你却可以通过使用装饰模式来改变其状态。
引入
实例的功能:对用户输入的敏感字眼进行过滤
应用场景:评论功能有时候需要对用户输入的某些敏感字眼进行过滤
实现架构:
模块一:前端页面:提供用户输入的界面,展示用户输入的内容
模块二:过滤器:对某些敏感字眼的过滤功能在此实现
模块三:servlet:在本实例中,因为用户的输入最终显示在用户输入的界面,因此servlet需要将用户输入的内容保存到request中,并且用requestDispatcher类请求转发到首页
示意图为:
源码:
首页index.jsp的源码如下:
<%@ page language="java" contentType="text/html" pageEncoding="GBK"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>意见反馈</title>
<style type="text/css">
body {
margin: 0px;
font-size: 12px;
}
td{
font-size: 12px;
}
.div1{
width: 1003px;
height: 707px;
background-image: url("images/bg.jpg");
}
.div2{
width: 500px;
margin-top:245px;
margin-left:180px;
text-align:left;
}
.tl{
width: 500px;
height: 20px;
font-weight: bold;
background: #A3C0C6;
padding: 5px;
}
.ct{
width: 500px;
padding-left: 30px;
padding-top: 5px;
padding-bottom: 5px;
}
.tt{
margin-left:5px;
width: 70px;
background: #A3C0C6;
padding: 5px;
font-weight: bold;
font-size: 13px;
}
</style>
</head>
<body>
<div align="center">
<div class="div1">
<div class="div2">
<%
String title = (String)request.getAttribute("title");
String content = (String)request.getAttribute("content");
if(title != null && !title.isEmpty()){
out.println("<span class='tl'>" + title + "</span>");
}
if(content != null && !content.isEmpty()){
out.println("<span class='ct'>" + content + "</span>");
}
%>
<span class="tl">谢谢你们</span>
<span class="ct">你们的公司服务态度非常好,谢谢你们!</span>
<span class="tl">谢谢你们</span>
<span class="ct">你们的公司服务态度非常好<br>但部分客服服务态度还要加强!</span>
<form action="filter" method="post">
<span class="tt">意见反馈</span>
<table border="0" width="500" align="center">
<tr>
<td align="right">标 题:</td>
<td><input type="text" name="title" size="30"></td>
</tr>
<tr>
<td align="right">内 容:</td>
<td>
<textarea rows="5" cols="40" name="content"></textarea>
</td>
</tr>
<tr>
<td align="center" colspan="2">
<input type="submit" value="提 交">
</td>
</tr>
</table>
</form>
</div>
</div>
</div>
</body>
</html>
过滤器MyFilterOne.java的代码如下:
-
package com.ll.filter;
-
import java.io.IOException;
-
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.annotation.WebFilter;
-
import javax.servlet.http.HttpServletRequest;
-
import javax.servlet.http.HttpServletRequestWrapper;
-
import org.apache.coyote.Request;
-
/**
-
* Servlet Filter implementation class MyFilterOne
-
*/
-
public class MyFilterOne implements Filter {
-
/**
-
* Default constructor.
-
*/
-
private String words[];//存放规定的敏感字
-
private String encoding;//存放要使用的编码格式
-
public MyFilterOne() {
-
// TODO Auto-generated constructor stub
-
}
-
/**
-
* @see Filter#destroy()
-
*/
-
public void destroy() {
-
// TODO Auto-generated method stub
-
this.words=null;
-
this.encoding =null;
-
}
-
/**
-
* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
-
*/
-
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
-
throws IOException, ServletException {
-
// TODO Auto-generated method stub
-
// place your code here
-
// pass the request along the filter chain
-
if(encoding!=null) {
-
request.setCharacterEncoding(encoding);//设置request字符编码
-
request=new Request((HttpServletRequest)request);
-
//将传递的ServletRequest对象转化为自定义的Request对象,即可实现非法字符的过滤
-
response.setContentType("text/html;charset="+encoding);//设置response字符编码
-
}
-
chain.doFilter(request, response);
-
}
-
/**
-
* @see Filter#init(FilterConfig)
-
*/
-
public void init(FilterConfig fConfig) throws ServletException {
-
// TODO Auto-generated method stub
-
words=new String[] {"糟糕","混蛋"};//定义敏感字符
-
encoding=fConfig.getInitParameter("encoding");
-
}
-
class Request extends HttpServletRequestWrapper{
-
/*创建内部类Request,
-
该类继承HttpServletRequestWrapper,
-
是HttpServletRequest的装饰类,
-
用来改变HttpServletRequest的状态,
-
从而达到对请求内容的过滤的功能*/
-
public Request(HttpServletRequest request) {
-
super(request);
-
// TODO 自动生成的构造函数存根
-
}
-
/*重写getParameter方法
-
* 对请求结果进行过滤*/
-
public String getParameter(String name) {
-
return filter(super.getRequest().getParameter("name"));
-
}
-
/*重写getParameterValues方法
-
* 通过循环取出每一个请求结果
-
* 再对请求结果进行过滤*/
-
public String[] getParameterValues(String name) {
-
String values[]=super.getRequest().getParameterValues("name");
-
for(int i=0;i<values.length;i++) {
-
values[i]=filter(values[i]);
-
}
-
return values;
-
}
-
}
-
/*创建过滤方法filter
-
* 当敏感字不为空的时候,
-
* 分别对每一个敏感字循环一次
-
* 如果在param中发现敏感字则将其替换为“****” */
-
public String filter(String param) {
-
try{if(words!=null&&words.length>0) {
-
for(int i=0;i<words.length;i++) {
-
if(param.indexOf(words[i])!=-1) {
-
param=param.replaceAll(words[i], "****");
-
}
-
}
-
}}catch(Exception e) {
-
e.printStackTrace();
-
}
-
return param;
-
}
-
}
servlet(MyServlet.java)的代码如下:
-
package com.ll.servlet;
-
import java.io.IOException;
-
import javax.servlet.ServletException;
-
import javax.servlet.annotation.WebServlet;
-
import javax.servlet.http.HttpServlet;
-
import javax.servlet.http.HttpServletRequest;
-
import javax.servlet.http.HttpServletResponse;
-
/**
-
* Servlet implementation class MyServlet
-
*/
-
@WebServlet("/MyServlet")
-
public class MyServlet extends HttpServlet {
-
private static final long serialVersionUID = 1L;
-
/**
-
* @see HttpServlet#HttpServlet()
-
*/
-
public MyServlet() {
-
super();
-
// TODO Auto-generated constructor stub
-
}
-
/**
-
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
-
*/
-
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
-
// TODO Auto-generated method stub
-
// response.getWriter().append("Served at: ").append(request.getContextPath());
-
}
-
/**
-
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
-
*/
-
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
-
// TODO Auto-generated method stub
-
// doGet(request, response);
-
//先取出用户输入的内容
-
String title=request.getParameter("title");
-
String content=request.getParameter("content");
-
//将用户输入的内容保存到request中
-
request.setAttribute("title", title);
-
request.setAttribute("content", content);
-
//用RequestDispatcher对象请求转发至index.jsp页面
-
request.getRequestDispatcher("index.jsp").forward(request, response);
-
}
-
}
然后在web.xml文件中进行配置
-
<?xml version="1.0" encoding="UTF-8"?>
-
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
-
<display-name>five</display-name>
-
<welcome-file-list>
-
<welcome-file>index.jsp</welcome-file>
-
</welcome-file-list>
-
<servlet>
-
<servlet-name>MyServlet</servlet-name>
-
<servlet-class>com.ll.servlet.MyServlet</servlet-class>
-
</servlet>
-
<servlet-mapping>
-
<servlet-name>MyServlet</servlet-name>
-
<url-pattern>/filter</url-pattern>
-
</servlet-mapping>
-
<filter>
-
<filter-name>MyFilterOne</filter-name>
-
<filter-class>com.ll.filter.MyFilterOne</filter-class>
-
<init-param>
-
<param-name>encoding</param-name>
-
<param-value>GBK</param-value>
-
</init-param>
-
</filter>
-
<filter-mapping>
-
<filter-name>MyFilterOne</filter-name>
-
<url-pattern>/*</url-pattern>
-
</filter-mapping>
-
</web-app>
HttpServletRequestWrapper类的使用
servlet规范中中引入的filter是非常有用的,因为它引入了一个功能强大的拦截模式。
filter是这样的一种java对象。它可以在request到达servlet之前拦截HttpServletRequest对象,也可以在服务方法转移控制后拦截HttpServletResponse对象。
我们可以使用filter对象完成的任务有:检查用户的输入、以及压缩web内容。
但是,当我们在使用filter的时候却会发现至少有一半的时间我们都想改变HttpServletRequest对象的参数。如:用filter在HttpServletRequest对象到达Servlet之前将用户输入的空格去掉。但是由于java.util.Map包装的HttpServletRequest对象的参数是不可改变的,那要怎么办呢?
幸运的是,尽管我们不能改变对象本身,但是可以通过装饰模式来改变其状态。
比如在上文中编写的内部类Request就是HttpServletRequest类的装饰类。
该类继承的HttpServletRequestWrapper类是HttpServletRequest类的装饰类。
这在jsp/servlet 中是非常有用的,web程序通过调用httpServletRequest对象的getParameter方法来处理表单,因此通过重写装饰类中的此方法就可以改变HttpServletRequest对象的状态。所以在上题的内部类Request中就重写了getParameter方法和getParameterValues方法。
因此,想要改变在httpServletRequest中的参数,可以通过httpServletRequest的装饰类HttpServletRequestWrapper来实现,只需要在装饰类中按照需要重写其getParameter(getParameterValues)方法即可。
参照资料:https://blog.csdn.net/qll19970326/article/details/80793465