自定义数据校验注解

695 阅读2分钟

1. 参考代码下载

下载代码分支dev-feature-yuhl

2. 创建自定义注解

所在Module:scrm-common
所在包:org.springblade.common.valid.annotation
注解:ListValue

说明:ListValueConstraintValidator.class为此注解的验证器

package org.springblade.common.valid.annotation;


import org.springblade.common.valid.validator.ListValueConstraintValidator;

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.RetentionPolicy.RUNTIME;

/**
 * 自定义注解
 */
@Documented
@Constraint(validatedBy = { ListValueConstraintValidator.class})
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface ListValue {
    String message() default "{com.scrm.common.valid.ListValue.message}";

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

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

    int[] vals() default {};
}

3. 创建提示信息

所在Module:scrm-common
路径:scrm-common/src/main/resources/ValidationMessages.properties

com.scrm.common.valid.ListValue.message=\u5FC5\u987B\u63D0\u4EA4\u6307\u5B9A\u7684\u503C
com.scrm.common.valid.ConstantValue.message=\u987B\u63D0\u4EA4\u5F20\u4E09

4. 创建验证器

所在Module:scrm-common
路径:org.springblade.common.valid.validator.ListValueConstraintValidator

package org.springblade.common.valid.validator;

import org.springblade.common.valid.annotation.ListValue;

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

/**
 * 验证器
 */
public class ListValueConstraintValidator 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);
        }

    }

    //判断是否校验成功

    /**
     *
     * @param value 需要校验的值
     * @param context
     * @return
     */
    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext context) {

        return set.contains(value);
    }
}

5. 统一异常处理

所在Module:scrm-member
路径:com.scrm.member.exception.MemberExceptionControllerAdvice

package com.scrm.member.exception;


import lombok.extern.slf4j.Slf4j;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.tool.api.IResultCode;
import org.springblade.core.tool.api.R;
import org.springframework.validation.BindException;
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;
import java.util.Map;

/**
 * 集中处理所有异常
 */
@Slf4j
@RestControllerAdvice(basePackages = "com.scrm.member.controller") // 包含@ResponseBody和@ControllerAdvice
public class MemberExceptionControllerAdvice extends ServiceException {


	public MemberExceptionControllerAdvice(String message) {
		super(message);
	}

	public MemberExceptionControllerAdvice(IResultCode resultCode) {
		super(resultCode);
	}

	public MemberExceptionControllerAdvice(IResultCode resultCode, Throwable cause) {
		super(resultCode, cause);
	}

	/**
     * 真对MethodArgumentNotValidException异常的处理逻辑
     * @param e
     * @return
     */
    @ExceptionHandler(value= MethodArgumentNotValidException.class)
    public R handleVaildException(MethodArgumentNotValidException e){
        log.error("数据校验出现问题{},异常类型:{}",e.getMessage(),e.getClass());
        BindingResult bindingResult = e.getBindingResult();

        //fieldError.getField() :可以获取具体那个字段有问题
        Map<String,String> errorMap = new HashMap<>();
        bindingResult.getFieldErrors().forEach((fieldError)->{
            errorMap.put(fieldError.getField(),fieldError.getDefaultMessage());
        });
		return R.fail("数据校验出现问题" + e.getMessage() + ",异常类型:" + e.getClass() + ")");
    }
    /**
     * 托底的异常处理逻辑
     * @param e
     * @return
     */
    @ExceptionHandler(value= Exception.class)
    public R handleVaildException(Exception e){
        log.error("数据校验出现问题{},异常类型:{}",e.getMessage(),e.getClass());
		return R.fail("系统未知异常");
    }
}

6. 创建Group

所在Module:scrm-common
路径:org.springblade.common.valid.group

7. 实体类

所在Module:scrm-member-api
路径:com.scrm.member.entity.Brand

package com.scrm.member.entity;


import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import org.hibernate.validator.constraints.URL;
import org.springblade.common.valid.annotation.ConstantValue;
import org.springblade.common.valid.group.AddGroup;
import org.springblade.common.valid.annotation.ListValue;
import org.springblade.common.valid.group.UpdateGroup;
import org.springblade.common.valid.group.UpdateStatusGroup;
import org.springblade.common.valid.group.UpdateZhangsanGroup;

import javax.validation.constraints.*;
import java.io.Serializable;

/**
 * 品牌
 *
 * @author yuhl
 * @email fsjwin@163.com
 * @date 2020-09-04 14:12:07
 */
