JavaWeb-19-springmvc视图解析

Table of Contents

一:转发和重定向

1:转发:forward

2:重定向

二:视图解析

1:任何方法的返回值,都会包装ModelAndView对象

2:processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

3:调用render(mv, request, response);渲染页面

4:View与ViewResolver的关系;

5:根据视图名得到View对象

6:视图渲染

三:视图

1:常用视图

2:常用视图解析器

3:使用jstlView视图快速支持国际化功能;

4:若希望直接响应通过 SpringMVC 渲染的页面,可以使用 mvc:view-controller 标签实现

5:创建自定义视图

1:创建自定义视图解析器--ViewResolver

2:创建自定义视图

3:将视图解析器放在容器中,并配置orderd属性

4:创建Controller访问逻辑


一:转发和重定向

转发或重定向后,不会在返回的视图解析器名上拼前缀后后缀

1:转发:forward

@RequestMapping("/handle01")
    public String handle01(){
        System.out.println("handle01");
        //绝对路径
        return "forward:/hello.jsp";
    }

    @RequestMapping("/handle02")
    public String handle02(){
        System.out.println("handle02");
        //绝对路径
        return "forward:/handle01";
    }

2:重定向

    @RequestMapping("/handle03")
    public String handle03(){
        System.out.println("handle03");
        //绝对路径
        return "redirect:/hello.jsp";
    }

二:视图解析

SpringMVC视图解析;

  • 1、方法执行后的返回值会作为页面地址参考,转发或者重定向到页面
  • 2、视图解析器可能会进行页面地址的拼串;

1:任何方法的返回值,都会包装ModelAndView对象

2:processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

来到页面的方法,视图渲染流程:将域中的数据在页面展示;页面就是用来渲染模型数据的;

3:调用render(mv, request, response);渲染页面

4:View与ViewResolver的关系;

ViewResolver的作用就是根据视图名返回View对象;

5:根据视图名得到View对象

protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
			Locale locale, HttpServletRequest request) throws Exception {
        
		if (this.viewResolvers != null) {
            //遍历所有的ViewResolver;
			for (ViewResolver viewResolver : this.viewResolvers) {
                //通过视图名得到视图对象
				View view = viewResolver.resolveViewName(viewName, locale);
				if (view != null) {
					return view;
				}
			}
		}
		return null;
	}

解析viewResolver.resolveViewName(viewName, locale);

@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);
		}
	}

解析view = createView(viewName, locale);

    @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.
        //检测是否以redirect开头(即重定向)
		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);
		}

		// Check for special "forward:" prefix.
        //检测是否以forward开头(即转发)
		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);
		}

		// Else fall back to superclass implementation: calling loadView.
        //没有前缀就是用父类默认创建一个视图
		return super.createView(viewName, locale);
	}

最终得到的view视图对象是这样的:

总结:

视图解析器得到View对象的流程就是,所有配置的视图解析器都来尝试根据视图名(返回值)得到View(视图)对象;如果能得到就返回,得不到就换下一个视图解析器;

6:视图渲染

public void render(@Nullable Map<String, ?> model, HttpServletRequest request,
			HttpServletResponse response) throws Exception {

		if (logger.isDebugEnabled()) {
			logger.debug("View " + formatViewName() +
					", model " + (model != null ? model : Collections.emptyMap()) +
					(this.staticAttributes.isEmpty() ? "" : ", static attributes " + this.staticAttributes));
		}

		Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
		prepareResponse(request, response);
        //渲染要给页面输出的所有数据
		renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
	}

 

InternalResourceView有这个方法renderMergedOutputModel();

    @Override
	protected void renderMergedOutputModel(
			Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {

		// Expose the model object as request attributes.
        //将model中的数据暴露在request请求域中
		exposeModelAsRequestAttributes(model, request);

		// Expose helpers as request attributes, if any.
		exposeHelpers(request);

		// Determine the path for the request dispatcher.
		String dispatcherPath = prepareForRendering(request, response);

		// Obtain a RequestDispatcher for the target resource (typically a JSP).
		RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
		if (rd == null) {
			throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +
					"]: Check that the corresponding file exists within your web application archive!");
		}

		// If already included or response already committed, perform include, else forward.
		if (useInclude(request, response)) {
			response.setContentType(getContentType());
			if (logger.isDebugEnabled()) {
				logger.debug("Including [" + getUrl() + "]");
			}
			rd.include(request, response);
		}

		else {
			// Note: The forwarded resource is supposed to determine the content type itself.
			if (logger.isDebugEnabled()) {
				logger.debug("Forwarding to [" + getUrl() + "]");
			}
            //进行servlet最原始的转发
			rd.forward(request, response);
		}
	}

