JSR 303 数据校验以及放入统一的返回结果

一、介绍

JSR是Java Specification Requests的缩写,意思是Java 规范提案。是指向JCP(Java Community Process)提出新增一个标准化技术规范的正式请求。任何人都可以提交JSR,以向Java平台增添新的API和服务。JSR已成为Java界的一个重要标准。

二、普通使用步骤

  1. 给Bean添加校验注解:javax.validation.constraints,并自定义 message提示

        /**
         * 品牌名
         */
        @NotBlank(message = "品牌名必须提交")
        private String name;
    
  2. 在Controller层添加校验功能 @Valid

        /**
         * 保存
         */
        @RequestMapping("/save")
        public R save(@Valid @RequestBody BrandEntity brand) {
            brandService.save(brand);
            return R.ok();
        }
    
  3. 效果:在postman测试,会有默认的响应

    {
        "timestamp": "2020-04-21T03:53:31.757+0000",
        "status": 400,
        "error": "Bad Request",
        "errors": [
            {
                "codes": [
                    "NotBlank.brandEntity.name",
                    "NotBlank.name",
                    "NotBlank.java.lang.String",
                    "NotBlank"
                ],
                "arguments": [
                    {
                        "codes": [
                            "brandEntity.name",
                            "name"
                        ],
                        "arguments": null,
                        "defaultMessage": "name",
                        "code": "name"
                    }
                ],
                "defaultMessage": "品牌名必须提交",
                "objectName": "brandEntity",
                "field": "name",
                "rejectedValue": "",
                "bindingFailure": false,
                "code": "NotBlank"
            }
        ],
        "message": "Validation failed for object='brandEntity'. Error count: 1",
        "path": "/product/brand/save"
    }
    

三、封装到统一返回结果

对实体类注明校验字段

@Data
@TableName("pms_brand")
public class BrandEntity implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 品牌id
     */
    @TableId
    private Long brandId;
    /**
     * 品牌名
     */
    @NotBlank(message = "品牌名必须提交")
    private String name;
    /**
     * 品牌logo地址
     */
    @NotEmpty
    @URL(message = "logo 必须是合法url地址")
    private String logo;
    /**
     * 介绍
     */
    private String descript;
    /**
     * 显示状态[0-不显示;1-显示]
     */
    private Integer showStatus;
    /**
     * 检索首字母
     */
    @NotEmpty
    @Pattern(regexp = "/^[a-zA-Z]$/", message = "检索首字母必须是一个字母")
    private String firstLetter;
    /**
     * 排序
     */
    @NotNull
    @Min(value = 0, message = "排序必须大于等于0")
    private Integer sort;

}

对Controller方法做处理

BindingResult 是处理的校验结果,对此分析并放入统一的返回结果里

/**
     * 保存
     *
     * @param brand
     * @param result 校验结果
     * @return
     */
@RequestMapping("/save")
// @RequiresPermissions("product:brand:save")
public R save(@Valid @RequestBody BrandEntity brand, BindingResult result) {
    if (result.hasErrors()) {
        Map<String, String> map = new HashMap<>();
        // 获取校验的错误结果
        result.getFieldErrors().forEach((item) -> {
            // 错误提示
            String message = item.getDefaultMessage();
            // 错误的属性名
            String field = item.getField();
            map.put(field, message);
        });
        return R.error(400, "提交的数据不合法").put("data", map);
    }
    brandService.save(brand);
    return R.ok();
}

测试结果

```json
{
    "msg": "提交的数据不合法",
    "code": 400,
    "data": {
        "logo": "不能为空",
        "sort": "不能为null",
        "firstLetter": "不能为空"
    }
}
```

四、分组校验

一个字段在不同情况下会有不同校验逻辑,比如id,在新增时不用填写,此时数据库里是自增的,但更新时则必须填写,此时可以对它们标注分组以区分不同的情况。

对实体类注明校验字段

在字段上指定不同的情况下的校验情况,分组是一个空接口,仅用以区分

    /**
     * 品牌id
     */
    @NotNull(message = "修改必须指定品牌id", groups = {UpdateGroup.class})
    @Null(message = "新增不能指定品牌id", groups = {AddGroup.class})
    @TableId
    private Long brandId;
    /**
     * 品牌名
     */
    @NotBlank(message = "品牌名必须提交", groups = {UpdateGroup.class, AddGroup.class})
    private String name;
    /**
     * 品牌logo地址
     */
    @NotBlank(groups = {AddGroup.class})
    @URL(message = "logo 必须是合法url地址", groups = {AddGroup.class, UpdateGroup.class})
    private String logo;
    /**
     * 介绍
     */
    private String descript;
    /**
     * 显示状态[0-不显示;1-显示]
     */
    private Integer showStatus;
    /**
     * 检索首字母
     */
    @NotEmpty(groups = {AddGroup.class})
    @Pattern(regexp = "/^[a-zA-Z]$/", message = "检索首字母必须是一个字母", groups = {UpdateGroup.class, AddGroup.class})
    private String firstLetter;
    /**
     * 排序
     */
    @NotNull(groups = {AddGroup.class})
    @Min(value = 0, message = "排序必须大于等于0", groups = {UpdateGroup.class, AddGroup.class})
    private Integer sort;

对Controller方法做处理

把之前的 JSR303提供的接口@Valid 变为 Spring提供的实现 @Validated。在不同方法上注明不同的情况

/**
 * 保存
 *
 * @param brand
 * @return
 */
@RequestMapping("/save")
public R save(@Validated({AddGroup.class}) @RequestBody BrandEntity brand) {
    brandService.save(brand);
    return R.ok();
}

/**
 * 修改
 */
@RequestMapping("/update")
// @RequiresPermissions("product:brand:update")
public R update(@Validated(UpdateGroup.class) @RequestBody BrandEntity brand) {
    brandService.updateById(brand);

    return R.ok();
}
posted @ 2020-04-21 12:49  duniqb  阅读(306)  评论(0编辑  收藏  举报