程序员社区

21. Spring MVC 之 RESTful 架构思想

Spring MVC 之 RESTful 架构思想

REST:Representational State Transfer,资源表现层状态转化,是目前最流行的一种互联网软件架构。它结构清晰,标准规范,易于理解,扩展方便,所以得到了越来越多网站的使用。

  • 资源(Resources):网络上的一个实体,或者说是网络上的一个具体信息。它可以是一个文件、一张图片、一首歌曲或是一段视频等,可以用一个 URI(统一资源定位符)指向它,每种资源都对应一个特定的 URI。要获取这个资源,访问它的 URI 即可,因此 URI 是每一个资源独一无二的的标识符。
  • 表现层(Representation):把资源具体内容呈现出来的形式,叫做它的表现层(Representation)。比如,文本可以用 TXT 格式表现,也可以用 HTML、XML、JSON 格式表现,甚至可以采用二进制的格式。
  • 状态转化(State Transfer):每发出一个请求,就代表了客户端和服务器的一次交互过程。HTTP 协议是一个无状态协议,即所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种方式,让服务器端发生“状态转化”,而这种转化是建立在表现层之上的,所以就是“表现层状态转化”。

特点:

  1. url 更加简洁,将参数通过 url 传到服务端;

    • 非 RESTful 的 URL:http://localhost:8080/query?id=1
    • RESTful 风格的 URL:http://localhost:8080/query/1
  2. 有利于不同系统之间的资源共享,只需要遵守规范,不需要做其他的配置就能达到资源共享;

Restful 具体来说就是四种表现形式,HTTP 协议中四个表示操作方式的动词:GET、POST、PUT、DELETE,分别对应四种基本操作:

  1. GET 用于获取资源;
  2. POST 用来创建或存储资源;
  3. PUT 用于修改资源;
  4. DELETE 用来删除资源;

但是我们知道 form 表单只支持 GET 与 POST 请求,并不支持 DELETE 和 PUT,如何解决这个问题呢?添加 HiddenHttpMethodFilter 过滤器,可以将 POST 请求转为 PUT 或 DELETE。

过滤器的实现原理大致是:检测请求参数中是否包含 _method 这个参数,如果包含,则获取其值,然后判断是哪种操作后继续传递。

具体步骤:

1、form 表单添加隐藏标签,设置 name="_method"value="PUT/DELETE"

<html>
<head>
    <title>Title</title>
</head>
<body>
    <form action="/put" method="post">
        <input type="hidden" name="_method" value="PUT">
        <input type="submit" value="修改"/>
    </form>
</body>
</html>

2、在 web.xml 中配置 HidddenHttpMethodFilter;

<filter>
    <filter-name>HidddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>HidddenHttpMethodFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

3、编写控制器的业务方法;

@Controller
public class TestHandler {
    @PutMapping("/put")
    @ResponseBody
    public String PUTMethod(){
        return "修改成功!";
    }
}

启动 Tomcat 服务器,运行程序:

在这里插入图片描述

请求响应成功!

在这里插入图片描述

如果直接在地址栏访问 http://localhost:8080/put ,发送的是 GET 类型的请求,此时请求返回错误代码 405.


上面是通过 form 表单来发送 PUT/DELETE 请求类型,若使用 AJAX 则不需要这么复杂,下面我们通过 AJAX 以 restful 的方式实现数据的增删改查操作。

1、客户端发送请求的 JSP 页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@page isELIgnored="false" %>
<html>
<head>
    <title>restful风格</title>
    <script type="text/javascript" src="js/jquery-2.0.0.min.js"></script>
    <script type="text/javascript">
        $(function () {
            //处理GET类型的请求
            $("#get").click(function () {
                var id = $("#get_id").val();
                $.ajax({
                    url:'/getById/'+id,
                    type:"GET",
                    dataType:"json",
                    success:function (data) {
                        alert("学号:" + data.id + ",姓名:" + data.name + ",年龄:" + data.age);
                        location.reload(true);
                    },
                    //返回值为空时,null无法转化成json,故报错
                    error:function () {
                        alert("该用户不存在!");
                        location.reload(true);
                    }

                })
            });
            //处理POST类型的请求
            $("#post").click(function () {
                var id = $("#post_id").val();
                var name = $("#post_name").val();
                var age = $("#post_age").val();
                $.ajax({
                    url:"/post/"+id+"/"+name+"/"+age,
                    type:"POST",
                    dataType:"json",  //返回的数据类型
                    success:function (data) {
                        alert(data);
                        location.reload(true);
                    }
                })
            });
            //处理PUT类型的请求
            $("#put").click(function () {
                var id = $("#put_id").val();
                var name = $("#put_name").val();
                var age = $("#put_age").val();
                $.ajax({
                    url:"/put/"+id+"/"+name+"/"+age,
                    type:"PUT",
                    dataType:"json",  //返回的数据类型
                    success:function (data) {
                        alert("学号:" + data.id + ",姓名:" + data.name + ",年龄:" + data.age);
                        location.reload(true);
                    },
                    error:function () {
                        alert("该用户不存在!");
                        location.reload(true);
                    }
                })
            });
            //处理DELETE类型的请求
            $("#delete").click(function () {
                var id = $("#delete_id").val();
                $.ajax({
                    url:"/delete/"+id,
                    type:"DELETE",
                    dataType:"json",  //返回的数据类型
                    success:function (data) {
                        alert(data);
                        location.reload(true);
                    }
                })
            });
        })
    </script>
