logo-cover-Spring Boot 2.0 REST API 接口的数据验证

1.概要

在本Spring boot教程中,我们将学习如何验证发送到PUT/POST API请求的数据BODY。我们还将学习在API响应中添加自定义错误消息以提示错误。

在这个演示中,我们将主要看到两个主要的验证案例 -
  1. HTTP POST /employees和请求正文不包含有效值或缺少一些字段。它将在响应主体中返回带有适当消息的HTTP状态代码400。
  2. /employees/{id}请求中会发送HTTP GET 和INVALID ID。它会在响应主体中返回HTTP状态码404和正确的消息。

2.创建REST 模型和API类

EmployeeVO.java
@XmlRootElement(name = "employee")
@XmlAccessorType(XmlAccessType.FIELD)
public class EmployeeVO extends ResourceSupport implements Serializable
{
    private Integer employeeId;
    private String firstName;
    private String lastName;
    private String email;
 
    public EmployeeVO(Integer id, String firstName, String lastName, String email) {
        super();
        this.employeeId = id;
        this.firstName = firstName;
        this.lastName = lastName;
        this.email = email;
    }
 
    public EmployeeVO() {
    }
     
    //Removed setter/getter for readability
}
EmployeeRESTController.java
@PostMapping(value = "/employees")
public ResponseEntity<EmployeeVO> addEmployee (@RequestBody EmployeeVO employee)
{
    EmployeeDB.addEmployee(employee);
    return new ResponseEntity<EmployeeVO>(employee, HttpStatus.OK);
}
 
@GetMapping(value = "/employees/{id}")
public ResponseEntity<EmployeeVO> getEmployeeById (@PathVariable("id") int id)
{
    EmployeeVO employee = EmployeeDB.getEmployeeById(id);
     
    if(employee == null) {
         throw new RecordNotFoundException("Invalid employee id : " + id);
    }
    return new ResponseEntity<EmployeeVO>(employee, HttpStatus.OK);
}

3.应用请求验证和异常处理

默认请求支持spring的验证
要应用默认验证,您只需在适当的位置添加相关注解。即

使用所需的验证特定注释来注释模型类
@XmlRootElement(name = "employee")
@XmlAccessorType(XmlAccessType.FIELD)
public class EmployeeVO extends ResourceSupport implements Serializable
{
    private static final long serialVersionUID = 1L;
     
    public EmployeeVO(Integer id, String firstName, String lastName, String email) {
        super();
        this.employeeId = id;
        this.firstName = firstName;
        this.lastName = lastName;
        this.email = email;
    }
 
    public EmployeeVO() {
    }
 
    private Integer employeeId;
 
    @NotEmpty(message = "first name must not be empty")
    private String firstName;
 
    @NotEmpty(message = "last name must not be empty")
    private String lastName;
 
    @NotEmpty(message = "email must not be empty")
    @Email(message = "email should be a valid email")
    private String email;
     
    //Removed setter/getter for readability
}

通过@Valid注释启用对请求主体的验证

自定义验证以添加有意义的信息

默认的弹簧验证工作,并提供有关错误的信息超载,这就是为什么你应该根据你的应用程序的需要定制它。您只能提供所需的错误信息,并且语句非常清晰。额外的信息也不建议。

建立有意义的例外并且足够好地描述问题始终是一个很好的建议。一种方法是创建单独的类来表示特定的业务用例失败,并在该用例失败时返回它们。

例如,我已经RecordNotFoundException为所有buch场景创建了一个类,在这个场景中,资源被其ID所请求,并且系统中找不到资源。

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
 
@ResponseStatus(HttpStatus.NOT_FOUND)
public class RecordNotFoundException extends RuntimeException
{
    public RecordNotFoundException(String exception) {
        super(exception);
    }
}
同样,我写了一个特殊的类,它将被返回所有失败案例。为所有API提供一致的错误消息结构,帮助API消费者编写更健壮的代码
import java.util.List;
import javax.xml.bind.annotation.XmlRootElement;
 
@XmlRootElement(name = "error")
public class ErrorResponse
{
    public ErrorResponse(String message, List<String> details) {
        super();
        this.message = message;
        this.details = details;
    }
 
    //General error message about nature of error
    private String message;
 
    //Specific errors in API request processing
    private List<String> details;
 
    //Getter and setters
}
现在添加一个类,ResponseEntityExceptionHandler并使用注释对其进行@ControllerAdvice注解ResponseEntityExceptionHandler是一个方便的基类,@RequestMapping通过@ExceptionHandler方法提供跨所有方法的集中式异常处理。@ControllerAdvice更适用于在应用程序启动时启用自动扫描和配置。
CustomExceptionHandler.java
import java.util.ArrayList;
import java.util.List;
 
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
 
