美文网首页SpringMvc我爱编程
SpringMvc 使用 REST 和 使用 AJAX 发送 R

SpringMvc 使用 REST 和 使用 AJAX 发送 R

作者: wanggs | 来源:发表于2018-05-12 17:33 被阅读12次

Spring MVC 提供了 REST 风格的注解支持,使用 GetMapping, PostMapping, PutMapping, DeleteMapping。JS 的 AJAX 原生支持 GET, PUT, POST, DELETE 请求,但是 Form 表单只支持 POST,不支持 PUT 和 DELETE,为了让 Form 表单也能够使用 REST 的风格进行提交,需要给表单额外提供一个参数 _method:

  • _method 为 put 表示 PUT 请求
  • _method 为 delete 表示 DELETE 请求

服务器端还需要一个 Filter 把 Form 表单的 REST 请求转换为 Spring MVC 识别的 REST 请求。

在 web.xml 里加上 HiddenHttpMethodFilter
<!-- 浏览器的 form 不支持 put, delete 等 method, 由该 filter 将 /blog?_method=delete 转换为标准的 http delete 方法 -->
<filter>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <servlet-name>springmvc</servlet-name>
</filter-mapping>

RestController
package com.xtuer.controller;
import com.xtuer.bean.Result;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@Controller
public class RestController {
    @GetMapping("/rest-form")
    public String restForm() {
        return "rest-form.html";
    }
    @GetMapping("/rest/{id}")
    @ResponseBody
    public Result handleGet(@PathVariable int id, @RequestParam String name, ModelMap map) {
        map.addAttribute("id", id);
        map.addAttribute("name", name);
        return new Result(true, "GET handled", map);
    }
    // 查询
    @GetMapping("/rest")
    @ResponseBody
    public Result handleGet(@RequestParam String name) {
        return new Result(true, "GET handled", name);
    }
    // 更新
    @PutMapping("/rest")
    @ResponseBody
    public Result handlePut() {
        return new Result(true, "UPDATE handled");
    }
    // 创建
    @PostMapping("/rest")
    @ResponseBody
    public Result handlePost() {
        return new Result(true, "CREATE handled");
    }
    // 删除
    @DeleteMapping("/rest")
    @ResponseBody
    public Result handleDelete() {
        return new Result(true, "DELETE handled");
    }
}
新建一个网页 rest-form.htm
  • 页面里有 4 个按钮,分别为 GET, PUT, POST, DELET

  • GET 按钮发送 GET 请求

  • PUT 按钮发送 PUT 请求

  • POST 按钮发送 POST 请求

  • DELETE 按钮发送 DELETE 请求

  • Form 表单默认支持 GET 和 POST 请求,但不支持 PUT 和 DELETE
    请求。

为了发送 PUT, DELETE请求,在 form 里添加一个隐藏域 _method 表明发送 PUT, DELETE 请求,使用 POST 提交。

<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
    <style>
        body { padding: 25px 50px; }
        button { width: 100px; }
    </style>
</head>
<body>
    <!-- 测试 form 的不同 method,default HTML form 不支持 put and delete -->
    <form action="/rest" method="get">
        <input type="hidden" name="name"/>
        <button type="submit">Get</button>
    </form>
    <form action="/rest" method="post">
        <button type="submit">Post</button>
    </form>
    <form action="/rest" method="post">
        <input type="hidden" name="_method" value="put"/>
        <button type="submit">Put</button>
    </form>
    <form action="/rest" method="post">
        <input type="hidden" name="_method" value="delete"/>
        <button type="submit">Delete</button>
    </form>
</body>
</html>

测试

访问 http://localhost:8080/rest-form 查看输出

使用 AJAX 发送 REST 请求

Form 表单不支持提交 PUT,DELETE 请求,所以我们通过隐藏域的方式间接的达到了目的。但是 AJAX 原生的就支持 GET, PUT, POST, DELETE 请求。

使用 REST 风格提交请求时,Content-Type 标准的来说应该用 application/json,但是服务器端获取请求的参数时必须从 Request Body 中获取,而且有些框架对从 Request Body 中获取数据支持不好,需要我们自己实现,SpringMVC 中使用注解 @RequestBody 从 Request Body 中获取数据,但不能使用 Filter 进行 XSS 过滤。

