亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.430618.com 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線(xiàn)咨詢(xún)客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

今天繼續(xù)為大家分享在工作中如何優(yōu)雅的校驗(yàn)接口的參數(shù)的合法性以及如何統(tǒng)一處理接口返回的json格式。每個(gè)字都是干貨,原創(chuàng)不易,分享不易。

Spring Boot 優(yōu)雅地實(shí)現(xiàn)接口參數(shù)校驗(yàn)

 

validation主要是校驗(yàn)用戶(hù)提交的數(shù)據(jù)的合法性,比如是否為空,密碼是否符合規(guī)則,郵箱格式是否正確等等,校驗(yàn)框架比較多,用的比較多的是hibernate-validator, 也支持國(guó)際化,也可以自定義校驗(yàn)類(lèi)型的注解,這里只是簡(jiǎn)單地演示校驗(yàn)框架在Spring Boot中的簡(jiǎn)單集成,要想了解更多可以參考 hibernate-validator。

1. pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

2. dto

public class UserInfoIDto {

    private Long id;

    @NotBlank
    @Length(min=3, max=10)
    private String username;

    @NotBlank
    @Email
    private String email;

    @NotBlank
    @Pattern(regexp="^((13[0-9])|(15[^4,\D])|(18[0,3-9]))\d{8}$", message="手機(jī)號(hào)格式不正確")
    private String phone;

    @Min(value=18)
    @Max(value = 200)
    private int age;

    @NotBlank
    @Length(min=6, max=12, message="昵稱(chēng)長(zhǎng)度為6到12位")
    private String nickname;

     // Getter & Setter
}

3. controller

import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;

@RestController
public class SimpleController {

    @PostMApping("/users")
    public String register(@Valid @RequestBody UserInfoIDto userInfoIDto, BindingResult result){
        if (result.hasErrors()) {
            FieldError fieldError = result.getFieldError();
            String field = fieldError.getField();
            String msg = fieldError.getDefaultMessage();

            return field + ":" + msg;
        }
        System.out.println("開(kāi)始注冊(cè)用戶(hù)...");

        return "success";
    }
}
Spring Boot 優(yōu)雅地實(shí)現(xiàn)接口參數(shù)校驗(yàn)

 

4. 去掉BindingResult參數(shù)

每個(gè)接口都需要BindingResult參數(shù),而且每個(gè)接口都需要處理錯(cuò)誤信息,這樣增加一個(gè)參數(shù)也不優(yōu)雅,處理錯(cuò)誤信息代碼量也很重復(fù)。如果去掉BindingResult參數(shù),系統(tǒng)就會(huì)報(bào)錯(cuò)MethodArgumentNotValidException,我們只需要使用全局異常來(lái)捕獲該錯(cuò)誤,處理一下就可以省略傳BindingResult參數(shù)了。

@RestController
public class SimpleController {

    @PostMapping("/users")
    public String register(@Valid @RequestBody UserInfoIDto userInfoIDto){
        System.out.println("開(kāi)始注冊(cè)用戶(hù)...");
        return "success";
    }
}

@RestControllerAdvice 用于攔截所有的@RestController

@RestControllerAdvice
public class GlobalExceptionHandlerAdvice {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public String methodArgumentNotValidException(MethodArgumentNotValidException e) {
        // 從異常對(duì)象中拿到ObjectError對(duì)象
        ObjectError objectError = e.getBindingResult().getAllErrors().get(0);
        // 然后提取錯(cuò)誤提示信息進(jìn)行返回
        return objectError.getDefaultMessage();
    }
}
Spring Boot 優(yōu)雅地實(shí)現(xiàn)接口參數(shù)校驗(yàn)

 

5. 統(tǒng)一返回格式

錯(cuò)誤碼枚舉

@Getter
public enum ErrorCodeEnum {
    SUCCESS(1000, "成功"),
    FAILED(1001, "響應(yīng)失敗"),
    VALIDATE_FAILED(1002, "參數(shù)校驗(yàn)失敗"),
    ERROR(5000, "未知錯(cuò)誤");

    private Integer code;
    private String msg;

    ErrorCodeEnum(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }
}

自定義異常。

