最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot validator參數(shù)驗證restful自定義錯誤碼響應方式

 更新時間:2021年10月19日 14:36:11   作者:shalousun  
這篇文章主要介紹了SpringBoot validator參數(shù)驗證restful自定義錯誤碼響應方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

validator參數(shù)驗證restful自定義錯誤碼響應

關于spring web應用中關于如何使用 Bean Validation API和hibernate-validator的文章已經很多,本文就不再重復敘述,今天要介紹的重點是在SpringBoot restful服務中如何根據(jù)不同驗證錯誤響應不同的自定義錯誤碼。下面直接上代碼。

一、定義restful統(tǒng)一結果返回

阿里java開發(fā)手冊中定義的一段參考【“對于公司外的 http/api 開放接口必須使用“錯誤碼”; 而應用內部推薦異常拋出;跨應用間 RPC 調用優(yōu)先考慮使用 Result 方式,封裝 isSuccess()方法、 “錯誤碼”、“錯誤簡短信息”。】。因此這里也定義個返回結構。

public class CommonResult<T> implements Serializable {
	
	/**
	 * serialVersionUID:.
	 */
	private static final long serialVersionUID = -7268040542410707954L;
 
	/**
	 * 是否成功
	 */
	private boolean success = false;
 
	/**
	 * 返回信息
	 */
	private String message;
 
	/**
	 * 裝在數(shù)據(jù)
	 */
	private T data;
 
	/**
	 * 錯誤代碼
	 */
	private String code;
 
	/**
	 * 默認構造器
	 */
	public CommonResult(){
		
	}
	/**
	 * 
	 * @param success
	 * 			是否成功
	 * @param message
	 * 			返回的消息
	 */
	public CommonResult(boolean success, String message){
		this.success = success;
		this.message = message;
	}
	/**
	 * 
	 * @param success
	 * 			是否成功
	 */
	public CommonResult(boolean success){
		this.success = success;
	}
 
	/**
	 *
	 * @param code error code
	 * @param message success or error messages
	 */
	public CommonResult(String code,String message){
		this.code = code;
		this.message = message;
	}
	/**
	 * 
	 * @param success
	 * 			是否成功
	 * @param message
	 * 			消息
	 * @param data
	 * 			數(shù)據(jù)
	 */
	public CommonResult(boolean success, String message, T data){
		this.success = success;
		this.message = message;
		this.data = data;
	}
    //省略get set
}

二、定義一個錯誤碼枚舉

在有需要國際化的項目,當然選擇通過i18n來配置更好,此處為了簡單直接采用枚舉定義。這里定義的錯誤僅供參考,不同公司每個應用在實際情況下可能都不大一樣。

/**
 * 錯誤代碼枚舉類
 *
 */
public enum ErrorCodeEnum { 
    SUCCESS("0000", "success"), 
    PARAM_EMPTY("1001", "必選參數(shù)為空"), 
    PARAM_ERROR("1002", "參數(shù)格式錯誤"), 
    UNKNOWN_ERROR("9999", "系統(tǒng)繁忙,請稍后再試...."); 
    private String code; 
    private String desc; 
    ErrorCodeEnum(String code, String desc) {
        this.code = code;
        this.desc = desc;
    }
 
    public String getCode() {
        return this.code;
    } 
 
    public String getDesc() {
        return desc;
    }
 
    @Override
    public String toString() {
        return "[" + this.code + "]" + this.desc;
    }
}

三、靜態(tài)封裝CommonResult

靜態(tài)封裝CommonResult主要是方便在項目中快速根據(jù)邏輯寫返回結果代碼。

/**
 * 公共響應結果成功失敗的靜態(tài)方法調用
 *
 */
public class ResultUtil {
 
 
    /**
     * return success
     *
     * @param data
     * @return
     */
    public static <T> CommonResult<T> returnSuccess(T data) {
        CommonResult<T> result = new CommonResult();
        result.setCode(ErrorCodeEnum.SUCCESS.getCode());
        result.setSuccess(true);
        result.setData(data);
        result.setMessage(ErrorCodeEnum.SUCCESS.getDesc());
        return result;
    }
 
    /**
     * return error
     *
     * @param code error code
     * @param msg  error message
     * @return
     */
    public static CommonResult returnError(String code, String msg) {
        CommonResult result = new CommonResult();
        result.setCode(code);
        result.setData("");
        result.setMessage(msg);
        return result; 
    }
 
    /**
     * use enum
     *
     * @param status
     * @return
     */
    public static CommonResult returnError(ErrorCodeEnum status) {
        return returnError(status.getCode(), status.getDesc());
    }
}

四、定義BaseController來處理驗證錯誤自定義錯誤碼返回

/**
 * BaseController
 *
 */
public abstract class BaseController { 
    private static final Logger LOGGER = LoggerFactory.getLogger(BaseController.class); 
    /**
     * validate params
     *
     * @param bindingResult
     * @return
     */
    protected CommonResult validParams(BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            FieldError fieldError = bindingResult.getFieldError();
            return processBindingError(fieldError);
        }
        return ResultUtil.returnSuccess("");
    }
 
    /**
     * 根據(jù)spring binding 錯誤信息自定義返回錯誤碼和錯誤信息
     *
     * @param fieldError
     * @return
     */
    private CommonResult processBindingError(FieldError fieldError) {
        String code = fieldError.getCode();
        LOGGER.debug("validator error code: {}", code);
        switch (code) {
            case "NotEmpty":
                return ResultUtil.returnError(ErrorCodeEnum.PARAM_EMPTY.getCode(), fieldError.getDefaultMessage());
            case "NotBlank":
                return ResultUtil.returnError(ErrorCodeEnum.PARAM_EMPTY.getCode(), fieldError.getDefaultMessage());
            case "NotNull":
                return ResultUtil.returnError(ErrorCodeEnum.PARAM_EMPTY.getCode(), fieldError.getDefaultMessage());
            case "Pattern":
                return ResultUtil.returnError(ErrorCodeEnum.PARAM_ERROR.getCode(), fieldError.getDefaultMessage());
            case "Min":
                return ResultUtil.returnError(ErrorCodeEnum.PARAM_ERROR.getCode(), fieldError.getDefaultMessage());
            case "Max":
                return ResultUtil.returnError(ErrorCodeEnum.PARAM_ERROR.getCode(), fieldError.getDefaultMessage());
            case "Length":
                return ResultUtil.returnError(ErrorCodeEnum.PARAM_ERROR.getCode(), fieldError.getDefaultMessage());
            case "Range":
                return ResultUtil.returnError(ErrorCodeEnum.PARAM_ERROR.getCode(), fieldError.getDefaultMessage());
            case "Email":
                return ResultUtil.returnError(ErrorCodeEnum.PARAM_ERROR.getCode(), fieldError.getDefaultMessage());
            case "DecimalMin":
                return ResultUtil.returnError(ErrorCodeEnum.PARAM_ERROR.getCode(), fieldError.getDefaultMessage());
            case "DecimalMax":
                return ResultUtil.returnError(ErrorCodeEnum.PARAM_ERROR.getCode(), fieldError.getDefaultMessage());
            case "Size":
                return ResultUtil.returnError(ErrorCodeEnum.PARAM_ERROR.getCode(), fieldError.getDefaultMessage());
            case "Digits":
                return ResultUtil.returnError(ErrorCodeEnum.PARAM_ERROR.getCode(), fieldError.getDefaultMessage());
            case "Past":
                return ResultUtil.returnError(ErrorCodeEnum.PARAM_ERROR.getCode(), fieldError.getDefaultMessage());
            case "Future":
                return ResultUtil.returnError(ErrorCodeEnum.PARAM_ERROR.getCode(), fieldError.getDefaultMessage());
            default:
                return ResultUtil.returnError(ErrorCodeEnum.UNKNOWN_ERROR);
        }
    }
}

五、驗證實例

這里直接給出一個簡單的參數(shù)驗證例子。

Controller繼承上面寫的BaseController

/**
 * 關于Validator使用測試
 *
 */ 
@RestController
@RequestMapping("validator")
public class ValidatorTestController extends BaseController { 
    private static final Logger LOGGER = LoggerFactory.getLogger(ValidatorTestController.class); 
    /**
     * validate驗證測試
     *
     * @param leader
     * @param bindingResult
     * @return
     */
    @PostMapping("/test")
    public CommonResult testSimpleValidate(@Valid @RequestBody Leader leader, BindingResult bindingResult) {
        LOGGER.debug("ReqParams:{}", JSON.toJSONString(leader));
        CommonResult result = validParams(bindingResult);
        if (!result.isSuccess()) {
            return result;
        }
        return ResultUtil.returnSuccess("");
    }
}

入?yún)ο驦eader代碼

public class Leader { 
    /**
     * 姓名
     */
    @NotEmpty
    private String name;
 
    /**
     * 生日
     */
    @Pattern(regexp = "^[0-9]{4}-[0-9]{2}-[0-9]{2}$", message = "出生日期格式不正確")
    private String birthday;
 
    /**
     * 年齡
     */
    @Min(value = 0)
    private Integer age; 
    //省略gettes and  setters 
}

