10.3 示例:AutoCorrectFilter

10.3示例:AutoCorrectFilter

Web应用中,用户经常在单词的前面或者后面输入空格,更有甚者在单词之间也加入空格。是否很想在应用的每个Servlet中,把多余的空格删除掉呢?本节的AutoCorrectFilter可以帮助你搞定它。该Filter包含了HttpServletRequestWrapper子类AutoCorrectHttpServletRequestWrapper,并重写了返回参数值的方法:getParametergetParameterValuesgetParameterMap

AutoCorrectFilter.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package 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;
@WebFilter(
filterName = "AutoCorrectFilter",
//过滤所有的URL
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);
}
}

代码详解

doFilter方法

这个FilterdoFilter方法非常简单:创建ServletRequest的修饰类实例,然后,把修饰类实例传给doFilter

1
2
3
4
5
6
7
8
9
10
//获取被修饰类的实例
HttpServletRequest httpServletRequest =
(HttpServletRequest) request;
//创建修饰类的实例
AutoCorrectHttpServletRequestWrapper
wrapper = new
AutoCorrectHttpServletRequestWrapper(
httpServletRequest);
//修饰类的实例代替被修饰类的实例
filterChain.doFilter(wrapper, response);

AutoCorrectHttpServletRequestWrapper.java

AutoCorrectHttpServletRequestWrapper.java实现了对HttpServletRequest对象的装饰.如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
package filter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
//装饰器类
class AutoCorrectHttpServletRequestWrapper
extends HttpServletRequestWrapper
{
//原来的请求对象
private HttpServletRequest httpServletRequest;
//构造函数的形式参数设置为要修饰的实例
public AutoCorrectHttpServletRequestWrapper(
HttpServletRequest httpServletRequest)
{
super(httpServletRequest);
this.httpServletRequest = httpServletRequest;
}
//重写原来的getParameter方法:
//- 对原来的方法的返回值做一些处理
//- 在原来方法的前后做一些处理
@Override
public String getParameter(String name)
{
//autoCorrect为修饰方法
return autoCorrect(
//原来的方法
httpServletRequest.getParameter(name)
);
}
@Override
public String[] getParameterValues(String name)
{
//处理原来方法的返回值
return autoCorrect(
//调用原来的方法
httpServletRequest.getParameterValues(name));
}
@Override
public Map<String,String[]> getParameterMap()
{
//获取原有的getParameterMap的返回值
final Map<String,String[]> parameterMap =
httpServletRequest.getParameterMap();
//创建一个新的Map用来存储处理的结果
Map<String,String[]> newMap =
new Map<String,String[]>()
{
@Override
public int size()
{
//使用原有的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)
{
//返回修饰后的get方法
return autoCorrect(
//调用原有的get方法
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<String> keySet()
{
//不改变
return parameterMap.keySet();
}
@Override
public Collection<String[]> values()
{
//返回修饰后的结果
return autoCorrect(
parameterMap.values());
}
@Override
public Set<Map.Entry<String,String[]>> 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<? extends String,? extends String[]> 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);
}
};
return newMap;
}
// #### 下面是修饰方法 ############################################################
/**
* 修饰方法,删除参数中的空白符.
* @param value 带有空白符的字符串参数.
* @return 没有空白符的字符串.
*/
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();
}
/**
* 删除字符串数组中元素中的空白符.
* @param values 字符串数组,数组元素可能带空白符的
* @return 字符串数组,数组元素中没有空白符.
*/
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;
}
/**
*
* @param valueCollection
* @return
*/
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;
}
}

修饰方法

在这个Filter背后的任何Servlet获得的HttpServletRequest都将被AutoCorrectHttpServletRequestWrapper所封装。这个封装类很长,但很好理解。简单地说,就是它把所有获取参数方法的返回值都用autoCorrect方法先处理删除其中的空格,然后使用autoCorrect方法处理后的结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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();
}

测试

测试这个Filter时,可以分别下面的test1.jsp,test2.jsp这两个页面。

test1.jsp页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<!DOCTYPE HTML>
<html>
<head>
<title>User Form</title>
<style>
table {
font-family: verdana, arial, sans-serif;
font-size: 16px;
color: #333333;
border-width: 1px;
border-color: #a9c6c9;
border-collapse: collapse;
background-color: #1f3de199;
}
table td {
border-width: 1px;
padding: 8px;
border-style: solid;
border-color: #a9c6c9;
}
</style>
</head>
<body>
<form action="test2.jsp" method="post">
<table>
<tr>
<td align="right">Name:</td>
<td><input name="name" /></td>
</tr>
<tr>
<td align="right">Address:</td>
<td><input name="address" /></td>
</tr>
<tr>
<td align="center" colspan="2">
<input type="submit" value="Login" />
</td>
</tr>
</table>
</form>
</body>
</html>

test2.jsp页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<!DOCTYPE HTML>
<html>
<head>
<title>Form Values</title>
<!-- 引入table CSS样式用到JS代码 -->
<script type="text/javascript" src="table.js"></script>
<!-- 引入table的css样式 -->
<link type="text/css" rel="styleSheet" href="table.css">
</head>
<body>
<table class="altrowstable" id="alternatecolor">
<tr>
<td align="right">Name:</td>
<td>
${param.name}(length:${fn:length(param.name)})
</td>
</tr>
<tr>
<td align="right">Address:</td>
<td>
${param.address}(length:${fn:length(param.address)})
</td>
</tr>
</table>
</body>
</html>

运行效果

可以使用如下URL路径访问test1.jsp页面:
http://localhost:8080/app10a/test1.jsp
输入一个带空格的单词,无论是前面、后面,还是在单词之间,然后点击提交。接下来,在显示器上你将看到这些输入单词都被修正过来。如下图所示: