我希望有人已经写了这个:
可以使用正则表达式搜索/替换模式配置的servlet过滤器,并将其应用于HTML输出。
这样的事情存在吗?
我找不到一个,所以写了一个:
RegexFilter.java
package com.example; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Pattern; 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.http.HttpServletResponse; /** * Applies search and replace patterns. To initialize this filter, the * param-names should be "search1", "replace1", "search2", "replace2", etc. */ public final class RegexFilter implements Filter { private List<Pattern> searchPatterns; private List<String> replaceStrings; /** * Finds the search and replace strings in the configuration file. Looks for * matching searchX and replaceX parameters. */ public void init(FilterConfig filterConfig) { Map<String, String> patternMap = new HashMap<String, String>(); // Walk through the parameters to find those whose names start with // search Enumeration<String> names = (Enumeration<String>) filterConfig.getInitParameterNames(); while (names.hasMoreElements()) { String name = names.nextElement(); if (name.startsWith("search")) { patternMap.put(name.substring(6), filterConfig.getInitParameter(name)); } } this.searchPatterns = new ArrayList<Pattern>(patternMap.size()); this.replaceStrings = new ArrayList<String>(patternMap.size()); // Walk through the parameters again to find the matching replace params names = (Enumeration<String>) filterConfig.getInitParameterNames(); while (names.hasMoreElements()) { String name = names.nextElement(); if (name.startsWith("replace")) { String searchString = patternMap.get(name.substring(7)); if (searchString != null) { this.searchPatterns.add(Pattern.compile(searchString)); this.replaceStrings.add(filterConfig.getInitParameter(name)); } } } } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // Wrap the response in a wrapper so we can get at the text after calling the next filter PrintWriter out = response.getWriter(); CharResponseWrapper wrapper = new CharResponseWrapper((HttpServletResponse) response); chain.doFilter(request, wrapper); // Extract the text from the completed servlet and apply the regexes String modifiedHtml = wrapper.toString(); for (int i = 0; i < this.searchPatterns.size(); i++) { modifiedHtml = this.searchPatterns.get(i).matcher(modifiedHtml).replaceAll(this.replaceStrings.get(i)); } // Write our modified text to the real response response.setContentLength(modifiedHtml.getBytes().length); out.write(modifiedHtml); out.close(); } public void destroy() { this.searchPatterns = null; this.replaceStrings = null; } }
CharResponseWrapper.java
package com.example; import java.io.CharArrayWriter; import java.io.PrintWriter; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; /** * Wraps the response object to capture the text written to it. */ public class CharResponseWrapper extends HttpServletResponseWrapper { private CharArrayWriter output; public CharResponseWrapper(HttpServletResponse response) { super(response); this.output = new CharArrayWriter(); } public String toString() { return output.toString(); } public PrintWriter getWriter() { return new PrintWriter(output); } }
示例web.xml
<web-app> <filter> <filter-name>RegexFilter</filter-name> <filter-class>com.example.RegexFilter</filter-class> <init-param><param-name>search1</param-name><param-value><![CDATA[(<\s*a\s[^>]*)(?<=\s)target\s*=\s*(?:'_parent'|"_parent"|_parent|'_top'|"_top"|_top)]]></param-value></init-param> <init-param><param-name>replace1</param-name><param-value>$1</param-value></init-param> </filter> <filter-mapping> <filter-name>RegexFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>