這時項目已經已經完全可以根據(jù)驗證錯誤來返回自定義的錯誤碼和提示了。

本例所涉及源代碼:https://github.com/shalousun/api-doc-test

小結一下

在一些對外服務提供restful的應用中,根據(jù)不同的驗證錯誤返回其實是避免不了。當然實現(xiàn)的方式可以有種,而本文所采用的方式相對來說簡單易懂。

使用validator-api驗證springboot的參數(shù)

作為服務端開發(fā),驗證前端傳入的參數(shù)的合法性是一個必不可少的步驟,但是驗證參數(shù)是一個基本上是一個體力活,而且冗余代碼繁多,也影響代碼的可閱讀性,所以有沒有一個比較優(yōu)雅的方式來解決這個問題?

這么簡單的問題當然早就有大神遇到并且解決了,這一篇文章主要講一下解決基于spring-boot的驗證參數(shù)的比較好的方法:利用validator-api來進行驗證參數(shù)。

在spring-boot-starter-web包里面有hibernate-validator包,它提供了一系列驗證各種參數(shù)的方法,所以說spring-boot已經幫我們想好要怎么解決這個問題了。

這篇文章針對spring-boot里面的spring-mvc介紹三種方式來驗證參數(shù)。

一、這個方法在網(wǎng)上大部分都可以查到

先假設我們的restful的接口接受一個GradeAndClassroomModel類型的對象,并且這個類被定義成

@Data
public class GradeAndClassroomModel {  
@Range(min = 1, max = 9, message = "年級只能從1-9")  
private int grade;  
@Range(min = 1, max = 99, message = "班級只能從1-99")  
private int classroomNumber;
}

利用validator提供的一系列注解,比如本例中的@Range,就可以表示參數(shù)的范圍和出錯時候的提示信息。還有很多其他注解,這里就不一一列出

然后我們的Controller層的代碼為

@RequestMapping(value = "/paramErrorTest", method = RequestMethod.GET)
public String paramErrorTest(    
  @Valid    
  @ModelAttribute    
  GradeAndClassroomModel gradeAndClassroomModel, 
  BindingResult result) {  
  return classroomService.getTeacherName(gradeAndClassroomModel.getGrade(), gradeAndClassroomModel.getClassroomNumber());
}

其中如果驗證出錯,result對象里面就會有錯誤信息,然后可以自己進行處理。

二、針對上面的例子

會有人說,就兩個參數(shù),為什么要作為對象呢?會不會太麻煩?確實,如果只有少數(shù)對象,直接把參數(shù)寫到Controller層,然后在Controller層進行驗證就可以了。

@RequestMapping(value = "/teacherName", method = RequestMethod.GET)
public String teacherName(
  @Range(min = 1, max = 9, message = "年級只能從1-9")        
  @RequestParam(name = "grade", required = true) 
  int grade,  
  @Min(value = 1, message = "班級最小只能1")    
  @Max(value = 99, message = "班級最大只能99")      
  @RequestParam(name = "classroom", required = true)    
  int classroom) {  
return classroomService.getTeacherName(grade, classroom);
}

如果直接把validator提供的注解移除來寫到請求參數(shù)上面的話是不是就可以了呢?答案是錯,為什么這樣不能成功的驗證參數(shù)呢?具體原因大家可以參考官方文檔

上面的文檔已經說的很清楚了,所以我們需要創(chuàng)建一個Bean

@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {  
  return new MethodValidationPostProcessor();
}

然后在類方法上面加上注解@Validated

@RestController
@RequestMapping("/spring-boot/classroom")
@Validated
public class ClassroomController {
 ...
}

然后之前沒有生效的注解@Range、@Min、@Max等validator包里面提供的注解就可以生效了。

三、估計到了這里又會有人問

如果validator包里面注解不能滿足我們的需求,我們是否可以自己定義參數(shù)驗證的邏輯。答案是肯定的,我們可以利用

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER, ElementType.FIELD})
@Constraint(validatedBy = {Validator.class})
public @interface ParamValidator {
  String message() default "Parameter error!";
  Class<?>[] groups() default {};
  Class<? extends Payload>[] payload() default {};
}

public class Validator implements ConstraintValidator<ParamValidator, Object> {
  ...
}

組合進行自定義,具體的例子網(wǎng)上其他文章就很多了,這里就不進行詳細的例子了,但是最終使用的時候就是

  @RequestMapping(value = "/paramValidator", method = RequestMethod.GET)
  public String paramValidator(
      @ParamValidator(isRequired = true, desc = "年級", range = "int:1~9", message = "年級只能從1-9")
      @RequestParam(name = "grade", required = true)
      int grade,
      @ParamValidator(isRequired = true, desc = "班級", range = "int:1~99", message = "班級只能從1-99")
      @RequestParam(name = "classroom", required = true)
      int classroom) {
    return classroomService.getTeacherName(grade, classroom);
  }

另外不要忘記方法二里面里面提到的MethodValidationPostProcessor這個bean,如果沒有初始化這個bean,自定義的驗證方法也不會執(zhí)行。驗證邏輯會失效。

是不是通過這樣寫注解的方式來驗證進行請求的參數(shù),代碼邏輯更佳清晰和優(yōu)雅?表達的含義也會更佳清楚?并且沒有了大量重復的類似的驗證代碼。

Ps:這里的代碼都是基于spring-mvc框架來試驗的,如果有人并沒有使用spring-mvc作為rest框架,而是使用jersey來作為rest框架的話,可能一些細節(jié)方面需要調整, 但是這三種方案應該都是可以兼容的。

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • JAVA開發(fā)環(huán)境Vs?code配置步驟詳解

    JAVA開發(fā)環(huán)境Vs?code配置步驟詳解

    這篇文章主要為大家介紹了JAVA開發(fā)環(huán)境Vs?code配置步驟詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-04-04
  • SpringMVC后端Controller頁面跳轉的三種方式匯總

    SpringMVC后端Controller頁面跳轉的三種方式匯總

    這篇文章主要介紹了SpringMVC后端Controller頁面跳轉的三種方式匯總,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • Spring+EHcache緩存實例詳解

    Spring+EHcache緩存實例詳解

    這篇文章主要為大家詳細介紹了Spring+EHcache緩存實例,EhCache是一個純Java的進程內緩存框架,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • 詳解Android開發(fā)中Fragment的使用

    詳解Android開發(fā)中Fragment的使用

    這篇文章主要介紹了詳解Android開發(fā)中Fragment的使用,包括Java代碼中調用Fragment的方法,需要的朋友可以參考下
    2015-07-07
  • java中繼承測試代碼分析

    java中繼承測試代碼分析

    這篇文章主要介紹了java中繼承測試代碼分析,具有一定借鑒價值,需要的朋友可以參考下。
    2017-12-12
  • Kafka在客戶端實現(xiàn)消息的發(fā)送與讀取

    Kafka在客戶端實現(xiàn)消息的發(fā)送與讀取

    這篇文章主要介紹了Kafka在客戶端實現(xiàn)消息的發(fā)送與讀取,KafkaProducer是用于發(fā)送消息的類,ProducerRecord類用于封裝Kafka的消息,KafkaProducer的實例化需要指定的參數(shù),Producer的參數(shù)定義在 org.apache.kafka.clients.producer.ProducerConfig類中,需要的朋友可以參考下
    2023-12-12
  • Java判斷絕對值的方法總結

    Java判斷絕對值的方法總結

    在本文中作者為大家分享了兩種Java判斷絕對值的方法,對此有興趣的朋友可以和小編一起學習下。
    2018-02-02
  • Java算法實現(xiàn)調整數(shù)組順序使奇數(shù)位于偶數(shù)之前的講解

    Java算法實現(xiàn)調整數(shù)組順序使奇數(shù)位于偶數(shù)之前的講解

    今天小編就為大家分享一篇關于Java算法實現(xiàn)調整數(shù)組順序使奇數(shù)位于偶數(shù)之前的講解,小編覺得內容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • Java Socket聊天室編程(二)之利用socket實現(xiàn)單聊聊天室

    Java Socket聊天室編程(二)之利用socket實現(xiàn)單聊聊天室

    這篇文章主要介紹了Java Socket聊天室編程(二)之利用socket實現(xiàn)單聊聊天室的相關資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-09-09
  • 基于RocketMQ推拉模式詳解

    基于RocketMQ推拉模式詳解

    這篇文章主要介紹了RocketMQ推拉模式的使用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07

最新評論

湾仔区| 温州市| 盘山县| 新乡市| 盐津县| 龙岩市| 巴彦淖尔市| 湘西| 海晏县| 宜兴市| 通许县| 延安市| 临湘市| 乐山市| 当雄县| 黄山市| 大石桥市| 广德县| 遂溪县| 会昌县| 福州市| 滦平县| 乌什县| 白银市| 鸡泽县| 镇宁| 射洪县| 兰考县| 垫江县| 长岛县| 手游| 灌云县| 清水县| 葫芦岛市| 民乐县| 嘉荫县| 天柱县| 徐水县| 宣汉县| 房产| 黄浦区|