SpringBoot參數校驗及異常捕獲


原文鏈接:https://blog.csdn.net/ROAOR1/article/details/114118542

參數校驗的簡單實現
創建一個springboot項目,引入校驗依賴依賴(版本可以更換)

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>2.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.18</version>
</dependency>
1
2
3
4
5
6
7
8
9
10
注意:這里@Validated需要打在類上,開啟方法驗證

@Validated
@RestController
@RequestMapping("/validate")
public class ValidateController {

@GetMapping("/run")
public void run(@NotBlank(message = "body不能為空") String body){
System.out.println(body);
}
}
1
2
3
4
5
6
7
8
9
10
這樣一個最基本的校驗就結束了

但是會發現去調用接口的時候,提示的是系統內部錯誤,這種情況下就不利於前后端聯調,明明是少傳的參數,結果提示的確實系統內部錯誤,這個時候就需要加一個全局異常處理器,特定處理參數校驗的異常,將我們想要的異常信息返回給前端


全局異常處理器
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

/**
* get請求中的參數校驗
* @param exception
* @return
*/
@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public CommonResult ConstraintViolationExceptionHandler(ConstraintViolationException exception){
log.error("參數異常信息 :", exception);
StringBuffer message = new StringBuffer();
exception.getConstraintViolations().forEach(e -> {
message.append(e.getMessage()).append(",");
});
String result = message.toString();
return CommonResult.fail(result.substring(0, result.length() - 1));
}

/**
* form-data格式的參數校驗
* @param exception
* @return
*/
@ExceptionHandler(BindException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public CommonResult bindExceptionHandler(BindException exception){
log.error("參數異常信息 :", exception);
StringBuffer message = new StringBuffer();
exception.getAllErrors().forEach(error -> {
message.append(error.getDefaultMessage()).append(",");
});
String result = message.toString();
return CommonResult.fail(result.substring(0, result.length() - 1));
}

/**
* json格式的參數校驗
* @param exception
* @return
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public CommonResult handle(MethodArgumentNotValidException exception) {
log.error("參數異常信息:", exception);
StringBuffer message=new StringBuffer();
exception.getBindingResult().getAllErrors().forEach((error) -> {
String errorMessage = error.getDefaultMessage();
message.append(errorMessage).append(",");
});
String result = message.toString();
return CommonResult.fail(result.substring(0, result.length() - 1));
}

/**
* 兜底的一個異常處理
* @param exception
* @return
*/
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public CommonResult excepitonHandler(Exception exception) {
log.error("服務器異常 :", exception);
return CommonResult.fail("服務器開小差了,請稍后重試!");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
這里我添加了三種參數校驗的異常處理,上面的例子就會被ConstraintViolationExceptionHandler這個處理器攔截到,進而處理成我們想要的格式返回給前端


@Getter
@Setter
public class BabyInfoIn {

private Integer id;

@NotBlank(message = "用戶名不能為空")
private String userName;
}
1
2
3
4
5
6
7
8
9
添加兩個方法用來觸發另外兩種異常,@Validated必須加在方法上,否則不會生效

/**
* form-data格式請求,觸發BindException異常
* @param babyInfo
*/
@PostMapping("/run2")
public void run2(@Validated BabyInfoIn babyInfoIn){
System.out.println("參數校驗成功");
}

/**
* json格式請求,觸發MethodArgumentNotValidException異常
* 必須有babyInfoIn這個對象時才會觸發,為null時不會觸發
* @param babyInfo
*/
@PostMapping("/run3")
public void run3(@Validated @RequestBody BabyInfoIn babyInfoIn){
System.out.println("參數校驗成功");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
我這里使用的通用返回

@Getter
@Setter
public class CommonResult<T> {

private Integer status;

private String msg;

private T date;

private CommonResult(T date){
this.status = CommonEnum.SUCCESS.getStatus();
this.msg = CommonEnum.SUCCESS.getMsg();
this.date = date;
}

private CommonResult(Integer status, String msg, T date){
this.status = status;
this.msg = msg;
this.date = date;
}

public static <T> CommonResult<T> ok(){
return new CommonResult<>(null);
}

public static <T> CommonResult<T> ok(T date){
return new CommonResult<>(date);
}

public static <T> CommonResult<T> fail(String msg){
return new CommonResult<>(CommonEnum.FAIL.getStatus(), msg, null);
}

public static <T> CommonResult<T> fail(String msg, T date){
return new CommonResult<>(CommonEnum.FAIL.getStatus(), msg, date);
}

public static <T> CommonResult<T> fail(Integer status,String msg, T date){
return new CommonResult<>(status, msg, date);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
簡單的返回枚舉

public enum CommonEnum {
SUCCESS(1,"成功"),
FAIL(-1, "失敗");
private Integer status;

private String msg;

CommonEnum(Integer status, String msg) {
this.status = status;
this.msg = msg;
}

public Integer getStatus() {
return status;
}

public String getMsg() {
return msg;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
參數校驗的常用注解


嵌套的參數校驗
在BabyInfoIn實體中,添加BabyInfo 實體,並添加@Valid注解
注意:@Validated不支持嵌套校驗

@Valid
private BabyInfo babyInfo;
1
2
@Getter
@Setter
public class BabyInfo implements Serializable {

private static final long serialVersionUID = 1L;

private Integer babyId;

@NotNull(message = "性別不能為空")
private Integer gender;
}
1
2
3
4
5
6
7
8
9
10
11
接着還是調用上面的run3方法,會發現嵌套異常校驗生效


參數校驗分組
在實際開發中,分組的概念是必不可少的,分組就是創建一個普通的接口,以接口實現區分

public @interface Create {
}
1
2
public @interface Select {
}
1
2
具體的實現也很簡單,以run3方法為例,就是在@Validated中加上屬性用於區分

@PostMapping("/run3")
public void run3(@Validated(Select.class) @RequestBody BabyInfoIn babyInfoIn){
System.out.println("參數校驗成功");
}
1
2
3
4
如果不寫groups 屬性,那就是default默認分組

@NotBlank(message = "用戶名不能為空",groups = Select.class)
private String userName;

//create和select都需要校驗該參數
@Length(min = 0, max = 50, message = "描敘需在0-50字符之間", groups = {Select.class, Create.class})
private String desc;
1
2
3
4
5
6
Validate配置
@Configuration
public class ValidateConfig {
@Bean
public Validator validator() {
ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
.configure()
//failFast設置為true表示只要出現校驗失敗的情況,就立即結束校驗,不再進行后續的校驗。
.failFast(true)
.buildValidatorFactory();
return validatorFactory.getValidator();
}

@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
MethodValidationPostProcessor methodValidationPostProcessor = new MethodValidationPostProcessor();
methodValidationPostProcessor.setValidator(validator());
return methodValidationPostProcessor;
}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM