Hibernate Validator 校验 (一)

还想看更多文章的朋友可以访问我的个人博客


Hibernate Validator 校验 (简单校验)

Validator 规范对约束的定义包括两部分,一是约束注解, @NotBlank 就是约束注解;二是约束验证器,每一个约束注解都存在对应的约束验证器,约束验证器用来验证具体的对象是否满足该约束注解声明的条件。

声明需要校验的字段

User实体为例,其中username字段使用注解:@NotBlank,该注解声明username字段不能为空(虽该注解也要求字段不能为null,但与@NotNull有本质区别,后面会列举常见校验注解的区别)。


@Entity // This tells Hibernate to make a table out of this class
public class User {

    @NotBlank
    private String username;

    ...
}

测试用例,模拟发出增添用户的 Post 请求(username字段为"")。

@Test
public void testValidUser() throws Exception {
    String content = "{\"username\":\"\",\"password\": \"password\",\"birthday\":" + new Date().getTime() + "}";
    mockMvc.perform(post("/user").contentType(MediaType.APPLICATION_JSON_UTF8)
            .content(content))
            .andExpect(status().isOk());
}

执行后结果如下:


image

很明显,我们预想的校验并没有生效。那如何让我们添加的字段校验生效呢?

Mapping 方法参数声明需要校验的参数实例

Controller 层需要对传入参数添加@Valid注解,使得校验生效,如下:

@RestController
public class UserController {
  @PostMapping
  public User addUser(@RequestBody @Valid User user) {
      return userService.addUser(user);
    }
}

执行之前的测试用例,测试结果:


image

可以看出,我们执行形同的的测试用例,这次的测试请求却是失败的,也就是说我们对User实体中username字段的校验生效了。

但是,如果发生错误时我们只是向用户提醒请求错误时不够的。怎样才能自己处理想管的校验错误呢?

收集错误信息、发生错误时进入方法体。

只需要在Controller 层传入(注入)封装了错误信息的参数BandingResult类型的实例,如下修改Mapping方法:

@RestController
@RequestMapping("/user")
public class UserController {
  @Autowired
  private UserService userService;

  @PostMapping
  public User addUser(@RequestBody @Valid User user, BindingResult result) {
    // 输出错误信息
    if (result.hasErrors()) {
        result.getAllErrors().forEach(err -> System.out.println(err.getDefaultMessage()));
    }

    return userService.addUser(user);
  }
}

测试结果如下:

image

终于,模拟发出的用户添加请求返回的 HTTP 状态码为200,并且在Controller层也成功输出了错误信息:must not be blank

如此,借助 Hibernate Validator 支持的注解,即可为实体字段添加简单的校验,并在 Controller 层对校验的错误信息做相应处理(比如返回给前端)。

获得具体的校验错误信息

BindingResultgetAllErrors()方法返回值为List<ObjectError>,将ObjectError的实力强转为FieldError即可获得字段名称等信息。只需修改 Controller 层代码如下:

@RestController
@RequestMapping("/user")
public class UserController {
  @Autowired
  private UserService userService;

  @PostMapping
  public User addUser(@RequestBody @Valid User user, BindingResult result) {
      // 输出字段名称与校验错误信息
      if (result.hasErrors()) {
          result.getAllErrors().forEach(err -> {
              if (err instanceof FieldError) {
                  FieldError error = (FieldError) err;
                  System.out.println(error.getField() + " " + error.getDefaultMessage());
              }
          });
      }

      return userService.addUser(user);
  }
}

测试结果如下:


image

这样一来,就可以为前端提供较为具体的响应信息。

尽管如此,那如何为需要校验的校验项自定义错误消息呢?

自定义校验错误消息

其实,Hibernate Validator 提供的索引校验注解都有共同的一个属性——message,通过声明该属性,即可为校验项自定义错误消息,修改实体User校验字段@NotBlank注解如下:

@Entity
public class User {

    @NotBlank(message = "用户名不能为空")
    private String username;

    ...
}

Controller 层与测试用例无需修改,测试结果如下:


image

当然,此时很明显我们没有必要再输出字段名了,所以应该修改Controller层处的错误处理代码,但这里就不一一列举了。

Hibernate Validator 提供的校验注解

这里列举一些常用的 Hibernate Validator 提供的校验注解,利用这些注解可以完成开发中绝大多数的校验逻辑。

注解 描述
@NotNull 值不能为 null
@NotBlank 字符串必须包含字符
@NotEmpty 字符串不为 null,集合必须有元素
@Null 值必须为空
@Pattern(regex=) 字符串必须满足于正则
@Size(min=,max=) 集合的元素数必须在 min 到 max 之间
@CreditCardNumber(ignoreNonDightCharacters=) 字符串必须是信用卡号(美国标准如何自定义信用卡校验
@Email 字符串必须是Email
@Length(min=,max=) 校验字符串的长度
@Range(min=,max=) min <= 数字 <= max
@SafeHtml 字符串是安全的 HTML
@URL 字符串是合法的URL
@AssertFalse 布尔值为 false
@AssertTrue 布尔值为 true
@DecimalMax(value=,inclusive=) 值必须小于等于(inclusive=true)/小于(inclusive=false)指定的value值。可注解在字符串值上
@DecimalMin(value=,inclusive=) 值必须大于等于(inclusive=true)/大于(inclusive=false)指定的value值。可注解在字符串值上
@Digits(integer=,fraction=) 数字格式校验。integer指定整数部分长度,fraction指定小数部分长度
@Future 值必须是未来的日期
@Past 值必须是过去的日期
@Max 值必须小于等于value值。不可注解在字符串值上
@Min 值必须大于等于value值。不可注解在字符串值上
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容

  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,748评论 6 342
  • Spring Web MVC Spring Web MVC 是包含在 Spring 框架中的 Web 框架,建立于...
    Hsinwong阅读 22,313评论 1 92
  • 空荡荡的教室里,除了灯光还有孤单的声音,不知哪里传来一阵悠扬的小号声,静静地听着,任时间像灰尘一样落下,覆盖了昨天...
    所为伊人阅读 182评论 0 0
  • 我想起了那个老人 好似是在路口单薄的身影 梦里的他 有着弯弯的背 那弯弯的背好似弯弯的桥 老人那褶皱中有双渴望的眼...
    何以至此阅读 184评论 0 1
  • 亲爱的家人们,晚上好!每天晚上记得汇报当日的功课完成情况啊。没有好坏对错,做功课也不是比赛,主要是我们一起养成活在...
    喜悦富足的小兔阅读 631评论 0 6