Java学习记录 08SpringMVC RESTful风格

SpringMVC REST风格

REST(Representational State Transfer)即 表述性转移,是目前最流行的一种软件架构风格

REST指的是一组架构 约束条件原则 。满足这些约束条件和原则的应用程序或设计就是RESTful

REST特性:

资源(Resources): 互联网所有的事物都可以被抽象为资源 。它可以是一段文本、一张图片、一首歌 曲、一种服务,总之就是一个具体的存在。可以用一个URI(统一资源定位符)指向它,每种资源对应 一个特性的URI。要获取这个资源,访问它的URI就可以,因此URI即为每一个资源的独一无二的识别符
PS: URI,统一资源标志符,表示的是web上每一种可用的资源

表现层(Representation): 把资源具体呈现出来的形式,叫做它的表现层(Representation)。比如,文 本可以用txt格式表现,也可以用HTML格式、XML格式、JSON格式表现,甚至可以采用二进制格式

状态转换(State Transfer): 每发出一个请求,就代表了客户端和服务器的一次交互过程。HTTP协议, 是一个无状态协议,即所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生“状态转换”(State Transfer)。而这种转换是建立在表现层之上的,所以就是“表现层状态转换”

REST URL请求形式

使用 URL 表示资源时,每个资源都用一个独一无二的 URL 来表示,并使用 HTTP 方法表示操作,即准确描述服务器对资源的处理动作(GET、POST、PUT、DELETE),实现资源的增删改查

请求类型 说明
GET 获取资源
PSOT 创建资源
PUT 更新资源
DELETE 删除资源

传统URL 与 REST风格的 URL 区别

传统URL REST风格URL 资源操作方式
http://localhost:8080/getUser.do?id=12 GET:http://localhost:8080/user/12 获取用户信息
http://localhost:8080/saveUser.do POST:http://localhost:8080/user 新建用户信息
http://localhost:8080/updateUser.do?=12 PUT:http://localhost:8080/user/12 更新用户信息
http://localhost:8080/deleteUser.do?=12 DELETE:http://localhost:8080/user/12 删除用户信息

REST应用

应用前提&注意:

  • 添加 过滤器 org.springframework.web.filter.HiddenHttpMethodFilter 指定 请求 or 所有请求
  • PUT 和 DELETE 请求类型 需要以POST请求 添加 _method 属性 值为 指定的 请求类型

web.xml配置过滤器 HiddenHttpMethodFilter

<!-- HiddenHttpMethodFilter过滤器可以将POST请求转化为put请求和delete请求! -->
<filter>
    <filter-name>hiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>hiddenHttpMethodFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

rest.jsp 页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<script src="/js/jquery-1.11.1.js"></script>
<html>
<head>
    <title>REST风格</title>
</head>
<body>
    <h1>REST风格 URL 测试</h1>
    
    <h2>普通请求 测试</h2>
    
    <h3>get请求</h3>
    <a href="/rest/12">Get</a>

    <h3>post请求</h3>
    <form action="/rest/12" method="post">
        <input type="submit" value="POST"/>
    </form>
    
    <h3>put请求</h3>
    <form action="/rest/12" method="post">
        <input type="hidden" name="_method" value="PUT" />
        <input type="submit" value="PUT" />
    </form>
    
    <h3>delete请求</h3>
    <input type="hidden" name="_method" value="DELETE"/>
    <form action="/rest/12" method="post">
        <input type="hidden" name="_method" value="DELETE" />
        <input type="submit" value="DELETE" />
    </form>
    
    <h2>AJAX请求 测试</h2>
    <form action="" id="myForm" method="post">
        id: <input type="text" id="id"> <br>
        name: <input type="text" id="name"> <br>
        age: <input type="text" id="age"> <br>
        <button type="button" id="getAjax">GET</button> <br>
        <button type="button" id="postAjax">POST</button>   <br>
        <button type="button" id="putAjax">PUT</button> <br>
        <button type="button" id="deleteAjax">DELETE</button>   <br>
    </form>

    <script>
        $(function(){
            // get
            $("#getAjax").click(function(){
                $.ajax({
                    type: "GET",
                    url: "/rest/"+$("#id").val(),
                    data:"name="+$("#name").val()+"&age="+$("#age").val(),
                    dataType:"json",
                    success: function(){}
                });
            });
            
            // post
            $("#postAjax").click(function(){
                $.ajax({
                    type: "POST",
                    url: "/rest/"+$("#id").val(),
                    data:{
                        "name":$("#name").val(),
                        "age":$("#age").val() },
                    dataType:"json",
                    success: function(){}
                });
            });
            
            // put
            $("#putAjax").click(function(){
                $.ajax({
                    type: "POST",
                    url: "/rest/"+$("#id").val(),
                    data:{
                        "_method":"PUT",
                        "name":$("#name").val(),
                        "age":$("#age").val() },
                    dataType:"json",
                    success: function(){}
                });
            });
            
            //delect
            $("#deleteAjax").click(function(){
                $.ajax({
                    type: "POST",
                    url: "/rest/"+$("#id").val(),
                    data:{
                        "_method":"DELETE",
                        "name":$("#name").val(),
                        "age":$("#age").val() },
                    dataType:"json",
                    success: function(){}
                });
            });
        });
    </script>
