SpringMVC自定义视图+内容协商(RESTful MVC)实现超级灵活的多视图协商

      这篇blog主要是介绍如何实现一个超级灵活的SpringMVC多视图协商配置,试想如果一个项目需要使用jsp、freemaker、jasper、 velosity等,而返回客服端数据需要用到json、xml。那么改如果配置SpringMVC视图呢?

      在本例中,我们提供了几种视图:JSP 文件、freemaker、jasper、SWF 文件(flash 文件)以及一个自定义后缀名(.config和.txt)的文件,为了更方便的支持 SWF 视图和自定义文件后缀名的视图,我们开发了自定义的视图对象,希望能够使用该视图对象来支持 SWF 文件和 .config .txt 文件,另外还开发了两个视图解析器来实现本例。

     实际上,Spring 已经提供了RESTful的多视图解析器-ContentNegotiatingViewResolver (以下简称CNV),它可以根据请求的文件后缀名或请求的 Accept 头或者请求的参数来查找视图。CNV本身并不负责查找视图,它只是将视图查找工作代理给所注册的视图解析器,但是在实际开发中如果把所以视图都交给CNV 处理,CVN就显得有点笨拙,比如我在测试中发现把freemarker和InternalResourceViewResolver都放到CNV的 viewResolvers里,所有返回freemarker的视图都跑到InternalResourceViewResolver里去处理了,结果导 致404。但是用CNV来处理json和xml可以说是相当的方便。本例中的RESTful MVC就是采用CNV来处理json和xml。比如访问http://localhost/sample/message.json 那么返回客服端的数 据内容格式为json,数据为ModelMap里携带的数据。

 

 

一、自定义视图类代码

为了简化程序该视图类只能用于处理浏览器能直接显示的请求文件资源,如文本文件、SWF 文件等

 

Java代码   收藏代码
  1. public class GenericFileView extends AbstractUrlBasedView {  
  2.   
  3.     // default content type  
  4.     private final static String CONTENT_TYPE = "text/plain";  
  5.       
  6.     //content of http response  
  7.     private String responseContent;  
  8.       
  9.     public GenericFileView() {  
  10.         super();  
  11.         setContentType(CONTENT_TYPE);  
  12.     }  
  13.   
  14.     @Override  
  15.     public void setContentType(String contentType) {  
  16.         super.setContentType(contentType);  
  17.     }  
  18.   
  19.     @Override  
  20.     protected void renderMergedOutputModel(Map model,  
  21.             HttpServletRequest request, HttpServletResponse response)  
  22.             throws Exception {  
  23.         response.setContentType(getContentType());  
  24.         response.getWriter().write(this.responseContent);  
  25.         response.getWriter().close();  
  26.     }  
  27.   
  28.     /** 
  29.      * Set http request content 
  30.      * @param responseContent 
  31.      */  
  32.     public void setResponseContent(String responseContent) {  
  33.         this.responseContent = responseContent;  
  34.     }   
  35.   
  36. }  

 

 

二、Spring视图解析器

有了视图类,我们还需要查找该视图类的视图解析器。所有的视图解析器都需要实现接口 org.springframework.web.servlet.ViewResolver,但同视图的实现一样,Spring 还提供了一个抽象类AbstractCachingViewResolver常用的 Spring 中的视图解析器都继承了该抽象类,我们同样可以通过实现该抽象类来节省开发工作。

 

Java代码   收藏代码
  1. public class GenericFileViewResolver extends AbstractCachingViewResolver  
  2.         implements Ordered {  
  3.   
  4.     private Logger logger = Logger.getLogger(GenericFileViewResolver.class  
  5.             .getName());  
  6.   
  7.     private int order = Integer.MIN_VALUE;  
  8.   
  9.     // requested file location under web app  
  10.     private String location;  
  11.   
  12.     // View  
  13.     private String viewName;  
  14.   
  15.   
  16.     public void setViewName(String viewName) {  
  17.         this.viewName = viewName;  
  18.     }  
  19.   
  20.     public void setOrder(int order) {  
  21.         this.order = order;  
  22.     }  
  23.   
  24.     public void setLocation(String location) {  
  25.         this.location = location;  
  26.     }  
  27.   
  28.   
  29.     public int getOrder() {  
  30.         return this.order;  
  31.     }  
  32.   
  33.     @Override  
  34.     protected View loadView(String viewName, Locale locale) throws Exception {  
  35.         if (location == null) {  
  36.             throw new Exception(  
  37.                     "No location specified for GenericFileViewResolver.");  
  38.         }  
  39.         String requestedFilePath = location + viewName;  
  40.         Resource resource = null;  
  41.         //String url = "";  
  42.         try {  
  43.             logger.finest(requestedFilePath);  
  44.             resource = getApplicationContext().getResource(requestedFilePath);  
  45.             //url = resource.getURI().toString();  
  46.         } catch (Exception e) {  
  47.             // this exception should be catched and return null in order to call  
  48.             // next view resolver  
  49.             logger.finest("No file found for file: " + requestedFilePath);  
  50.             return null;  
  51.         }  
  52.         logger.fine("Requested file found: " + requestedFilePath + ", viewName:" + viewName);  
  53.         //get view from application content, scope=prototype  
  54.         GenericFileView view = this.getApplicationContext().getBean(this.viewName, GenericFileView.class);  
  55.         view.setUrl(requestedFilePath);  
  56.         view.setResponseContent(inputStreamTOString(resource.getInputStream(), "UTF-8"));  
  57.         return view;  
  58.     }  
  59.       
  60.     final static int BUFFER_SIZE = 4096;  
  61.   
  62.     /** 
  63.      * Convert Input to String based on specific encoding 
  64.      * 
  65.      * @param in 
  66.      * @param encoding 
  67.      * @return 
  68.      * @throws Exception 
  69.      */  
  70.     public static String inputStreamTOString(InputStream in, String encoding)  
  71.             throws Exception {  
  72.         ByteArrayOutputStream outStream = new ByteArrayOutputStream();  
  73.         byte[] data = new byte[BUFFER_SIZE];  
  74.         int count = -1;  
  75.         while ((count = in.read(data, 0, BUFFER_SIZE)) != -1)  
  76.             outStream.write(data, 0, count);  
  77.   
  78.         data = null;  
  79.         return new String(outStream.toByteArray(), encoding);  
  80.     }  
  81.   
  82. }  

 

三、自定义多视图解析器

 

 

Java代码   收藏代码
  1. package org.mkwu.web.view.viewresolver;  
  2.   
  3. import java.util.Iterator;  
  4. import java.util.Locale;  
  5. import java.util.Map;  
  6.   
  7. import org.springframework.core.Ordered;  
  8. import org.springframework.util.StringUtils;  
  9. import org.springframework.web.servlet.View;  
  10. import org.springframework.web.servlet.ViewResolver;  
  11. import org.springframework.web.servlet.view.AbstractCachingViewResolver;  
  12.   
  13. public class MultipleViewResolver extends AbstractCachingViewResolver implements Ordered{  
  14.     private int order = Integer.MIN_VALUE;  
  15.       
  16.     public int getOrder() {  
  17.         return order;  
  18.     }  
  19.   
  20.     public void setOrder(int order) {  
  21.         this.order = order;  
  22.     }  
  23.       
  24.     private Map resolvers;  
  25.       
  26.     public void setResolvers(Map resolvers) {  
  27.         this.resolvers = resolvers;  
  28.     }  
  29.     private String getViewResolverKey(String fileExtension){  
  30.         Iterator keyIt = resolvers.keySet().iterator();  
  31.         while (keyIt.hasNext()) {  
  32.             String viewResolverKey = (String) keyIt.next();  
  33.             String[] arr = viewResolverKey.split(",");  
  34.             for (String subKey : arr) {  
  35.                 if(subKey.equals(fileExtension)) return viewResolverKey;  
  36.             }  
  37.         }  
  38.         return null;  
  39.     }  
  40.       
  41.     @Override  
  42.     protected View loadView(String viewName, Locale locale) throws Exception {  
  43.         String fileExtension = StringUtils.getFilenameExtension(viewName);  
  44.         // return null to invoke next resolver if no extension found  
  45.         if (fileExtension == null) {  
  46.             return null;  
  47.         }  
  48.         String viewResolverKey = getViewResolverKey(fileExtension);  
  49.         ViewResolver resolver = resolvers.get(viewResolverKey);  
  50.           
  51.         // get resolver by extension  
  52.         //return null to invoke next resolver if no resolver found  
  53.         return resolver == null ? null : resolver.resolveViewName(viewName,locale);  
  54.   
  55.     }  
  56. }  

 

四、SpringMVC配置 也是本文的重点

 

 

Xml代码   收藏代码
  1. xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4. xmlns:context="http://www.springframework.org/schema/context"  
  5. xmlns:p="http://www.springframework.org/schema/p"  
  6. xmlns:mvc="http://www.springframework.org/schema/mvc"  
  7. xmlns:util="http://www.springframework.org/schema/util"  
  8. xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd  
  9. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd  
  10. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd  
  11. http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">  
  12.    
  13.   
  14. <context:component-scan base-package="com.martinwu.example" use-default-filters="false">  
  15. <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>  
  16. context:component-scan>  
  17. <mvc:annotation-driven/>   
  18.   
  19. <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">     
  20.             <property name="messageConverters">     
  21.                 <list>  
  22.                      
  23.                     <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">     
  24.                         <property name="supportedMediaTypes">     
  25.                             <list>     
  26.                                 <value>text/html;charset=UTF-8value>     
  27.                             list>     
  28.                         property>     
  29.                     bean>  
  30.                          
  31.                     <bean class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter"p:marshaller-ref="xstreamMarshaller" p:unmarshaller-ref="xstreamMarshaller" />  
  32.                     <bean class="org.springframework.http.converter.FormHttpMessageConverter">bean>     
  33.                     <bean class="org.springframework.http.converter.BufferedImageHttpMessageConverter">bean>     
  34.                     <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter">bean>     
  35.                     <bean class="org.springframework.http.converter.StringHttpMessageConverter">bean>     
  36.                     <bean class="org.springframework.http.converter.ResourceHttpMessageConverter">bean>     
  37.                 list>  
  38.             property>  
  39. bean>  
  40.     
  41. <bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">  
  42.     <property name="classesToBeBound">  
  43.        <list>  
  44.          <value>com.martinwu.example.entity.Uservalue>  
  45.        list>  
  46.     property>  
  47. bean>  
  48.   
  49. <bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">  
  50.     <property name="streamDriver">  
  51.         <bean class="com.thoughtworks.xstream.io.xml.StaxDriver" />  
  52.     property>  
  53.     <property name="annotatedClasses">  
  54.         <list>  
  55.            <value>com.martinwu.example.entity.Uservalue>  
  56.         list>  
  57.     property>  
  58. bean>  
  59.   
  60. <bean id="messageSource"class="org.springframework.context.support.ResourceBundleMessageSource">  
  61.     <property name="basenames">  
  62.       <list>  
  63.         <value>i18n/messagesvalue>  
  64.       list>  
  65.     property>  
  66.     <property name="useCodeAsDefaultMessage" value="true"/>  
  67. bean>  
  68.   
  69.   
  70. <mvc:default-servlet-handler/>  
  71.    
  72.   
  73.   
  74.     
  75.     <bean id="freemarkerConfigurer"  class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">    
  76.         <property name="templateLoaderPath" value="/WEB-INF/freemarker/" />    
  77.         <property name="defaultEncoding" value="UTF-8" />    
  78.         <property name="freemarkerSettings">    
  79.             <props>    
  80.                 <prop key="template_update_delay">10prop>    
  81.                 <prop key="locale">zh_CNprop>    
  82.                 <prop key="datetime_format">yyyy-MM-dd HH:mm:ssprop>    
  83.                 <prop key="date_format">yyyy-MM-ddprop>    
  84.                 <prop key="number_format">#.##prop>  
  85.             props>    
  86.         property>    
  87.     bean>        
  88.        
  89.   
  90. <bean id="multipleViewResolver" class="com.martinwu.example.view.viewresolver.MultipleViewResolver" p:order="0">   
  91.         <property name="resolvers">   
  92.             <map>  
  93.               <entry key="config,txt">   
  94.                     <bean class="com.martinwu.example.view.viewresolver.GenericFileViewResolver"  
  95.                        p:location="/WEB-INF/config/" p:cache="false">  
  96.                        <property name="viewName" value="configFileView"/>  
  97.                      bean>   
  98.               entry>  
  99.               <entry key="swf">   
  100.                     <bean class="com.martinwu.example.view.viewresolver.GenericFileViewResolver"  
  101.                       p:location="/WEB-INF/swf/" p:cache="false">  
  102.                         <property name="viewName" value="swfFileView"/>  
  103.                     bean>  
  104.                entry>  
  105.                <entry key="ftl">   
  106.                     <bean id="freeMarkerResolver"  class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver" p:order="2">    
  107.                        <property name="viewClass"   value="org.springframework.web.servlet.view.freemarker.FreeMarkerView" />    
  108.                        <property name="contentType" value="text/html;charset=UTF-8" />    
  109.                        <property name="exposeRequestAttributes" value="true" />    
  110.                        <property name="exposeSessionAttributes" value="true" />    
  111.                        <property name="exposeSpringMacroHelpers" value="true" />    
  112.                     bean>  
  113.                 entry>  
  114.                 <entry key="jasper">  
  115.                   
  116.                     <bean id="jasperReportsViewResolver" class="org.springframework.web.servlet.view.jasperreports.JasperReportsViewResolver"  
  117.                         p:viewClass="com.scinvest.util.support.JasperView"  
  118.                         p:requestContextAttribute="rc"  
  119.                         p:prefix="/WEB-INF/reportView/">  
  120.                           
  121.                         <property name="reportDataKey">  
  122.                              <value>datasourcevalue>  
  123.                         property>  
  124.                         <property name="exporterParameters">  
  125.                              <map>  
  126.                                     
  127.                                   <entry key="net.sf.jasperreports.engine.export.JRHtmlExporterParameter.IMAGES_URI">  
  128.                                       <value>#{rpe.resourceRoot}/images/reports/value>  
  129.                                   entry>  
  130.                                   <entry key="net.sf.jasperreports.engine.export.JRHtmlExporterParameter.CHARACTER_ENCODING">  
  131.                                        <value>UTF-8value>  
  132.                                   entry>  
  133.                                   <entry key="net.sf.jasperreports.engine.export.JRXlsExporterParameter.IS_ONE_PAGE_PER_SHEET">  
  134.                                        <bean id="java.lang.Boolean.TRUE" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean"/>  
  135.                                   entry>  
  136.                              map>  
  137.                         property>  
  138.                     bean>  
  139.                entry>  
  140.                <entry key="jsp">  
  141.                     <bean id="defaultViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
  142.                         <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>  
  143.                         <property name="contentType" value="text/html"/>          
  144.                         <property name="prefix" value="/WEB-INF/views/"/>  
  145.                     bean>  
  146.                 entry>  
  147.             map>   
  148.         property>   
  149.     bean>  
  150.         
  151.     <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver" p:order="1">    
  152.             
  153.          <property name="ignoreAcceptHeader" value="true"/>   
  154.              
  155.          <property name="favorPathExtension" value="true"/>    
  156.              
  157.          <property name="favorParameter" value="false"/>    
  158.          <property name="parameterName" value="format"/>   
  159.          <property name="defaultContentType" value="text/html"/>  
  160.          <property name="mediaTypes">    
  161.              <map>  
  162.   
  163.   
  164.                  <entry key="html" value="text/html;charset=UTF-8"/>  
  165.                  <entry key="xml" value="application/xml" />  
  166.                  <entry key="json" value="application/json" />  
  167.              map>    
  168.          property>  
  169.          <property name="defaultViews">  
  170.              <list>  
  171.                      
  172.                  <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" />  
  173.                      
  174.                  <bean class="org.springframework.web.servlet.view.xml.MarshallingView" >    
  175.                      <constructor-arg>  
  176.                          <ref bean="xstreamMarshaller"/>  
  177.                      constructor-arg>  
  178.                  bean>    
  179.              list>  
  180.          property>  
  181.      bean>   
  182.      <bean id="configFileView" class="com.martinwu.example.view.GenericFileView"   
  183.           p:contentType="text/plain" p:url="" scope="prototype"/>  
  184.      <bean id="swfFileView" class="com.martinwu.example.view.GenericFileView"  
  185.           p:contentType="application/x-shockwave-flash" p:url="" scope="prototype"/>  
  186.          
  187.      <bean id="viewResolver"  class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver" p:order="3">    
  188.          <property name="viewClass"   value="org.springframework.web.servlet.view.freemarker.FreeMarkerView" />    
  189.          <property name="suffix" value=".ftl" />    
  190.          <property name="contentType" value="text/html;charset=UTF-8" />    
  191.          <property name="exposeRequestAttributes" value="true" />    
  192.          <property name="exposeSessionAttributes" value="true" />    
  193.          <property name="exposeSpringMacroHelpers" value="true" />    
  194.      bean>        
  195.         
  196.     <bean id="defaultViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:order="5">  
  197.         <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>  
  198.         <property name="contentType" value="text/html"/>          
  199.         <property name="prefix" value="/WEB-INF/views/"/>  
  200.         <property name="suffix" value=".jsp"/>  
  201.     bean>   
  202.   
  203.     <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">  
  204.           
  205.         <property name="maxUploadSize" value="100000"/>  
  206.     bean>  
  207.    
  208.   
  209.     <mvc:view-controller path="/" view-name="redirect:/welcome"/>  
  210. beans>  

 

 

 

 

参考:http://www.ibm.com/developerworks/cn/java/j-lo-springview/

你可能感兴趣的:(Spring,MVC,Spring)