Spring Web MVC 多viewResolver视图解析器解决方案

xiaoxiao2021-02-28  101

viewResolver的定义如下: public interface ViewResolver { View resolveViewName(String viewName, Locale locale) throws Exception; } 在spring 中,常用的ViewResolver 有如下几种: InternalResourceViewResolver 将逻辑视图名字解析为一个路径 BeanNameViewResolver 将逻辑视图名字解析为bean的Name属性,从而根据name属性,找定义View的bean ResourceBundleResolver 和BeanNameViewResolver一样,只不过定义的view-bean都在一个properties文件中,用这个类进行加载这个properties文件 XmlViewResolver 和ResourceBundleResolver一样,只不过定义的view-bean在一个xml文件中,用这个类来加载xml文件 当我们需要多个viewResolver的时候,spring 框架为我们提供了很好的支持,我们只要在[spring-dispatcher-name]-servlet.xml中定义多个ViewResolver就可以了。如: 复制代码 <!-- 定义JSP视图解析器--> <bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/"></property> <property name="suffix" value=".jsp"></property> <property name="order" value="1" /> </bean> <bean id="freemarkerViewResolver" class="com.founder.web.commom.springmvc.view.ExtFreeMarkerViewResolver"> <property name="contentType" value="text/html; charset=UTF-8"/> <property name="exposeRequestAttributes" value="false"/> <property name="exposeSessionAttributes" value="false"/> <property name="exposeSpringMacroHelpers" value="true"/> <property name="cacheUnresolved" value="false"/> <property name="order" value="0" /> </bean> 复制代码 DispatcherServlet会加载所有的viewResolver到一个list中,并按照优先级进行解析。 注意:①order中的值越小,优先级越高。 ②而id为viewResolver的viewResolver的优先级是最低的。 PS: 如果某个解析器没有找到合适的视图,Spring会在上下文中寻找是否配置了其它的解析器。 如果有,它会继续进行解析,否则,Srping会抛出一个Exception。 要记住,当一个视图解析器找不到合适的视图时,它可能 返回null值。 但是,不是每个解析器都这么做。这是因为,在某些情况下,解析器可能无法侦测出符合要求的视图是否存在。 比如,InternalResourceViewResolver在内部调用了RequestDispatcher。 请求分发是检查一个JSP文件是否存在的唯一方法,不幸的是,这个方法只能用一次。 同样的问题在VelocityViewResolver和其它解析器中也有。 当使用这些解析器时,最好仔细阅读它们的Javadoc,看看需要的解析器是否无法发现不存在的视图。 这个问题产生的副作用是,如果InternalResourceViewResolver解析器没有放在链的末端, InternalResourceViewResolver后面的那些解析器根本得不到使用, 因为InternalResourceViewResolver总是返回一个视图! 在SpringMVC模式当中可以通过如下配置来支持多视图解析 <!-- jsp jstl --> <bean id="JSPViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> <property name="viewNames" value="*jsp" /> <property name="contentType" value="text/html; charset=utf-8"/> <property name="prefix" value="/" /> <property name="suffix" value="" /> <property name="order" value="1"></property> </bean> <bean id="FMViewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.freemarker.FreeMarkerView"/> <property name="viewNames" value="*html" /> <property name="contentType" value="text/html; charset=utf-8"/> <property name="cache" value="true" /> <property name="prefix" value="/" /> <property name="suffix" value="" /> <property name="order" value="0"></property> </bean> 首先可以使用order属性进行设置 系统首先按解析器的order值进行查找 首先使用FreeMarkerViewResolver解析器调用canHandle方法,判断当前解析器对视图是否能够解析。如不能解析在依次调用。 最近被问到过几次关于springmvc多视图解析器解析的问题;总结一下。 假设我有两个jsp: 1 WEB-INF/html/a.jsp 2 WEB-INF/report/b.jsp 且我配置了视图解析器: <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:order="1"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> <property name="contentType" value="text/html"/> <property name="prefix" value="/WEB-INF/html/"/> <property name="suffix" value=".jsp"/> </bean> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:order="2"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> <property name="contentType" value="text/html"/> <property name="prefix" value="/WEB-INF/report/"/> <property name="suffix" value=".jsp"/> </bean> 然后呢,我分别返回视图名为a和b;为什么a能找到,而b的时候是404;我配置了两个视图解析器,第一个找不到的话,第二个能找到啊?遇到过这个问题的朋友基本上会有类似的问题; 分析 此处我们使用了InternalResourceViewResolver,其有一个buildView方法,该方法一定会创建一个View;所以呢View永远不为null(即使该jsp不存在);问题就是出在这;因为我们使用这个的时候默认是使用servlet forward转发的,此时并不知道该jsp是否存在。 解决方案 最简单的办法是使用其viewNames属性,来指定一个是否可以处理的规则 <property name= "viewNames" value= "html*" /> <property name= "viewNames" value= "report*" /> 如上两个的意思是对html或report开头的视图名进行处理,比如返回的视图名为html/a 那么会交给viewNames为html*的那个解析器处理;支持的规则可以查看javadoc。

总结:

看了前辈的博客后,使用order时失效的原因是因为:在视图内中需要配置一下viewNames.问不同视图的文件名称进行统一标记一下.

转载请注明原文地址: https://www.6miu.com/read-35152.html

最新回复(0)