@Data
@TableName("brand")
public class Brand implements Serializable {
	private static final long serialVersionUID = 1L;

	/**
	 * 品牌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地址
	 */
	@URL(message = "logo必须是一个url地址",groups = {UpdateGroup.class,AddGroup.class})
	@NotBlank(groups = AddGroup.class)
	private String logo;
	/**
	 * 介绍
	 */
	private String descript;
	/**
	 * 显示状态[0-不显示;1-显示]
	 */
//	@Pattern()
	@ListValue(vals = {0,1},groups = {AddGroup.class, UpdateStatusGroup.class})
	@NotNull(groups = {AddGroup.class,UpdateStatusGroup.class})
	private Integer showStatus;
	/**
	 * 检索首字母
	 * @Pattern 自定义正则
	 */
	@Pattern(regexp = "^[a-zA-Z]$",message = "检索输字母必须是一个字母",groups = {UpdateGroup.class,AddGroup.class})
	@NotEmpty(groups = {AddGroup.class})
	private String firstLetter;
	/**
	 * 排序
	 */
	@Min(value=0,message = "排序必须大于等于0",groups = {UpdateGroup.class,AddGroup.class})
	@NotNull(groups = {AddGroup.class})
	private Integer sort;

	@ConstantValue(value = "张三",groups = {AddGroup.class, UpdateStatusGroup.class})
	@NotNull(groups = {UpdateZhangsanGroup.class})
	@TableField(exist = false)
	private String other;
}

8. controller使用

所在Module:scrm-member
路径:com.scrm.member.controller.BrandController

package com.scrm.member.controller;

import com.scrm.member.entity.Brand;
import org.springblade.common.valid.group.AddGroup;
import org.springblade.common.valid.group.UpdateGroup;
import org.springblade.common.valid.group.UpdateStatusGroup;
import org.springblade.common.valid.group.UpdateZhangsanGroup;
import org.springblade.core.tool.api.R;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 品牌
 *
 * @author yuhl
 * @email fsjwin@163.com
 * @date 2020-09-04 14:48:33
 */
@RestController
@RequestMapping("brand")
public class BrandController {
     /**
     * 信息
     */
    @RequestMapping("/infos")
    public R info(@RequestParam("brandIds") List<Long> brandIds){

        //List<Brand> brands = brandService.getBrandByIds(brandIds);

		return R.success("成功");
    }

    /**
     * 保存
     * 使用BindingAdvise去感知异常,不在自己使用BindingResult封装异常
     */
    @RequestMapping("/save1")
    public R save1(@Valid @RequestBody Brand brand, BindingResult result){
        if(result.hasErrors()){
            Map<String,String> map = new HashMap();
            //1 获得验证的错误结果
            result.getFieldErrors().forEach((item)->{
                //FieldError 获得到错误提示
                String message = item.getDefaultMessage();
                //获取错误的属性的名字
                String field = item.getField();
                map.put(field,message);
            });
			return R.fail("提交的数据不合法");
        } else {
            //brandService.save(brand);
        }
        //brandService.save(brand);
        return R.success("成功!");
    }

    /**
     * 保存
     */
    @RequestMapping("/save")
    public R save(@Validated({AddGroup.class})@RequestBody Brand brand){
        //brandService.save(brand);
		return R.success("成功!");
    }

    @RequestMapping("/mysave")
    public R mysave(@Valid @RequestBody Brand brand){
		//brandService.save(brand);
		return R.success("成功!");
    }

    /**
     * 修改
     */
    @RequestMapping("/update")
    public R update(@Validated(UpdateGroup.class) @RequestBody Brand brand){
        //brandService.updateDetail(brand);
		return R.success("成功!");
    }

	/**
	 * 修改
	 */
	@RequestMapping("/updatezhangsan")
	//@RequiresPermissions("product:brand:update")
	public R updatezhangsan(@Validated(UpdateZhangsanGroup.class) @RequestBody Brand brand){
		//brandService.updateDetail(brand);
		return R.success("成功!");
	}

    /**
     * 修改状态
     */
    @RequestMapping("/update/status")
    public R updateStatus(@Validated(UpdateStatusGroup.class) @RequestBody Brand brand){
        //brandService.updateById(brand);

		return R.success("成功!");
    }

    /**
     * 删除
     */
    @RequestMapping("/delete")
    public R delete(@RequestBody Long[] brandIds){
		//brandService.removeByIds(Arrays.asList(brandIds));
		return R.success("成功!");
    }

}