@SuppressWarnings({"unchecked","rawtypes"})
@ControllerAdvice
public class CustomExceptionHandler extends ResponseEntityExceptionHandler
{
    @ExceptionHandler(Exception.class)
    public final ResponseEntity<Object> handleAllExceptions(Exception ex, WebRequest request) {
        List<String> details = new ArrayList<>();
        details.add(ex.getLocalizedMessage());
        ErrorResponse error = new ErrorResponse("Server Error", details);
        return new ResponseEntity(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
 
    @ExceptionHandler(RecordNotFoundException.class)
    public final ResponseEntity<Object> handleUserNotFoundException(RecordNotFoundException ex, WebRequest request) {
        List<String> details = new ArrayList<>();
        details.add(ex.getLocalizedMessage());
        ErrorResponse error = new ErrorResponse("Record Not Found", details);
        return new ResponseEntity(error, HttpStatus.NOT_FOUND);
    }
 
    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        List<String> details = new ArrayList<>();
        for(ObjectError error : ex.getBindingResult().getAllErrors()) {
            details.add(error.getDefaultMessage());
        }
        ErrorResponse error = new ErrorResponse("Validation Failed", details);
        return new ResponseEntity(error, HttpStatus.BAD_REQUEST);
    }
}
以上类处理各种异常情况,包括RecordNotFoundException:它还处理@RequestBody注释对象中的请求验证错误。让我们看看它是如何工作的。

请求验证演示

1)HTTP GET / employees / 1 [有效]

HTTP Status : 200
 
{
    "employeeId": 1,
    "firstName": "firstName",
    "lastName": "lastName",
    "email": "email@gamil.com",
}
测试请求1
2)HTTP GET / employees / 23 [INVALID]
HTTP Status : 404
 
{
    "message": "Record Not Found",
    "details": [
        "Invalid employee id : 23"
    ]
}
输入错误的ID号查询
3)HTTP POST / employees [INVALID]
请求参数:
{
    "lastName": "Bill",
    "email": "ibill@gmail.com"
}
响应结果:
HTTP Status : 400
 
{
    "message": "Validation Failed",
    "details": [
        "first name must not be empty"
    ]
}
数据测试三
4)HTTP POST / employees [INVALID]
请求参数:
{
    "email": "ibill@gmail.com"
}
响应结果:
HTTP Status : 400
 
{
    "message": "Validation Failed",
    "details": [
        "last name must not be empty",
        "first name must not be empty"
    ]
}
测试结果4
5)HTTP POST / employees [INVALID]
请求参数:
{
    "firstName":"Lokesh",
    "email": "ibill_gmail.com" //invalid email in request
}
响应内容:
HTTP Status : 400
 
{
    "message": "Validation Failed",
    "details": [
        "last name must not be empty",
        "email should be a valid email"
    ]
}

测试结果5
可用的注解

在上面的例子中,我们只使用了几个注释,如@NotEmpty@Email。还有更多这样的注释来验证请求数据。需要时检查出来。

注解 使用说明
@AssertFalse 注释的元素必须是false。
@AssertTrue 注释的元素必须为true。
@DecimalMax 带注释的元素必须是其值必须小于或等于指定最大值的数字。
@DecimalMin 带注释的元素必须是其值必须高于或等于指定最小值的数字。
@Future 注释元素必须是未来的即时,日期或时间。
@Max 带注释的元素必须是其值必须小于或等于指定最大值的数字。
@Min 带注释的元素必须是其值必须高于或等于指定最小值的数字。
@Negative 带注释的元素必须是严格负数。
@NotBlank 带注释的元素不得null并且必须至少包含一个非空白字符。
@NotEmpty 带注释的元素不能null也不是空的。
@NotNull 注释的元素不能是null
@Null 注释的元素必须是null
@Pattern 注释的CharSequence必须与指定的正则表达式匹配。
@Positive 带注释的元素必须是严格的正数。
@Size 注释的元素大小必须在指定的边界之间(包含)。
 

总结

spring boot REST验证教程中,我们学到了 -
  1. 通过ID获取资源时验证ID。
  2. 验证POST / PUT API中的请求主体字段。
  3. 在API响应中发送一致且结构化的错误响应。

提示:源码将会在下方提供下载,仅需2积分。每天登陆签到可以获取1积分哟。

温馨提示:如果博客包含隐藏资源,登录后的账户必须通过邮箱验证才能获取。
暂无评论