Spring Boot統一異常處理以及引數校驗

程式狗兒發表於2019-02-17

Spring Boot統一異常處理以及引數校驗

引數自動校驗

一般情況我們前端向後端傳遞引數都是2種方式 JSON或者表單提交

因此本文分別講述JSON提交引數校驗和表單提交引數校驗在Spring Boot中是如何操作,以及校驗失敗如何統一轉交給異常處理類去處理的。

Api設計如下:

表單方式: http://localhost:8080/get-args-valid?username=xxx&password=xxx

JSON方式: http://localhost:8080/post-args-valid

{
    "username":"123",
    "password":"123"
}

複製程式碼

採用JSON方式提交,所以設定content-type如下:

Content-Type: application/json

新建一個Spring Boot專案

Api如下設計:


/**
 * @author: hujiansong
 * @email: 1358199510@qq.com
 * @since: 2019/1/29 16:53
 */
@RestController
public class ValidController {

    @GetMapping("/get-args-valid")
    public String getArgsValid(String username, String password) {
        return null;
    }

    @PostMapping("/post-args-valid")
    public String postArgsValid(@RequestBody User user) {
        return null;
    }

    @Data
    class User {
        String username;

        String password;
    }
}

複製程式碼

先講JSON方式如何進行引數校驗

JSON方式:

@RestController
public class ValidController {


    @PostMapping("/post-args-valid")
    public String postArgsValid(@Valid<1> @RequestBody User user) {
        return null;
    }

    @Data
    static class User {
        @NotNull(message = "使用者名稱不能為空")<2>
        String username;

        @NotNull(message = "密碼不能為空")
        String password;
    }
}

複製程式碼

注意: 這裡內部類User需要加上static,否則json傳過來無法解析

<1>: @Valid表示這個實體引數交給Spring去校驗

<2>: @NotNull校驗規則

如上2步操作就可以完成引數校驗:

JSON方式校驗

可以看到如何password不傳遞,spring 已經幫我們做了引數校驗,再來看看表單方式

表單方式:

@RestController
@Validated<1>
public class ValidController {

    @GetMapping("/get-args-valid")
    public String getArgsValid(@NotNull(message = "使用者名稱不能空")<2> String username, @NotNull(message = "密碼不能為空") String password) {
        return null;
    }

}

複製程式碼

同樣也是2步搞定

<1>: @Validated,交給Spring去校驗

<2>: @NotNull校驗規則

看看如果password不傳遞會返回什麼:

表單提交方式

可見,Spring已經替我們做了引數校驗

Spring 還包含了很多校驗規則如下:

註解 解釋
@Null 被註釋的元素必須為 null
@NotNull 被註釋的元素必須不為 null
@AssertTrue 被註釋的元素必須為 true
@AssertFalse 被註釋的元素必須為 false
@Min(value) 被註釋的元素必須是一個數字,其值必須大於等於指定的最小值
@Max(value) 被註釋的元素必須是一個數字,其值必須小於等於指定的最大值
@DecimalMin 被註釋的元素必須是一個數字,其值必須大於等於指定的最小值
@DecimalMax 被註釋的元素必須是一個數字,其值必須小於等於指定的最大值
@Size(max=, min=) 被註釋的元素的大小必須在指定的範圍內
@Digits 被註釋的元素必須是一個數字,其值必須在可接受的範圍內
@Past 被註釋的元素必須是一個過去的日期
@Future 被註釋的元素必須是一個將來的日期
@Pattern(regex=) 被註釋的元素必須符合指定的正規表示式

異常統一處理

上面介紹瞭如何讓Spring校驗我們的引數,那麼可以看到JSON方式校驗返回的結果一大串,不是十分優雅。那麼利用統一異常處理則可優雅返回引數校驗結果。

JSON方式:校驗失敗後,會丟擲一個 MethodArgumentNotValidException

表單方式:校驗失敗,會丟擲一個ConstraintViolationException

因此只需要在統一異常處理類裡面處理這2個異常即可。

ExceptionHanlder

表單方式:

@RestControllerAdvice
public class ExceptionHandler {

    @org.springframework.web.bind.annotation.ExceptionHandler(ConstraintViolationException.class)
    public Map<String, Object> methodArgNotValidException(ConstraintViolationException cve, HttpServletRequest httpServletRequest) {
        Set<ConstraintViolation<?>> cves = cve.getConstraintViolations();
        StringBuffer errorMsg = new StringBuffer();
        cves.forEach(ex -> errorMsg.append(ex.getMessage()));
        Map<String, Object> respMap = new HashMap<>(4);
        respMap.put("code", -1);
        respMap.put("msg", errorMsg);
        return respMap;
    }
}
複製程式碼

重新呼叫:

表單方式異常統一處理

JSON方式:

@RestControllerAdvice
public class ExceptionHandler {

    @org.springframework.web.bind.annotation.ExceptionHandler({MethodArgumentNotValidException.class})
    public Map<String, Object> methodDtoNotValidException(Exception ex, HttpServletRequest request) {
        MethodArgumentNotValidException c = (MethodArgumentNotValidException) ex;
        List<ObjectError> errors = c.getBindingResult().getAllErrors();
        StringBuffer errorMsg = new StringBuffer();
        errors.stream().forEach(x -> {

            errorMsg.append(x.getDefaultMessage()).append(";");
        });
        Map<String, Object> respMap = new HashMap<>(4);
        respMap.put("code", -1);
        respMap.put("msg", errorMsg);
        return respMap;
    }

}
複製程式碼

同樣呼叫,這次username為空試試看:

JSON方式異常捕獲

完整的程式碼

Spring Boot統一異常處理以及引數校驗

相關文章