/* * Copyright 2007-2009 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.paoding.rose.web; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import javax.servlet.http.HttpServletRequest; import net.paoding.rose.web.annotation.ReqMethod; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.web.util.WebUtils; /** * @author 王志亮 [qieqie.wang@gmail.com] */ public class RequestPath { private static Log logger = LogFactory.getLog(RequestPath.class); private ReqMethod method; private String uri; // = contextPath + ctxpath + pathInfo private String ctxpath; // by servlet container private String rosePath; // = modulePath + controllerPath + actionPath private String modulePath; // private String controllerPathInfo; // private String controllerPath; private String actionPath; private Dispatcher dispatcher; public RequestPath(ReqMethod method, String uri, String ctxpath, Dispatcher dispatcher) { this.setMethod(method); setUri(uri); setCtxpath(ctxpath); setDispatcher(dispatcher); setRosePath(uri.substring(ctxpath.length())); } public RequestPath(HttpServletRequest request) { // method setMethod(parseMethod(request)); // ctxpath setCtxpath(request.getContextPath()); String invocationCtxpath = null; // 对include而言,invocationCtxPath指的是被include的ctxpath // dispather, uri, ctxpath String uri; if (WebUtils.isIncludeRequest(request)) { setDispatcher(Dispatcher.INCLUDE); uri = (String) request.getAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE); invocationCtxpath = ((String) request .getAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE)); setRosePath((String) request.getAttribute(WebUtils.INCLUDE_SERVLET_PATH_ATTRIBUTE)); } else { uri = request.getRequestURI(); this.setRosePath(request.getServletPath()); if (request.getAttribute(WebUtils.FORWARD_REQUEST_URI_ATTRIBUTE) == null) { this.setDispatcher(Dispatcher.REQUEST); } else { this.setDispatcher(Dispatcher.FORWARD); } } if (uri.startsWith("http://") || uri.startsWith("https://")) { int start = uri.indexOf('/', 9); if (start == -1) { uri = ""; } else { uri = uri.substring(start); } } if (uri.indexOf('%') != -1) { try { String encoding = request.getCharacterEncoding(); if (encoding == null || encoding.length() == 0) { encoding = "UTF-8"; } uri = URLDecoder.decode(uri, encoding); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } this.setUri(uri); // 记录到requestPath的ctxpath值在include的情况下是invocationCtxpath if (getCtxpath().length() <= 1) { setRosePath(getUri()); } else { setRosePath(getUri().substring( (invocationCtxpath == null ? getCtxpath() : invocationCtxpath).length())); } } private ReqMethod parseMethod(HttpServletRequest request) { ReqMethod reqMethod = ReqMethod.parse(request.getMethod()); if (reqMethod != null && reqMethod.equals(ReqMethod.POST)) { // 为什么不用getParameter: // 1、使_method只能在queryString中,不能在body中 // 2、getParameter会导致encoding,使用UTF-8? 尽量不做这个假设 String queryString = request.getQueryString(); if (queryString != null) { boolean methodChanged = false; int start = queryString.indexOf("_method="); if (start == 0 || (start > 0 && queryString.charAt(start - 1) == '&')) { int end = queryString.indexOf('&', start); String method = queryString.substring(start + "_method=".length(),// end > 0 ? end : queryString.length()); ReqMethod _reqMethod = ReqMethod.parse(method); if (_reqMethod != null) { if (logger.isDebugEnabled()) { logger.debug("override http method from POST to " + _reqMethod); } reqMethod = _reqMethod; methodChanged = true; } } if (!methodChanged) { int inBodyStart = queryString.indexOf("_method_in_body=1"); if (inBodyStart == 0 || (inBodyStart > 0 && queryString.charAt(inBodyStart - 1) == '&')) { String method = request.getParameter("_method"); ReqMethod _reqMethod = ReqMethod.parse(method); if (_reqMethod != null) { if (logger.isDebugEnabled()) { logger.debug("override http method from POST to " + _reqMethod); } reqMethod = _reqMethod; methodChanged = true; } } } } } return reqMethod; } public boolean isIncludeRequest() { return dispatcher == Dispatcher.INCLUDE; } public boolean isForwardRequest() { return dispatcher == Dispatcher.FORWARD; } public void setDispatcher(Dispatcher dispatcher) { this.dispatcher = dispatcher; } public Dispatcher getDispatcher() { return dispatcher; } public ReqMethod getMethod() { return method; } public void setMethod(ReqMethod method) { this.method = method; } public String getUri() { return uri; } public void setUri(String uri) { this.uri = uri; } public String getCtxpath() { return ctxpath; } public void setCtxpath(String ctxpath) { this.ctxpath = ctxpath; } public String getRosePath() { return rosePath; } public void setRosePath(String rosePath) { // 如果是"/",也转化为"" if (rosePath.equals("") || rosePath.equals("/")) { this.rosePath = ""; return; } // 只判断一次,如果有以request请求以'//'结尾的,rose肯定会映射失败,但是rose不会为了兼容做这个事情 if (rosePath.charAt(rosePath.length() - 1) == '/') { rosePath = rosePath.substring(0, rosePath.length() - 1); } this.rosePath = rosePath; } public String getModulePath() { return modulePath; } public void setModulePath(String modulePath) { this.modulePath = modulePath; } public String getControllerPathInfo() { if (controllerPathInfo == null) { controllerPathInfo = rosePath.substring(modulePath.length()); } return controllerPathInfo; } public String getControllerPath() { return controllerPath; } public void setControllerPath(String controllerPath) { this.controllerPath = controllerPath; } public String getActionPath() { return actionPath; } public void setActionPath(String actionPath) { this.actionPath = actionPath; } @Override public String toString() { return "ctxpath=" + ctxpath + "; pathInfo=" + rosePath + "; modulePath=" + modulePath + "; controllerPath=" + controllerPath + "; actionPath=" + actionPath; } }