package org.nutz.mvc; import java.io.IOException; import java.util.HashSet; import java.util.Set; 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.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.nutz.lang.Lang; import org.nutz.lang.Strings; import org.nutz.lang.util.Context; import org.nutz.log.Log; import org.nutz.log.Logs; import org.nutz.mvc.config.FilterNutConfig; /** * 同 JSP/Serlvet 容器的挂接点 * * @author zozoh(zozohtnt@gmail.com) * @author juqkai(juqkai@gmail.com) * @author wendal(wendal1985@gmail.com) */ public class NutFilter implements Filter { private static final Log log = Logs.get(); protected ActionHandler handler; private static final String IGNORE = "^.+\\.(jsp|png|gif|jpg|js|css|jspx|jpeg|swf|ico)$"; protected Pattern ignorePtn; private String selfName; protected SessionProvider sp; private NutFilter2 proxyFilter;//代理老版本的Filter /** * 需要排除的路径前缀 */ protected Pattern exclusionsPrefix; /** * 需要排除的后缀名 */ protected Pattern exclusionsSuffix; /** * 需要排除的固定路径 */ protected Set<String> exclusionPaths; public void init(FilterConfig conf) throws ServletException { if ("true".equals(Strings.sNull(conf.getInitParameter("skip-mode"), "false").toLowerCase())) { log.infof("NutFilter[%s] run as skip-mode", conf.getFilterName()); proxyFilter = new NutFilter2(); return; } log.infof("NutFilter[%s] starting ...", conf.getFilterName()); Mvcs.setServletContext(conf.getServletContext()); this.selfName = conf.getFilterName(); Mvcs.set(selfName, null, null); FilterNutConfig config = new FilterNutConfig(conf); Mvcs.setNutConfig(config); handler = new ActionHandler(config); String regx = Strings.sNull(config.getInitParameter("ignore"), IGNORE); if (!"null".equalsIgnoreCase(regx)) { ignorePtn = Pattern.compile(regx, Pattern.CASE_INSENSITIVE); } String exclusions = config.getInitParameter("exclusions"); if (exclusions != null) { String[] tmps = Strings.splitIgnoreBlank(exclusions); Set<String> prefix = new HashSet<String>(); Set<String> suffix = new HashSet<String>(); Set<String> paths = new HashSet<String>(); for (String tmp : tmps) { tmp = tmp.trim().intern(); if (tmp.length() > 1) { if (tmp.startsWith("*")) { prefix.add(tmp.substring(1)); continue; } else if (tmp.endsWith("*")) { suffix.add(tmp.substring(0, tmp.length() - 1)); continue; } } paths.add(tmp); } if (prefix.size() > 0) { exclusionsPrefix = Pattern.compile("^("+Lang.concat("|", prefix)+")", Pattern.CASE_INSENSITIVE); log.info("exclusionsPrefix = " + exclusionsPrefix); } if (suffix.size() > 0) { exclusionsSuffix = Pattern.compile("^("+Lang.concat("|", suffix)+")", Pattern.CASE_INSENSITIVE); log.info("exclusionsSuffix = " + exclusionsSuffix); } if (paths.size() > 0) { exclusionPaths = paths; log.info("exclusionsPath = " + exclusionPaths); } } sp = config.getSessionProvider(); } public void destroy() { if (proxyFilter != null) return; Mvcs.resetALL(); Mvcs.set(selfName, null, null); if (handler != null) handler.depose(); Mvcs.setServletContext(null); Mvcs.close(); } /** * 过滤请求. 过滤顺序(ignorePtn,exclusionsSuffix,exclusionsPrefix,exclusionPaths) * @param matchUrl * @return * @throws IOException * @throws ServletException */ protected boolean isExclusion(String matchUrl) throws IOException, ServletException { if (ignorePtn != null && ignorePtn.matcher(matchUrl).find()) { return true; } if (exclusionsSuffix != null) { if (exclusionsSuffix.matcher(matchUrl).find()) { return true; } } if (exclusionsPrefix != null) { if (exclusionsPrefix.matcher(matchUrl).find()) { return true; } } if (exclusionPaths != null) { for (String exclusionPath : exclusionPaths) { if (exclusionPath.equals(matchUrl)) { return true; } } } return false; } public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { if (proxyFilter != null) { proxyFilter.doFilter(req, resp, chain); return; } HttpServletRequest request = (HttpServletRequest)req; HttpServletResponse response = (HttpServletResponse)resp; RequestPath path = Mvcs.getRequestPathObject(request); String matchUrl = path.getUrl(); String preName = Mvcs.getName(); Context preContext = Mvcs.resetALL(); try { if (sp != null) req = sp.filter(request, response, Mvcs.getServletContext()); Mvcs.set(this.selfName, request, response); if (!isExclusion(matchUrl)) { if (handler.handle(request, response)) return; } nextChain(request, response, chain); } finally { Mvcs.resetALL(); //仅当forward/incule时,才需要恢复之前设置 if (null != (request.getAttribute("javax.servlet.forward.request_uri"))) { if (preName != null) Mvcs.set(preName, request, response); if (preContext != null) Mvcs.ctx.reqThreadLocal.set(preContext); } } } protected void nextChain(HttpServletRequest req, HttpServletResponse resp, FilterChain chain) throws IOException, ServletException { // 更新 Request 必要的属性 Mvcs.updateRequestAttributes((HttpServletRequest) req); // 本过滤器没有找到入口函数,继续其他的过滤器 chain.doFilter(req, resp); } }