我们在 Spring Boot Web:处理 HTTP 请求体中的 JSON 数据 的基础上看下如何使用 @Valid 验证请求数据。
示例1:基础示例
项目结构:
.
├── build.gradle
└── src
└── main
├── java
│ └── hello
│ ├── Application.java
│ ├── BaseResponse.java
│ ├── GreetingController.java
│ ├── GreetingRequest.java
│ └── GreetingResponse.java
└── resources
修改 GreetingRequest :
package hello;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
@Data
@NoArgsConstructor
public class GreetingRequest {
@NotNull(message = "msg不能为空")
@Size(min = 1, message = "msg长度不能小于1")
private String msg;
}
修改 GreetingController :
package hello;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
@RestController
public class GreetingController {
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
@RequestMapping(value = "/greeting1")
public BaseResponse greeting1(@Valid @RequestBody GreetingRequest request) {
return BaseResponse.success("", new GreetingResponse(counter.incrementAndGet(), String.format(template, request.getMsg())));
}
}
运行 Application 类。使用Postman构建 POST 请求到http://127.0.0.1:8080/greeting1
,请求体是json:
{"msg": ""}
响应体:
{
"timestamp": "2018-07-23T00:57:19.507+0000",
"status": 400,
"error": "Bad Request",
"errors": [
{
"codes": [
"Size.greetingRequest.msg",
"Size.msg",
"Size.java.lang.String",
"Size"
],
"arguments": [
{
"codes": [
"greetingRequest.msg",
"msg"
],
"arguments": null,
"defaultMessage": "msg",
"code": "msg"
},
2147483647,
1
],
"defaultMessage": "msg长度不能小于1",
"objectName": "greetingRequest",
"field": "msg",
"rejectedValue": "",
"bindingFailure": false,
"code": "Size"
}
],
"message": "Validation failed for object='greetingRequest'. Error count: 1",
"path": "/greeting1"
}
是的,这个响应并没有用我们自定义的 BaseResponse 来包装。如何包装呢?看下面。
示例2:使用 ExceptionHandler 捕捉 valid 异常
我们希望把错误信息msg长度不能小于1
放到BaseResponse中返回。怎么办? 加一个 ExceptionHandler 。
新建类 CustomExceptionHandler :
package hello;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
@ControllerAdvice
public class CustomExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(value = HttpStatus.OK)
@ResponseBody
public BaseResponse handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
String msg = ex.getBindingResult().getAllErrors().get(0).getDefaultMessage(); // todo: 需要加null判断
return BaseResponse.fail("请求数据有误: "+msg, null);
}
}
运行 Application 类。使用Postman构建 POST 请求到http://127.0.0.1:8080/greeting1
,请求体是json:
{"msg": ""}
响应体:
{
"success": false,
"msg": "msg长度不能小于1",
"result": null
}
示例3:使用 BindingResult 捕捉 valid 错误
对于 GreetingController 中的greeting1函数,如果参数增加一个 BindingResult :
@RequestMapping(value = "/greeting1")
public BaseResponse greeting1(@Valid @RequestBody GreetingRequest request, BindingResult bindingResult) {
return BaseResponse.success("", new GreetingResponse(counter.incrementAndGet(), String.format(template, request.getMsg())));
}
那么,错误信息会被放进 bindingResult 。而示例2中的@ExceptionHandler就无效了。
这种方法适合返回数据是渲染的HTML网页的场景。可以看下 https://spring.io/guides/gs/validating-form-input/ 。