zoukankan      html  css  js  c++  java
  • Spring之SpringMVC的RequestToViewNameTranslator(源码)分析

    前言

       SpringMVC如果在处理业务的过程中发生了异常,这个时候是没有一个完整的ModelAndView对象返回的,它应该是怎么样处理呢?或者说应该怎么去获取一个视图然后去展示呢。下面就是要讲的RequestToViewNameTranslator。

    1.引出问题

      DispathcerServlet在处理完请求获取Me的lAndView之后就会获取相应的视图名称,然后渲染解析。这个是通过调用doDispatch()中的processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);方法来完成的,但是如果在处理这个请求的过程中发生了异常,并且这个异常类型不是ModelAndViewDefiningException类型的话,就会调用processHandlerException来处理一个异常,返回默认缺省的视图:

    	protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
    			Object handler, Exception ex) throws Exception {
    
    		// Check registered HandlerExceptionResolvers...
    		ModelAndView exMv = null;
    		for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {
    			exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);
    			if (exMv != null) {
    				break;
    			}
    		}
    		if (exMv != null) {
    			if (exMv.isEmpty()) {
    				return null;
    			}
    			// We might still need view name translation for a plain error model...
    			if (!exMv.hasView()) {
    				exMv.setViewName(getDefaultViewName(request));
    			}
    			if (logger.isDebugEnabled()) {
    				logger.debug("Handler execution resulted in exception - forwarding to resolved error view: " + exMv, ex);
    			}
    			WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
    			return exMv;
    		}
    
    		throw ex;
    	}
    

      在处理的过程中有这么一个需要注意exMv.setViewName(getDefaultViewName(request));如果没有提供的视图名字,那么胸膛会根据请求来获取一个默认的视图名。来看下具体获取默认视图的过程。

    protected String getDefaultViewName(HttpServletRequest request) throws Exception {
    		return this.viewNameTranslator.getViewName(request);
    	}
    

      原来是通过RequestToViewNameTranslator viewNameTranslator;的getViewName来获取视图名称的。终于讲到今天的主角RequestToViewNameTranslator接口及其的默认实现类DefaultRequestToViewNameTranslator。

     2.RequestToViewNameTranslator接口

    首先看源码,

    public interface RequestToViewNameTranslator {
    
    	String getViewName(HttpServletRequest request) throws Exception;
    
    }
    

      这个接口只有一个方法,就是根据请求对象获取一个视图名称。具体来讲就是在没有明确指定一个视图名称的时候,根据一个输入的请求获取一个逻辑视图名称。

    3.DefaultRequestToViewNameTranslator实现

    作为RequestToViewNameTranslator接口唯一的实现类,在没有扩展指定接口时候的时候,系统就会加载这个作为默认的实现。来看看具体时候涉及到的实现代码,

    public String getViewName(HttpServletRequest request) {
    		String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
    		return (this.prefix + transformPath(lookupPath) + this.suffix);
    	}
    
    
    	protected String transformPath(String lookupPath) {
    		String path = lookupPath;
    		if (this.stripLeadingSlash && path.startsWith(SLASH)) {
    			path = path.substring(1);
    		}
    		if (this.stripTrailingSlash && path.endsWith(SLASH)) {
    			path = path.substring(0, path.length() - 1);
    		}
    		if (this.stripExtension) {
    			path = StringUtils.stripFilenameExtension(path);
    		}
    		if (!SLASH.equals(this.separator)) {
    			path = StringUtils.replace(path, SLASH, this.separator);
    		}
    		return path;
    	}
    

      主要实现就是调用UrlPathHelper的getLookupPathForRequest的方法获取一个looup路径。transformPath方法主要是对获取的路径字符串再做个简单处理罢了。主要是UrlPathHelper的getLookupPathForRequest的实现:

    	public String getLookupPathForRequest(HttpServletRequest request) {
    		// Always use full path within current servlet context?
    		if (this.alwaysUseFullPath) {
    			return getPathWithinApplication(request);
    		}
    		// Else, use path within current servlet mapping if applicable
    		String rest = getPathWithinServletMapping(request);
    		if (!"".equals(rest)) {
    			return rest;
    		}
    		else {
    			return getPathWithinApplication(request);
    		}
    	}
    
    	public String getPathWithinApplication(HttpServletRequest request) {
    		String contextPath = getContextPath(request);
    		String requestUri = getRequestUri(request);
    		String path = getRemainingPath(requestUri, contextPath, true);
    		if (path != null) {
    			// Normal case: URI contains context path.
    			return (StringUtils.hasText(path) ? path : "/");
    		}
    		else {
    			return requestUri;
    		}
    	}
    	public String getPathWithinServletMapping(HttpServletRequest request) {
    		String pathWithinApp = getPathWithinApplication(request);
    		String servletPath = getServletPath(request);
    		String sanitizedPathWithinApp = getSanitizedPath(pathWithinApp);
    		String path;
    
    		// if the app container sanitized the servletPath, check against the sanitized version
    		if(servletPath.indexOf(sanitizedPathWithinApp) != -1) {
    			path = getRemainingPath(sanitizedPathWithinApp, servletPath, false);
    		}
    		else {
    			path = getRemainingPath(pathWithinApp, servletPath, false);
    		}
    
    		if (path != null) {
    			// Normal case: URI contains servlet path.
    			return path;
    		}
    		else {
    			// Special case: URI is different from servlet path.
    			String pathInfo = request.getPathInfo();
    			if (pathInfo != null) {
    				// Use path info if available. Indicates index page within a servlet mapping?
    				// e.g. with index page: URI="/", servletPath="/index.html"
    				return pathInfo;
    			}
    			if (!this.urlDecode) {
    				// No path info... (not mapped by prefix, nor by extension, nor "/*")
    				// For the default servlet mapping (i.e. "/"), urlDecode=false can
    				// cause issues since getServletPath() returns a decoded path.
    				// If decoding pathWithinApp yields a match just use pathWithinApp.
    				path = getRemainingPath(decodeInternal(request, pathWithinApp), servletPath, false);
    				if (path != null) {
    					return pathWithinApp;
    				}
    			}
    			// Otherwise, use the full servlet path.
    			return servletPath;
    		}
    	}
    
    	public String getPathWithinApplication(HttpServletRequest request) {
    		String contextPath = getContextPath(request);
    		String requestUri = getRequestUri(request);
    		String path = getRemainingPath(requestUri, contextPath, true);
    		if (path != null) {
    			// Normal case: URI contains context path.
    			return (StringUtils.hasText(path) ? path : "/");
    		}
    		else {
    			return requestUri;
    		}
    	}
    

      

      首先判断当前上下文的完整路径是否为空,如果不为空就会调用getPathWithinApplication()方法返回这个路径名字。如果为空的话,则首先获取到当前请求的映射的完整路径,如果路径不为空就返回这个路径,如果路径为空则返回当前请求的完整路径了。

  • 相关阅读:
    优先队列
    Problem W UVA 662 二十三 Fast Food
    UVA 607 二十二 Scheduling Lectures
    UVA 590 二十一 Always on the run
    UVA 442 二十 Matrix Chain Multiplication
    UVA 437 十九 The Tower of Babylon
    UVA 10254 十八 The Priest Mathematician
    UVA 10453 十七 Make Palindrome
    UVA 10163 十六 Storage Keepers
    UVA 1252 十五 Twenty Questions
  • 原文地址:https://www.cnblogs.com/zhangminghui/p/4957901.html
Copyright © 2011-2022 走看看