在日常开发中,经常会对参数的格式进行校验,所以我们常用的就是基于JSR303
标准实现的hibernate Validator
,通常是要用的格式包含:邮件格式、字符串判空等等,但是有时候创建和编辑中所涉及的属性基本上都一样,除了编辑可能包含主键ID之外,基本没有差别,通常情况下,我们应该将分成两个对象接收处理,但是有时候会想偷懒,就想着使用同一个对象,但是这就这涉及到了参数验证的问题,比如只有在编辑的时候,主键ID才是不可为空的,而创建的时候,主键ID是交给数据库自动生成的,因此这里就需要使用到Group
分组这个概念,按照这种思路,我们先把代码写出来:
版本一:
@RestController
@RequestMapping("/test")
@Api(tags="测试控制器")
public class TestController {
@PostMapping("/create")
@ApiOperation("创建")
@WebLog(description = "创建", operateType = OperateConstant.CREATE)
public JsonResult<Void> create(@RequestBody @Validated(BizInsert.class) MyClass param){
return JsonResult.success();
}
@PostMapping("/edit")
@ApiOperation("编辑")
@WebLog(description = "编辑", operateType = OperateConstant.EDIT)
public JsonResult<Void> edit(@RequestBody @Validated({BizInsert.class, BizUpdate.class}) MyClass param){
return JsonResult.success();
}
/**
* 新增分组
*
*/
public interface BizInsert {
}
/**
* 更新分组
*
*/
public interface BizUpdate {
}
@ApiModel
@Data
public static class MyClass {
@ApiModelProperty("主键ID")
@NotBlank(message = "主键ID不可为空", groups = {BizUpdate.class})
private String id;
@ApiModelProperty("名称")
@NotBlank(message = "名称不可为空", groups = {BizInsert.class, BizUpdate.class})
private String name;
}
}
我们会发现一个问题,那就是name
属性无论是新增还是编辑都是必须做校验的,而只有主键ID只在编辑时做校验,如果我们的数据除了name
还有其他必须的属性时,比如邮箱、身份证等等,这些都是无论是否新增还是编辑都是必须的,那么我们是不是必须每个属性上都要加上groups = {BizInsert.class, BizUpdate.class}
这一段呢?这就有点太笨了,虽然有效,但是不符合我们简约的风格,绝对不做这种重复性的操作,接下来就是改进后的第二版。
第二版(改进版):
@RestController
@RequestMapping("/test")
@Api(tags="测试控制器")
public class TestController {
@PostMapping("/create")
@ApiOperation("创建")
@WebLog(description = "创建", operateType = OperateConstant.CREATE)
public JsonResult<Void> create(@RequestBody @Validated MyClass param){
return JsonResult.success();
}
@PostMapping("/edit")
@ApiOperation("编辑")
@WebLog(description = "编辑", operateType = OperateConstant.EDIT)
public JsonResult<Void> edit(@RequestBody @Validated({BizUpdate.class, Default.class}) MyClass param){
return JsonResult.success();
}
/**
* 新增分组
*
*/
public interface BizInsert {
}
/**
* 更新分组
*
*/
public interface BizUpdate {
}
@ApiModel
@Data
public static class MyClass {
@ApiModelProperty("主键ID")
@NotBlank(message = "主键ID不可为空", groups = {BizUpdate.class})
private String id;
@ApiModelProperty("名称")
@NotBlank(message = "名称不可为空")
private String name;
}
}
package javax.validation.groups;
/**
* Default Bean Validation group.
* <p>
* Unless a list of groups is explicitly defined:
* <ul>
* <li>constraints belong to the {@code Default} group</li>
* <li>validation applies to the {@code Default} group</li>
* </ul>
* Most structural constraints should belong to the default group.
*
* @author Emmanuel Bernard
*/
public interface Default {
}
默认情况下,使用@Validated
时,我们并没有设置Group
,所以默认走的是javax.validation.groups.Default
这个规则,只要添加了相关的格式校验注解,框架都会自动帮我们做数据格式校验,因此我们在做新增操作时,直接按照默认执行格式校验即可;但是做编辑操作时,由于主键ID必须在编辑时校验,因此如果必须指定group = BizUpdate.class
,但是如果仅仅指定它,会导致属性name
的格式校验不会触发,因此需要有还需要追加默认的group
,所以最终就成了:@Validated({BizUpdate.class, Default.class}
,这样主键ID的格式校验以及name
的格式校验也会执行。
最终效果:创建时,采用默认的格式校验;编辑时,除了包含默认的格式校验,还包含了只有在编辑时才有的校验规则,所以最终我们在没有改变原来创建操作时校验的情况下,额外增加了编辑时才有的校验操作,秉持了只扩展而不修改的原则,也符合设计模式的基本理念。