Spring Boot REST APIDevelopment

LearningSpring Boot REST APIDevelopment, includingRESTfuldesignprinciples, 控制器Development and requestresponseprocessing

1. RESTfuldesignprinciples

REST (Representational State Transfer) is a软件architecture风格, 用于designnetworkapplication程序. RESTful API is 遵循RESTprinciples APIdesign方式.

1.1 RESTfuldesign coreprinciples

  • resource (Resources) : 将一切视 for resource, usingURI (统一resource标识符) 标识resource
  • 表现层 (Representation) : resource 表现形式, such asJSON, XMLetc.
  • status转移 (State Transfer) : throughHTTPmethodimplementationresourcestatus 转移
  • 无status (Stateless) : server不保存客户端status, 每次request都package含完整information
  • 客户端-server (Client-Server) : 客户端 and server分离, 独立演进
  • cache (Cache) : supportcache, improvingperformance
  • 分层system (Layered System) : system可以分层deployment, 客户端不需要知道system in 部structure

1.2 HTTPmethod and resourceoperation

RESTful APIusingHTTPmethod来表示 for resource operation:

HTTPmethod operationclass型 exampleURI describes
GET 读取 /api/users 获取所 has user
GET 读取 /api/users/1 获取ID for 1 user
POST creation /api/users creation new user
PUT update /api/users/1 updateID for 1 user
PATCH 部分update /api/users/1 部分updateID for 1 user
DELETE delete /api/users/1 deleteID for 1 user

1.3 RESTful API best practices

  • using名词而不 is 动词来命名resource
  • using复数形式命名resourcecollection
  • usingHTTPstatus码表示response结果
  • using一致 命名规则
  • providing适当 errorinformation
  • supportfilter, sort and 分页
  • usingversion控制

2. creationREST API控制器

in Spring Bootin, 我们using@RestController注解creationREST API控制器. @RestController is @Controller and @ResponseBody 组合, 用于返回JSON or XMLetc.response体.

2.1 creation第一个REST控制器

package com.example.demo.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping("/api/hello")
    public String hello() {
        return "Hello, REST API!";
    }

}

2.2 控制器class层次structure

for 于 complex API, 我们可以creation控制器层次structure, using@RequestMapping注解指定Basicspath:

package com.example.demo.controller;

import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/users")
public class UserController {

    @GetMapping
    public List getAllUsers() {
        // 返回所 has user
    }

    @GetMapping("/{id}")
    public User getUserById(@PathVariable Long id) {
        // 返回指定ID user
    }

    @PostMapping
    public User createUser(@RequestBody User user) {
        // creation new user
    }

    @PutMapping("/{id}")
    public User updateUser(@PathVariable Long id, @RequestBody User user) {
        // updateuser
    }

    @DeleteMapping("/{id}")
    public void deleteUser(@PathVariable Long id) {
        // deleteuser
    }

}

3. requestmap

Spring Bootproviding了 many 种注解用于requestmap:

3.1 pathmap注解

  • @GetMapping: processingGETrequest
  • @PostMapping: processingPOSTrequest
  • @PutMapping: processingPUTrequest
  • @DeleteMapping: processingDELETErequest
  • @PatchMapping: processingPATCHrequest
  • @RequestMapping: commonrequestmap, 可以指定 many 种HTTPmethod

3.2 pathvariable

using@PathVariable注解获取URLin pathvariable:

@GetMapping("/users/{id}")
public User getUserById(@PathVariable Long id) {
    // usingidparameter
}

// 可以指定variable名
@GetMapping("/users/{user_id}")
public User getUserById(@PathVariable("user_id") Long id) {
    // usingidparameter
}

// 可选pathvariable
@GetMapping("/users/{id?}")
public List getUsers(@PathVariable(required = false) Long id) {
    // such as果providing了id, 则返回指定user, 否则返回所 has user
}

3.3 requestparameter

using@RequestParam注解获取requestparameter:

