热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

HibernateValidator自定义验证

前言在自己的摸索下对HibernateValidator有了初步的认识,可以使用已有的约束条件对字段做出限制,减少不要代码的出现,使代码更简洁。但在最近的实际使用中,出现了一些无法

前言

在自己的摸索下对HibernateValidator有了初步的认识,可以使用已有的约束条件对字段做出限制,减少不要代码的出现,使代码更简洁。
但在最近的实际使用中,出现了一些无法使用框架处理的问题,例如,在第三方请求我的接口时,根据status字段区分不同的业务逻辑;status=1进行A逻辑处理,status=2进行B逻辑处理;在网络了检索了相关信息后,做出如下总结。

步骤

  1. 使用通用Mapper插件生成实体类和mapper,这里为了聚焦对HibernateValidator的使用,把关注点放在实体类Brand中,在实体类中,对status字段添加自定义约束@StatusConstraint

    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;
    }

  2. @StatusConstraint实现步骤和自定义注解相似

    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[] payload() default {};
    }

  3. 通过查看源代码里面的文档得知要要实现ConstraintValidator接口

    @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.
    *


    * 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>[] validatedBy();
    }

  4. 实现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 {
    @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;
    }
    }

  5. 至此,对字段添加约束条件已完成。还存在一个重要的操作是对约束的校验,这里通过工具类实现

    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 cOnstraintViolations=
    validator.validate(object, groups);
    if (constraintViolations.size() > 0) {
    String message = constraintViolations.iterator().next().getMessage();
    throw new MissingParameterException(message);
    }
    }
    }

  6. 将message信息抛出之后,需要以更统一的方式返回给第三方,使用统一异常处理机制解决

    • 自定义异常类MissingParameterException

      package com.codeup.mybatisjoin.validation;
      public class MissingParameterException extends RuntimeException {
      public MissingParameterException(String message) {
      super(message);
      }
      }

    • 统一异常处理

      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 invalidParameter(MissingParameterException e) {
      Map 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 go(@RequestBody Brand brand) {
    ValidatorUtil.result(brand);
    Map map = new LinkedHashMap<>();
    log.info("brand:{}", brand);
    return map;
    }
    }

  1. 请求

    // request
    {
    "brandId": 1,
    "vendorId": 1,
    "brandName": "demoData",
    "description": "demoData",
    "status": "3"
    }
    // response
    {
    "code": 500,
    "message": "[status]为1或者2"
    }

如有不妥之处,请吐槽我


推荐阅读
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文介绍了Perl的测试框架Test::Base,它是一个数据驱动的测试框架,可以自动进行单元测试,省去手工编写测试程序的麻烦。与Test::More完全兼容,使用方法简单。以plural函数为例,展示了Test::Base的使用方法。 ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • Java自带的观察者模式及实现方法详解
    本文介绍了Java自带的观察者模式,包括Observer和Observable对象的定义和使用方法。通过添加观察者和设置内部标志位,当被观察者中的事件发生变化时,通知观察者对象并执行相应的操作。实现观察者模式非常简单,只需继承Observable类和实现Observer接口即可。详情请参考Java官方api文档。 ... [详细]
  • Spring学习(4):Spring管理对象之间的关联关系
    本文是关于Spring学习的第四篇文章,讲述了Spring框架中管理对象之间的关联关系。文章介绍了MessageService类和MessagePrinter类的实现,并解释了它们之间的关联关系。通过学习本文,读者可以了解Spring框架中对象之间的关联关系的概念和实现方式。 ... [详细]
  • 数组的排序:数组本身有Arrays类中的sort()方法,这里写几种常见的排序方法。(1)冒泡排序法publicstaticvoidmain(String[]args ... [详细]
  • (三)多表代码生成的实现方法
    本文介绍了一种实现多表代码生成的方法,使用了java代码和org.jeecg框架中的相关类和接口。通过设置主表配置,可以生成父子表的数据模型。 ... [详细]
  • Android系统源码分析Zygote和SystemServer启动过程详解
    本文详细解析了Android系统源码中Zygote和SystemServer的启动过程。首先介绍了系统framework层启动的内容,帮助理解四大组件的启动和管理过程。接着介绍了AMS、PMS等系统服务的作用和调用方式。然后详细分析了Zygote的启动过程,解释了Zygote在Android启动过程中的决定作用。最后通过时序图展示了整个过程。 ... [详细]
author-avatar
维生素-熙
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有