简介
在springmvc中,我们返回的数据默认都会构成ModelAndView,这个View就是要跳转的页面,如果我们返回一个字符串,那么该字符串就会被默认视图解析器解析作为转发路径。当然,视图解析器也可以自定义。
默认视图解析器
springmvc中默认视图解析器是InternalResourceViewReslover,用于解析handler返回的信息。
看类图可以发现它继承了UrlBasedViewResolver,下面来看看InternalResourceViewReslover和UrlBasedViewResolver这2个类的注释
InternalResourceViewReslover注释大概意思就是建议我们将文件放到WEB-INF目录下,这样可以阻止直接请求访问。还有一个注意事项就是 InternalResourceViewReslover是作为最后一个解析器进行解析的。注意:springmvc包含多种解析器,还可能有自定义解析器。下面再看下UrlBasedViewResolver这个类注释
通过类上面的注释,我们可以知道UrlBasedViewResolver会将返回值作为视图名称解析解析,寻找项目中的资源,同时还会添加前缀和后缀,前缀和后缀都是自定义的。该类还会解析返回值十分是forward:或者redirect:开头的,如果是,那么就会进行转发或者重定向到对应资源,而不是进行标准视图解析。
为了测试方便,创建一个jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>成功</title>
</head>
<body>
<h1>测试成功!!!</h1>
</body>
</html>
通过上面的注释,可以知道,我们可以给默认视图解析器配置一个prefix和suffix,下面在配置文件中进行配置
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
下面编写java代码进行测试
@RequestMapping("/view")
@Controller
public class ViewController {
@RequestMapping("/f1")
public String f1() {
System.out.println("f1.....");
return "success";
}
}
上面代码就可以知道,f1方法会转发到/WEB-INF/pages/success.jsp页面,使用postman进行测试
测试没有问题,下面写法就是转发和重定向,就不测试了
@RequestMapping("/f2")
public String f2() {
System.out.println("f2.....");
//会转发到f1,以当前路径为参考,不会添加prefix和suffix,
return "forward:f1";
}
@RequestMapping("/f3")
public String f3() {
System.out.println("f3.....");
//会重定向到f1,以当前路径为参考,不会添加prefix和suffix,
return "redirect:f1";
}
自定义视图
通过上面的默认视图,可以发现局限性是很大的,这是,我们就可以自定义视图,下面来进行说明。
自定义视图主要分为4个部分,如下
- 创建类继承AbstractView,实现renderMergedOutputModel 方法
- 将其添加进spring容器,设置id
- 配置自定义视图解析器,该解析器名称是BeanNameViewResolver,它会处理我们的视图
- 将自定义解析器优先级调高
下面就是具体的代码实现,先创建自己的视图解析
@Component("myView")
public class MyView extends AbstractView {
@Override
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("自定义视图---调用了MyView的renderMergedOutputModel方法");
String url = "/WEB-INF/pages/success.jsp";
request.getRequestDispatcher(url).forward(request, response);
}
}
配置自定义视图的解析器,设置其优先级,通过order设置,默认是Integer.MAX_VALUE,值越小,优先级越高。
上面就是该类的主要注释,可以发现该类就是用来解析自定义视图的
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
<property name="order" value="99"/>
</bean>
然后创建handler进行测试,我们直接返回视图的id即可,id就是直接的视图在spribg容器中的名称
@RequestMapping("f4")
public String f4() {
System.out.println("f4.....");
return "myView";
}
访问该handler,自定义视图没有问题
可以发现,使用十分简单,下面就开始debug源码,看底层是如何实现的。
Debug源码
自定义视图Debug
如果不知道底层原理,那么出现bug时就很难解决了,下面就开始debug吧。先debug自定义视图部分
进入该方法,发现就是判断我们是否设置了返回的视图,继续往下执行
进入解析视图方法,查看如何实现的
下面就是所有的解析器
进入自定义视图的resolveViewName
到这里,自定义视图就debug完成了,下面开始默认视图的
默认视图Debug
debug前面部分都是相同的,下面从遍历所有解析器开始debug
请求的是f1方法,会返回success的视图名称,下面就是自定义视图先进行解析,因为优先级更高
然后就是默认视图解析,我们进行默认视图的resolveViewName方法
由于我们返回的值不是redirect和forward,会继续调用父类的createView方法,一直往里面追,直到看见构建最终的视图url
到这里,默认视图的debug也完成了
总结
自定义视图还是比较简单的,容易理解,为了加深理解,可以自己进行debug