Spring MVC 之 ContentNegotiatingViewResolver

 咱們已經知道 對於 RequestMappingInfoHandlerMapping, 它在對帶有後綴的http 請求進行匹配的時候,若是找不到精確的pattern, 那麼就會 pattern+.* 後再匹配 url。  它會處理多個不一樣形式是 url, 可是返回的只是一個view。web

ContentNegotiatingViewResolver 貌似也有這樣的功能,但其實是大不同的。ContentNegotiatingViewResolver 有些難懂, 開始的時候, 我也是一直沒有搞懂,反而搞暈了, 很是鬱悶和尷尬。 它有些複雜,但也還好。spring

 

如今考慮這麼一個狀況,只配置一個@RequestMapping, 匹配多個 url, 這些url 可能有三個方面的不一樣:json

1 其餘都相同,只是後綴不一樣。 好比 /aa.jsp /aa.pdf  /aa.xml  /aa.json /aa (無後綴)mvc

2 其餘都相同,只是format參數不一樣。 好比 /aa?view=jsp /aa?view=pdf  /aa?view=xml  /aa?view=json  /aa(無view 參數) app

3 其餘都相同,只是accept-type不一樣。 好比 /aa HTTP Request Header中的Accept 分別是 text/jsp,  text/pdf,  text/xml,  text/json,  無Accept 請求頭yii

 

若是是RequestMappingInfoHandlerMapping, 那麼沒法一個@RequestMapping知足這樣的要求, 它須要多個@RequestMapping。jsp

 

 ContentNegotiatingViewResolver 能夠一個@RequestMapping,返回多個view。ide

個人配置以下:測試

<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
   <property name="favorParameter" value="true"/>
   <property name="favorPathExtension" value="true"/>
   <property name="mediaTypes">
         <map>
            <entry key="xml" value="application/xml"/>   // 
            <entry key="json" value="application/json"/> // 這裏, 對於 json ,必須是application/json
            <!--<entry key="json" value="text/plain"/>-->
            <entry key="xls" value="application/vnd.ms-excel"/>
         </map>
   </property>
   <property name="viewResolvers"> 
      <list>
         <ref bean="jaxb2MarshallingXmlViewResolver"></ref>
         <ref bean="jsonViewResolver"></ref>
         <ref bean="excelViewResolver"></ref>
      </list>
   </property>
</bean>

上面的 viewResolvers 屬性是能夠不用配置的, 默認spring 會查找全部 ViewResolver類型的對象。這樣, 就同時支持了 parameter參數方式和 後綴拓展名方式。url

這裏我直接使用了ContentNegotiatingViewResolver, 實際spring 給咱們提供了 ContentNegotiationManagerFactoryBean這是推薦的方式。 配置上相似。

 

默認是支持path 後綴拓展方式, 也支持accept 請求頭,但不支持 format 參數的。 所以若是咱們想使用 進行參數方式匹配, 那麼咱們須要把favorParameter 設置爲true, 另外此時mediaTypes 也是必須正確配置的。 我感受有些不合理。 應該是默認支持的, 如今卻要我手動配置, 不過,我測試就是這樣的結果。

源碼是:


private boolean favorPathExtension = true; // 支持

private boolean favorParameter = false; // 默認不支持

private boolean ignoreAcceptHeader = false; // 默認支持accept頭

private Map<String, MediaType> mediaTypes = new HashMap<String, MediaType>();

private boolean ignoreUnknownPathExtensions = true;

private Boolean useJaf;

private String parameterName = "format";

除了xml 方式配置, 咱們可使用註解方式配置:

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.yiibai.springmvc")
public class AppConfig extends WebMvcConfigurerAdapter {

    /*
     * Configure ContentNegotiationManager
     */
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.ignoreAcceptHeader(true).defaultContentType(
                MediaType.TEXT_HTML);
    }

    /*
     * Configure ContentNegotiatingViewResolver
     */
    @Bean
    public ViewResolver contentNegotiatingViewResolver(ContentNegotiationManager manager) {
        ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
        resolver.setContentNegotiationManager(manager);

        // Define all possible view resolvers
        List<ViewResolver> resolvers = new ArrayList<ViewResolver>();

        resolvers.add(jaxb2MarshallingXmlViewResolver());
        resolvers.add(jsonViewResolver());
        resolvers.add(jspViewResolver());
        resolvers.add(pdfViewResolver());
        resolvers.add(excelViewResolver());
        
        resolver.setViewResolvers(resolvers);
        return resolver;
    }

    /*
     * Configure View resolver to provide XML output Uses JAXB2 marshaller to
     * marshall/unmarshall POJO's (with JAXB annotations) to XML
     */
    @Bean
    public ViewResolver jaxb2MarshallingXmlViewResolver() {
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
        marshaller.setClassesToBeBound(Pizza.class);
        return new Jaxb2MarshallingXmlViewResolver(marshaller);
    }

    /*
     * Configure View resolver to provide JSON output using JACKSON library to
     * convert object in JSON format.
     */
    @Bean
    public ViewResolver jsonViewResolver() {
        return new JsonViewResolver();
    }

    /*
     * Configure View resolver to provide PDF output using lowagie pdf library to
     * generate PDF output for an object content
     */
    @Bean
    public ViewResolver pdfViewResolver() {
        return new PdfViewResolver();
    }

    /*
     * Configure View resolver to provide XLS output using Apache POI library to
     * generate XLS output for an object content
     */
    @Bean
    public ViewResolver excelViewResolver() {
        return new ExcelViewResolver();
    }

    /*
     * Configure View resolver to provide HTML output This is the default format
     * in absence of any type suffix.
     */
    @Bean
    public ViewResolver jspViewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setViewClass(JstlView.class);
        viewResolver.setPrefix("/WEB-INF/views/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }

}
 

 對於boot, 其自動配置了一個

        @Bean
        @ConditionalOnBean({ViewResolver.class})
        @ConditionalOnMissingBean(
            name = {"viewResolver"},
            value = {ContentNegotiatingViewResolver.class}
        )
        public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
            ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
            resolver.setContentNegotiationManager((ContentNegotiationManager)beanFactory.getBean(ContentNegotiationManager.class));
            resolver.setOrder(-2147483648);
            return resolver;
        }


        @Bean
        public ContentNegotiationManager mvcContentNegotiationManager() {
            ContentNegotiationManager manager = super.mvcContentNegotiationManager();
            List<ContentNegotiationStrategy> strategies = manager.getStrategies();
            ListIterator iterator = strategies.listIterator();

            while(iterator.hasNext()) {
                ContentNegotiationStrategy strategy = (ContentNegotiationStrategy)iterator.next();
                if (strategy instanceof PathExtensionContentNegotiationStrategy) { // 只支持後綴 方式匹配
                    iterator.set(new WebMvcAutoConfiguration.OptionalPathExtensionContentNegotiationStrategy(strategy)); 
                }
            }

            return manager;
        }

可是, 它只支持 後綴方式匹配。

 

參考 

http://blog.csdn.net/fw0124/article/details/48315523

 http://blog.csdn.net/fw0124/article/details/48315523

http://blog.csdn.net/z69183787/article/details/41696709

相關文章
相關標籤/搜索