SpringBoot2.x系列教程82--构建RESTful风格的API接口

SpringBoot2.x系列教程82--构建RESTful风格的API接口

作者:一一哥

一. RESTful架构介绍

1. RESTful架构概述

RESTful架构,是目前最流行的一种互联网软件架构风格,它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多的网站采用。

但是,RESTful架构到底是怎么一回事呢?

2. RESTful架构起源

REST这个词,是Roy Thomas Fielding在他2000年的博士论文中提出的,Roy Thomas Fielding是一个很重要的人,他是HTTP协议(1.0版和1.1版)的主要设计者、Apache服务器软件的作者之一、Apache基金会的第一任主席。

所以,他的这篇论文一发表,就引起了很多人的关注,并且立即对互联网开发产生了深远的影响。

Roy Thomas Fielding将他对互联网软件的架构原则,定名为REST,也就是REpresentational State Transfer(3个单词的首字母)的缩写,一般翻译为"表现层状态转化"或者是”表述性状态转移“。

3. RESTful架构含义

如果我们想理解RESTful架构风格,则需要先理解RESTful这个单词的组成。

  • 资源(Resources)

    REST的名称是"表现层状态转化",
    其实是资源(Resources)的"表现层状态转化"。

    这里所谓的"资源",其实就是网络上存储的一个具体信息或数据,它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的数据。

    我们可以用一个URI(统一资源标识符)指向这些资源,每种资源都对应一个特定的URI。要获取这个资源,通过访问它对应的URI就可以了,因此该URI就代表了每一个资源的地址或独一无二的识别符号。

  • 表述性(REpresentational):

    "资源"是一种信息实体,它可以有多种外在的表现形式,我们把"资源"具体呈现出来的形式,叫做它的"表现层"(Representation)。

    REST 资源实际上可以用各种形式来进行表现,比如文本可以用txt格式表现,也可以用HTML格式、XML格式、JSON格式表现,甚至可以采用二进制格式;图片可以用JPG格式表现,也可以用PNG格式表现,我们可以使用最适合资源的任意形式。

  • 状态(State): 当使用 REST 的时候,我们更关注资源的状态而不是对资源采取的行为。

  • 转义(Transfer): REST 涉及到转移资源数据,它以某种表述性形式从一个应用转移到另一个应用。

    如果客户端想要操作服务器,必须通过某种手段,让服务器端发生"状态转化"(State Transfer),而这种转化是建立在表现层之上的,所以就是"表现层状态转化"。

    客户端用到的手段,只能是HTTP协议。具体来说,就是HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源。

4. RESTful架构

综合上面的解释,我们总结一下什么是RESTful架构:

  • 每一个URI都代表一种资源;

  • 客户端通过四个HTTP动词,对服务器端资源进行操作,实现"表现层状态转化”。

简单的说,RESTful就是将资源的状态以适合客户端或服务端的形式从服务端转移到客户端(或者反过来)。在 RESTful中,资源通过 URI 进行识别和定位,然后通过某种行为(即 HTTP的方法)来完成某种功能。

也就是说如果一个架构符合REST原则,就称它为RESTful架构。

二. 实例讲解

1. Http请求方法

我们在平时的 Web 开发中,常用的http请求方法是 GET 和 POST,但是实际上,HTTP 方法还有 PATCH、DELETE、PUT 等其他方法,这些方法通常会匹配为如下的 CRUD 动作:

但这并不是严格的限制,有时候 PUT 也可以用来创建新的资源,POST 也可以用来更新资源。实际上,POST 请求非幂等的特性(即同一个 URL 可以得到不同的结果)使其成一个非常灵活地方法,对于无法适应其他 HTTP 方法语义的操作,它都能够胜任。

2. HTTP请求方法的用法

HTTP方法中的GET和HEAD请求都是安全的,无论请求多少次,都不会改变服务器状态。GET、HEAD、PUT和DELETE请求都是满足幂等性要求的,也就是无论对资源操作多少次,结果总是一样的,后面的请求并不会产生比第一次更多的影响。

  • 幂等性:对同一REST接口的多次访问,得到的资源状态是相同的。

  • 安全性:对该REST的接口访问,不会使服务器端资源的状态发生改变。

  • GET:安全且幂等;

  • POST:不安全且不幂等;

  • PUT:不安全但幂等;

  • DELETE:不安全但幂等;

3. RESTful案例

在使用 RESTful 风格之前,我们如果想要增加一条分类数据通常是这样的:

/addCategory?name=xxx

但是使用了 RESTful 风格之后就会变成:

