Java 中过滤器的主要优点之一是您可以在将响应发送到客户端之前使用它来更改或更改网页的响应,而无需触及 Web 应用程序的任何现有代码。例如,您可以使用过滤器在每页末尾添加命中计数器信息;或在网页标题末尾附加公司名称等。
下图说明了过滤机制用于修改网页响应的工作原理:
过滤器中代码的工作流程应该是这样的(伪代码):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class
Filter {
?????
????``public
void
doFilter(request, response, chain) {
?
????????``// create a response wrapper to capture the original response
?????????
????????``// allow the request to reach the target page,
????????``// but the response is written to the wrapper
????????
????????``chain.doFilter(request, wrapper);
?????????
????????``// modify the response
????????``// write the altered content to the response
????``}
}
因为网页的响应是 text/html(字符),所以我们可以编写一个响应包装类,如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package
net.codejava;
import
java.io.*;
import
javax.servlet.http.*;
public
class
CharResponseWrapper?``extends
HttpServletResponseWrapper {
????``private
CharArrayWriter writer;
?????
????``public
CharResponseWrapper(HttpServletResponse response) {
????????``super``(response);
????????``writer =?``new
CharArrayWriter();
????``}
?????
????``public
PrintWriter getWriter() {
????????``return
new
PrintWriter(writer);
????``}
?????
????``public
String toString() {
????????``return
writer.toString();
????``}
?
}
请注意,此响应包装类必须扩展Servlet API 提供的HttpServletResponseWrapper类。它重写getWriter()方法以返回包装CharArrayWriter对象的PrintWriter对象。因此 servlet 容器会将目标页面的响应写入此编写器——因此原始响应被“捕获”。我们还重写了toString()方法以将 writer 的内容作为字符串返回。
以下伪代码解释了如何修改原始响应并将更改后的响应发送给客户端:
1
2
3
4
5
// get the writer object of the original response
// get content from the wrapper and modify it
// use the writer object to write altered content to the response
例如,以下过滤器类片段修改响应以将版权信息放在页面末尾:
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
package
net.codejava;
import
java.io.*;
import
javax.servlet.*;
import
javax.servlet.annotation.WebFilter;
import
javax.servlet.http.HttpServletResponse;
@WebFilter``(``"/*"``)
public
class
ResponseFilter?``implements
Filter {
????``@Override
????``public
void
init(FilterConfig filterConfig)?``throws
ServletException {
????``}
????``@Override
????``public
void
doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
????????????``throws
IOException, ServletException {
????????``CharResponseWrapper wrapper =?``new
CharResponseWrapper((HttpServletResponse) response);
????????
????????``chain.doFilter(request, wrapper);
????????
????????``PrintWriter responseWriter = response.getWriter();
????????
????????``if
(wrapper.getContentType().contains(``"text/html"``)) {
????????????``CharArrayWriter charWriter =?``new
CharArrayWriter();
????????????``String originalContent = wrapper.toString();
????????????
????????????``int
indexOfCloseBodyTag = originalContent.indexOf(``"</body>"``) -?``1``;
?????????????
????????????``charWriter.write(originalContent.substring(``0``, indexOfCloseBodyTag));
?????????????
????????????``String copyrightInfo =?``"<p>Copyright CodeJava.net</p>"``;
????????????``String closeHTMLTags =?``"</body></html>"``;
????????????
????????????``charWriter.write(copyrightInfo);
????????????``charWriter.write(closeHTMLTags);
?????????????
????????????``String alteredContent = charWriter.toString();
????????????``response.setContentLength(alteredContent.length());
????????????``responseWriter.write(alteredContent);??????????
????????``}
????????
????``}
????``@Override
????``public
void
destroy() {
????????
????``}
}
**注意:**如果您使用 Servlet API 4.0 或更高版本,则只能覆盖doFilter()方法,因为 Servlet 4.0 实现了默认方法,因此您只能覆盖您需要的方法,而不是接口的所有方法。
您可以使用 String 类的正则表达式替换功能来更改每个页面的标题,例如:
1
2
3
4
5
String originalContent = wrapper.toString();
String regex =?``"<title>(.*?)</title>"``;
String replacement =?``"<title>$1 - CodeJava.net</title>"``;
originalContent = originalContent.replaceAll(regex, replacement);
这会将文本“CodeJava.net”附加到所有页面标题的末尾。
这是使用 Java 过滤器修改 HTTP 响应的示例。根据本教程中的代码,您可以根据需要进行调整。感谢您的阅读。