View Javadoc
1   /**
2    * Copyright By Grandsoft Company Limited.  
3    * 2012-11-9 上午09:54:49
4    */
5   package gboat2.base.plugin.servlet.filter;
6   
7   import gboat2.base.bridge.GboatAppConstants;
8   import gboat2.base.bridge.debug.AbstractDebugHook;
9   
10  import java.io.File;
11  import java.io.IOException;
12  import java.net.URLDecoder;
13  import java.util.regex.Matcher;
14  import java.util.regex.Pattern;
15  
16  import javax.servlet.Filter;
17  import javax.servlet.FilterChain;
18  import javax.servlet.FilterConfig;
19  import javax.servlet.ServletContext;
20  import javax.servlet.ServletException;
21  import javax.servlet.ServletRequest;
22  import javax.servlet.ServletResponse;
23  import javax.servlet.http.HttpServletRequest;
24  import javax.servlet.http.HttpServletResponse;
25  
26  import org.apache.commons.io.FileUtils;
27  import org.apache.commons.lang3.StringUtils;
28  import org.slf4j.Logger;
29  import org.slf4j.LoggerFactory;
30  
31  /**
32   * 静态资源调试的过滤器,如果启用了该过滤器,那么在修改了静态资源文件后无需重启 Tomcat 等应用服务器,就可以直接访问到最新的静态文件。<br>
33   * 使用方法:<pre>
34   * 1. 在 web.xml 中添加如下配置:
35   * <code>&lt;!-- 静态文件调试过滤器,注意顺序,必须在css过滤器(GboatCSSFilter)之后 --&gt;
36   * &lt;filter&gt;
37   *     &lt;filter-name&gt;staticFileDebugFilter&lt;/filter-name&gt;
38   *     &lt;filter-class&gt;gboat2.base.plugin.servlet.filter.StaticFileDebugFilter&lt;/filter-class&gt;
39   * &lt;/filter&gt;
40   * &lt;filter-mapping&gt;
41   *     &lt;filter-name&gt;staticFileDebugFilter&lt;/filter-name&gt;
42   *     &lt;url-pattern&gt;/static/*&lt;/url-pattern&gt;
43   * &lt;/filter-mapping&gt;
44   * </code>
45   * 2. 在 WEB-INF/config/debug.properties 中添加如下配置:
46   * <code># 是否开启静态文件的调试模式
47   * resource.file.devMode=true
48   * # 需要开启调试模式的 Bundle 列表,多值之间用逗号分隔,不区分大小写
49   * debug.bundles=glodon.gem.expert,glodon.gem.extract,glodon.gem.voice,glodon.gbmp.attachment
50   * # 开启调试的所有 Bundle 源代码所在的目录
51   * projects.root.path=F:/myEclipse_workspace
52   * # 开启调试的 Bundle 与其源代码的映射关系,规则为 bundelNameRegex_1@location_1,bundelNameRegex_2@location_2,...,bundelNameRegex_N@location_N
53   * bundleName.path.mapping.rules=^glodon\\.gem\\..*@gbp-lyg, ^glodon\\.gbmp\\..*@G2_Bundles
54   * </code></pre>
55   * @date 2012-11-9
56   * @author tanxw
57   * @author <a href="mailto:[email protected]">何明旺</a>
58   * @since 1.0
59   * @deprecated 已由 {@link gboat2.base.plugin.struts.dispatcher.GboatStaticContentLoader} 取代
60   */
61  public class StaticFileDebugFilter extends AbstractDebugHook implements Filter {
62  
63  	private Logger logger = LoggerFactory.getLogger(StaticFileDebugFilter.class);
64  
65  	// private static final String PROPERTY_STATIC_FILE_PROXY_REDIRECT = "static.file.proxy.redirect";
66  
67  	// private static final String CONTEXT_ROOT_PATH = "/debug";
68  
69  	// 是否采用反向代理进行重定向
70  	// private boolean proxyRedirect = false;
71  
72  	private ServletContext servletContext;
73  
74      @Override
75      public void init(FilterConfig filterConfig) throws ServletException {
76          servletContext = filterConfig.getServletContext();
77          initConfig(filterConfig.getServletContext().getResourceAsStream(CONFIG_FILE));
78          // try {
79          //      // 是否启用反向代理进行重定向
80          //      proxyRedirect = "true".equals(prop.getProperty(PROPERTY_STATIC_FILE_PROXY_REDIRECT));
81          // } catch (Exception e) {
82          //      logger.warn("调试配置文件" + CONFIG_FILE + "读取出错, static.file.proxy.redirect", e);
83          // }
84      }
85      
86  	@Override
87  	public void destroy() {
88  	}
89  
90  	/**
91  	 * 重定向到 nginx 的上下文,如 : "/debug/trunk/gboat2.web/src/main/resources"
92  	 */
93  	// private String getDebugContextPath(String bundle) {
94  	//     return CONTEXT_ROOT_PATH + getResourcesContextPath(bundle);
95  	// }
96  
97  	@Override
98  	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
99  	        throws IOException, ServletException {
100 		HttpServletRequest req = (HttpServletRequest) request;
101 		HttpServletResponse res = (HttpServletResponse) response;
102 
103         if (devMode) { // 如果是开发模式
104             String reqURL = StringUtils.removeStart(req.getRequestURI(), req.getContextPath());
105             Matcher matcher = Pattern.compile("^/static/(.+?)/.*$").matcher(reqURL);
106             if (matcher.matches()) { // 如果请求的是bundle中的静态资源
107                 String bundle = matcher.group(1);
108                 if (isBundleDebugEnabled(bundle)) {
109                     hook(req, res, bundle, reqURL);
110                     return;// 停止传递拦截器链
111                 }
112             }
113         }
114 
115 		chain.doFilter(request, response);
116 	}
117 
118 	// 做真的的拦截
119 	private void hook(HttpServletRequest request, HttpServletResponse response, String bundle, String reqURL)
120 	        throws IOException {
121 		// if (proxyRedirect) {
122 		//    response.sendRedirect(getDebugContextPath(bundle) + reqURL);
123 		// } else {
124 		reqURL = URLDecoder.decode(reqURL, GboatAppConstants.ENCODING_UTF8);
125 		String pathname = getResourcesAbsolutPath(bundle) + reqURL;
126 		logger.debug("use debug file : {}", pathname);
127 		File file = new File(pathname);
128 		if (file.exists()) {
129 			String contenType = servletContext.getMimeType(pathname);
130 			if (null != contenType) {
131 				response.setContentType(contenType);
132 			}
133 			response.setContentLength((int) file.length());
134 			response.setHeader("Cache-Control", "no-cache");
135 			response.setHeader("Pragma", "no-cache");
136 			response.setHeader("Expires", "-1");
137 			FileUtils.copyFile(file, response.getOutputStream());
138 		} else {
139 			response.sendError(HttpServletResponse.SC_NOT_FOUND, pathname);
140 		}
141 		// }
142 	}
143 }