/category

我们可以使用同一个 URI ,通过约定不同的 HTTP 方法来实现不同的业务,例如下图所示:

4. RESTful的反面案例

RESTful风格的接口要求使用标准的HTTP方法对资源进行操作,所以URI只应该用来表示资源的名称,而不应该包括对资源的动作操作。

通俗来说,URI不应该使用动作来描述。例如,下面是一些不符合统一接口要求的URI:

GET /getUser/1
POST /createUser
PUT /updateUser/1
DELETE /deleteUser/1

三. SpringBoot中实现RESTful架构风格

1. 需求分析

我们以操作用户相关的业务为例,如果采用RESTful API 设计,可以如下所示:

2. 添加依赖包

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
    </dependency>

    <!--简化bean代码-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
</dependencies>

3. 创建一个实体类User

package com.yyg.boot.domain;

import lombok.Data;

import java.io.Serializable;

/**
 * @Author 一一哥Sun
 * @Date Created in 2020/5/13
 * @Description Description
 */
@Data
public class User implements Serializable {

    private Long id;

    private String name;

    private Integer age;

}

4. 创建Controller接口方法

package com.yyg.boot.web;

import com.yyg.boot.domain.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import java.util.*;

/**
 * @Author 一一哥Sun
 * @Date Created in 2020/5/13
 * @Description Description
 */
@Slf4j
@RestController
@RequestMapping("/users")
public class UserController {

    /**
     * 创建线程安全的Map
     */
    private static Map<Long, User> users = Collections.synchronizedMap(new HashMap<>());

    /**
     * 处理GET请求,用来获取用户列表.
     * 可以通过@RequestParam获取从页面中传递进来的查询条件或者翻页信息等参数.
     */
    @GetMapping(value="/")
    public List<User> getUserList() {
        return new ArrayList<>(users.values());
    }

    /**
     * 处理POST请求,用来创建User.
     * 除了@ModelAttribute绑定参数之外,还可以通过@RequestParam从页面中传递参数.
     */
    @PostMapping(value="/")
    public String addUser(@RequestBody User user) {
        users.put(user.getId(), user);
        log.warn("user==="+users.get(user.getId()));
        return "success";
    }

    /**
     * 处理GET请求,用来获取url中id值的User信息;
     * url中的id可通过@PathVariable绑定到函数的参数中.
     */
    @GetMapping(value="/{id}")
    public User getUser(@PathVariable Long id) {
        return users.get(id);
    }

    /**
     * 处理PUT请求,用来更新User信息.
     */
    @PutMapping(value="/{id}")
    public String updateUser(@PathVariable Long id, @RequestBody User user) {
        User u = users.get(id);
        u.setName(user.getName());
        u.setAge(user.getAge());
        users.put(id, u);
        return "success";
    }

    /**
     * 处理DELETE请求,用来删除User
     */
    @DeleteMapping(value="/{id}")
    public String deleteUser(@PathVariable Long id) {
        users.remove(id);
        return "success";
    }

}

5. 创建入口类

package com.yyg.boot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @Author 一一哥Sun
 * @Date Created in 2020/5/13
 * @Description Description
 */
@SpringBootApplication
public class RestfulApplication {

    public static void main(String[] args){
        SpringApplication.run(RestfulApplication.class,args);
    }

}

四. 运行测试

1. 添加一个新用户

执行post请求,传递json格式的参数.

2. 查询全部用户

执行get请求,查询刚才添加的用户,不需要传递任何参数.

3. 更新用户信息

执行put请求,传递id作为参数.

查询更新后的结果

4. 删除用户

执行delete请求,删除id为1的用户

查询删除后的结果

至此我们实现了SpringBoot中的RESTful风格的uri设计。




 

一一哥Sun CSDN认证博客专家 Elasticsearch Java 架构
十年软件开发授课经验,专注大学生毕业设计及面试求职私塾式指导!对Android/JavaWeb/微服务/H5等技术领域有深入研究!曾任国内最大的智能物联网平台架构师,参与国内最大的智能物流系统平台天眼/冷链/订单/车次系统研发;曾主导国内首款国学教育App及后台架构;负责大庆油田采油管理系统,铝业云计算系统,湖南广电地面波机顶盒等项目的研发。目前担任某著名培训机构教学主管,培养了大批入职阿里,IBM,百度,国家电网等名企的高薪学生.本人坚持只有一心做教育,才能做一流教育的理念,被学生爱称为"一一哥"!QQ:2312119590,今日头条号:一一哥Sun;知乎ID:一一哥
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页