在Spring Boot使用Java Bean validator 類別驗證器驗證傳入物件的日期範圍。
新增一個類別驗證annotation @DateRange
,用來掛在要驗證的物件類別上。屬性beginDateFieldName
及endDateFieldName
用來指定要驗證物件中的起始日期及結束日期欄位名稱。
DateRange
package com.abc.demo.validation.annotation;
import com.abc.demo.validation.validator.DateRangeValidator;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Constraint(validatedBy = DateRangeValidator.class)
@Target({ TYPE }) // Class-level constraints
@Retention(RUNTIME)
@Documented
public @interface DateRange {
String message() default "End date must be equal or after begin date";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String beginDateFieldName();
String endDateFieldName();
}
新增@DateRange
依賴的驗證器DateRangeValidator
,繼承ConstraintValidator
。若起始日期超過結束日期則返回錯誤。
DateRangeValidator
package com.abc.demo.validation.validator;
import com.abc.demo.validation.annotation.DateRange;
import org.apache.commons.beanutils.BeanUtils;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class DateRangeValidator implements ConstraintValidator<DateRange, Object> {
private String beginDateFieldName;
private String endDateFieldName;
@Override
public void initialize(DateRange constraintAnnotation) {
beginDateFieldName = constraintAnnotation.beginDateFieldName(); // 從@DateRange取得要驗證的欄位名稱
endDateFieldName = constraintAnnotation.endDateFieldName();
}
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
if (value == null) { // value為掛有@DateRange的類別,也就是DateRangeRequestDto
return false;
}
try {
String beginDate = BeanUtils.getProperty(value, beginDateFieldName); // Apache Commons BeanUtils取得指定欄位名稱的值
String endDate = BeanUtils.getProperty(value, endDateFieldName);
LocalDate beginLocalDate = LocalDate.parse(beginDate, DateTimeFormatter.ISO_DATE); // yyyy-MM-dd, e.g. 2020-05-10
LocalDate endLocalDate = LocalDate.parse(endDate, DateTimeFormatter.ISO_DATE);
return !beginLocalDate.isAfter(endLocalDate);
} catch (Exception e) {
return false;
}
}
}
此為API的傳入參數物件,在類別前面掛上@DateRange
驗證日期範圍是否正確。使用屬性beginDateFieldName
及endDate
指定要驗證的起始日期及結束日期欄位名稱。
DateRangeRequestDto
package com.abc.demo.controller.dto;
import com.abc.demo.validation.annotation.DateRange;
@DateRange(beginDateFieldName = "beginDate", endDateFieldName = "endDate")
public class DateRangeRequestDto {
private String beginDate;
private String endDate;
// getters and setters
}
DemoController.createLogByDateRange()
接收前端傳來的DateRangeRequestDto
,傳入參數前要掛上@Valid
才會被驗證。
DemoController
package com.abc.demo.controller;
import com.abc.demo.controller.dto.DateRangeRequestDto;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
@RestController
public class DemoController {
@PostMapping(value = "/log")
public void createLogByDateRange(@Valid @RequestBody DateRangeRequestDto requestDto) {
String message = String.format("Create log from %s to %s", requestDto.getBeginDate(), requestDto.getEndDate());
System.out.println(message);
}
}
使用下面json傳入API POST /log
測試。
{
"beginDate": "2020-05-10",
"endDate": "2020-05-09"
}
參考github
沒有留言:
張貼留言