Spring视图解析器(ViewResolve)
视图解析器会将Controller中String的返回值(视图名)进行拼串。
@Controller
public class HelloController{
@RequestMapping("/hello")
public String hello(){
return "../../hello";
}
}
//forward:转发到一个页面
// /hello.jsp:转发到当前项目下的hello
@RequestMapping("/handle01")
public String handler01(){
return "forward:/hello.jsp";
}
forward前缀可以实现多重跳转
@RequestMapping("/handle01")
public String handle01(){
return "forward:/hello.jsp";
}
@RequestMappint("/handle02")
public String handle02(){
return "forward:/handle01";
}
redirect也可以实现上述功能。有前缀的转发和重定向操作和视图解析器就不会进行拼串。
SpringMVC视图解析原理
- 方法执行后的返回值会作为页面地址参考,转发或重定向到页面。
- 视图解析器可能会进行页面地址的拼串。
processDispatchResult(processedRequest,response,mappedHandler,mv,dispatchException);
来到页面的方法
视图渲染流程,将域中的数据在页面展示,页面就是用来渲染模型数据的。
-
调用
render(mv,request,response);
渲染页面 -
View与ViewResolver:
ViewResolver的作用是根据视图名(ViewName,方法的返回值)得到view对象。 -
怎么能根据ViewName得到View对象。
@Nullable
protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
Locale locale, HttpServletRequest request) throws Exception {
if (this.viewResolvers != null) {
for (ViewResolver viewResolver : this.viewResolvers) {
//viewResolver视图解析器根据方法的返回值,得到一个View对象;
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
return view;
}
}
}
return null;
}
@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对象
view = createView(viewName, locale);
if (view == null && this.cacheUnresolved) {
view = UNRESOLVED_VIEW;
}
if (view != null) {
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);
}
}
@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结尾的视图名就创建一个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.
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.
//如果没有前缀,就是用父类默认创建一个View对象。
return super.createView(viewName, locale);
}
通过以上流程会创建一个InternalResourceView,返回View对象。
视图解析器得到View对象的流程就是:
-
所有配置的视图解析器都来根据ViewName(方法的返回值)得到对象;如果能得到就返回,得不到就换下一个视图解析器。
-
调用View对象的Render方法。
//将模型域中的数据暴露在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);
}
});
}
将参数中Map方法中的数据放入request域。
View对象的作用就是进行转发域重定向,将数据放在request域中。视图解析器只是为了得到视图对象,视图对象才能真正转发或者重定向到页面。
mvc:view-controller标签
path指定哪个请求
<mvc:view-controller path="/toLoginPage" view-name=""/>
该标签可以走整个SpringMVC视图解析器流程。
mvc注解驱动模式
<mvc:annotation-driven></mvc:annotation-driven>
自定义视图解析器和视图
- 让视图解析器工作;
- 得到我们的视图对象;
- 我们的视图对象自定义渲染逻辑
response.getWriter().write("<h1> 即将展现精彩内容</h1>");
- 自定义视图解析器的步骤
- 编写自定义的视图解析器,和视图实现类。
- 将视图解析器添加到ioc容器中。
public class MyMeiNvViewResolver implements ViewResolver, Ordered {
private int order = 0;
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
if(viewName.startsWith("meinv:")){
return new MyView();
}else{
return null;
}
}
//Ordered接口规定了在InternalResourcesView中获得ResourceViews的访问顺序
@Override
public int getOrder() {
return order;
}
public void setOrder(Integer order){
this.order = order;
}
}
- 自定义View
public class MyView implements View {
@Override
public String getContentType() {
return "text/html";
}
@Override
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("之前保存的数据:"+model);
response.setContentType("text/html");
response.getWriter().write("<h1> 即将展现精彩内容</h1>");
}
}