zoukankan      html  css  js  c++  java
  • springmvc学习指南 之---第28篇 springmvc的controller 如何解析视图view? 如何解析json,html,jsp?

    writedby 张艳涛 通常我们使用controller,会标注RequestMapping,那么通常是返回值是String类型,那么return "一个字符串",这个字符串应该解析什么呢?

    目录:

    1. @ResponseBody注解的用途
    2. 前端如何请求xml类型,json类型的返回值
    3. 后端的springmvc是如何解析的
    4. 扩展:如果前端发送的请求没有设置accept的值,那么返回的responsebody会为什么格式呢?
    5.   consumes = "application/json", produces = "application/json;charset=UTF-8"两个注解的讲解

    @ResponseBody注解的用途

    1.1基本用法举例,摘自spring-mvc-showcase

    @Controller
    public class SimpleController {
    
        @RequestMapping("/simple")
        public @ResponseBody
        String simple() {
            return "Hello world!";
        }
    }

    1.2前端请求

        <div id="simple">
            <h2>Simple</h2>
            <p>
                See the <code>org.springframework.samples.mvc.simple</code> package for the @Controller code
            </p>
            <ul>
                <li>
                    <a id="simpleLink" class="textLink" href="<c:url value="/simple" />">GET /simple</a>
                </li>
                <li>
                    <a id="simpleRevisited" class="textLink" href="<c:url value="/simple/revisited" />">GET /simple/revisited</a>
                </li>
            </ul>
        </div>
        $("a.textLink").click(function(){
            var link = $(this);
            $.ajax({ url: link.attr("href"), dataType: "text", success: function(text) { MvcUtil.showSuccessResponse(text, link); }, error: function(xhr) { MvcUtil.showErrorResponse(xhr.responseText, link); }});
            return false;
        });

    1.3返回类型

    如果看respnose headers 和responsebody信息如下:


    HTTP/1.1 200

    Content-Type: text/plain;charset=ISO-8859-1

    Content-Length: 12

    Date: Mon, 02 Aug 2021 09:49:35 GMT

    Hello world!

    1.4以上就解释了@responsebody的作用是将controller的返回字符串 添加为response的body里面了,还要注意到context-Type为text/plain了

    1.5上述没有说Accept的用途,accept的用途是指定response返回数据的格式,spring会根据accapt的格式设置body的内容格式

    如果对上面的发送ajax做个手脚

        $("a.textLink").click(function(){
            var link = $(this);
            $.ajax({ url: link.attr("href"), dataType: "text",
                beforeSend: function(req) {
    
                        req.setRequestHeader("Accept", "application/xml");
    
                },
                success: function(text) { MvcUtil.showSuccessResponse(text, link); },
                error: function(xhr) { MvcUtil.showErrorResponse(xhr.responseText, link); }});
            return false;
        });

    那么看返回的是response

    Content-Type: application/xml Content-Length: 12 Date: Mon, 02 Aug 2021 09:59:06 GMT

    看到了返回的是一个xml类型的信息,其字符串还是Hello World!

    这个例子不是很明显,accept启的作用,

        $("a.writeXmlLink").click(function() {
            var link = $(this);
            $.ajax({ url: link.attr("href"),
                beforeSend: function(req) { 
                    if (!this.url.match(/.xml$/)) {
                        req.setRequestHeader("Accept", "application/xml");
                    }
                },
                success: function(xml) {
                    MvcUtil.showSuccessResponse(MvcUtil.xmlencode(xml), link);
                },
                error: function(xhr) { 
                    MvcUtil.showErrorResponse(xhr.responseText, link);
                }
            });
            return false;
        });        

    json的

        $("a.writeJsonLink").click(function() {
            var link = $(this);
            $.ajax({ url: this.href,
                beforeSend: function(req) {
                    if (!this.url.match(/.json$/)) {
                        req.setRequestHeader("Accept", "application/json");
                    }
                },
                success: function(json) {
                    MvcUtil.showSuccessResponse(JSON.stringify(json), link);
                },
                error: function(xhr) {
                    MvcUtil.showErrorResponse(xhr.responseText, link);
                }});
            return false;
        });

    在看下controllre内容

        @RequestMapping(value="/xml", method=RequestMethod.GET)
        public @ResponseBody JavaBean writeXml() {
            return new JavaBean("bar", "apple");
        }
    
    ////=====
        @RequestMapping(value="/json", method=RequestMethod.GET)
        public @ResponseBody JavaBean writeJson() {
            return new JavaBean("bar", "apple");
        }

    第一个返回值为

    HTTP/1.1 200 Content-Type: application/xml Transfer-Encoding: chunked Date: Mon, 02 Aug 2021 10:05:29 GMT

    <javaBean>

    <foo>bar</foo>

    <fruit>apple</fruit>

    第二个

    HTTP/1.1 200 Content-Type: application/json;charset=UTF-8 Transfer-Encoding: chunked Date: Mon, 02 Aug 2021 10:17:07 GMT

    {"foo":"bar","fruit":"apple"}

    通过设置了不同的accept头,springmvc区别对待,返回了不同的值

    1.6以上是通过ajax来发送请求的,那么vue呢?不好意,我对前端也是有研究的

    // 全部管理机构
    asyncSetList({ commit }) {
    // 发请求获取list数据
    return new Promise((resolve, reject) => {
    const params = {
    url: 'api/application/CommonQueryAPI/queryLdCom'
    }
    apiByPost(params).then(res => {
    if (res.status === 0) {
    // 异步操作mutation函数赋值给state.ManageComlist
    commit('setList', res.data)
    resolve(res)
    }
    }).catch(error => {
    reject(error)
    })
    })
    },
    export function apiByPost(params) {
      return request({
        url: process.env.NODE_ENV === 'production' ? serviceSplit(params.url).substring(3) : serviceSplit(params.url),
        method: 'post',
        data: params.data
      })
    }
    
    export function apiByPost2(params) {
      return request({
        url: process.env.NODE_ENV === 'production' ? serviceSplit(params.url).substring(3) : serviceSplit(params.url),
        method: 'post',
        data: params.data,
        headers: { 'Content-Type': 'multipart/form-data' }
      })
    }

    那么看请求头

    如图所示,axios将accept设置为了

     

    Accept:  application/json, text/plain, */*
    springmvc处理为了json,那么spirngmvc背后逻辑是什么呢?
     

     2springmvc解析response的背后逻辑

     2.1debug进入代码

    2.2进入 selectHandler 方法

    对于返回值的处理器有17个,通过 handler.supportsReturnType(returnType) 来确定1-17那个处理满足要求就用哪个

    就是比较controller的返回值类型和handler是否匹配,看下面能知道返回值类型为 public class JavaBean 

    现在到了序号为13的处理器,看内部

    就是看有没有@Responsebody注解,那么咱们的方法上是有的,那么就使用这个处理器

    2.3进入 writeWithMessageConverters

    request要求的格式为

    springmvc能产出的格式为

    逻辑为

    以此找到合适的就是json,那么摔死messageConverter消息转换器来转换,

    有9个转换器

    现在在第8个解析器的时候,

    有俩个条件,一看JavaBean类上有没有注解

    package org.springframework.samples.mvc.mapping;
    
    import javax.xml.bind.annotation.XmlRootElement;
    
    @XmlRootElement
    public class JavaBean {
    
        private String foo = "bar";
    
        private String fruit = "apple";
    
        public String getFoo() {
            return foo;
        }
    
        public void setFoo(String foo) {
            this.foo = foo;
        }
    
        public String getFruit() {
            return fruit;
        }
    
        public void setFruit(String fruit) {
            this.fruit = fruit;
        }
    
        @Override
        public String toString() {
            return "JavaBean {foo=[" + foo + "], fruit=[" + fruit + "]}";
        }
    
    }

    现在是有注解,在看

    在看xml的类型和传入对比的一样吗

    现在是不一样,那么就返回对比不成功

    支持类型一共有3

    最后的一个handler,json解析,支持类型有2个

    答案马上揭晓了

    准备写入

    显示父类的,设置了contextType

    接着进入子类 AbstractJackson2HttpMessageConverter

     

    3如果不设置accept的值,默认情况(此为ajax的默认,不是axio的默认)

    代码如下

        $("a.writeJsonLink").click(function() {
            var link = $(this);
            $.ajax({ url: this.href,
                beforeSend: function(req) {
                    if (!this.url.match(/.json$/)) {
                        // req.setRequestHeader("Accept", "application/json");
                    }
                },
                success: function(json) {
                    MvcUtil.showSuccessResponse(JSON.stringify(json), link);
                },
                error: function(xhr) {
                    MvcUtil.showErrorResponse(xhr.responseText, link);
                }});
            return false;
        });

    查看请求结果

    说明了什么?说明了,spring并不只能的给你返回来xml格式的responsebody,

    此时如果浏览器如果按照xml解析,是解析不出来内容的,原因是什么呢?

    是在messageConverters对象是一个ArrayList其中是由顺序的,其中xml解析在json解析之前

    如图

    所以在accept为"*/*"的时候,就是按照转换器那个优先那个先执行 

    4 consumes = "application/json", produces = "application/json;charset=UTF-8"两个注解

    4.1用例

        @RequestMapping(value = "/json", method = RequestMethod.GET
                , consumes = "application/json", produces = "application/json;charset=UTF-8")
        public @ResponseBody
        JavaBean writeJson() {
            return new JavaBean("bar", "apple");
        }

    4.2这两个注解的作用

    第一个,consumes = "application/json" 作用要和来的请求reqeust进行比较,如果你的request的ContextType!=null 且和注解consumes一致就通过,否则不能匹配

    第二个,produces是将设置responsebody的格式,就是显性的设置,效果和accept效果是一致的,如果前端不设置accept,那么后端可以设置produces,当然也可以不设置, 

    使用pringmvc默认策略(在不出错的情况下)

    4.3对consumes="application/json"设置后,handlermapping的匹配逻辑

     关键在这里

    逻辑是查看request 中有没有设置contentType的值,本例是没有,那么 

    contentType= application/octet-stream

    查看controller上的consumes="xxx,xxx"中有没有octet-stream,如果没有则不能匹配,就根据给出的url找不到controller

    end: 

  • 相关阅读:
    针对数据库索引的优化
    acd
    HDOJ 5045 Contest
    《计算机时代》2015年第7期刊登出《基于数据仓库星形模式的广东省快速公路一张网资金结算情况分析系统》
    为什么大多数编程语言中的数组都从0開始
    十年,青春就是一转眼的事
    电子商务系统的设计与实现(十四):菜单高亮
    最近1个月的财务计划没有做好,囧啊
    最近1个月的财务计划没有做好,囧啊
    雷观(十九):我的人生观
  • 原文地址:https://www.cnblogs.com/zytcomeon/p/15091369.html
Copyright © 2011-2022 走看看