Servlet API包含4个可修饰的类,用于改变Servlet Request以及Servlet Response。这种修饰允许修改 ServletRequest以及ServletResponse或者HTTP中的等价 类(即HttpServletRequest和HttpServletResponse)中的 任务方法。这种修饰遵循Decorator模式或者Wrapper模 式,因此在使用修饰前,需要了解一下该模式的内容。
一.Decorator 模式( 装饰器模式)
Decorator模式或者Wrapper模式允许修饰或者封装 (在字面意义中,即修改行为)一个对象,即使你没有 该对象的源代码或者该对象标识为final。
Decorator模式适用于无法继承该类(例如,对象的 实现类使用final标识)或者无法创建该类的实例,但可 以从另外的系统中可以取得该类的实现时。例如, Servlet容器方法。只有一种方法可以修改ServletRequest 或者ServletResponse行为,即在另外的对象中封装该实 例。唯一的限制是,修饰对象必须继承一个接口,然后 实现接口以封装这些方法。
类图说明了一个Component接口以及它 的实现类ComponentImpl。Component接口定义了A的方 法。为了修饰ComponentImpl的实例,需要创建一个 Decorator类,并实现Component的接口,然后在子类中 扩展Decorator的新行为。在类图中DecoratorA就是 Decorator的一个子类。每个Decorator实例需要包含 Component的一个实例。Decorator类代码如下(注意在 构建函数中获取了Component的实例,这意味着创建 Decorator对象只能传入Component的实例):
public class Decorator implements Component {private Component decorated;// constructor takes a Component implementationpublic Decorator(Component component) {this.decorated = component;}// undecorated method@Overridepublic void methodA(args) {decorated.methodA(args);}// decorated method@Overridepublic void methodB(args) {decorated.methodB(args)}}
在Decorator类中,有修饰的方法就是可能在子类中 需要修改行为的方法,在子类中不需要修饰的方法可以 不需要实现。所有的方法,无论是否需要修饰,都叫作 Component中的配对方法。Decorator是一个非常简单的 类,便于提供每个方法的默认实现。修改行为在它的子 类中。
需要牢记一点,Decorator类及被修饰对象的类需要 实现相同的接口。为了实现Decorator,可以在Decorator 中封装修饰对象,并把Decorator作为Component的一个 实现。任何Component的实现都可以在Decorator中注 入。事实上,你可以把一个修饰的对象传入另一个修饰 的对象,以实现双重的修饰。
二. Servlet封装类
Servlet API源自于4个实现类,它很少被使用,但 是十分强大:ServletRequestWrapper、 ServletResponseWrapper以及 HttpServletRequestWrapper、 HttpServletResponseWrapper。
ServletRequestWrapper(或者其他3个Wrapper类) 非常便于使用,因为它提供了每个方法的默认实现:即 ServletRequest封闭的配置方法。通过继承 ServletRequestWrapper,只需要实现你需要变更的方法 就可以了。如果不用ServletRequestWrapper,则需要继 承ServletRequest并实现ServletRequest中所有的方法。
图所示为Decorator模式中 ServletRequestWrapper的类图。Servlet容器在每次 Servlet服务调用时创建ServletRequest、ContainerImpl。 直接扩展ServletRequestWrapper就可以修饰 ServletRequest了。
三. 示例:AutoCorrect Filter
在Web应用中,用户经常在单词的前面或者后面输 入空格,更有甚者在单词之间也加入空格。是否很想在 应用的每个Servlet中,把多余的空格删除掉呢?本节的 AutoCorrect Filter可以帮助你搞定它。该Filter包含了 HttpServletRequestWrapper子类 AutoCorrectHttpServletRequestWrapper,并重写了返回 参数值的方法:getParameter、getParameterValues及 getParameterMap。代码如下所示。
AutoCorrectFilter 类
package filter;import java.io.IOException;import java.util.ArrayList;import java.util.Collection;import java.util.HashSet;import java.util.Map;import java.util.Set;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;// urlPatterns={"/*"} 不能过滤链接@WebFilter(filterName = "AutoCorrectFilter", urlPatterns = { "*" })public class AutoCorrectFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void destroy() { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest httpServletRequest = (HttpServletRequest) request; AutoCorrectHttpServletRequestWrapper wrapper = new AutoCorrectHttpServletRequestWrapper(httpServletRequest); filterChain.doFilter(wrapper, response); } class AutoCorrectHttpServletRequestWrapper extends HttpServletRequestWrapper { private HttpServletRequest httpServletRequest; public AutoCorrectHttpServletRequestWrapper(HttpServletRequest httpServletRequest) { super(httpServletRequest); this.httpServletRequest = httpServletRequest; } @Override public String getParameter(String name) { return autoCorrect(httpServletRequest.getParameter(name)); } @Override public String[] getParameterValues(String name) { return autoCorrect(httpServletRequest.getParameterValues(name)); } //用匿名内部类 重写 getParameterMap() 方法 @Override public MapgetParameterMap() { // 得到request的 parameterMap final Map parameterMap = httpServletRequest.getParameterMap(); // 重写 parameterMap Map newMap = new Map () { @Override public int size() { return parameterMap.size(); } @Override public boolean isEmpty() { return parameterMap.isEmpty(); } @Override public boolean containsKey(Object key) { return parameterMap.containsKey(key); } @Override public boolean containsValue(Object value) { return parameterMap.containsValue(value); } @Override public String[] get(Object key) { return autoCorrect(parameterMap.get(key)); } @Override public void clear() {// this will throw an IllegalStateException// but let the user get the original// exception parameterMap.clear(); } @Override public Set keySet() { return parameterMap.keySet(); } @Override public Collection values() { return autoCorrect(parameterMap.values()); } @Override public Set > entrySet() { return autoCorrect(parameterMap.entrySet()); } @Override public String[] put(String key, String[] value) {// this will throw an IllegalStateException// but let the user get the original// exception return parameterMap.put(key, value); } @Override public void putAll(Map map) {// this will throw an IllegalStateException// but let// the user get the original exception parameterMap.putAll(map); } @Override public String[] remove(Object key) {// this will throw an IllegalStateException,// but let// the user get the original exception return parameterMap.remove(key); } }; //返回一个新的map return newMap; } } private String autoCorrect(String value) { if (value == null) { return null; } // 去除String头尾空格 value = value.trim(); int length = value.length(); StringBuilder temp = new StringBuilder(); boolean lastCharWasSpace = false; for (int i = 0; i < length; i++) { char c = value.charAt(i); // 如果是空格 if (c == ' ') { // 如果是空格且是最后一个字符 就添加到temp if (!lastCharWasSpace) { temp.append(c); } lastCharWasSpace = true; } else { // 不是空格的字符直接添加到temp temp.append(c); lastCharWasSpace = false; } } return temp.toString(); } private String[] autoCorrect(String[] values) { if (values != null) { int length = values.length; for (int i = 0; i < length; i++) { values[i] = autoCorrect(values[i]); } return values; } return null; } private Collection autoCorrect(Collection valueCollection) { Collection newCollection = new ArrayList (); for (String[] values : valueCollection) { newCollection.add(autoCorrect(values)); } return newCollection; } private Set > autoCorrect(Set > entrySet) { Set > newSet = new HashSet >(); for (final Map.Entry entry : entrySet) { Map.Entry newEntry = new Map.Entry () { @Override public String getKey() { return entry.getKey(); } @Override public String[] getValue() { return autoCorrect(entry.getValue()); } @Override public String[] setValue(String[] value) { return entry.setValue(value); } }; newSet.add(newEntry); } return newSet; }}
这个Filter的doFilter方法非常简单:创建 ServletRequest的修饰实现,然后,把修饰类传给 doFilter
HttpServletRequest httpServletRequest =(HttpServletRequest) request;AutoCorrectHttpServletRequestWrapper wrapper = newAutoCorrectHttpServletRequestWrapper(httpServletRequest);filterChain.doFilter(wrapper, response);
在这个Filter背后的任何Servlet获得的 HttpServletRequest都将被AutoCorrectHttp ServletRequestWrapper 所封装。这个封装类很长,但很 好理解。简单地说,就是它把所有获取参数的响应都调 用了一下autoCorrect方法:
test1.jsp页面
User Form
test2.jsp页面
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>Form Values
Name: | ${param.name} (length:${fn:length(param.name)}) |
Address: | ${param.address} (length:${fn:length(param.address)}) |
输入一个带空格的单词,无论是前面、后面,还是 在单词之间,然后点击提交。接下来,在显示器上你将 看到这些输入单词都被修正过来