这里主要使用 SpringMVC 来作为后端进行介绍,SpringMVC 提供了一个 Filter HiddenHttpMethodFilter,把 Content-Type 为 application/x-www-form-urlencoded 的 POST 请求,参数中 _method 值为 PUT 的请求分发为 PUT 请求,为 DELETE 请求分发为 DELETE 请求,实现了普通表单的 REST 风格提交,这样就可以使用 @RequestParam 获取参数的值了。

下面结合 SpringMVC 来介绍:
  • Content-Type 为 application/x-www-form-urlencoded + HiddenHttpMethodFilter

    • 优点: 服务器端 GET, PUT, POST, DELETE 时直接参数映射为对象,或则都使用 @RequestParam 获取参数,使用形式一致、简洁
    • 缺点:
      • 不是标准的 REST 规范
        参数是按照 key/value 的形式发送的,和普通表单的参数形式一样,有兴趣的可以在 Chrome 的 Network 中查看请求的 Headers
        不方便传递复杂对象,例如 value 又是一个 Json 对象,不过估计 90% 的情况简单的 key/value 就够了
        PUT 时参数中需要带上 _method=PUT,DELETE 时参数中需要带上 _method=DELETE
  • Content-Type 为 application/json

    • 优点: 标准的 REST 规范,GET 处理和上面的一样,但是 POST, PUT, DELETE 的参数是序列化后的 JSON 字符串,能够传递复杂的对象
    • 缺点:
      • 服务器端直接参数映射为对象,或则 GET 时使用 @RequestParam 获取参数,POST, PUT, DELETE 使用 @RequestBody 获取参数到 Map 中,然后再从 Map 中获取一个一个的参数,非常繁琐
        GET 和 POST, PUT, DELETE 获取参数的形式不统一,一个用 @RequestParam,其他的用 @RequestBody,需要脑子转换一下
        还有就是浏览器端 PUT, POST, DELETE 传递的 JSON 对象需要序列化后才能传给服务器端,可以使用 JSON.stringify(jsonObject) 进行序列化

总结下来,在 SpringMVC 中推荐使用 application/x-www-form-urlencoded + HiddenHttpMethodFilter 的方式实现 REST 的请求,就是为了获取参数时比较统一,当需要传递复杂的参数时,例如属性是多层嵌套的对象,Json 对象的数组,这时再使用 application/json 的方式。

为了简化 Rest Ajax 的访问,下面对 jQuery 的 Ajax 进行了简单的封装成插件 jQuery.rest,下面的例子展示了更新用户名原始实现和简化后的代码:
$.ajax({
    url        : '/users/1/username',
    data       : JSON.stringify({name: 'Bob'}),
    type       : 'PUT',
    dataType   : 'json',
    contentType: 'application/json'
})
.done(function(result) {
    console.log(result);
});
如果每个 REST 的请求都像上面这样写一遍: PUT, POST, DELETE 时需要 JSON.stringify(data), 请求不同时 type 也不同,dataType 和 contentType 是固定的,这么多限制,很容易出错。使用下面实现的 rest 插件后,简化如下,只需要关心参数和回调,不需要处理其他额外信息,而且 $.rest.update 名字也更有语义化,一看就知道是更新操作:
$.rest.update({
    url    : '/users/1/username', 
    data   : {name: 'Bob'}, 
    success: function(result) {
        console.log(result);
    }
});

更多例子:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>REST</title>
</head>
<body>
    <script src="http://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
    <script src="/js/jquery.rest.js"></script>
    <script>
        // [1] 服务器端的 GET 需要启用 UTF-8 才不会乱吗
        $.rest.get({url: '/rest', data: {name: 'Alice'}, success: function(result) {
            console.log(result);
        }});
        // [2] 普通 form 表单提交 rest Ajax 请求
        $.rest.create({url: '/rest', success: function(result) {
            console.log(result);
        }});
        $.rest.update({url: '/rest', data: {name: '黄飞鸿', age: 22}, success: function(result) {
            console.log(result);
        }});
        $.rest.remove({url: '/rest', success: function(result) {
            console.log(result);
        }});
        // [3] 使用 request body 传递复杂 Json 对象
        $.rest.create({url: '/rest/requestBody', data: {name: 'Alice'}, jsonRequestBody: true, success: function(result) {
            console.log(result);
        }});
        $.rest.update({url: '/rest/requestBody', data: {name: 'Alice'}, jsonRequestBody: true, success: function(result) {
            console.log(result);
        }});
        $.rest.remove({url: '/rest/requestBody', data: {name: 'Alice'}, jsonRequestBody: true, success: function(result) {
            console.log(result);
        }});
    </script>
