在本身的摸索下對HibernateValidator有了初步的認識,能夠使用已有的約束條件對字段作出限制,減小不要代碼的出現,使代碼更簡潔。
但在最近的實際使用中,出現了一些沒法使用框架處理的問題,例如,在第三方請求個人接口時,根據status字段區分不一樣的業務邏輯;status=1進行A邏輯處理,status=2進行B邏輯處理;在網絡了檢索了相關信息後,作出以下總結。java
使用通用Mapper插件生成實體類和mapper,這裏爲了聚焦對HibernateValidator的使用,把關注點放在實體類Brand中,在實體類中,對status字段添加自定義約束@StatusConstraintweb
package com.codeup.mybatisjoin.model; import com.codeup.mybatisjoin.validation.StatusConstraint; import lombok.Data; import javax.persistence.Column; import javax.persistence.Id; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; @Data public class Brand { @Id @Column(name = "brand_ID") private Long brandId; /** * 使用`@NotNull`添加約束 */ @Column(name = "vendor_ID") @NotNull(message = "[vendorId]不可爲空") private Long vendorId; /** * 使用`@NotBlank`添加約束 */ @Column(name = "brand_name") @NotBlank(message = "[brandName]字段不可爲空") private String brandName; private String description; /** * 自定義約束 */ @StatusConstraint(message = "[status]爲1或者2") private String status; }
@StatusConstraint
實現步驟和自定義註解類似spring
package com.codeup.mybatisjoin.validation; import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @ProjectName: mybatisjoin * @Package: com.codeup.mybatisjoin.validation * @ClassName: StatusConstraint * @Author: lhc * @Description: 狀態約束 * @Date: 2019/8/22 下午 3:36 */ @Target({ElementType.FIELD, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) /** * 指出當前約束是經過`StatusConstraintValidator.class`來實現的 */ @Constraint(validatedBy = StatusConstraintValidator.class) public @interface StatusConstraint { /** * 配置message信息 * @return */ String message() default "違規參數"; /** * 分組 * @return */ Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
經過查看源代碼裏面的文檔得知要要實現ConstraintValidator
接口json
@Documented @Target({ ANNOTATION_TYPE }) @Retention(RUNTIME) public @interface Constraint { /** * {@link ConstraintValidator} classes implementing the constraint. The given classes * must reference distinct target types for a given {@link ValidationTarget}. If two * {@code ConstraintValidator}s refer to the same type, an exception will occur. * <p> * At most one {@code ConstraintValidator} targeting the array of parameters of * methods or constructors (aka cross-parameter) is accepted. If two or more * are present, an exception will occur. * * @return array of {@code ConstraintValidator} classes implementing the constraint */ Class<? extends ConstraintValidator<?, ?>>[] validatedBy(); }
實現ConstraintValidator
接口,重寫isValid()
方法,實現本身的判斷邏輯網絡
package com.codeup.mybatisjoin.validation; import lombok.extern.slf4j.Slf4j; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; /** * @ProjectName: mybatisjoin * @Package: com.codeup.mybatisjoin.validation * @ClassName: StatusConstraintValidator * @Author: lhc * @Description: TODO * @Date: 2019/8/22 下午 3:38 */ @Slf4j public class StatusConstraintValidator implements ConstraintValidator<StatusConstraint,Object> { @Override public boolean isValid(Object value, ConstraintValidatorContext context) { String statCode = (String) value; // 等於1或2返回true,反之 if ("1".equals(statCode) || "2".equals(statCode)) { return true; } return false; } }
至此,對字段添加約束條件已完成。還存在一個重要的操做是對約束的校驗,這裏經過工具類實現mybatis
package com.codeup.mybatisjoin.validation; import org.hibernate.validator.HibernateValidator; import javax.validation.ConstraintViolation; import javax.validation.Validation; import javax.validation.Validator; import java.util.Set; /** * @ProjectName: mybatisjoin * @Package: com.codeup.mybatisjoin.validation * @ClassName: ValidatorConfig * @Author: lhc * @Description: TODO * @Date: 2019/8/22 下午 4:31 */ public class ValidatorUtil { /** * 配置hibernate_validator和快速失敗模式 */ private static Validator validator = Validation.byProvider(HibernateValidator.class) .configure() .failFast(true) .buildValidatorFactory() .getValidator(); /** * 參數校驗,若未匹配約束,則經過已將將以前定義的`message`拋出 * @param object 參數 * @param groups 屬於組 */ public static void result(Object object, Class<?>... groups) { Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object, groups); if (constraintViolations.size() > 0) { String message = constraintViolations.iterator().next().getMessage(); throw new MissingParameterException(message); } } }
將message信息拋出以後,須要以更統一的方式返回給第三方,使用統一異常處理機制解決app
自定義異常類MissingParameterException框架
package com.codeup.mybatisjoin.validation; public class MissingParameterException extends RuntimeException { public MissingParameterException(String message) { super(message); } }
統一異常處理ide
package com.codeup.mybatisjoin.validation; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import java.util.HashMap; import java.util.Map; @RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(MissingParameterException.class) public Map<String, Object> invalidParameter(MissingParameterException e) { Map<String, Object> map = new HashMap<>(); map.put("code", 500); map.put("message", e.getMessage()); return map; } }
經過請求查看返回結果工具
package com.codeup.mybatisjoin.controller; import com.codeup.mybatisjoin.model.Brand; import com.codeup.mybatisjoin.validation.ValidatorUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.LinkedHashMap; import java.util.Map; @Slf4j @RestController @RequestMapping(value = "/brandConroller") public class BrandConroller { @PostMapping(value = "/go") public Map<String, Object> go(@RequestBody Brand brand) { ValidatorUtil.result(brand); Map<String, Object> map = new LinkedHashMap<>(); log.info("brand:{}", brand); return map; } }
請求
// request { "brandId": 1, "vendorId": 1, "brandName": "demoData", "description": "demoData", "status": "3" } // response { "code": 500, "message": "[status]爲1或者2" }
若有不妥之處,請吐槽我