深入解析Java的Servlet过滤器的原理及其应用
1.Servlet过滤器
package com.zj.sample; 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; public class SimpleFilter1 implements Filter { @SuppressWarnings("unused") private FilterConfig filterConfig; public void init(FilterConfig config) throws ServletException { this.filterConfig = config; } public void doFilter(ServletRequest request,FilterChain chain) { try { System.out.println("Within SimpleFilter1:Filtering the Request..."); chain.doFilter(request,response);// 把处理发送到下一个过滤器 System.out .println("Within SimpleFilter1:Filtering the Response..."); } catch (IOException ioe) { ioe.printStackTrace(); } catch (ServletException se) { se.printStackTrace(); } } public void destroy() { this.filterConfig = null; } } package com.zj.sample; 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; public class SimpleFilter2 implements Filter { @SuppressWarnings("unused") private FilterConfig filterConfig; public void init(FilterConfig config) throws ServletException { this.filterConfig = config; } public void doFilter(ServletRequest request,FilterChain chain) { try { System.out.println("Within SimpleFilter2:Filtering the Request..."); chain.doFilter(request,response); // 把处理发送到下一个过滤器 System.out.println("Within SimpleFilter2:Filtering the Response..."); } catch (IOException ioe) { ioe.printStackTrace(); } catch (ServletException se) { se.printStackTrace(); } } public void destroy() { this.filterConfig = null; } } <filter> <filter-name>filter1</filter-name> <filter-class>com.zj.sample.SimpleFilter1</filter-class> </filter> <filter-mapping> <filter-name>filter1</filter-name> <url-pattern>/*</url-pattern>//为所有的访问做过滤 </filter-mapping> <filter> <filter-name>filter2</filter-name> <filter-class>com.zj.sample.SimpleFilter2</filter-class> </filter> <filter-mapping> <filter-name>filter2</filter-name> <url-pattern>/*</url-pattern>//为所有的访问做过滤 </filter-mapping> Within SimpleFilter1:Filtering the Request... Within SimpleFilter2:Filtering the Request... Within SimpleFilter2:Filtering the Response... Within SimpleFilter1:Filtering the Response... 4.报告过滤器 package com.zj.sample; import java.io.IOException; import java.util.Date; 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.HttpServletRequest; public class SimpleFilter1 implements Filter { @SuppressWarnings("unused") private FilterConfig filterConfig; public void init(FilterConfig config) throws ServletException { this.filterConfig = config; } public void doFilter(ServletRequest request,FilterChain chain) { try { System.out.println("Within SimpleFilter1:Filtering the Request..."); HttpServletRequest req = (HttpServletRequest) request; System.out.println(req.getRemoteHost() + " tried to access " + req.getRequestURL() + " on " + new Date() + "."); chain.doFilter(request,response); System.out.println("Within SimpleFilter1:Filtering the Response..."); } catch (IOException ioe) { ioe.printStackTrace(); } catch (ServletException se) { se.printStackTrace(); } } public void destroy() { this.filterConfig = null; } } Within SimpleFilter1:Filtering the Request... 0:0:0:0:0:0:0:1 tried to access [url]http://localhost:8080/Test4Jsp/login.jsp[/url] on Sun Mar 04 17:01:37 CST 2007. Within SimpleFilter2:Filtering the Request... Within SimpleFilter2:Filtering the Response... Within SimpleFilter1:Filtering the Response... 5.访问时的过滤器(在过滤器中使用servlet初始化参数) package com.zj.sample; import java.io.IOException; import java.text.DateFormat; import java.util.Calendar; import java.util.GregorianCalendar; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; public class SimpleFilter2 implements Filter { @SuppressWarnings("unused") private FilterConfig config; private ServletContext context; private int startTime,endTime; private DateFormat formatter; public void init(FilterConfig config) throws ServletException { this.config = config; context = config.getServletContext(); formatter = DateFormat.getDateTimeInstance(DateFormat.MEDIUM,DateFormat.MEDIUM); try { startTime = Integer.parseInt(config.getInitParameter("startTime"));// web.xml endTime = Integer.parseInt(config.getInitParameter("endTime"));// web.xml } catch (NumberFormatException nfe) { // Malformed or null // Default: access at or after 10 p.m. but before 6 a.m. is // considered unusual. startTime = 22; // 10:00 p.m. endTime = 6; // 6:00 a.m. } } public void doFilter(ServletRequest request,FilterChain chain) { try { System.out.println("Within SimpleFilter2:Filtering the Request..."); HttpServletRequest req = (HttpServletRequest) request; GregorianCalendar calendar = new GregorianCalendar(); int currentTime = calendar.get(Calendar.HOUR_OF_DAY); if (isUnusualTime(currentTime,startTime,endTime)) { context.log("WARNING: " + req.getRemoteHost() + " accessed " + req.getRequestURL() + " on " + formatter.format(calendar.getTime())); // The log file is under <CATALINA_HOME>/logs.One log per day. } chain.doFilter(request,response); System.out .println("Within SimpleFilter2:Filtering the Response..."); } catch (IOException ioe) { ioe.printStackTrace(); } catch (ServletException se) { se.printStackTrace(); } } public void destroy() {} // Is the current time between the start and end // times that are marked as abnormal access times? private boolean isUnusualTime(int currentTime,int startTime,int endTime) { // If the start time is less than the end time (i.e.,// they are two times on the same day),then the // current time is considered unusual if it is // between the start and end times. if (startTime < endTime) { return ((currentTime >= startTime) && (currentTime < endTime)); } // If the start time is greater than or equal to the // end time (i.e.,the start time is on one day and // the end time is on the next day),then the current // time is considered unusual if it is NOT between // the end and start times. else { return (!isUnusualTime(currentTime,endTime,startTime)); } } } 6.禁止站点过滤器 public void doFilter(ServletRequest request,FilterChain chain) throws ServletException,IOException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse res = (HttpServletResponse) response; if (isUnusualCondition(req)) { res.sendRedirect("http://www.somesite.com"); } else { chain.doFilter(req,res); } } 下例是一个禁止站点过滤器,如果不希望某些站点访问你的网站,你可以在web.xml的param-value中列出它的站点,然后应用上面的原理跳出常规过滤,给出禁止访问的页面。 package com.zj.sample; import java.io.IOException; import java.io.PrintWriter; import java.net.MalformedURLException; import java.net.URL; import java.util.HashSet; import java.util.StringTokenizer; 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.HttpServletRequest; public class BannedAccessFilter implements Filter { private HashSet<String> bannedSiteTable; /** * Deny access if the request comes from a banned site or is referred here * by a banned site. */ public void doFilter(ServletRequest request,IOException { System.out.println("Within BannedAccessFilter:Filtering the Request..."); HttpServletRequest req = (HttpServletRequest) request; String requestingHost = req.getRemoteHost(); String referringHost = getReferringHost(req.getHeader("Referer")); String bannedSite = null; boolean isBanned = false; if (bannedSiteTable.contains(requestingHost)) { bannedSite = requestingHost; isBanned = true; } else if (bannedSiteTable.contains(referringHost)) { bannedSite = referringHost; isBanned = true; } if (isBanned) { showWarning(response,bannedSite); } else { chain.doFilter(request,response); } System.out.println("Within BannedAccessFilter:Filtering the Response..."); } /** * Create a table of banned sites based on initialization parameters. * Remember that version 2.3 of the servlet API mandates the use of the * Java 2 Platform. Thus,it is safe to use HashSet (which determines * whether a given key exists) rather than the clumsier Hashtable * (which has a value for each key). */ public void init(FilterConfig config) throws ServletException { bannedSiteTable = new HashSet<String>(); String bannedSites = config.getInitParameter("bannedSites"); // Default token set: white space. StringTokenizer tok = new StringTokenizer(bannedSites); while (tok.hasMoreTokens()) { String bannedSite = tok.nextToken(); bannedSiteTable.add(bannedSite); System.out.println("Banned " + bannedSite); } } public void destroy() {} private String getReferringHost(String refererringURLString) { try { URL referringURL = new URL(refererringURLString); return (referringURL.getHost()); } catch (MalformedURLException mue) { // Malformed or null return (null); } } // Replacement response that is returned to users // who are from or referred here by a banned site. private void showWarning(ServletResponse response,String bannedSite) throws ServletException,IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); String docType = "<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 " + "Transitional//EN">n"; out.println(docType + "<HTML>n" + "<HEAD><TITLE>Access Prohibited</TITLE></HEAD>n" + "<BODY BGCOLOR="WHITE">n" + "<H1>Access Prohibited</H1>n" + "Sorry,access from or via " + bannedSite + "n" + "is not allowed.n" + "</BODY></HTML>"); } } <filter> <filter-name>BannedAccessFilter</filter-name> <filter-class>com.zj.sample.BannedAccessFilter</filter-class> <init-param> <param-name>bannedSites</param-name> <param-value> [url]www.competingsite.com[/url] [url]www.bettersite.com[/url] [url]www.moreservlets.com[/url] 127.0.0.1//我们测试这个 </param-value> </init-param> </filter> <filter-mapping> <filter-name>BannedAccessFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> [url]http://localhost:8080/Test4Jsp/[/url] 7.替换过滤器 package com.zj.sample; import java.io.CharArrayWriter; import java.io.PrintWriter; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; /** * A response wrapper that takes everything the client would normally * output and saves it in one big character array. */ public class CharArrayWrapper extends HttpServletResponseWrapper { private CharArrayWriter charWriter; /** * Initializes wrapper. * <P> * First,this constructor calls the parent constructor. That call *is crucial so that the response is stored and thus setHeader,*setStatus,addCookie,and so forth work normally. * <P> * Second,this constructor creates a CharArrayWriter that will * be used to accumulate the response. */ public CharArrayWrapper(HttpServletResponse response) { super(response); charWriter = new CharArrayWriter(); } /** * When servlets or JSP pages ask for the Writer,don't give them * the real one. Instead,give them a version that writes into * the character array. * The filter needs to send the contents of the array to the * client (perhaps after modifying it). */ public PrintWriter getWriter() { return (new PrintWriter(charWriter)); } /** * Get a String representation of the entire buffer. * <P> * Be sure <B>not</B> to call this method multiple times on the same * wrapper. The API for CharArrayWriter does not guarantee that it * "remembers" the previous value,so the call is likely to make * a new String every time. */ public String toString() { return (charWriter.toString()); } /** Get the underlying character array. */ public char[] toCharArray() { return (charWriter.toCharArray()); } } package com.zj.sample; import java.io.IOException; import java.io.PrintWriter; 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; /** * Filter that replaces all occurrences of a given string with a * replacement. * This is an abstract class: you <I>must</I> override the getTargetString * and getReplacementString methods in a subclass. * The first of these methods specifies the string in the response * that should be replaced. The second of these specifies the string * that should replace each occurrence of the target string. */ public abstract class ReplaceFilter implements Filter { private FilterConfig config; public void doFilter(ServletRequest request,IOException { CharArrayWrapper responseWrapper = new CharArrayWrapper( (HttpServletResponse) response); // Invoke resource,accumulating output in the wrapper. chain.doFilter(request,responseWrapper); // Turn entire output into one big String. String responseString = responseWrapper.toString(); // In output,replace all occurrences of target string with replacement // string. responseString = FilterUtils.replace(responseString,getTargetString(),getReplacementString()); // Update the Content-Length header. updateHeaders(response,responseString); PrintWriter out = response.getWriter(); out.write(responseString); } /** * Store the FilterConfig object in case subclasses want it. */ public void init(FilterConfig config) throws ServletException { this.config = config; } protected FilterConfig getFilterConfig() { return (config); } public void destroy() { } /** * The string that needs replacement. *Override this method in your subclass. */ public abstract String getTargetString(); /** * The string that replaces the target. Override this method in * your subclass. */ public abstract String getReplacementString(); /** * Updates the response headers. This simple version just sets *the Content-Length header,assuming that we are using a *character set that uses 1 byte per character. * For other character sets,override this method to use * different logic or to give up on persistent HTTP connections. * In this latter case,have this method set the Connection header * to "close". */ public void updateHeaders(ServletResponse response,String responseString) { response.setContentLength(responseString.length()); } } package com.zj.sample; /** * Small utility to assist with response wrappers that return strings. */ public class FilterUtils { /** * Change all occurrences of orig in mainString to replacement. */ public static String replace(String mainString,String orig,String replacement) { String result = ""; int oldIndex = 0; int index = 0; int origLength = orig.length(); while ((index = mainString.indexOf(orig,oldIndex)) != -1) { result = result + mainString.substring(oldIndex,index) + replacement; oldIndex = index + origLength; } result = result + mainString.substring(oldIndex); return (result); } } 7.3.2实现一个字符替换过滤器 假设百度收购了google(只是假设),现在所有的页面上凡是出现google字样的文字都必须替换为百度!ReplaceSiteNameFilter.java继承上文ReplaceFilter.java来实现这一功能。 ReplaceSiteNameFilter.java package com.zj.sample; public class ReplaceSiteNameFilter extends ReplaceFilter { public String getTargetString() { return ("google.com.cn"); } public String getReplacementString() { return ("baidu.com"); } } <filter> <filter-name>ReplaceSiteNameFilter</filter-name> <filter-class>com.zj.sample.ReplaceSiteNameFilter</filter-class> </filter> <filter-mapping> <filter-name>ReplaceSiteNameFilter</filter-name> <url-pattern>/login.jsp</url-pattern> </filter-mapping> 过滤后 8.压缩过滤器 package com.zj.sample; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.util.zip.GZIPOutputStream; 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.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Filter that compresses output with gzip (assuming that browser supports * gzip). */ public class CompressionFilter implements Filter { private FilterConfig config; /** * If browser does not support gzip,invoke resource normally. If browser * <I>does</I> support gzip,set the Content-Encoding response header and * invoke resource with a wrapped response that collects all the output. * Extract the output and write it into a gzipped byte array. Finally,write * that array to the client's output stream. */ public void doFilter(ServletRequest request,IOException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse res = (HttpServletResponse) response; if (!isGzipSupported(req)) { // Invoke resource normally. chain.doFilter(req,res); } else { // Tell browser we are sending it gzipped data. res.setHeader("Content-Encoding","gzip"); // Invoke resource,accumulating output in the wrapper. CharArrayWrapper responseWrapper = new CharArrayWrapper(res); chain.doFilter(req,responseWrapper); // Get character array representing output. char[] responseChars = responseWrapper.toCharArray(); // Make a writer that compresses data and puts it into a byte array. ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); GZIPOutputStream zipOut = new GZIPOutputStream(byteStream); OutputStreamWriter tempOut = new OutputStreamWriter(zipOut); // Compress original output and put it into byte array. tempOut.write(responseChars); // Gzip streams must be explicitly closed. tempOut.close(); // Update the Content-Length header. res.setContentLength(byteStream.size()); // Send compressed result to client. OutputStream realOut = res.getOutputStream(); byteStream.writeTo(realOut); } } /** * Store the FilterConfig object in case subclasses want it. */ public void init(FilterConfig config) throws ServletException { this.config = config; } protected FilterConfig getFilterConfig() { return (config); } public void destroy() {} private boolean isGzipSupported(HttpServletRequest req) { String browserEncodings = req.getHeader("Accept-Encoding"); return ((browserEncodings != null) && (browserEncodings.indexOf("gzip") != -1)); } } LongServlet.java package com.zj.sample; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Servlet with <B>long</B> output. Used to test the effect of the compression * filter of Chapter 9. */ public class LongServlet extends HttpServlet { public void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); String docType = "<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 " + "Transitional//EN">n"; String title = "Long Page"; out.println(docType + "<HTML>n" + "<HEAD><TITLE>" + title + "</TITLE></HEAD>n" + "<BODY BGCOLOR="#FDF5E6">n" + "<H1 ALIGN="CENTER">" + title + "</H1>n"); String line = "Blah,blah,blah. " + "Yadda,yadda,yadda."; for (int i = 0; i < 10000; i++) { out.println(line); } out.println("</BODY></HTML>"); } } <filter> <filter-name>CompressionFilter</filter-name> <filter-class>com.zj.sample.CompressionFilter</filter-class> </filter> <filter-mapping> <filter-name>CompressionFilter</filter-name> <servlet-name>LongServlet</servlet-name> </filter-mapping> <servlet> <servlet-name>LongServlet</servlet-name> <servlet-class>com.zj.sample.LongServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>LongServlet</servlet-name> <url-pattern>/LongServlet</url-pattern> </servlet-mapping> (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |