Spring Boot经验

Spring、 Spring Boot经验

本文记录作者在实际使用Spring或则Spring Boot过程中遇到比较好的案例或则经验,以供开发学习使用

1. 校验篇

生产过程中前后端都会进行数据格式的校验,后端校验一般采用JSR303的校验模式

1.1 使用

引入依赖

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

1.2 简单校验

在相关实体类上增加校验注解

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

然后在实际需要校验的地方增加@Valid注解或则@Validated注解

public R update(@Validated(value = {UpdateGroup.class}) @RequestBody BrandEntity brand);

1.3 分组校验


import org.springframework.validation.annotation.Validated; //来源于Spring Boot

@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Validated {

	/**
	 * Specify one or more validation groups to apply to the validation step
	 * kicked off by this annotation.
	 * <p>JSR-303 defines validation groups as custom annotations which an application declares
	 * for the sole purpose of using them as type-safe group arguments, as implemented in
	 * {@link org.springframework.validation.beanvalidation.SpringValidatorAdapter}.
	 * <p>Other {@link org.springframework.validation.SmartValidator} implementations may
	 * support class arguments in other ways as well.
	 */
	Class<?>[] value() default {};

}

在@Valid注解源码中可以看到value是个class的数组,可以进行分组作用
上文中有相关例子,在校验时如果使用分组校验,其他不匹配的分组校验或则不分组的校验将不生效。

自定义组

public interface UpdateGroup {
}

1.4 自定义异常

默认异常可以通过源码查看,也可以指定message
默认的返回值不一定符合系统设计时的结构,可以自定义全局异常来进行设置。

1.5 自定义校验规则

先查看@NotEmpty注解

@Documented
@Constraint(validatedBy = { }) //指定校验器
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface NotEmpty {

    //默认提示
	String message() default "{javax.validation.constraints.NotEmpty.message}";

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

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

例子

  • 自定义校验注解

    package com.cx.common.valid;
    
    import com.cx.common.valid.validator.ListValueValidator;
    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;
    
    /**
    * @ClassName : ListValue
    * @Description :
    * @Author : cx
    * @Date: 2023-04-28 17:47
    */
    @Documented
    @Constraint(validatedBy = { ListValueValidator.class })
    @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
    @Retention(RUNTIME)
    public @interface ListValue {
    
    	String message() default "{com.cx.common.valid.ListValue.message}";
    
    	Class<?>[] groups() default { };
    
    	Class<? extends Payload>[] payload() default { };
    
    	int[] value();
    }
    

    com.cx.common.valid.ListValue.message 是定义在resources下的ValidationMessages.properties文件中,如果有中文用unicode表示。

    img

  • 是用自定义校验注解

    /**
     * 显示状态[0-不显示;1-显示]
     */
    @ListValue(value = {0, 1}, groups = {AddGroup.class})
    private Integer showStatus;
    
  • 增加校验解析器

    package com.cx.common.valid.validator;
    
    import com.cx.common.valid.ListValue;
    
    import javax.validation.ConstraintValidator;
    import javax.validation.ConstraintValidatorContext;
    import java.util.Arrays;
    import java.util.HashSet;
    import java.util.Set;
    
    /**
    * @ClassName : ListValueValidator
    * @Description :
    * @Author : cx
    * @Date: 2023-04-28 17:57
    */
    public class ListValueValidator implements ConstraintValidator<ListValue, Integer> {
    
    	private Set<Integer> set = new HashSet<>();
    
    	@Override
    	public boolean isValid(Integer value, ConstraintValidatorContext context) {
    		if(set.contains(value)) return true;
    		return false;
    	}
    
    	@Override
    	public void initialize(ListValue constraintAnnotation) {
    		int[] values = constraintAnnotation.value();
    		for (int value : values) {
    			set.add(value);
    		}
    	}
    }
    

    注意: 里面的ListValue指的就是自定义的校验注解, Integer是指这个校验注解针对哪一种类型进行校验,例如

    img

    如果是Double类型的就是写成Double,对于多种类型,需要写多个校验器,在自定义校验注解的时候可以指定多个类型的校验器,可以参看已有的

    img

posted @   ChenLiuyu  阅读(24)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示