Spring MVC 之 ContentNegotiatingViewResolver


 我們已經知道 對於 RequestMappingInfoHandlerMapping, 它在對帶有后綴的http 請求進行匹配的時候,如果找不到精確的pattern, 那么就會 pattern+.* 后再匹配 url。  它會處理多個不同形式是 url, 但是返回的只是一個view。

ContentNegotiatingViewResolver 貌似也有這樣的功能,但實際上是大不一樣的。ContentNegotiatingViewResolver 有些難懂, 開始的時候, 我也是一直沒有搞懂,反而搞暈了, 非常郁悶和尷尬。 它有些復雜,但也還好。

 

現在考慮這么一個情況,只配置一個@RequestMapping, 匹配多個 url, 這些url 可能有三個方面的不同:

1 其他都相同,只是后綴不同。 比如 /aa.jsp /aa.pdf  /aa.xml  /aa.json /aa (無后綴)

2 其他都相同,只是format參數不同。 比如 /aa?view=jsp /aa?view=pdf  /aa?view=xml  /aa?view=json  /aa(無view 參數) 

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

 

如果是RequestMappingInfoHandlerMapping, 那么無法一個@RequestMapping滿足這樣的要求, 它需要多個@RequestMapping。

 

 ContentNegotiatingViewResolver 可以一個@RequestMapping,返回多個view。

我的配置如下:

<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參數方式和 后綴拓展名方式。

這里我直接使用了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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM