2023年12月10日 星期日

JSR-303 Bean Validation

 在以往Bean Validation通常會在service的function寫上好長一段判斷如下


//合法性校驗
  if (StringUtils.isBlank(dto.getName())) {
   throw new XueChengPlusException("課程名稱為空");
  }

  if (StringUtils.isBlank(dto.getMt())) {
   throw new XueChengPlusException("課程分類為空");
  }

  if (StringUtils.isBlank(dto.getSt())) {
   throw new XueChengPlusException("課程分類為空");
  }

  if (StringUtils.isBlank(dto.getGrade())) {
   throw new XueChengPlusException("課程等級為空");
  }

然而當欄位多起來的時候,code看起來就會變得冗長

且如果不同的function都要來一段這個,這些也有許多重複的程式碼其實也有改進空間

而在JavaEE6規範中就定義了參數校驗的規範

它就是JSR-303,它定義了Bean Validation,即對bean屬性進行校驗

SpringBoot提供了JSR-303的支持,它就是spring-boot-starter-validation,它的底層使用Hibernate Validator,Hibernate Validator是Bean Validation 的參考實現。

所以,我們準備在Controller層使用spring-boot-starter-validation完成對請求參數的基本合法性進行校驗。

以下的組合是可以讓不同的controller使用不同組的校驗文字
我們在專案中的exception包定出GlobalExceptionHandler和ValidationGroups



GlobalExceptionHandler

@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
    @ResponseBody
    @ExceptionHandler(XueChengPlusException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public RestErrorResponse customException(XueChengPlusException e) {
        log.error("【系統異常】{}",e.getErrMessage(),e);
        return new RestErrorResponse(e.getErrMessage());

    }

    @ResponseBody
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public RestErrorResponse exception(Exception e) {

        log.error("【系統異常】{}",e.getMessage(),e);

        return new RestErrorResponse(CommonError.UNKOWN_ERROR.getErrMessage());

    }

    @ResponseBody
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public RestErrorResponse methodArgumentNotValidException(MethodArgumentNotValidException e) {

        BindingResult bindingResult = e.getBindingResult();
        List msgList = new ArrayList<>();
        bindingResult.getFieldErrors().stream().forEach(item->{
            msgList.add(item.getDefaultMessage());
        });
        String msg = StringUtils.join(msgList, ",");
        log.error("【系統異常】{}",msg);
        return new RestErrorResponse(msg);

    }
}


ValidationGroups

public class ValidationGroups {
    public interface Insert{};
    public interface Update{};
    public interface Delete{};
}

目前將ValidationGroups分成新增, 更新, 刪除三個類別

在bean上設置的檢核訊息如下


@Data
@ApiModel(value="AddCourseDto", description="新增課程基本信息")
public class AddCourseDto {

 @NotEmpty(groups = {ValidationGroups.Insert.class},message = "新增課程名稱不能為空")
 @NotEmpty(groups = {ValidationGroups.Update.class},message = "修改課程名稱不能為空")
 @ApiModelProperty(value = "課程名稱", required = true)
 private String name;
 ...
 }

然後使用上, 我們在controller就可以這樣寫, 比方說我們此類為新增 就使用Insert @Validated({ValidationGroups.Insert.class})


    @ApiOperation("新增課程基礎信息")
    @PostMapping("/course")
    public CourseBaseInfoDto createCourseBase(@RequestBody @Validated({ValidationGroups.Insert.class}) AddCourseDto addCourseDto){
        //獲取到用戶所屬機構id
        Long companyId = 1232141425L;
        return courseBaseInfoService.createCourseBase(companyId,addCourseDto);
    }

沒有留言:

張貼留言

[leetcode] [KMP] KMP

ABCDABD... ABCDABF... 簡單的說, 傳統解兩字串匹配部分 可能會來個雙迴圈, 哀個比對, 當不匹配的時候, 會將下方列再後移1位 然後不匹配再後移 然而 如果像上放已經有4個屬於匹配的字串, 她就應該直接往後移四位來匹配, 而不是只移動1位 隱藏的思維是, 當...