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

来源:互联网 发布:finale打谱软件汉化 编辑:程序博客网 时间:2024/06/05 18:04

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


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

@Configuration@EnableWebMvcpublic 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@EnableWebMvcpublic 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解析器:

@Beanpublic 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 0