</body>
</html>

RestController类 控制器

package com.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping("rest")
public class RestController {
    
    @RequestMapping("torest")
    public String torest() {
        return "jsp/rEST";
    }
    
    @RequestMapping(value = "{id}",method = RequestMethod.GET)
    public String getTest(String name ,Integer age) {
        System.out.println("get请求");
        System.out.println("name : " + name);
        System.out.println("age : " + age);
        return "jsp/ok";
    }
    
    @RequestMapping(value = "{id}",method = RequestMethod.POST)
    public String postTest(String name ,Integer age) {
        System.out.println("post请求");
        System.out.println("name : " + name);
        System.out.println("age : " + age);
        return "jsp/ok";
    }
    
    @RequestMapping(value = "{id}",method = RequestMethod.PUT)
    public String putTest(String name ,Integer age) {
        System.out.println("put请求");
        System.out.println("name : " + name);
        System.out.println("age : " + age);
        return "jsp/ok";
    }
    
    @RequestMapping(value = "{id}",method = RequestMethod.DELETE)
    public String deleteTest(String name ,Integer age) {
        System.out.println("delete请求");
        System.out.println("name : " + name);
        System.out.println("age : " + age);
        return "jsp/ok";
    }
    
}

通过进入页面进行点击测试响应!!!

REST URL问题

避免多级URL

如果资源有多级分类,不建议写多级URL如:

GET: /class/12/student/1002 建议=> GET:/class/12?student=1002 (查班级中指定学生)

传参问题

采用Restful风格 PUT 和 DELETE 请求传递参数无效,传递到后台的参数值为 null

Tomcat封装请求说明:

  • 将请求中的数据封装成map
  • request.getParameter(Key)会获取map中的值
  • SpringMVC封装了POJO对象,但POJO会通过 request.getParameter(Key) 进行获取,因此 UPT 和 DELETE 请求时 request.getParameter(Key) 会拿不到
  • Tomcat检测到 PUT、DELETE不会封装请求 数据map

解决方案

利用POST请求 添加 _method 属性 值为 指定的 请求类型 (PUT、DELETE、…),前提需要过滤器

  1. web.xml配置过滤器 HiddenHttpMethodFilter

    <!-- HiddenHttpMethodFilter过滤器可以将POST请求转化为put请求和delete请求! -->
    <filter>
        <filter-name>hiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>hiddenHttpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
  2. 页面 请求

    ···
    <!--form表单请求
    	添加隐藏 属性 _method
    	请求类型为 : PUT
    -->
    <form action="/rest/12" method="post">
        <input type="hidden" name="_method" value="PUT" />
        <input type="submit" value="PUT" />
    </form>
    ···
    <!--ajax请求
    	添加 属性 _method
    	请求类型为 :DELETE
    -->
    <button id="deleteAjax">DELETE请求</button>
    ···
    <script>
        $(function(){
            //delect
            $("#deleteAjax").click(function(){
                $.ajax({
                    type: "POST",
                    url: "/rest/12",
                    data:{"_method":"DELETE"},
                    dataType:"json",
                    success: function(){}
                });
            });
        });
    </script>
    
上一篇:Controller与RestFul风格


下一篇:Restful Web Service设计规范