@GetMapping("/users")
public List getUsers(
        @RequestParam(required = false) String name,
        @RequestParam(defaultValue = "0") int page,
        @RequestParam(defaultValue = "10") int size) {
    // usingrequestparameterforfilter, 分页etc.operation
}

3.4 request头

using@RequestHeader注解获取request头information:

@GetMapping("/users")
public List getUsers(@RequestHeader("Authorization") String authorization) {
    // usingauthorization头information
}

3.5 Cookie

using@CookieValue注解获取Cookie值:

@GetMapping("/users")
public List getUsers(@CookieValue("sessionId") String sessionId) {
    // usingsessionIdforsessionmanagement
}

4. request体processing

using@RequestBody注解将request体转换 for Javaobject:

4.1 creation实体class

package com.example.demo.model;

public class User {
    private Long id;
    private String name;
    private String email;
    // getter and settermethod
}

4.2 接收request体

@PostMapping("/users")
public User createUser(@RequestBody User user) {
    // processingusercreationrequest
    return userService.save(user);
}

4.3 verificationrequest体

可以usingBean Validation API (JSR-380) for request体forverification:

package com.example.demo.model;

import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;

public class User {
    private Long id;
    
    @NotBlank(message = "姓名不能 for 空")
    @Size(min = 2, max = 50, message = "姓名 long 度必须 in 2 to 50个字符之间")
    private String name;
    
    @NotBlank(message = "邮箱不能 for 空")
    @Email(message = "邮箱格式不正确")
    private String email;
    
    // getter and settermethod
}

in 控制器in添加@Valid注解:

@PostMapping("/users")
public ResponseEntity createUser(@Valid @RequestBody User user, BindingResult result) {
    if (result.hasErrors()) {
        // processingverificationerror
        return ResponseEntity.badRequest().build();
    }
    // processingusercreationrequest
    return ResponseEntity.ok(userService.save(user));
}

5. responseprocessing

Spring Bootproviding了 many 种方式processingresponse:

5.1 返回 simple class型

@GetMapping("/hello")
public String hello() {
    return "Hello, REST API!";
}

@GetMapping("/count")
public int getCount() {
    return 100;
}

5.2 返回object or collection

@GetMapping("/users/{id}")
public User getUserById(@PathVariable Long id) {
    return userService.findById(id);
}

@GetMapping("/users")
public List getAllUsers() {
    return userService.findAll();
}

5.3 usingResponseEntity

ResponseEntityclass允许我们完全控制response, includingstatus码, response头 and response体:

@GetMapping("/users/{id}")
public ResponseEntity getUserById(@PathVariable Long id) {
    User user = userService.findById(id);
    if (user == null) {
        return ResponseEntity.notFound().build();
    }
    return ResponseEntity.ok(user);
}

@PostMapping("/users")
public ResponseEntity createUser(@Valid @RequestBody User user) {
    User savedUser = userService.save(user);
    return ResponseEntity.status(HttpStatus.CREATED)
            .header("Location", "/api/users/" + savedUser.getId())
            .body(savedUser);
}

5.4 自定义responsestructure

可以creation统一 responsestructure, package含status码, message and data:

package com.example.demo.dto;

public class ApiResponse {
    private int status;
    private String message;
    private T data;
    
    // constructmethod, getter and setter
    
    public static  ApiResponse success(T data) {
        return new ApiResponse<>(200, "success", data);
    }
    
    public static  ApiResponse error(int status, String message) {
        return new ApiResponse<>(status, message, null);
    }
}

in 控制器inusing:

@GetMapping("/users/{id}")
public ApiResponse getUserById(@PathVariable Long id) {
    User user = userService.findById(id);
    if (user == null) {
        return ApiResponse.error(404, "user不存 in ");
    }
    return ApiResponse.success(user);
}

6. exceptionprocessing

Spring Bootproviding了 many 种方式processingexception:

6.1 全局exceptionprocessing

using@RestControllerAdvice注解creation全局exceptionprocessing器:

@RestControllerAdvice
public class GlobalExceptionprocessingr {
    
