springmvc 中关于“内容协商”的小记

springmvc 中关于“内容协商”的小记


0、第一步,你要先配置,对吧,像下边这样:

@Configuration
@EnableWebMvc
public class MvcConfiguration extends WebMvcConfigurerAdapter {
 
  /**
    * Setup a simple strategy:
    *      1. Only path extension is taken into account, Accept headers are ignored.
    *      2. Return HTML by default when not sure.
    */
  @Override
  public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
      configurer.ignoreAcceptHeader(true)
                      .defaultContentType(MediaType.TEXT_HTML);
  }

  /**
    * Create the CNVR.  Get Spring to inject the ContentNegotiationManager created by the
    * configurer (see previous method).
    */
  @Bean
  public ViewResolver contentNegotiatingViewResolver(
        ContentNegotiationManager manager) {
    ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
    resolver.setContentNegotiationManager(manager);
    return resolver;
  }
}


1、其次,CNVR是指Content Negotiating View Resolver。既然是内容协商,那么CNVR就是其他视图解析器的老大咯!对于CNVR,它本身也是一个视图解析器,那么“order”这个概念对它是是不具备约束的。老大是通过ContentNegotiatingViewResolver  配置中的mediaTypes来指派具体由哪个视图解析器来resolve,spring通过你传过去的参数决定返回哪种mediaType。


2、你可以用一个List<ViewResolver> resolvers = new ArrayList<ViewResolver>();来作为视图解析器的集合,装入其他视图解析器,然后放入老大CNVR中进行统一调度。就像下边这样:

@Configuration
@EnableWebMvc
public class MvcConfiguration extends WebMvcConfigurerAdapter {
 
  // .. Other methods/declarations

  /**
    * Create the CNVR.  Specify the view resolvers to use explicitly.  Get Spring to inject
    * the ContentNegotiationManager created by the configurer (see previous method).
    */
  @Bean
  public ViewResolver contentNegotiatingViewResolver(
        ContentNegotiationManager manager) {
    // Define the view resolvers
    List<ViewResolver> resolvers = new ArrayList<ViewResolver>();

    XmlViewResolver r1 = new XmlViewResolver();
    resolver.setLocation(new ServletContextResource(servletContext,
            "/WEB-INF/spring/spreadsheet-views.xml"));
    resolvers.add(r1);

    InternalResourceViewResolver r2 = new InternalResourceViewResolver();
    r2.setPrefix("WEB-INF/views");
    r2.setSuffix(".jsp");
    resolvers.add(r2);

    // Create the CNVR plugging in the resolvers and the content-negotiation manager
    ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
    resolver.setViewResolvers(resolvers);
    resolver.setContentNegotiationManager(manager);
    return resolver;
  }
}


3、如果这样了,你还不满足,毕竟spring提供的视图解析器就那么几种。你可以定义自己的视图解析器,比如json解析器:

@Bean
public class JsonViewResolver implements ViewResolver {
    /**
      * Get the view to use.
      *
      * @return Always returns an instance of {@link MappingJacksonJsonView}.
     */
    @Override
    public View resolveViewName(String viewName, Locale locale) throws Exception {
		MappingJacksonJsonView view = new MappingJacksonJsonView();
		view.setPrettyPrint(true);      // Lay the JSON out to be nicely readable 
		return view;
    }
}

这样,你已经可以解析不少东西啦,看看:



4、看到这,我只想说 乖乖,现在我都玩restful啦,光一个试图解析算个毛啊。小伙伴们都在往注解的坑了跳,你要跟我一起跳吗?比如,玩玩@ResponseBody

其实为了更好的支持restful(包括修改数据的能力),我们是通过结合HTTP Message Converters以及用@controller注解的方法来玩的。views玩坏了,就只剩@ResponseBody当接盘侠了。或者,脚踏两条船,两者一起玩吧。艾玛,spring也真实灵活啊-。-


5、好,那我们继续来看下HttpMessageConverter

     首先,我得说Content-type ,http请求中都会包含,请自行f12.

然后,说一下,MediaType,即是Internet Media Type,互联网媒体类型;也叫做MIME类型,在Http协议消息头中,使用Content-Type来表示具体请求中的媒体类型信息.Content-Type是返回消息中非常重要的内容,表示后面的文档属于什么MIME类型。

Content-Type: [type]/[subtype]; parameter。例如最常见的就是text/html,它的意思是说返回的内容是文本类型,这个文本又是HTML格式的。原则上浏览器会根据Content-Type来决定如何显示返回的消息体内容。

然后,咱列个Content-Type的表:

常见的媒体格式类型如下:

        text/html : HTML格式
        text/plain :纯文本格式     
        text/xml :  XML格式
        image/gif :gif图片格式   
        image/jpeg :jpg图片格式
        image/png:png图片格式

   以application开头的媒体格式类型:

       application/xhtml+xml :XHTML格式
       application/xml     : XML数据格式
       application/atom+xml  :Atom XML聚合格式   
       application/json    : JSON数据格式
       application/pdf       :pdf格式
       application/msword  : Word文档格式
       application/octet-stream : 二进制流数据(如常见的文件下载)
       application/x-www-form-urlencoded : <form encType=””>中默认的encType,form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式)

   另外一种常见的媒体格式是上传文件之时使用的:

        multipart/form-data : 需要在表单中进行文件上传时,就需要使用该格式

     以上就是我们在日常的开发中,经常会用到的若干content-type的内容格式。

其中,springmvc会踩到的一个坑是:application/x-www-form-urlencoded : <form encType=””>中默认的encType,form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式)   。遇到    415 Unsupported Media Type的神坑时的我还根本反应过来。。竟然是converter配置出问题了。

小样,前端传个表格你unsupport是几个意思=。=  god,请自行来一打FormHttpMessageConverter转转吧。


好啦,列一下常用的HttpMessageConverter:

ByteArrayHttpMessageConverter: 负责读取二进制格式的数据和写出二进制格式的数据;
StringHttpMessageConverter:   负责读取字符串格式的数据和写出二进制格式的数据;(字符串格式是什么啊 orz)
 ResourceHttpMessageConverter:负责读取资源文件和写出资源文件数据;
FormHttpMessageConverter:       负责读取form提交的数据(能读取的数据格式为 application/x-www-form-urlencoded,不能读取multipart/form-data格式数据);负责写入application/x-www-from-urlencoded和multipart/form-data格式的数据;
MappingJacksonHttpMessageConverter:  负责读取和写入json格式的数据;
SourceHttpMessageConverter:                   负责读取和写入 xml 中javax.xml.transform.Source定义的数据;
Jaxb2RootElementHttpMessageConverter:  负责读取和写入xml 标签格式的数据;
AtomFeedHttpMessageConverter:              负责读取和写入Atom格式的数据;
RssChannelHttpMessageConverter:           负责读取和写入RSS格式的数据;

还不够?自行脑部!

6,科普完概念,我们看看流程,HttpMessageConverter请求信息转换器执行的:

默念五分钟,闭眼脑部:

跟我一起读----当用户发送请求后,@Requestbody 注解会读取请求body中的数据,默认的请求转换器HttpMessageConverter通过获取请求头Header中的Content-Type(上边我说过了)来确认请求头的数据格式,从而来为请求数据适配合适的转换器(有哪些,给我默写去)。例如contentType:applicatin/json,那么转换器会适配MappingJacksonHttpMessageConverter。响应时候的时候同理,@Responsebody注解会启用HttpMessageConverter,通过检测Header中Accept属性来适配的响应的转换器。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值