Springmvc视图和视图解析器(四)

请求处理方法执行完成后,最终返回一个 ModelAndView 对象。对于返回其他类型(String、Model、View等)的处理方法,Spring MVC也会在内部将它们转换成 ModelAndView 对象,它是包含了逻辑名和模型对象的视图。

SpringMVC 借助视图解析器(ViewResolver) 得到最终的视图(View)对象。最终的视图可以使是 JSP,也可能是Excel、JFreeChart等各种形式的视图。对于最终究竟采取何种视图对象对模型数据进行渲染,处理器并不关心,处理器的工作重点聚焦在生产模型上,从而实现 MVC 的充分解耦。

SpringMVC的视图解析流程

  1. 调用目标方法,SpringMVC将目标方法返回的String、View、ModelMap或是ModelAndView都转换为一个ModelAndView对象;
  2. 然后通过视图解析器(ViewResolver)对ModelAndView对象中的View对象进行解析,将该逻辑视图View对象解析为一个物理视图View对象;
  3. 最后调用物理视图View对象的render()方法进行视图渲染,得到响应结果。

一、视图

视图的作用是渲染模型数据,将模型里的数据以某种形式展现给客户。为了实现视图模型和具体实现技术的解耦,Spring在 org.springframework.web.servlet 中定义了高度解耦的 View 接口。
视图对象由视图解析器负责实例化。由于他们是无状态的,所以是线程安全的。

常用的视图解析器

大类视图类型说明
URL视资源图InternalResourceView将JSP或者其它资源封装成一个视图,是 InternalResourceViewResolver 默认使用的视图实现类
JstlView如果JSP文件中使用了JSTL标签则需要使用该视图
文档视图AbstractExcelViewExcel 文档视图的抽象类。该视图类基于 POI 构造 Excel 文档
AbstractPdfViewPDF 文档视图的抽象类。该视图类基于 IText 构造 PDF 文档
报表视图ConfigurableJsperReportsView几个使用JsperReports报表技术的视图
JsperReportsCsvView
JsperReportsMultiFormatView
JsperReportsHtmlView
JsperReportsPdfView
JsperReportsXlsView
JSON视图MappingJacksonJsonView将模型数据通过Jackson开源框架的 ObjectMapper 以JSON 方式输出

二、视图解析器

ViewResolver的主要作用是把一个逻辑上的视图名称解析为一个真正的视图。
SpringMVC为逻辑视图名的解析提供了不同的策略,可以在Spring WEB上下文中配置一种或多种解析策略,并指定他们之间的先后顺序。每一种映射策略对应一个具体的视图解析器实现类。程序员可以选择一种视图解析器或混用多种视图解析器。可以通过order属性指定解析器的优先顺序,order越小优先级越高,SpringMVC会按视图解析器顺序的优先顺序对逻辑视图名进行解析,直到解析成功并返回视图对象,否则抛出ServletException异常。

Spring为我们提供了非常多的视图解析器,下面将列举一些视图解析器:

  • AbstractCachingViewResolver:这是一个抽象类,这种视图解析器会把它曾经解析过的视图保存起来,然后每次要解析视图的时候先从缓存里面找,如果找到了对应的视图就直接返回,如果没有就创建一个新的视图对象,然后把它放到一个用于缓存的map中,接着再把新建的视图返回。使用这种视图缓存的方式可以把解析视图的性能问题降到最低。
  • UrlBasedViewResolver:它是对ViewResolver的一种简单实现,而且继承了AbstractCachingViewResolver,主要就是提供的一种拼接URL的方式来解析视图,它可以让我们通过prefix属性指定一个指定的前缀,通过suffix属性指定一个指定的后缀,然后把返回的逻辑视图名称加上指定的前缀和后缀就是指定的视图URL了。如prefix=/WEB-INF/jsps/,suffix=.jsp,返回的视图名称viewName=test/indx,则UrlBasedViewResolver解析出来的视图URL就是/WEB-INF/jsps/test/index.jsp。默认的prefix和suffix都是空串。

    注意:使用UrlBasedViewResolver的时候必须指定属性viewClass,表示解析成哪种视图,一般使用较多的就是InternalResourceView,利用它来展现jsp,但是当我们使用JSTL的时候我们必须使用JstlView。下面是一段UrlBasedViewResolver的定义,根据该定义,当返回的逻辑视图名称是test的时候,UrlBasedViewResolver将把逻辑视图名称加上定义好的前缀和后缀,即“/WEB-INF/test.jsp”,然后新建一个viewClass属性指定的视图类型予以返回,即返回一个url为“/WEB-INF/test.jsp”的InternalResourceView对象。

    URLBasedViewResolver支持支持URL在客户端的跳转,只需在返回视图名称中加上redirect:forword:前缀。

    • 如当返回的视图名称是”redirect:test.do”的时候,URLBasedViewResolver发现返回的视图名称包含”redirect:”前缀,于是把返回的视图名称前缀”redirect:”去掉,取后面的test.do组成一个RedirectView,RedirectView中将把请求返回的模型属性组合成查询参数的形式组合到redirect的URL后面,然后调用HttpServletResponse对象的sendRedirect方法进行重定向。
    • 对于视图名称中包含forword:前缀的视图名称将会被封装成一个InternalResourceView对象,然后在服务器端利用RequestDispatcher的forword方式跳转到指定的地址。
<bean  
   class="org.springframework.web.servlet.view.UrlBasedViewResolver">  
   <property name="prefix" value="/WEB-INF/" />  
   <property name="suffix" value=".jsp" />  
   <property name="viewClass" value="org.springframework.web.servlet.view.InternalResourceView"/>  
</bean> 
  • InternalResourceViewResolver:它是 UrlBasedViewResolver的子类,它将InternalResourceView作为缺省的View类,如果当前classpath中有jstl的jar包时则使用JstlView作为缺省的view来渲染结果。因此以下使用InternalResourceViewResolver的定义应该和之前使用UrlBasedViewResolver定义的viewResolver的作用相同。

    除此之外,InternalResourceViewResolver还提供了
    alwaysInclude属性来要求返回的结果使用include方式而不是forward方式
    exposeContextBeansAsAttributes属性以将当前spring 环境中的 beans作为request attritbutes来暴露到页面上。
    exposedContextBeanNames属性来限制能够暴露到页面上的spring bean的名称列表。

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

若希望直接响应通过SpringMVC渲染的页面,可以使用mvc:view-controller

  • FreeMarkerViewResolver、VolocityViewResolver:这两个视图解析器都是UrlBasedViewResolver的子类。FreeMarkerViewResolver会把Controller处理方法返回的逻辑视图解析为FreeMarkerView,而VolocityViewResolver会把返回的逻辑视图解析为VolocityView。因为这两个视图解析器类似,所以这里我就只挑FreeMarkerViewResolver来做一个简单的讲解。FreeMarkerViewResolver和VilocityViewResolver都继承了UrlBasedViewResolver。

    对于FreeMarkerViewResolver而言,它会按照UrlBasedViewResolver拼接URL的方式进行视图路径的解析。但是使用FreeMarkerViewResolver的时候不需要我们指定其viewClass,因为FreeMarkerViewResolver中已经把viewClass定死为FreeMarkerView了。

    我们先在SpringMVC的配置文件里面定义一个FreeMarkerViewResolver视图解析器,并定义其解析视图的order顺序为1。

<bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">  
   <property name="prefix" value="fm_"/>  
   <property name="suffix" value=".ftl"/>  
   <property name="order" value="1"/>  
</bean>  

那么当我们请求的处理器方法返回一个逻辑视图名称viewName的时候,就会被该视图处理器加上前后缀解析为一个url为“fm_viewName.ftl”的FreeMarkerView对象。对于FreeMarkerView我们需要给定一个FreeMarkerConfig的bean对象来定义FreeMarker的配置信息。FreeMarkerConfig是一个接口,Spring已经为我们提供了一个实现,它就是FreeMarkerConfigurer。我们可以通过在SpringMVC的配置文件里面定义该bean对象来定义FreeMarker的配置信息,该配置信息将会在FreeMarkerView进行渲染的时候使用到。对于FreeMarkerConfigurer而言,我们最简单的配置就是配置一个templateLoaderPath,告诉Spring应该到哪里寻找FreeMarker的模板文件。这个templateLoaderPath也支持使用“classpath:”和“file:”前缀。当FreeMarker的模板文件放在多个不同的路径下面的时候,我们可以使用templateLoaderPaths属性来指定多个路径。在这里我们指定模板文件是放在“/WEB-INF/freemarker/template”下面的。

<bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">  
   <property name="templateLoaderPath" value="/WEB-INF/freemarker/template"/>  
</bean>  

接下来我们定义如下一个Controller:

@Controller  
@RequestMapping("/mytest")  
public class MyController {  

    @RequestMapping("freemarker")  
    public ModelAndView freemarker() {  
       ModelAndView mav = new ModelAndView();  
       mav.addObject("hello", "andy");  
       mav.setViewName("freemarker");  
       return mav;  
    }  
}  

由上面的定义我们可以看到这个Controller的处理器方法freemarker返回的逻辑视图名称是“freemarker”。那么如果我们需要把该freemarker视图交给FreeMarkerViewResolver来解析的话,我们就需要根据上面的定义,在模板路径下定义视图对应的模板,即在“/WEB-INF/freemarker/template”目录下建立fm_freemarker.ftl模板文件。这里我们定义其内容如下:

<html>  
    <head>  
       <title>FreeMarker</title>  
    </head>  
    <body>  
       <b>Hello World</b>  
       <font color="red">Hello World!</font>  
       ${hello}  
    </body>  
</html>  

经过上面的定义当我们访问/mytest/freemarker.do的时候就会返回一个逻辑视图名称为“freemarker”的ModelAndView对象,根据定义好的视图解析的顺序,首先进行视图解析的是FreeMarkerViewResolver,这个时候FreeMarkerViewResolver会试着解析该视图,根据它自身的定义,它会先解析到该视图的URL为fm_freemarker.ftl,然后它会看是否能够实例化该视图对象,即在定义好的模板路径下是否有该模板存在,如果有则返回该模板对应的FreeMarkerView。在这里的话/WEB-INF/freemarker/template目录下是存在模板文件fm_freemarker.ftl的,所以会返回一个url为fm_freemarker.ftl的FreeMarkerView对象。接着FreeMarkerView就可以利用该模板文件进行视图的渲染了。

  • BeanNameViewResolver:将逻辑视图名解析为一个Bean,Bean的id为逻辑视图名(自定义视图解析器)
  • JasperReportsViewResolver:JasperReports是一个基于java的开源报表工具,该解析器将视图名解析为报表文件对应的URL

注意:我们可以选择一种解析器或者多种混用,每个解析器都实现了Ordered接口并开放出一个order属性,可以通过order属性指定解析器的优先顺序,order越小优先级越高。常用的放后边,不常用的放前边。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值