</body>
</html>

输出:
{code: 0, data: "Alice", message: "GET handled", success: true}
{code: 0, message: "CREATE handled", success: true}
{code: 0, message: "DELETE handled", success: true}
{code: 0, data: "黄飞鸿 : 22", message: "UPDATE handled", success: true}
{code: 0, message: "UPDATE requestBody handled: {\"name\":\"Alice\"}", success: true}
{code: 0, message: "CREATE requestBody handled: {\"name\":\"Alice\"}", success: true}
{code: 0, message: "DELETE requestBody handled: {\"name\":\"Alice\"}", success: true}

REST 插件 jquery.rest.js:
(function($) {
    /**
     * 执行 REST 请求的 jQuery 插件,不以 sync 开头的为异步请求,以 sync 开头的为同步请求:
     *      Get    请求调用 $.rest.get(),    $.rest.syncGet()
     *      Create 请求调用 $.rest.create(), $.rest.syncCreate()
     *      Update 请求调用 $.rest.update(), $.rest.syncUpdate()
     *      Delete 请求调用 $.rest.remove(), $.rest.syncRemove()
     *
     * 默认使用 contentType 为 application/x-www-form-urlencoded 的方式提交请求,只能传递简单的 key/value,
     * 就是普通的 form 表单提交,如果想要向服务器传递复杂的 json 对象,可以使用 contentType 为 application/json 的格式,
     * 此时只要设置请求的参数 jsonRequestBody 为 true 即可,例如
     *      $.rest.update({url: '/rest', data: {name: 'Alice'}, jsonRequestBody: true, success: function(result) {
     *          console.log(result);
     *      }});
     *
     * 调用示例:
     *      // 异步请求
     *      $.rest.get({url: '/rest', data: {name: 'Alice'}, success: function(result) {
     *          console.log(result);
     *      }});
     *
     *      // 同步请求
     *      $.rest.syncGet({url: '/rest', data: {name: 'Alice'}, success: function(result) {
     *          console.log(result);
     *      }});
     *
     *      // url 中的 bookId 会被替换为 urlParams 中的 bookId
     *      $.rest.update({url: '/rest/books/{bookId}', urlParams: {bookId: 23}, data: {name: 'C&S'}, success: function(result) {
     *          console.log(result);
     *      }}, fail: function(failResponse) {});
     * 提示:
     *     绝大多数时候不需要传入 fail 的回调函数,已经默认提供了 401,403,404,服务器抛异常时的 500,服务不可达的 502 等错误处理: 弹窗提示和打印错误信息。
     */
    $.rest = {
        /**
         * 使用 Ajax 的方式执行 REST 的 GET 请求(服务器响应的数据根据 REST 的规范,必须是 Json 对象,否则浏览器端会解析出错)。
         * 如果没有设置 fail 的回调函数,则默认会把错误信息打印到控制台,可自定义 $.rest.defaultFail 函数例如使用弹窗显示错误信息。
         *
         * 以下几个 REST 的函数 $.rest.create(), $.rest.update(), $.rest.remove() 只是请求的 HTTP 方法和 data 处理不一样,
         * 其他的都是相同的,所以就不再重复注释说明了。
         *
         * @param {Json} options 有以下几个选项:
         *               {String}   url       请求的 URL        (必选)
         *               {Json}     urlParams URL 中的变量,例如 /rest/users/{id},其中 {id} 为要被 urlParams.id 替换的部分(可选)
         *               {Json}     data      请求的参数         (可选)
         *               {Boolean}  jsonRequestBody 是否使用 application/json 的方式进行请求,默认为 false 不使用(可选)
         *               {Function} success   请求成功时的回调函数(可选)
         *               {Function} fail      请求失败时的回调函数(可选)
         *               {Function} complete  请求完成后的回调函数(可选)
         * @return 没有返回值
         */
        get: function(options) {
            options.httpMethod = 'GET';
            this.sendRequest(options);
        },
        create: function(options) {
            options.data = options.data || {};
            options.httpMethod = 'POST';
            this.sendRequest(options);
        },
        update: function(options) {
            options.data = options.data || {};
            options.httpMethod   = 'POST';
            options.data._method = 'PUT'; // SpringMvc HiddenHttpMethodFilter 的 PUT 请求
            this.sendRequest(options);
        },
        remove: function(options) {
            options.data = options.data || {};
            options.httpMethod   = 'POST';
            options.data._method = 'DELETE'; // SpringMvc HiddenHttpMethodFilter 的 DELETE 请求
            this.sendRequest(options);
        },
        // 阻塞请求
        syncGet: function(options) {
            options.async = false;
            this.get(options);
        },
        syncCreate: function(options) {
            options.async = false;
            this.create(options);
        },
        syncUpdate: function(options) {
            options.async = false;
            this.update(options);
        },
        syncRemove: function(options) {
            options.async = false;
            this.remove(options);
        },
        /**
         * 执行 Ajax 请求,不推荐直接调用这个方法.
         *
         * @param {Json} options 有以下几个选项:
         *               {String}   url        请求的 URL        (必选)
         *               {String}   httpMethod 请求的方式,有 GET, PUT, POST, DELETE (必选)
         *               {Json}     urlParams  URL 中的变量      (可选)
         *               {Json}     data       请求的参数        (可选)
         *               {Boolean}  async      默认为异步方式     (可选)
         *               {Boolean}  jsonRequestBody 是否使用 application/json 的方式进行请求,默认为 false 不使用(可选)
         *               {Function} success    请求成功时的回调函数(可选)
         *               {Function} fail       请求失败时的回调函数(可选)
         *               {Function} complete   请求完成后的回调函数(可选)
         */
        sendRequest: function(options) {
            var self = this;
            // 默认设置
            var defaults = {
                data           : {},
                async          : true,
                jsonRequestBody: false,
                contentType    : 'application/x-www-form-urlencoded;charset=UTF-8',
                success        : function() {},
                fail           : function() {},
                complete       : function() {}
            };
            // 使用 jQuery.extend 合并用户传递的 options 和 defaults
            var settings = $.extend(true, {}, defaults, options);
            // 使用 application/json 的方式进行请求时,需要处理相关参数
            if (settings.jsonRequestBody) {
                if (settings.data._method === 'PUT') {
                    settings.httpMethod = 'PUT';
                } else if (settings.data._method === 'DELETE') {
                    settings.httpMethod = 'DELETE';
                }
                delete settings.data._method; // 没必要传递一个无用的参数
                settings.contentType = 'application/json;charset=UTF-8';
                // 非 GET 时 json 对象需要序列化
                if (settings.data.httpMethod !== 'GET') {
                    settings.data = JSON.stringify(settings.data);
                }
            }
            // 替换 url 中的变量,例如 /rest/users/{id}, 其中 {id} 为要被 settings.urlParams.id 替换的部分
            if (settings.urlParams) {
                settings.url = settings.url.replace(/\{\{|\}\}|\{(\w+)\}/g, function(m, n) {
                    // m 是正则中捕捉的组 $0,n 是 $1,function($0, $1, $2, ...)
                    if (m == '{{') { return '{'; }
                    if (m == '}}') { return '}'; }
                    return settings.urlParams[n];
                });
            }
            // 执行 AJAX 请求
            $.ajax({
                url        : settings.url,
                data       : settings.data,
                async      : settings.async,
                type       : settings.httpMethod,
                dataType   : 'json', // 服务器的响应使用 JSON 格式
                contentType: settings.contentType,
                // 服务器抛异常时,有时 Windows 的 Tomcat 环境下竟然取不到 header X-Requested-With, Mac 下没问题,
                // 正常请求时都是好的,手动添加 X-Requested-With 为 XMLHttpRequest 后所有环境下正常和异常时都能取到了
                headers: {'X-Requested-With': 'XMLHttpRequest'},
                // 各种状态的错误可以在此拦截统一处理,弹窗提示,应用里就不需要单一一独处理了
                statusCode: {
                    401: function() {
                        alert( "Token 无效" );
                    },
                    403: function() {
                        alert('权限不够');
                    },
                    404: function() {
                        alert('URL 不存在');
                    },
                    500: function(error) {
                        // 发生 500 错误时服务器抛出异常,在控制台打印出异常信息
                        console.error(error.responseJSON.data);
                        alert('服务器抛出异常,请联系管理员\n\n详细错误信息请查看控制台输出 (Chrome 按下快捷键 F12)');
                    },
                    502: function() {
                        // 发生 502 错误时,Tomcat Web 服务器不可到达,一般有 2 个原因
                        // 1. Nginx 配置出错
                        // 2. Tomcat 的 Web 服务没启动或者不接收请求
                        alert('502 错误,服务器不可到达');
                    }
                }
            })
            .done(function(data, textStatus, jqXHR) {
                settings.success(data, textStatus, jqXHR);
            })
            .fail(function(jqXHR, textStatus, failThrown) {
                // data|jqXHR, textStatus, jqXHR|failThrown
                settings.fail(jqXHR, textStatus, failThrown);
            })
            .always(function() {
                settings.complete();
            });
        }
    };
    /**
     * 执行 Jsonp 请求,服务器端访问回调函数名使用 key 为 'callback'
     *
     * @param  {String}   url      请求的 URL
     * @param  {Function} callback 请求成功的回调函数,参数为服务器端返回的结果
     * @return 无返回值
     */
    $.jsonp = function(url, callback) {
        $.ajax({
            url     : url,
            type    : 'GET',
            dataType: 'jsonp',
            success : function(data) {
                callback && callback(data);
            }
        });
    };
})(jQuery);

服务器端

添加下面的 Filter 到 web.xml, servlet-name 为 DispatcherServlet 的 servlet-name,根据自己的配置进行修改

<!-- 浏览器的 form 不支持 put, delete 等 method, 由该 filter 将 /blog?_method=delete 转换为标准的 http delete 方法 -->
<filter>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <servlet-name>springmvc</servlet-name>
</filter-mapping>

Controller 的实现:
package com.xtuer.controller;
import com.xtuer.bean.Result;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@Controller
public class RestController {
    /**
     * REST 读取
     * URL: http://localhost:8080/rest
     * 参数: name
     *
     * @param name
     * @return
     */
    @GetMapping("/rest")
    @ResponseBody
    public Result restGet(@RequestParam String name) {
        return Result.ok("GET handled", name);
    }
    /**
     * REST 创建
     * URL: http://localhost:8080/rest
     * 参数: 无
     *
     * @return
     */
    @PostMapping("/rest")
    @ResponseBody
    public Result restPost() {
        return new Result(true, "CREATE handled");
    }
    /**
     * REST 的更新
     * URL: http://localhost:8080/rest
     * 参数: name, age
     *
     * @param name
     * @param age
     * @return
     */
    @PutMapping("/rest")
    @ResponseBody
    public Result restPut(@RequestParam String name, @RequestParam int age) {
        return new Result(true, "UPDATE handled", name + " : " + age);
    }
    /**
     * REST 删除
     * URL: http://localhost:8080/rest
     * 参数: 无
     *
     * @return
     */
    @DeleteMapping("/rest")
    @ResponseBody
    public Result restDelete() {
        return new Result(true, "DELETE handled");
    }
    /**
     * REST 创建,处理 application/json 的请求
     * URL: http://localhost:8080/rest/requestBody
     * 参数: name
     *
     * @return
     */
    @PostMapping("/rest/requestBody")
    @ResponseBody
    public Result restPostJsonRequestBody(@RequestBody String content) {
        return new Result(true, "CREATE requestBody handled: " + content);
    }
    /**
     * REST 更新,处理 application/json 的请求
     * URL: http://localhost:8080/rest/requestBody
     * 参数: name
     *
     * @return
     */
    @PutMapping("/rest/requestBody")
    @ResponseBody
    public Result restUpdateJsonRequestBody(@RequestBody String content) {
        return new Result(true, "UPDATE requestBody handled: " + content);
    }
    /**
     * REST 删除,处理 application/json 的请求
     * URL: http://localhost:8080/rest/requestBody
     * 参数: name
     *
     * @return
     */
    @DeleteMapping("/rest/requestBody")
    @ResponseBody
    public Result restDeleteJsonRequestBody(@RequestBody String content) {
        return new Result(true, "DELETE requestBody handled: " + content);
    }
}

