Table of Contents
2:processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
3:调用render(mv, request, response);渲染页面
4:若希望直接响应通过 SpringMVC 渲染的页面,可以使用 mvc:view-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:常用视图解析器

- 程序员可以选择一种视图解析器或混用多种视图解析器
- 每个视图解析器都实现了 Ordered 接口并开放出一个 order 属性,可以通过 order 属性指定解析器的优先顺序,order 越小优先级越高。
- 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"/>
- 配置<mvc:view-controller>会导致其他请求路径失效
- 解决办法:
| <!-- 在实际开发过程中都需要配置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";
}

487

被折叠的 条评论
为什么被折叠?



