6. 谷粒商城统一处理异常、JSR303校验

统一处理异常

后端

1、创建异常枚举类

通用模块:gulimall-common

BizCodeEnum.java

package com.indi.common.enums;

@Getter
@AllArgsConstructor
public enum BizCodeEnum {
    // 通用异常
    UNKOWN_EXCEPTION(10000,"系统未知异常"),
    VAILID_EXCEPTION(10001,"参数格式校验失败");

    private int code;       // 响应状态码
    private String message;     // 响应信息
}

2、创建异常处理类

通用模块:gulimall-common

UnifiedExceptionHandler.java

package com.indi.common.exception;

@Slf4j
@RestControllerAdvice
public class UnifiedExceptionHandler {
    /**
     * 处理参数异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public R handleValidException(MethodArgumentNotValidException e) {
        log.error("数据校验出现问题{},异常类型:{}", e.getMessage(), e.getClass());
        BindingResult bindingResult = e.getBindingResult();
        Map<String, String> map = new HashMap<>();
        bindingResult.getFieldErrors().forEach(fieldError -> {
            map.put( fieldError.getField(),fieldError.getDefaultMessage());
        });
        return R.error(BizCodeEnum.VAILID_EXCEPTION.getCode(), BizCodeEnum.VAILID_EXCEPTION.getMessage()).put("data", map);
    }

    @ExceptionHandler(value = Throwable.class)
    public R handleException(Throwable throwable) {
        return R.error(BizCodeEnum.UNKOWN_EXCEPTION.getCode(), BizCodeEnum.UNKOWN_EXCEPTION.getMessage());
    }
}

3、启动类上添加扫描

商品服务:gulimall-product

GulimallProductApplication.java

在这里插入图片描述

4、开启校验功能

商品服务:gulimall-product

AdminBrandController.java

此处以校验参数异常为例,不需要针对异常再做任何处理,只需要开启校验功能@Valid即可

    public R save(@Valid @RequestBody BrandEntity brand) {
		// ...
    }

JSR303校验

自定义校验注解

创建注解

通用模块:gulimall-common

ListValue.java

package com.indi.common.valid;

@Documented
@Constraint(validatedBy = ListValueConstraintValidator.class)  // 使用哪个校验器进行校验,这里不指定,就需要在初始化时指定
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })   // 注解的标注位置
@Retention(RUNTIME) // 注解的时机,表示在运行时获取到
public @interface ListValue {

    // 想要自定义校验注解,必须包含以下3个属性
    String message() default "{com.indi.common.valid.ListValue.message}"; // 错误信息的位置

    Class<?>[] groups() default { };    // 需要支持分组校验的功能

    Class<? extends Payload>[] payload() default { };   // 可以自定义一些负载信息

    int[] values() default {};  // 指定的值
}

创建校验器

通用模块:gulimall-common

ListValueConstraintValidator.java

package com.indi.common.valid;

/**
 * 校验器
 */
public class ListValueConstraintValidator implements ConstraintValidator<ListValue, Integer> {
    private Set<Integer> set = new HashSet<>();

    /**
     * 初始化方法
     *
     * @param constraintAnnotation
     */
    @Override
    public void initialize(ListValue constraintAnnotation) {
        int[] values = constraintAnnotation.values();
        if (values != null && values.length > 0) {
            for (int value : values) {
                set.add(value);
            }
        }
    }

    /**
     * 判断是否校验成功
     *
     * @param value 需要校验的值
     * @param context   整个校验的上下文环境
     * @return
     */
    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext context) {
        return set.contains(value);
    }
}

创建异常提示

通用模块:gulimall-common

ValidationMessages.properties

com.indi.common.valid.ListValue.message=显示状态只能是0、1

使用

商品服务:gulimall-product

BrandEntity.java

    /**
     * 显示状态[0-不显示;1-显示]
     */
    @ListValue(values = {0, 1})
    private Integer showStatus;

分组校验

不指定分组的注解,在分组模式下,不会启用

实体类上添加校验

商品服务:gulimall-product

BrandEntity.java

    /**
     * 品牌id
     */
    @NotNull(message = "修改必须指定品牌", groups = UpdateGroup.class)
    @Null(message = "新增不能指定id", groups = AddGroup.class)
    @TableId
    private Long brandId;

    /**
     * 品牌名√
     */
    @NotBlank(message = "品牌名不能为空", groups = {AddGroup.class, UpdateGroup.class})
    private String name;

    /**
     * 品牌logo地址√
     */
    @NotBlank(message = "logo地址不能为空", groups = {AddGroup.class, UpdateGroup.class})
    private String logo;

    /**
     * 介绍
     */
    @NotBlank(message = "品牌介绍不能为空", groups = {AddGroup.class, UpdateGroup.class})
    private String descript;

    /**
     * 显示状态[0-不显示;1-显示]
     * <p>
     * 需要为其单独添加一个组,只在更新显示状态用
     * 如果不单独指定,与update使用一个的话,只更新显示状态,不更新其它字段,会触发其它不允许为空的校验
     */
    @NotNull(message = "显示状态只能为0、1", groups = {AddGroup.class, UpdateGroup.class, UpdateStatusGroup.class})
    @ListValue(values = {0, 1}, groups = {AddGroup.class, UpdateGroup.class, UpdateStatusGroup.class})
    private Integer showStatus;

    /**
     * 检索首字母
     */
    @Pattern(regexp = "^[a-zA-Z]$", message = "检索首字母必须是一个字母", groups = {AddGroup.class, UpdateGroup.class})
    private String firstLetter;

    /**
     * 排序
     */
    @NotNull(message = "排序必须为正整数", groups = {AddGroup.class, UpdateGroup.class})
    @Min(value = 0, message = "排序必须为正整数", groups = {AddGroup.class, UpdateGroup.class})
    private Integer sort;

    /**
     * 更新状态的分组
     */	
    public interface UpdateStatusGroup { }

创建分组

通用模块:gulimall-common

valid包下创建两个接口:AddGroup.javaUpdateGroup.java

一个用来添加、一个用来更新

开启校验

商品服务:gulimall-product

AdminBrandController.java

1、新增品牌

2、更新品牌

3、更新显示状态

如果更新显示状态和更新品牌都用update分组的话,只修改状态的时候,没有品牌名,就会报错,所以需要单独为显示状态创建一个分组,然后修改的接口还要单独再一遍,但是里面的内容不变,就是变了一下请求地址跟启用的分组,不知道以后有没有别的校验方法,总感觉这个很麻烦。

    /**
     * 保存
     */
    @ApiOperation("添加品牌")
    @PostMapping("/save")
    public R save(@Validated({AddGroup.class}) @RequestBody BrandEntity brand) {
        brandService.save(brand);
        return R.ok();
    }

    /**
     * 修改
     */
    @ApiOperation("修改品牌")
    @PostMapping("/update")
    public R update(@Validated(UpdateGroup.class) @RequestBody BrandEntity brand) {
        brandService.updateById(brand);
        return R.ok();
    }

    /**
     * 修改状态
     */
    @ApiOperation("修改状态")
    @PostMapping("/updateStatus")
    public R updateStatus(@Validated(UpdateStatusGroup.class) @RequestBody BrandEntity brand) {
        brandService.updateById(brand);
        return R.ok();
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值