Result.java

Result 用于统一服务器端返回的 JSON 格式,例如:

{
    "code": 0,
    "message": "Short message",
    "success": true,
    "data": {
        "name": "Alice"
    }
}


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONPObject;
import lombok.Getter;
import lombok.Setter;
/**
 * Http Ajax 请求返回时用作返回的对象,FastJson 自动转换为 Json 字符串返回给前端。
 * 提供了多个变种的 ok() 和 fail() 方法简化创建 Result 对象。
 *
 * 虽然同一个请求在不同情况下返回的 Result 中的 data 类型可能不同,例如 Result<User> findUserByName(String name),
 * 查询到用户时返回 Result 中 data 是 User 对象,查询不到用户时可返回 Result 中 data 是 String 对象,不过没关系,
 * 在我们的实现中允许这么做,好处是标志出了请求正确响应时返回的数据类型,因为这个才是我们最关心的。
 */
@Getter
@Setter
public final class Result<T> {
    private boolean success; // 成功时为 true,失败时为 false
    private String  message; // 成功或则失败时的描述信息
    private Object  data;    // 成功或则失败时的更多详细数据,一般失败时不需要
    private Integer code;    // 状态码,一般是当 success 为 true 或者 false 时不足够表达时才使用,平时忽略即可
    public Result(boolean success, String message) {
        this(success, message, null);
    }
    public Result(boolean success, String message, Object data) {
        this(success, message, data, null);
    }
    public Result(boolean success, String message, Object data, Integer code) {
        this.success = success;
        this.message = message;
        this.data = data;
        this.code = code;
    }
    public static <T> Result<T> ok() {
        return new Result<>(true, "success");
    }
    public static <T> Result<T> ok(Object data) {
        return new Result<>(true, "success", data);
    }
    public static <T> Result<T> ok(String message, Object data) {
        return new Result<>(true, message, data);
    }
    public static <T> Result<T> ok(String message, Object data, Integer code) {
        return new Result<>(true, message, data, code);
    }
    public static <T> Result<T> fail() {
        return new Result<>(false, "fail");
    }
    public static <T> Result<T> fail(Object data) {
        return new Result<>(false, "fail", data);
    }
    public static <T> Result<T> fail(String message, Object data) {
        return new Result<>(false, message, data);
    }
    public static <T> Result<T> fail(String message, Object data, Integer code) {
        return new Result<>(false, message, data, code);
    }
    /**
     * 使用传入的回调函数名字 callback 和参数 params 构造一个 JSONP 响应格式的字符串。
     *
     * @param callback 浏览器端 JSONP 回调函数的名字
     * @param data 参数列表
     * @return 返回 JSONP 格式的字符串
     */
    public static String jsonp(String callback, Object data) {
        JSONPObject jp = new JSONPObject(callback);
        jp.addParameter(data);
        return jp.toString();
    }
    // 测试
    public static void main(String[] args) {
        // Result
        Result<User> r1 = Result.ok();
        Result<User> r2 = Result.ok(new User("Alice", "Passw0rd"));
        Result<User> r3 = Result.ok("Yes", new Demo(123456L, "Physics"));
        Result<User> r4 = Result.ok("Yes", new Demo(123456L, "Physics"), 1024);
        // JSON
        System.out.println(JSON.toJSONString(r1));
        System.out.println(JSON.toJSONString(r2));
        System.out.println(JSON.toJSONString(r3));
        System.out.println(JSON.toJSONString(r4));
        System.out.println(r3.getData());
        // JSONP
        System.out.println(Result.jsonp("callback", Result.ok("Hello")));
    }
}

参考资料

为了理解 Content-Type 为 application/x-www-form-urlencoded 和 application/json 的区别,可以参考四种常见的 POST 提交数据方式 https://imququ.com/post/four-ways-to-post-data-in-http.html
https://blog.csdn.net/w605283073/article/details/51338765

相关文章

网友评论

  • 38c65df179d4:首评给你,把应用讲的最明白就是这篇。感谢!

本文标题:SpringMvc 使用 REST 和 使用 AJAX 发送 R

本文链接:https://www.haomeiwen.com/subject/ypjhdftx.html