springMVC 配置——viewResolver

在springmvc的配置中,很重要的一个就是viewResolver,中文叫做视图解析器。他的作用就是处理MVC模式下从C到V的连接。视图可以使jsp的,也可以是velocity的,也可以是freemarker的,针对于不同的视图,springmvc定义了不同的视图解析器,所有的这些在org.springframework.web.servlet.view.UrlBasedViewResolver类的源码中都可以找到。今天我就把我对这个类的源码的总结记录下来。

视图解析器有很多个,一般的我们使用jsp作为视图的时候会使用org.springframework.web.servlet.view.InternalResourceViewResolver,使用velocity作为视图时会选择org.springframework.web.servlet.view.velocity.VelocityViewResolver,他们的共同的配置都在这个UrlBasedViewResolver中。

普遍的配置如下:prefix="/WEB-INF/JSP/" suffix=".jsp" 从controller返回的viewname是test,那么最终的跳转到的是/WEB-INF/jsp/test.jsp。

1、redirect:

如果一个路径是以redirect开头的,比如“redirect:myAction.do”,会出发一个重定向的指令,即302,而不是和普通的路径一样找视图。

2、forward:

如果一个路径是以forward开头的,比如forward:myAction.do就会出发一次新的访问,就是重新访问一次springmvc的servlet,这个就像是我们在使用servlet开发时的forward,只不过servlet中的forward是跳转的有jsp生成的servlet。

3、配置多个resolver,

如果配置多个viewResolver的话,可以使用下面的order或者是viewNames,但是不能使用前缀或者是后缀,因为这两个都是用来添加到viewName上的的,不是用来区别viewName的。 

在配置多个resolver的时候,还有个需要注意的地方,即当没有找打指定的url对应的资源的时候,除了InternalViewResolver外,都会让停止解析,但是InternalViewResolver不会,所以源码中说要将InternalViewResolver放在最后,不过我觉得最好的办法还是使用viewNames来判断,比如我们有jsp和velocity的,我们可以在jsp的InternalViewResolver中设置suffix为“”,(默认就是“”),viewNames为“*.jsp”,然后再controller中返回的是xxx.jsp,在velocity的viewResolver中设置suffix为.vm,然后再controller中返回的就是xxx.vm,这样就不存在解析顺序的问题两天。

4、contentType属性

设置所有视图的属性,也就是jsp中的<meta Content-Type..../>,源码中的javadoc中说这个可能被忽略,如果视图已经有了这个配置的话,比如jsp中。

5、redirectContextRelative

这个属性很重要,默认是true,表示的是在重定向时,要不要以当前的contextPath以相对路径,如果是在servlet中的重定向时,我们必须写上当前应用的contextPath,但是在springmvc中我们在重定向时不用写,我想起来刚开始学习springmvc时我还烦了错误,现在知道了原来springmvc默认自动给我们加上了contextPath,当然我们是可以通过这个配置为false的。

6、viewNames  

是一个字符串的数组

这个属性是我今天第一次发现,他的意思是这样的,在我们配置的viewResolver中,在解析视图时先回调用这个类中的canHandle方法,这个方法内部就是调用正则表达式判断要解析的viewName能不能匹配当前viewResolver的newNames,只有在能解析的时候才会继续解析。

canhandle的源码:

protected boolean canHandle(String viewName, Locale locale) {
    String[] viewNames = getViewNames();
    return (viewNames == null || PatternMatchUtils.simpleMatch(viewNames, viewName));
}

 可以发现当viewName是null就会解析,PatternMatchUtils.simpleMath的源码如下:

public static boolean simpleMatch(String[] patterns, String str) {
	if (patterns != null) {
		for (int i = 0; i < patterns.length; i++) {
			if (simpleMatch(patterns[i], str)) {
				return true;
			}
		}
	}
	return false;
}

这个的判定条件是正则表达式匹配,只要有个匹配即可。 在viewResolver的viewName中可以使用简单的通配符,比如*。

我这里做了一个实验:

我的springmvc的配置文件是这样的:

<!-- 跳转到jsp的viewResolver -->
<bean
	class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<property name="prefix" value="/WEB-INF/jsp/" />
	<property name="suffix" value=".jsp" />
	<property name="viewNames">
	    <array>
	       <value>a*</value>
	    </array>
	</property>
</bean>

 我的意图是这个viewResolver只能解析以a开头的试图,其他的都不能解析,我的controller是这样的

@Controller
@RequestMapping("/hello")
public class HelloWorldController {
	
	@RequestMapping("aaa.do")
	public String aaa(){
		return "aaa";
	}
	
	@RequestMapping("bbb.do")
	public String bbb(){
		return "bbb";
	}

当我访问aaa.do的时候,正常访问,但是当我访问bbb.do的时候就报了一下的错误:

[Could not resolve view with name 'bbb' in servlet with name 'springDispatcherServlet'] with root cause

javax.servlet.ServletException: Could not resolve view with name 'bbb' in servlet with name 'springDispatcherServlet',于是我们的理解得到验证。

7、order属性

 int类型的,源码的doc中说的是制定这个resolver的执行顺序,我做了如下的测试

我在springmvc的配置文件中加入了两个viewResolver,然后给他们不同的前缀和order,看一下到底是哪一个执行还是两个都执行

我的配置的截图如下:

<bean  name="resolver1"
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/jsp/" />
    <property name="suffix" value=".jsp" />
    <property name="order" value="1"></property>
</bean>

<bean name="resolver2"
	class="org.springframework.web.servlet.view.InternalResourceViewResolver">
         <property name="prefix" value="/WEB-INF/jsp2/" />
	<property name="suffix" value=".jsp" />
	<property name="order" value="2"></property>
</bean>

 然后在/WEB-INF下创建了一个jsp2的文件夹,然后再访问之前的aaa.do,发现是配置的order=1的resolver起作用了,然后我又把原先order=1的resolver改为order=3,发现是仅仅执行了order=2的resolver,可以总结order小的先执行,而且执行完了之后其他的resolver不会执行了。

相关推荐