    @Exceptionprocessingr(ResourceNotFoundException.class)
    public ResponseEntity> handleResourceNotFoundException(ResourceNotFoundException ex) {
        return ResponseEntity.status(HttpStatus.NOT_FOUND)
                .body(ApiResponse.error(404, ex.getMessage()));
    }
    
    @Exceptionprocessingr(MethodArgumentNotValidException.class)
    public ResponseEntity> handleValidationException(MethodArgumentNotValidException ex) {
        // processingverificationexception
    }
    
    @Exceptionprocessingr(Exception.class)
    public ResponseEntity> handleGenericException(Exception ex) {
        // processingotherexception
    }
}

6.2 自定义exception

creation自定义exceptionclass:

public class ResourceNotFoundException extends RuntimeException {
    public ResourceNotFoundException(String message) {
        super(message);
    }
}

in service层抛出exception:

public User findById(Long id) {
    return userRepository.findById(id)
            .orElseThrow(() -> new ResourceNotFoundException("user不存 in , ID: " + id));
}

7. APIdocumentation

for REST API生成documentation is 非常 important , Spring Bootsupport many 种APIdocumentationtool:

7.1 SpringDoc OpenAPI

SpringDoc OpenAPI is a 用于生成OpenAPIdocumentation library, supportSpring Boot 3.0+.

7.1.1 添加依赖

<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
    <version>2.3.0</version>
</dependency>

7.1.2 configurationSpringDoc

in application.propertiesinconfiguration:

# APIdocumentation标题
springdoc.api-docs.title=Spring Boot REST API
# APIdocumentationdescribes
springdoc.api-docs.description=Spring Boot REST API Documentation
# APIversion
springdoc.api-docs.version=v1
# 启用APIdocumentation
springdoc.api-docs.enabled=true
# Swagger UIpath
springdoc.swagger-ui.path=/swagger-ui.html

7.1.3 访问APIdocumentation

  • Swagger UI: http://localhost:8080/swagger-ui.html
  • OpenAPI JSON: http://localhost:8080/v3/api-docs

7.2 using注解增强documentation

可以usingOpenAPI注解增强APIdocumentation:

@RestController
@RequestMapping("/api/users")
@Tag(name = "usermanagement", description = "user相关operation")
public class UserController {
    
    @GetMapping
    @Operation(summary = "获取所 has user", description = "返回systemin所 has user list")
    public List getAllUsers() {
        // implementation
    }
    
    @GetMapping("/{id}")
    @Operation(summary = "根据ID获取user", description = "根据userID返回userinformation")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "成功获取user", 
                        content = @Content(schema = @Schema(implementation = User.class))),
            @ApiResponse(responseCode = "404", description = "user不存 in ")
    })
    public ResponseEntity getUserById(@PathVariable Long id) {
        // implementation
    }
    
    // othermethod
}

练习 1: creationREST API控制器

  1. creation一个Spring Bootproject, 添加Spring Web依赖
  2. creation一个User实体class, package含id, name, email字段
  3. creation一个UserController, implementation以 under API:
    • GET /api/users - 获取所 has user
    • GET /api/users/{id} - 获取指定ID user
    • POST /api/users - creation new user
    • PUT /api/users/{id} - updateuser
    • DELETE /api/users/{id} - deleteuser
  4. usingPostman or curltestAPI

练习 2: implementationrequestverification and exceptionprocessing

  1. for User实体class添加verification注解 (@NotBlank, @Emailetc.)
  2. in 控制器in添加verification逻辑
  3. creation自定义exceptionclassResourceNotFoundException
  4. creation全局exceptionprocessing器, processingResourceNotFoundException and verificationexception
  5. testverification and exceptionprocessingfunctions

练习 3: 集成APIdocumentation

  1. 添加SpringDoc OpenAPI依赖
  2. configurationAPIdocumentationbasicinformation
  3. usingOpenAPI注解增强APIdocumentation
  4. 访问Swagger UI, 查看生成 APIdocumentation