第21章 Spring Boot新手指南:一文学会RESTful API开发

2,159 阅读8分钟

任务描述

任务要求

使用IDEA开发工具构建一个项目多模块工程。study-springboot-chapter17学习关于Springboot开发前端控制层,方便实现前后端分离

  1. 基于study-springboot工程,复制study-springboot-chapter17标准项目,坐标groupId(com.cbitedu)、artifactId(study-springboot-chapter17),其他默认
  2. 继承study-springboot工程依赖
  3. 构建Restful API

任务收获

  1. Spring Boot开发Restful API服务
  2. 学会使用JUnit完成单元测试
  3. 掌握web开发原理
  4. 熟悉SpringMVC的基础配置

任务准备

环境要求

  1. JDK1.8+
  2. MySQL8.0.27+
  3. Maven 3.6.1+
  4. IDEA/VSCode

数据库准备

-- ----------------------------
-- Table structure for tb_user
-- ----------------------------
DROP TABLE IF EXISTS `tb_user`;
CREATE TABLE `tb_user`  (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `username` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户名',
  `password` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '密码,加密存储',
  `phone` varchar(11) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '注册手机号',
  `created` datetime NOT NULL COMMENT '创建时间',
  `salt` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '密码加密的salt值',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `username`(`username` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户表' ROW_FORMAT = DYNAMIC;

-- ----------------------------
-- Records of tb_user
-- ----------------------------
INSERT INTO `tb_user` VALUES (1, 'tosea', '44f871f0a390c5ca0731ebb0f5a17e73', '13037889034', '2019-04-11 11:36:45', '802ae2cb978b4cc2b5705e9e525f3c7d');
INSERT INTO `tb_user` VALUES (2, 'tellsea', 'a11a53405c18b7bd9793396a5ada044c', '18386474459', '2019-04-17 23:02:43', 'aabaf92f1d10459d84d2b0f076fb3fdd');

工程目录要求

study-springboot-chapter17

任务实施

前端控制层常用的@Controller、@RestController、@RequestMapping注解。

  1. @Controller:修饰class,用来创建处理http请求的对象
  2. @RestController:Spring4之后加入的注解,原来在@Controller中返回json需要@ResponseBody来配合,如果直接用@RestController替代@Controller就不需要再配置@ResponseBody,默认返回json格式
  3. @RequestMapping:配置url映射。现在更多的也会直接用以Http Method直接关联的映射注解来定义,比如:GetMapping、PostMapping、DeleteMapping、PutMapping等

下面我们通过使用Spring MVC来实现一组对User对象操作的RESTful API,配合注释详细说明在Spring MVC中如何映射HTTP请求、如何传参、如何编写单元测试。

RESTful API具体设计如下:

Method介绍幂等
GET数据的查询操作Yes
HEADGET相同, 区别是响应中不包含响应体. 可以用来获取资源的元数据, 如 header 等Yes
POST信息的创建:创建成功应该返回响应码 201No
PATCH用于局部更新 从 POST 请求分出来的, POST 全量更新, PATCH 局部更新.No
PUT信息的更新Yes
DELETE数据删除Yes
OPTIONSAPI 相关信息 如探测服务支持的所有Method, 或者检测服务通不通.Yes
CONNECTED与服务器建立链接, 通过服务器代理客户端请求 说白了就是一个 HTTP 代理Yes
TRACE对请求路径的环回测试Yes

幂等, 上面表格中幂等的意思就是, 接口调2次和调1次结果一样, 既可以重复调用.

GET(SELECT):从服务器取出资源(一项或多项)。
POST(CREATE):在服务器新建一个资源。
PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。
DELETE(DELETE):从服务器删除资源。

例如:

响应码介绍
1xx请求已收到, 需要继续操作
2xx请求成功处理
3xx重定向, 需要进一步请求
4xx客户端错误
5xx服务器错误

定义User实体

package com.cbitedu.springboot.entity;

import lombok.Data;

@Data
public class User {

    private Long id;
    private String username;
    private String password;
    private Integer age;

}

定义状态响应辅助类

package com.cbitedu.springboot.utils;


import lombok.Builder;
import lombok.Data;

@Data
@Builder  // 作用:调用时使用链式写法
public class ResultResponse {
    private String code;
    private String message;
    private Object data;
}

@Data注解可以实现在编译器自动添加set和get函数的效果。该注解是lombok提供的,只需要在pom中引入加入下面的依赖就可以支持:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

实现对User对象的操作接口

package com.cbitedu.springboot.controller;

import com.cbitedu.springboot.entity.User;
import com.cbitedu.springboot.utils.ResultResponse;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@Slf4j
@RequestMapping(value = "demo")  // 类中所有接口地址的前缀
public class UserController {
    // @RequestMapping(value="loginGet", method= RequestMethod.GET)
    @GetMapping("loginGet")
    public String loginGet() {
        return "登录成功";
    }

    // @RequestMapping(value="loginPost", method= RequestMethod.POST)
    @PostMapping("loginPost")  // 简便写法
    public String loginPost(@RequestBody User user) {  // 如果没用 @RequestBody,则获取结果为 null
        log.info("username : " + user.getUsername());
        log.info("password : " + user.getPassword());
        return "登录成功:" + user.getUsername();
    }

    // 访问:http://localhost:8080/demo/userId/1/2
    // @RequestMapping(value="userId/{userId}/{id}", method=RequestMethod.GET)
    @GetMapping("getUser/{userid}/{id}")
    public String loginUser1(@PathVariable("userid") Integer userid, @PathVariable("id") Integer id) {
        log.info("userid : " + userid);
        log.info("id : " + id);
        return "userid: " + userid + "  id: " + id;
    }

    // 访问:http://localhost:8080/demo/getUser?userid=1&id=2
    // 访问:http://localhost:8080/demo/getUser?user=1&id=2,则 userid 值为 null
    @GetMapping("getUser")
    public String loginUser2(@RequestParam(value = "userid", required = false) Integer userid,  // required=false:参数非必须传
                             @RequestParam("id") Integer id) {
        log.info("userid : " + userid);
        log.info("id : " + id);
        return "userid: " + userid + "  id: " + id;
    }

    @GetMapping("loginSuccess")
    public ResponseEntity loginSuccess() {
        User user = new User();
        user.setUsername("creatorblue");
        user.setPassword("admin123");
        ResultResponse resultResponse = ResultResponse.builder().code("00").message("登录成功").data(user).build();
        return ResponseEntity.status(HttpStatus.OK).body(resultResponse);
    }

    @GetMapping("loginFail")
    public ResponseEntity loginFail() {
        User user = new User();
        user.setUsername("creatorblue");
        user.setPassword("admin123");
        ResultResponse resultResponse = ResultResponse.builder().code("02").message("登录失败").data(user).build();
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(resultResponse);
    }
}

用更细化的@GetMapping、@PostMapping等系列注解替换了以前的@RequestMaping注解;另外,还使用@RequestBody替换了@ModelAttribute的参数绑定。

测试

http://localhost:8080/demo/loginSuccess

小结

至此,我们通过引入web模块(没有做其他的任何配置),就可以轻松利用Spring MVC的功能,以非常简洁的代码完成了对User对象的RESTful API的创建以及单元测试的编写。其中同时介绍了Spring MVC中最为常用的几个核心注解:@RestController,RequestMapping以及一些参数绑定的注解:@PathVariable,@RequestBody等。

后端接收前端数据的三种注解方式:

第一种:@RequestParam注解

  • 作用: 将指定的请求参数赋值给方法中的形参。
  • 接收形式: Get传参请求。
  • 属性:
    (1)value :绑定请求的参数名,默认绑定为同名的形参;
    (2)required:是否必须,默认是true,表示请求中一定要有相应的参数,否则将报错;
    (3)defaultValue:默认值,表示如果请求中没有接收到值时的默认值。
  • 用法示例:
@GetMapping("/test")
public void test(@RequestParam(required = true)String name,@RequestParam(defaultValue = "20")Integer age) {
System.out.println("name:"+name+",age:"+age);
}

第二种:@PathVariable注解

  • 作用: 接收请求路径中占位符的值。
  • 接收形式: Get路径请求。
  • 属性: value:String类型,绑定请求的参数名,默认绑定为同名的形参。
  • 用法示例:
@GetMapping("/selectOne/{id}")
public void test(@PathVariable Integer id) {
System.out.println("id:"+id);
}

第三种:@RequestBody注解

  • 作用: 接收前端传递的Json对象的字符串。
  • 接收形式: Post请求。
  • 用法示例:
@PostMapping("/test")
public void test(@RequestBody User user){
System.out.println("user:"+user);
}

实验实训

1、重点学习Spring MVC前端注解

2、重点复习RestFul接口命名规范

附录

SpringBoot 核心注解

注解说明
Component声明为 SpringBoot 的 bean
Repository用于 dao 层的 bean
Autowired用于向一个 bean 中注入其他 bean
Service用于 service 层的 bean
Configuration用于声明 SpringBoot 的配置文件类
Value("${key)")获取 SpringBoot 配置文件中的值
Bean声明其为 bean 实例,常和 Configuration 配合使用

SpringBoot Restful 接口实现

注解说明
SpringBootApplicationSpringBoot 主类,用来加载 SpringBoot 各种特性
RestControllerSpringBoot 会转换返回值并自动将其写入 HTTP 响应
RequestMapping用于类和方法,在方法级别时,用于处理 HTTP 的各种方法
RequestBody将请求 Body 中的 json/xml 对象解析成该参数类型的 JavaBean 对象
PathVariable处理动态 URI,即 URI 的值可以作为控制器中处理方法的入参
Post/Put/Get/DeleteMapping在方法的级别上使用,在方法级别时,用于处理 HTTP 的各种方法
RequestParam处理 get 请求的参数

在本文中,我们深入探讨了如何使用Spring MVC构建RESTful API,并且了解了多种注解的应用,如@RestController、@RequestMapping、@GetMapping等,它们共同帮助我们设计出了既简洁又高效的API接口。然而,在实际开发过程中,除了关注API的功能实现外,维护一份清晰、准确的API文档同样至关重要。这不仅能提升团队内部的协作效率,还能极大地便利外部用户的接入与使用。鉴于此,接下来我们将介绍如何基于Spring Boot使用Swagger2来构建强大的API文档。Swagger2不仅能够自动生成文档,还提供了便捷的测试功能,使得API的设计与维护变得更加直观与高效。让我们一起进入Swagger2的世界,看看它是如何简化这一过程的。