</head>
<body>
    GET:<input type="text" id="get_id"/><input type="button" value="查询" id="get">
    <hr/>
    POST:<br/>
    编号:<input type="text" id="post_id"><br/>
    姓名:<input type="text" id="post_name"><br/>
    年龄:<input type="text" id="post_age"><br>
    <input type="button" value="提交" id="post">
    <hr/>
    PUT:<br/>
    编号:<input type="text" id="put_id"><br/>
    姓名:<input type="text" id="put_name"><br/>
    年龄:<input type="text" id="put_age"><br>
    <input type="button" value="修改" id="put">
    <hr/>
    DELETE:<br/>
    <input type="text" id="delete_id"><input type="button" value="删除" id="delete">
</body>
</html>

2、创建 Student 实体类

package com.trainingl.entity;

public class Student {
    private Integer id;
    private String name;
    private Integer age;

    public Student(){

    }

    public Student(Integer id, String name, Integer age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

3、编写控制器的业务方法;

package com.trainingl.handler;

import com.trainingl.entity.Student;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;

@Controller
public class RestfulHandler {
    private static Map<Integer,Student> studentMap;

    static {
        studentMap = new HashMap<Integer,Student>();
        studentMap.put(1,new Student(1,"张三",23));
        studentMap.put(2,new Student(2,"李四",24));
        studentMap.put(3,new Student(3,"王五",25));
    }


    @RequestMapping(value = "/getById/{id}",method = RequestMethod.GET)
    @ResponseBody
    public Student httpGet(@PathVariable("id")int id){
        Student student = studentMap.get(id);
        return student;
    }

    @PostMapping("/post/{id}/{name}/{age}")
    @ResponseBody
    public String httpPost(@PathVariable("id")int id,@PathVariable("name")String name,@PathVariable("age")int age){
        studentMap.put(id,new Student(id,name,age));
        return "添加成功!";
    }

    @PutMapping("/put/{id}/{name}/{age}")
    @ResponseBody
    public Student httpPut(@PathVariable("id")int id,@PathVariable("name")String name,@PathVariable("age")int age){
        Student student = studentMap.get(id);
        if(student == null){
            return null;
        } else {
            Student stu = new Student(id,name,age);
            studentMap.put(id,stu);
            return stu;
        }
    }

    @DeleteMapping("/delete/{id}")
    @ResponseBody
    public String httpDelete(@PathVariable("id")int id){
        if(studentMap.get(id) != null){
            studentMap.remove(id);
            return "删除成功!";
        }else {
            return "该用户不存在!";
        }
    }
}

4、服务器后台返回的对象转化成 JSON 数据,需要在 springmvc.xml 中添加配置

  1. 消息转换器解决的是后台向前端返回数据的编码问题;
  2. fastjson 解决 JavaBean 转为 JSON 数据格式不匹配的问题;
<mvc:annotation-driven conversion-service="conversionService">
    <!-- 消息转换器 -->
    <mvc:message-converters register-defaults="true">
        <bean class="org.springframework.http.converter.StringHttpMessageConverter">
            <property name="supportedMediaTypes" value="text/html;charset=UTF-8"></property>
        </bean>
        <!-- 配置fastjson -->
        <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter"></bean>
    </mvc:message-converters>
</mvc:annotation-driven>

5、启动 Tomcat 服务器,运行 Web 应用程序,测试不同的请求类型。


21. Spring MVC 之 RESTful 架构思想插图2

至此,Spring MVC 实现了 Restful 架构中不同的业务操作对应不同 HTTP 请求类型。(注:CRUD——POST、GET、PUT、DELETE)

赞(0) 打赏
未经允许不得转载:IDEA激活码 » 21. Spring MVC 之 RESTful 架构思想

一个分享Java & Python知识的社区