将model中的数据暴露在request域中

protected void exposeModelAsRequestAttributes(Map<String, Object> model,
			HttpServletRequest request) throws Exception {

		model.forEach((name, value) -> {
			if (value != null) {
				request.setAttribute(name, value);
			}
			else {
				request.removeAttribute(name);
			}
		});
	}

 

一句话:

视图解析器只是为了得到视图对象;视图对象才能真正的转发(将模型数据全部放在请求域中)或者重定向到页面

视图对象才能真正的渲染视图;

三:视图

1:常用视图

2:常用视图解析器

  1. 程序员可以选择一种视图解析器或混用多种视图解析器
  2. 每个视图解析器都实现了 Ordered 接口并开放出一个 order 属性,可以通过 order 属性指定解析器的优先顺序order  越小优先级越高
  3. SpringMVC 会按视图解析器顺序的优先顺序对逻辑视图名进行解析,直到解析成功并返回视图对象,否则将抛出 ServletException 异常

3:使用jstlView视图快速支持国际化功能;

 

1、导包导入了jstl的时候会自动创建为一个jstlView;可以快速方便的支持国际化功能;

<!--jstl快速支持国际化-->
<!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>jstl</artifactId>
  <version>1.2</version>
</dependency>

2、可以支持快速国际化;

     1)、javaWeb国际化步骤;

               1)、得得到一个Locale对象;

               2)、使用ResourceBundle绑定国际化资源文件;

               3)、使用ResourceBundle.getString("key");获取到国际化配置文件中的值;

               4)、web页面的国际化,fmt标签库来做;

                         <fmt:setLocale>

                         <fmt:setBundle >   

                         <fmt:message>

     2)、有了JstlView以后;

               1)、让Spring管理国际化资源就行

<bean id="MessageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
    <property name="basename" value="i18n"></property>
</bean>

             

               2)、直接去页面使用<fmt:message>;

 

fmt:message key="welcomeinfo"/>

</h1>

<form action="">

    <fmt:message key="username"/>:<input /><br/>

    <fmt:message key="password"/>:<input /><br/>

    <input type="submit" value='<fmt:message key="loginBtn"/>'/>

</form>

注:

一定要过SpringMVC的视图解析流程,人家会创建一个jstlView帮你快速国际化;

也不能写forward:

 

4:若希望直接响应通过 SpringMVC 渲染的页面,可以使用 mvc:view-controller 标签实现

<!-- 直接配置响应的页面:无需经过控制器来执行结果 -->

<mvc:view-controller path="/success" view-name="success"/>

  1. 配置<mvc:view-controller>会导致其他请求路径失效
  2. 解决办法:

<!-- 在实际开发过程中都需要配置mvc:annotation-driven标签,后面讲,这里先配置上 -->

<mvc:annotation-driven/>

5:创建自定义视图

 

1、自定义视图和视图解析器的步骤;

     1)、编写自定义的视图解析器,和视图实现类

     2)、视图解析器必须放在ioc容器中,让其工作,能创建出我们的自定义视图对象;

1:创建自定义视图解析器--ViewResolver

创建自定义视图解析器,按照自己的逻辑解析

注意必须实现Orderd接口,这样才能在xml中设置order属性,排在默认的解析器前边

package com.wkl.view;

import org.springframework.core.Ordered;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;

import java.util.Locale;

/**
 * Description:
 * Date:       2020/7/29 - 下午 1:16
 * author:     wangkanglu
 * version:    V1.0
 */
public class MyViewRrsoulver implements ViewResolver, Ordered {
    private Integer order;

    public void setOrder(Integer order) {
        this.order = order;
    }

    @Override
    public View resolveViewName(String viewName, Locale locale) throws Exception {
        if(viewName.startsWith("wkl")){
            return new MyViem();
        }else {
            return null;
        }
    }

    @Override
    public int getOrder() {
        return order;
    }
}

2:创建自定义视图

创建自定义视图,确立展示逻辑

package com.wkl.view;

import org.springframework.web.servlet.View;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

/**
 * Description:
 * Date:       2020/7/29 - 下午 1:16
 * author:     wangkanglu
 * version:    V1.0
 */
public class MyViem implements View {
    @Override
    public String getContentType() {
        return "test/html";
    }

    @Override
    public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
        response.setContentType("text/html");
        response.getWriter().write("哈哈");
    }
}

3:将视图解析器放在容器中,并配置orderd属性

<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
    <property name="basename" value="i18n"></property>

</bean>

4:创建Controller访问逻辑

    @RequestMapping("/handle04")
    public String handle04(){
        System.out.println("handle03");
        //绝对路径
        return "wkl:aaa";
    }

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苍煜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值