JSR303JavaBean参数校验+统一处理异常

一、JSR303介绍

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

二、JSR303使用

  • 使用场景:当前端进行表单验证后,还是可以使用postman去恶意传参,所以JSR303一般用于后台的表单验证,即验证java bean
  • 使用依赖:
    1.基本的import javax.validation.constraints.*
    在这里插入图片描述
    2.hibernate也封装扩展了一些import org.hibernate.validator.constraints.*
<!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>8.0.0.Final</version>
</dependency>

在这里插入图片描述
3.当查询某个字段不为空的时候,返回字段名import com.fasterxml.jackson.annotation.JsonInclude;比如查询sort的数据库结果为空,返回给前端的时候就不包含此字段


	/**
	 * 排序
	 */
	@JsonInclude(JsonInclude.Include.NON_NULL)
	private Integer sort;

具体使用类型参考其他博客:JsonInclude注解
4.如果自己也需要扩展校验规则,可使用@Pattern(regexp="")传一个正则表达式去验证
在这里插入图片描述

  • 使用步骤:
    1.直接在javabean上添加校验注解,如邮箱验证:
import javax.validation.constraints.*;

	//规定长度
    @Length(min = 6, max = 19, message = "用户名长度是6-18位")
    @ApiModelProperty(value = "用户名", required = true)
    private String username;
    
    @ApiModelProperty(value = "密码", required = true)
    private String password;
    
    //不能是空的
    @NotEmpty
    @ApiModelProperty(value = "用户头像")
    private String icon;
    
    @Email(message = "邮箱格式错误")
    @ApiModelProperty(value = "邮箱")
    private String email;
    
    @NotNull
    @ApiModelProperty(value = "用户昵称")
    private Stringname;
    
    @ApiModelProperty(value = "备注")
    private String note;
    
 	@URL(message = "Invalid URL", protocols = {"http", "https"})  
    private String websiteUrl;  

2.在controller上添加@Valid
在这里插入图片描述
这时用postman将name传空字符串,返回400错误
在这里插入图片描述
3.统一处理校验失败结果
(1)获取所有校验结果
在controller请求方法的参数列表新加一个参数BingingResult result
在这里插入图片描述
(2)根据result.hasErrors()判断是否校验成功
在这里插入图片描述

public save(@Valid @RequestBody UmsAdminParam user,BindingResult result) {
        //得到所有错误信息计数
        int errorCount = result.getErrorCount();
        //错误数大于0
        if (errorCount>0){
            //得到所有错误
            List<FieldError> fieldErrors = result.getFieldErrors();
            //迭代错误
            fieldErrors.forEach((fieldError)->{
            	//错误信息
                String field = fieldError.getField();
                log.debug("属性:{},传来的值是:{},出错的提示消息:{}",
                        field,fieldError.getRejectedValue(),fieldError.getDefaultMessage());
            });
            return fieldError.getRejectedValue()+"出错:"+fieldError.getDefaultMessage();
        }else{
			return "成功";
        }
    }

再次传非法参数测试结果:
在这里插入图片描述

三、统一处理异常

  1. 将之前的验证结果参数注释掉,让验证失败后先抛出异常,后面统一处理
    在这里插入图片描述
  2. 使用springmvc提供的@ControllerAdvice来统一拦截异常
    新建包exception,新建类MyExcControllerAdvice,统一拦截校验失败后抛出的MethodArgumentNotValidException,代码如下
package com.furenqiang.gulimall.product.exception;

import com.furenqiang.common.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.HashMap;

/**
 * 集中处理所有异常
 * */
@Slf4j
@RestControllerAdvice(basePackages = "com.furenqiang.gulimall.product.controller")
public class GulimallExceptionControllerAdvice {

    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    private R handleVaildExcepction(MethodArgumentNotValidException e){
        log.error("校验出现异常{},异常类型{}",e.getMessage(),e.getClass());
        BindingResult bindingResult = e.getBindingResult();
        HashMap<String,String> errMap=new HashMap<String,String>();
        if (bindingResult.hasErrors()){
            bindingResult.getFieldErrors().forEach((item)->{
                errMap.put(item.getField(),item.getDefaultMessage());
            });
        }
        return R.error(400,"参数校验不合法").put("data",errMap);
    }

    @ExceptionHandler(value = Throwable.class)
    private R handleVaildExcepction(Throwable throwable){
        log.error("出现异常{},异常类型{}",throwable.getMessage(),throwable.getClass());
        return R.error();
    }
}

注意:这里的MethodArgumentNotValidException异常是spring自带的org.springframework.web.bind.MethodArgumentNotValidException,如果要捕捉自定义异常,可按照下面的写法:
在这里插入图片描述
抛出自定义的异常
在这里插入图片描述

四、JSR303分组校验

  1. 新建valid包,创建新增分组接口AddGroup、UpdateGroup
  2. 在javabean上指定所属分组,只有匹配上分组后才会使用相应的校验规则
    在这里插入图片描述
  3. 在controller上将@Valid改成spring提供的@Validated({AddGroup.class}),可指定分组
    /**
     * 保存
     */
    @RequestMapping("/save")
    //@RequiresPermissions("product:brand: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();
    }

五、更灵活的自定义校验

第一种方式是使用@Pattern(regexp="")传一个正则表达式去验证,需要在controller类上加上@Validated注解,否则正则验证不生效
第二种方式:完全自定义

  1. 编写自定义校验注解
package com.furenqiang.common.valid;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;

@Documented
@Constraint(
        validatedBy = {ListValueConstraintValidator.class}//自定义的校验器
)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ListValue {

    String message() default "{com.furenqiang.common.value.ListValid.message}";//对应ValidationMessages.properties的配置

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

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

    int[] vals() default {};
}
  1. 编写自定义校验器
package com.furenqiang.common.valid;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.HashSet;
import java.util.Set;

/**
 * 自定义校验器,要实现 implements  ConstraintValidator<ListValue,Integer>
 */
public class ListValueConstraintValidator implements  ConstraintValidator<ListValue,Integer> {

    private Set<Integer> set=new HashSet<>();

    @Override
    public void initialize(ListValue constraintAnnotation) {
        //获取注解上的指定值,遍历放入set
        for (int val : constraintAnnotation.vals()) {
            set.add(val);
        }
    }

    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext constraintValidatorContext) {
        //判断set中的指定值是否包含前端传来的参数value
        return set.contains(value);
    }
}

在资源包resources下新建ValidationMessages.properties写入如下配置

com.furenqiang.common.value.ListValue.message=必须提交指定的值
  1. 关联自定义注解和自定义校验器
	/**
	 * 显示状态[0-不显示;1-显示]
	 */
	@ListValue(vals = {0,1},groups = {AddGroup.class})
	private Integer showStatus;
  1. 测试
    在这里插入图片描述

六、补充JavaBean实体类包名划分规范

PO:完整对应数据库字段
在这里插入图片描述

DO :在这里插入图片描述

TO:不同服务之间通过feign远程调用时传输的对象
在这里插入图片描述

DTO:前端调用接口时候传入的对象
在这里插入图片描述

VO:前端传给服务端的参数对象或者服务端返回给前端的封装对象
当VO包含Entity实体类字段名时,可使用
import org.springframework.beans.BeanUtils; BeanUtils.copyProperties(VO,Entity);将相同名称的字段赋值,此方法无返回值,调用后即完成转换,如果要忽略某字段的拷贝,比如name,可以使用BeanUtils.copyProperties(sensorGroupPageListDto, sensorInfoGroup, new String[]{"name"});即可忽略掉name字段
在这里插入图片描述

BO、POJO、DAO:
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值