@Getter
public class APIException extends RuntimeException {
    private int code;
    private String msg;

    public APIException(ErrorCodeEnum errorCodeEnum) {
        super(errorCodeEnum.getMsg());
        this.code = errorCodeEnum.getCode();
        this.msg = errorCodeEnum.getMsg();
    }
}

定義返回格式。

@Getter
public class Response<T> {
    /**
     * 狀態(tài)碼,比如1000代表響應(yīng)成功
     */
    private int code;

    /**
     * 響應(yīng)信息,用來(lái)說(shuō)明響應(yīng)情況
     */
    private String msg;

    /**
     * 響應(yīng)的具體數(shù)據(jù)
     */
    private T data;


    public Response(T data) {
        this.code = ErrorCodeEnum.SUCCESS.getCode();
        this.msg = ErrorCodeEnum.SUCCESS.getMsg();
        this.data = data;
    }

    public Response(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }
}

全局異常處理器增加對(duì)APIException的攔截,并修改異常時(shí)返回的數(shù)據(jù)格式。

@RestControllerAdvice
public class GlobalExceptionHandlerAdvice {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Response<String> methodArgumentNotValidException(MethodArgumentNotValidException e) {
        // 從異常對(duì)象中拿到ObjectError對(duì)象
        ObjectError objectError = e.getBindingResult().getAllErrors().get(0);
        // 然后提取錯(cuò)誤提示信息進(jìn)行返回
        return new Response<>(ErrorCodeEnum.VALIDATE_FAILED.getCode(), objectError.getDefaultMessage());
    }


    @ExceptionHandler(APIException.class)
    public Response<String> APIExceptionHandler(APIException e) {
        return new Response<>(e.getCode(), e.getMsg());
    }
}

SimpleController 增加一個(gè)拋出異常的方法。

@RestController
public class SimpleController {

    @PostMapping("/users")
    public String register(@Valid @RequestBody UserInfoIDto userInfoIDto){
        System.out.println("開(kāi)始注冊(cè)用戶(hù)...");
        return "success";
    }

    @GetMapping("/users")
    public Response<UserInfoIDto> list() {
        UserInfoIDto userInfoIDto = new UserInfoIDto();
        userInfoIDto.setUsername("monday");
        userInfoIDto.setAge(30);
        userInfoIDto.setPhone("123456789");
        if (true) {
            throw new APIException(ErrorCodeEnum.ERROR);
        }
        // 為了保持?jǐn)?shù)據(jù)格式統(tǒng)一,必須使用Response包裝一下
        return new Response<>(userInfoIDto);
    }
}
Spring Boot 優(yōu)雅地實(shí)現(xiàn)接口參數(shù)校驗(yàn)

 

報(bào)錯(cuò)返回的格式。

Spring Boot 優(yōu)雅地實(shí)現(xiàn)接口參數(shù)校驗(yàn)

 

不報(bào)錯(cuò),返回的格式。

Spring Boot 優(yōu)雅地實(shí)現(xiàn)接口參數(shù)校驗(yàn)

 

6. 去掉接口中的Response包裝

@RestControllerAdvice既可以全局?jǐn)r截異常也可攔截指定包下正常的返回值,可以對(duì)返回值進(jìn)行修改。

@RestControllerAdvice(basePackages = {"com.example.validator.controller"})
public class ResponseControllerAdvice implements ResponseBodyAdvice<Object> {

    /**
     * 對(duì)那些方法需要包裝,如果接口直接返回Response就沒(méi)有必要再包裝了
     *
     * @param returnType
     * @param aClass
     * @return 如果為true才會(huì)執(zhí)行beforeBodyWrite
     */
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> aClass) {
        return !returnType.getParameterType().equals(Response.class);
    }


    @Override
    public Object beforeBodyWrite(Object data, MethodParameter returnType, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest request, ServerHttpResponse response) {
        // String類(lèi)型不能直接包裝,所以要進(jìn)行些特別的處理
        if (returnType.getGenericParameterType().equals(String.class)) {
            ObjectMapper objectMapper = new ObjectMapper();
            try {
                // 將數(shù)據(jù)包裝在Response里后,再轉(zhuǎn)換為json字符串響應(yīng)給前端
                return objectMapper.writeValueAsString(new Response<>(data));
            } catch (JsonProcessingException e) {
                throw new APIException(ErrorCodeEnum.ERROR);
            }
        }
        // 這里統(tǒng)一包裝
        return new Response<>(data);
    }
}
@RestController
public class SimpleController {

    @GetMapping("/users")
    public UserInfoIDto list() {
        UserInfoIDto userInfoIDto = new UserInfoIDto();
        userInfoIDto.setUsername("monday");
        userInfoIDto.setAge(30);
        userInfoIDto.setPhone("123456789");
        // 直接返回值,不需要再使用Response包裝
        return userInfoIDto;
    }
}
Spring Boot 優(yōu)雅地實(shí)現(xiàn)接口參數(shù)校驗(yàn)

 

7. 每個(gè)校驗(yàn)錯(cuò)誤都對(duì)應(yīng)不同的錯(cuò)誤碼

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface ValidateErrorCode {
    /** 校驗(yàn)錯(cuò)誤碼 code */
    int value() default 100000;
}
@Data
public class UserInfoIDto {
    @NotBlank
    @Email
    @ValidateErrorCode(value = 20000)
    private String email;

    @NotBlank
    @Pattern(regexp="^((13[0-9])|(15[^4,\D])|(18[0,3-9]))\d{8}$", message="手機(jī)號(hào)格式不正確")
    @ValidateErrorCode(value = 30000)
    private String phone;
}

校驗(yàn)異常獲取注解中的錯(cuò)誤碼。

@ExceptionHandler(MethodArgumentNotValidException.class)
    public Response<String> methodArgumentNotValidException(MethodArgumentNotValidException e) throws NoSuchFieldException {
        // 從異常對(duì)象中拿到ObjectError對(duì)象
        ObjectError objectError = e.getBindingResult().getAllErrors().get(0);

        // 參數(shù)的Class對(duì)象,等下好通過(guò)字段名稱(chēng)獲取Field對(duì)象
        Class<?> parameterType = e.getParameter().getParameterType();
        // 拿到錯(cuò)誤的字段名稱(chēng)
        String fieldName = e.getBindingResult().getFieldError().getField();
        Field field = parameterType.getDeclaredField(fieldName);
        // 獲取Field對(duì)象上的自定義注解
        ValidateErrorCode annotation = field.getAnnotation(ValidateErrorCode.class);
        if (annotation != null) {
            return new Response<>(annotation.value(),objectError.getDefaultMessage());
        }

        // 然后提取錯(cuò)誤提示信息進(jìn)行返回
        return new Response<>(ErrorCodeEnum.VALIDATE_FAILED.getCode(), objectError.getDefaultMessage());
    }
Spring Boot 優(yōu)雅地實(shí)現(xiàn)接口參數(shù)校驗(yàn)

 


Spring Boot 優(yōu)雅地實(shí)現(xiàn)接口參數(shù)校驗(yàn)

 

8. 個(gè)別接口不統(tǒng)一包裝響應(yīng)

有時(shí)候第三方接口回調(diào)我們的接口,我們的接口必須按照第三方定義的返回格式來(lái),此時(shí)第三方不一定和我們自己的返回格式一樣,所以要提供一種可以繞過(guò)統(tǒng)一包裝的方式。

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface NotResponseWrap {
}
@RestController
public class SimpleController {

    @NotResponseWrap
    @PostMapping("/users")
    public String register(@Valid @RequestBody UserInfoIDto userInfoIDto){
        System.out.println("開(kāi)始注冊(cè)用戶(hù)...");
        return "success";
    }
}

ResponseControllerAdvice 增加一個(gè)不包裝的條件,配置了@NotResponseWrap注解就跳過(guò)包裝。

@Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> aClass) {
        return !(returnType.getParameterType().equals(Response.class) || returnType.hasMethodAnnotation(NotResponseWrap.class));
    }
Spring Boot 優(yōu)雅地實(shí)現(xiàn)接口參數(shù)校驗(yàn)

分享到:
標(biāo)簽:Spring Boot
用戶(hù)無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定