12.1、Decorator模式
即使没有某一个对象的类的源代码,甚至即便这个类是声明为final的,Decorator模式和Wrapper模式都允许装饰或包装这个对象。
Decorator模式适用于无法使用继承的情况(比如,所指对象的类为final),或者你不想亲自创建对象,而是想从另一个子系统中获取。例如,Servlet容器创建了一个ServletRequest和一个ServletResponse,并将他们传给Servlet的service方法。改变ServletRequest和ServletResponse行为的唯一方法是将他们包在其他对象中。唯一必须满足的条件是,被装饰对象的类要实现一个接口,并且要包装的方法必须从这个接口处继承。
12.2、Servlet Wrapper类
Servlet API中提供了4个类,他们很少用到,但是功能非常强大,分别是:ServletRequestWrapper、ServletResponseWrapper,以及HttpServletRequestWrapper和HttpServletResponseWrapper。
ServletRequestWrapper使用起来非常方便,由于它为调用被包装ServletRequest中的对等方法的每一个方法都提供了默认实现。通过继承则只好直接实现ServletRequest,并为接口中的每一个方法都提供实现。
12.3、范例:AutoCorrect过滤器
在web应用程序中,用户经常会在输入值时,在其前面或者后面添加一些空格,甚至在词与词之间也会有多余空格。你又不想到应用程序的逐个Servlet中进行检查并删除多余的空格。那么本届介绍的AutoCorrect过滤器的特性就可以帮你完成这些工作。这个过滤器中包含一个HttpServletRequestWrapper的子类,命名为AutoCorrectHttpServletRequestWrapper,并覆盖返回一个或多个参数值的下列方法:getParameter、getParameterValues和getParameterMap。
AutoCorrectFilter.java
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; @WebFilter(filterName = "AutoCorrectFilter", urlPatterns = {"/*"}) public class AutoCorrectFilter implements Filter{ @Override public void destroy() { // TODO Auto-generated method stub } @Override public void init(FilterConfig arg0) throws ServletException { // TODO Auto-generated method stub } @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) { // TODO Auto-generated method stub return autoCorrect(httpServletRequest.getParameterValues(name)); } @Override public Map<String, String[]> getParameterMap() { // TODO Auto-generated method stub final Map<String, String[]> parameterMap = httpServletRequest.getParameterMap() ; Map<String, String[]> newMap = new Map<String, String[]>(){ @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 String[] put(String key, String[] value) { return parameterMap.put(key, value); } @Override public String[] remove(Object key) { return parameterMap.remove(key); } @Override public void putAll(Map<? extends String, ? extends String[]> m) { parameterMap.putAll(m); } @Override public void clear() { parameterMap.clear(); } @Override public Set<String> keySet() { return parameterMap.keySet(); } @Override public Collection<String[]> values() { return autoCorrect(parameterMap.values()); } @Override public Set<java.util.Map.Entry<String, String[]>> entrySet() { return autoCorrect(parameterMap.entrySet()); } } ; return newMap ; } } private String autoCorrect(String value){ if(value == null){ return null ; } 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 == ' '){ if(!lastCharWasSpace){ temp.append(c) ; } lastCharWasSpace = true ; }else{ 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 ; } @SuppressWarnings("unused") private Collection<String[]> autoCorrect(Collection<String[]> valueCollection){ Collection<String[]> newCollection = new ArrayList<String[]>() ; for(String[] values : valueCollection){ newCollection.add(autoCorrect(values)) ; } return newCollection ; } private Set<Map.Entry<String, String[]>> autoCorrect(Set<Map.Entry<String, String[]>> entrySet){ Set<Map.Entry<String, String[]>> newSet = new HashSet<Map.Entry<String, String[]>>() ; for(final Map.Entry<String, String[]> entry : entrySet){ Map.Entry<String, String[]> newEntry = new Map.Entry<String, String[]>() { @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 ; } }
test1.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>User Form</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> <form action="test2.jsp" method="post"> <table> <tr> <td>Name:</td> <td><input name="name"/></td> </tr> <tr> <td>Address:</td> <td><input name="address"/></td> </tr> <tr> <td colspan="2"> <input type="submit" value="Login"/> </td> </tr> </table> </form> </body> </html>
test2.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>Form Values</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> <table> <tr> <td>Name:</td> <td> ${param.name} (length:${fn:length(param.name)}) </td> </tr> <tr> <td>Address:</td> <td> ${param.address} (length:${fn:length(param.address)}) </td> </tr> </table> </body> </html>
运行结果: