Springmvc ViewResolver设计实现过程解析

网友投稿 311 2022-11-15


Springmvc ViewResolver设计实现过程解析

总结:

ViewResolver 如果要改需要自己注入到容器中并进行修改, springmvc使用的是InterResourceViewResover

view不需要自己改,是springmvc根据return返回值选的

既然看到有ModelAndView直接跳转jsp的, 有请求转发的,有重定向的,这里整体是怎么设计的: (@ResponseBody的在此不作展开)

HiController:

@Controller

public class HiController {

@RequestMapping("/hi")

public ModelAndView getHi() {

ModelAndView mav = new ModelAndView("me");

return mav;

}

@RequestMapping("/yes")

public String forwardYes() {

return "forward:patch";

}

@RequestMapping("/no")

public String RedirectNo() {

return "redirect:patch";

}

@ResponseBody

@RequestMapping("/patch")

public String redirectNo() {

return "from forward or redirect request"; // 这种情况没有view,在这里不讨论

}

}

主要代码:

DispatcherServlet.doDispatch()里的:

DispatcherServlet.render方法:

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {

// Determine locale for request and apply it to the response.

Locale locale =

(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());

response.setLocale(locale);

View view;

String viewName = mv.getViewName();

if (viewName != null) {

// We need to resolve the view name.

view = resolveViewName(viewName, mv.getModelInternal(), locale, request); // 1

if (view == null) {

throw new ServletException("Could not resolve view with name '" + mv.getViewName() +

"' in servlet with name '" + getServletName() + "'");

}

}

else {

// No need to lookup: the ModelAndView object contains the actual View object.

view = mv.getView();

if (view == null) {

throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +

"View object in servlet with name '" + getServletName() + "'");

}

}

// Delegate to the View object for rendering.

if (loggehttp://r.isTraceEnabled()) {

logger.trace("Rendering view [" + viehttp://w + "] ");

}

try {

if (mv.getStatus() != null) {

response.setStatus(mv.getStatus().value());

}

view.render(mv.getModelInternal(), request, response); // 2

}

catch (Exception ex) {

if (logger.isDebugEnabled()) {

logger.debug("Error rendering view [" + view + "]", ex);

}

throw ex;

}

}

1. view = resolveViewName()会根据不同的路径生成不同的view, return mav 会返回JstlView, return "forward:/patch" 会返回InternalResourceView, return "direct:/patch" 会返回IndirectView

2. 不同的view去走不同的view.render(), 根据不同的view重写abstract void renderMergedOutputModel方法

再来看是如何生成不同的view:[/code][code]view = resolveViewName() 进去,走到

DiapatcherServlet先有ViewResolver这个,用来生成不同的view

protected View resolveViewName(String viewName, @Nullable Map model,

Locale locale, HttpServletRequest request) throws Exception {

if (this.viewResolvers != null) {

for (ViewResolver viewResolver : this.viewResolvers) {

View view = viewResolver.resolveViewName(viewName, locale);

if (view != null) {

return view;

}

}

}

return null;

}

ViewResolver 接口只有一个方法

public interface ViewResolver {

@Nullable

View resolveViewName(String viewName, Locale locale) throws Exception;

}

要配置具体的视图解析器,springMVC中使用的是InterResourceViewResover,InterResourceViewResover 和他的父类UrlBasedViewResolver中都没有重写resolveViewName方法,再上一层的父类AbstractCahingViewResolver实现了resolveViewName方法

AbstractCahingViewResolver:

@Override

@Nullable

public View resolveViewName(String viewName, Locale locale) throws Exception {

if (!isCache()) {

return createView(viewName, locale);

}

else {

Object cacheKey = getCacheKey(viewName, locale);

View view = this.viewAccessCache.get(cacheKey);

if (view == null) {

synchronized (this.viewCreationCache) {

view = this.viewCreationCache.get(cacheKey);

if (view == null) {

// Ask the subclass to create the View object.

view = createView(viewName, locale);

if (view == null && this.cacheUnresolved) {

view = UNRESOLVED_VIEW;

}

if (view != null && this.cacheFilter.filter(view, viewName, locale)) {

this.viewAccessCache.put(cacheKey, view);

this.viewCreationCache.put(cacheKey, view);

}

}

}

}

else {

if (logger.isTraceEnabled()) {

logger.trace(formatKey(cacheKey) + "served from cache");

}

}

return (view != UNRESOLVED_VIEW ? view : null);

}

}

InterResourceViewResover中没有createView方法,所以是调用它父类UrlBasedViewResolver的createView方法:

@Override

protected View createView(String viewName, Locale locale) throws Exception {

// If this resolver is not supposed to handle the given view,

// return null to pass on to the next resolver in the chain.

if (!canHandle(viewName, locale)) {

return null;

}

// Check for special "redirect:" prefix.

if (viewName.startsWith(REDIRECT_URL_PREFIX)) {

String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());

RedirectView view = new RedirectView(redirectUrl,

isRedirectContextRelative(), isRedirectHttp10Compatible());

String[] hosts = getRedirectHosts();

if (hosts != null) {

view.setHosts(hosts);

}

return applyLifecycleMethods(REDIRECT_URL_PREFIX, view); // return "direct:/patch"在这里构造view

}

// Check for special "forward:" prefix.

if (viewName.startsWith(FORWARD_URL_PREFIX)) {

String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());

InternalResourceView view = new InternalResourceView(forwardUrl);

return applyLifecycleMethods(FORWARD_URL_PREFIX, view); // return "forward:/patch" 在这里构造view

}

// Else fall back to superclass implementation: calling loadView.

return super.createView(viewName, locale); // return mav 在这里构造view

}

关于ViewResolver的代码执行顺序, 前面分析那么多,这里再打断点快速验证一下:

进DispatcherServlet的doDispatch看到就是这个解析器:

断点放在这里,

然后下一步:


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Intellij搭建springmvc常见问题解决方案
下一篇:项目为什么引入log4j而不是logback代码
相关文章

 发表评论

暂时没有评论,来抢沙发吧~