后端数据校检

前端防君子,后端防小人

前端做了数据校检以后,为了保证数据的正确性,需要在后端进行校检。

  • 使用JSR303进行数据校检
    javax.validation.constraints
    第一步需要在需要校检的实体类的属性中添加注解
@Null
@TableId	
private Long brandId;

第二布在方法参数中添加@Valid注解

public R save(@Valid @RequestBody BrandEntity brand)

可以在属性注解中添加自己的数据提示;

  • 校验数据是否出错没出错可以自定义在方法属性后添加一个属性BindingResult result就可以
@RequestMapping("/save")
    //@RequiresPermissions("product:brand:save")
    public R save(@Valid @RequestBody BrandEntity brand, BindingResult result){
        //判断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);
        }else {
            brandService.save(brand);
        }
        //不处理异常,只考虑正确情况
        return R.ok();

只不过这种情况不太适合企业开发环境,所以我们可以创建一个包,在此包下集中处理异常

/*
*
* 集中处理所有异常
* */
@Slf4j
//统一处理异常
//@ResponseBody									1
//@ControllerAdvice(basePackages ="com.atguli.gulimall.product.controller")		2
@RestControllerAdvice(basePackages = "com.atguli.gulimall.product.controller")		1 2注解在此注解中都包含
public class GulimallExceptionControllerAdvice {

    //精准异常MethodArgumentNotValidException
    @ResponseBody
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public R handleVaildException(MethodArgumentNotValidException exception){
    	//需要获取准确异常类型可以通过Exception来获取将属性类型和注解属性类型全部设置为exception即可
        log.error("数据检验出现问题:{},异常类型:{}",exception.getMessage(),exception.getClass());
        Map<String,String> map = new HashMap<>();
        //获取到错误信息
        BindingResult bindingResult = exception.getBindingResult();
        //获取到当前文件的错误信息
        bindingResult.getFieldErrors().forEach((item)->{
            //获取到当前错误的文件
            String field = item.getField();
            //获取到当前文件的错误提示
            String defaultMessage = item.getDefaultMessage();
            map.put(field,defaultMessage);
        });
        return R.error(400,"数据校检错误").put("data",map);
    }
}

异常信息都有错误状态码,我们可以将他们写为枚举类型

public enum BizCodeEnume {

    //枚举间隔为,结尾不为;
    UNKNOW_EXCEPTION(10000,"系统未知异常"),
    VAILD_EXCEPTION(10001,"参数格式校检失败");

    private int code;

    private String msg;

    BizCodeEnume(int code,String msg){
        this.code = code;
        this.msg = msg;
    }

    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
}

此处全局异常处理类可以修改为

@Slf4j
//统一处理异常
@RestControllerAdvice(basePackages = "com.atguli.gulimall.product.controller")
public class GulimallExceptionControllerAdvice {

    //精准
    @ResponseBody
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public R handleVaildException(MethodArgumentNotValidException exception){
        log.error("数据检验出现问题:{},异常类型:{}",exception.getMessage(),exception.getClass());
        Map<String,String> map = new HashMap<>();
        //获取到错误信息
        BindingResult bindingResult = exception.getBindingResult();
        //获取到当前文件的错误信息
        bindingResult.getFieldErrors().forEach((item)->{
            //获取到当前错误的文件
            String field = item.getField();
            //获取到当前文件的错误提示
            String defaultMessage = item.getDefaultMessage();
            map.put(field,defaultMessage);
        });
        return R.error(BizCodeEnume.VAILD_EXCEPTION.getCode(),BizCodeEnume.VAILD_EXCEPTION.getMsg()).put("data",map);
    }

    //全局
    @ExceptionHandler(value = Throwable.class)
    public R handleException(Throwable throwable){
        return R.error(BizCodeEnume.UNKNOW_EXCEPTION.getCode(),BizCodeEnume.UNKNOW_EXCEPTION.getMsg());
    }
}

数据校验分组功能在新增和修改时,需要的参数不同就需要有不同的检验规则,这时候就可以使用分组校检功能
可以创建两个空接口,不需要实现
新增

public interface AddGroup {
}

修改

public interface UpdataGroup {
}

实体类

@NotNull(message = "修改品牌id不能为空",groups = {UpdataGroup.class,UpdateStatusGroup.class})
@Null(message = "新增品牌id必须为空",groups = {AddGroup.class})
@TableId
private Long brandId;		id属性添加不需要,数据库会自动添加,在修改时就需要id属性了

方法修改

public R save(@Validated(AddGroup.class) @RequestBody BrandEntity brand/*)

升级版本

自定义校检功能
1编写自定义校检注解
@ListValue

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Documented
@Constraint(validatedBy = {ListValueValidationMessages.class})
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface ListValue {
    String message() default "{com.atguli.common.valid.ListValue.message}";//当前类的地址

    Class<?>[] groups() default { };

    Class<? extends Payload>[] payload() default { };
    int[] vals() default { };
}

导入依赖

<dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>2.0.1.Final</version>
</dependency>

在properties配置包下添加一个ValidationMessages.properties文件

com.atguli.common.valid.ListValue.message=必须提交指定的值

2.编写自定义校检器

public class ListValueValidationMessages implements ConstraintValidator<ListValue,Integer> {
    private Set<Integer> set = new HashSet<>();
    //初始化
    @Override
    public void initialize(ListValue constraintAnnotation) {
        int[] vals = constraintAnnotation.vals();
        for (int val : vals) {
            set.add(val);
        }
    }

    //判断是否检验成功
    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext context) {
        return set.contains(value);
    }
}

3.关联自定义的校检注解和校检器

@Constraint(validatedBy = {ListValueValidationMessages.class})//在自定义注解中添加此注解可以指定多个校检器

完结撒花

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值