Springboot 自定义验证注解及提示消息模板

依赖

plugins {
    id 'org.springframework.boot' version '2.5.3'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
	id 'java'
}

group = 'com.stone'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.11'

repositories {
    mavenLocal()
    maven {
        url 'https://maven.aliyun.com/repository/public/'
    }
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web:2.5.3'

    // Lombok
    compileOnly 'org.projectlombok:lombok:1.18.20'
    annotationProcessor 'org.projectlombok:lombok:1.18.20'

    // Hutool 工具包
    implementation 'cn.hutool:hutool-all:5.7.7'

    // 参数验证
    implementation 'org.springframework.boot:spring-boot-starter-validation:2.5.3'

	testImplementation('org.springframework.boot:spring-boot-starter-test:2.5.3') {
		exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
	}
}

自定义验证注解 InspectFilePath.java

import com.stone.common.config.validator.InspectFilePathValidator;

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

/**
 * @author <a href="https://github.com/zichen1019">zichen</a>
 */
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = InspectFilePathValidator.class)
public @interface InspectFilePath {

    String message() default "文件{param}禁止包含特殊符号:{toast}";

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

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

    boolean isFileName() default false;

}

自定义注解实现类 InspectFilePathValidator.java

import cn.hutool.core.util.StrUtil;
import com.stone.common.config.annotations.InspectFilePath;
import com.stone.common.utils.common.PreventFilePathAttacks;
import org.hibernate.validator.constraintvalidation.HibernateConstraintValidator;
import org.hibernate.validator.constraintvalidation.HibernateConstraintValidatorContext;
import org.hibernate.validator.constraintvalidation.HibernateConstraintValidatorInitializationContext;

import javax.validation.ConstraintValidatorContext;
import javax.validation.metadata.ConstraintDescriptor;

/**
 * @author <a href="https://github.com/zichen1019">zichen</a>
 */
public class InspectFilePathValidator implements HibernateConstraintValidator<InspectFilePath, CharSequence> {

    private boolean isFileName;

    @Override
    public void initialize(ConstraintDescriptor<InspectFilePath> constraintDescriptor, HibernateConstraintValidatorInitializationContext initializationContext) {
        isFileName = constraintDescriptor.getAnnotation().isFileName();
    }

    /**
     * 检查是否符合规则
     *
     * @param value 被检查的值
     * @param constraintValidatorContext    验证上下文
     * @return  true 符合规则 false 不符合规则
     */
    @Override
    public boolean isValid(CharSequence value, ConstraintValidatorContext constraintValidatorContext) {
        String toast;
        if (isFileName) {
            toast = PreventFilePathAttacks.inspectFileName(value.toString());
            if (StrUtil.isNotBlank(toast)) {
                constraintValidatorContext.unwrap( HibernateConstraintValidatorContext.class ).addMessageParameter( "file", "名称" ).addMessageParameter( "toast", toast );
                return false;
            }
        }
        toast = PreventFilePathAttacks.inspectFilePath(value.toString());
        if (StrUtil.isNotBlank(toast)) {
            constraintValidatorContext.unwrap( HibernateConstraintValidatorContext.class ).addMessageParameter( "file", "路径" ).addMessageParameter( "toast", toast );
            return false;
        }
        return true;
    }

}

注入校验对象

import org.hibernate.validator.HibernateValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.validation.Validation;
import javax.validation.Validator;

/**
 * 默认会校验完所有属性,然后将错误信息一起返回,但很多时候不需要这样,一个校验失败了,其它就不必校验了.
 *
 * @author zichen
 */
@Configuration
public class ValidatorConfig {

    @Bean
    public Validator validator() {
        return Validation.byProvider(HibernateValidator.class)
                .configure()
                .failFast(true)
                .buildValidatorFactory()
                .getValidator();
    }

}

请求方法上添加验证注解@Validated

    @GetMapping("/xxx")
    public void xxx(@Validated XxxDTO xxxDTO) {
    }

实体类增加验证

import com.stone.common.config.annotations.InspectFilePath;
import lombok.Data;

/**
 * @author <a href="https://github.com/zichen1019">zichen</a>
 */
@Data
public class YsjlDeleteEnclosureImgDTO {

    @InspectFilePath(isFileName = true)
    private String fileName;

    private String id;

}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,关于SpringBoot自定义Redis注解AOP的问题,我可以为您提供一些基本的介绍和示例代码。 Redis作为一种高性能的缓存和数据存储解决方案,被广泛应用于各种应用程序中。在SpringBoot应用程序中,使用Redis通常需要编写大量的重复代码,比如获取Redis连接、执行Redis命令、释放Redis连接等。这些重复代码不仅增加了开发和维护的难度,还影响了应用程序的性能。而AOP作为一种切面编程的技术,可以很好地解决这些问题。 下面是一个简单的示例代码,演示如何通过自定义注解实现对Redis操作的AOP处理: 首先,定义一个自定义注解: ```java @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface RedisCacheable { String key() default ""; long expire() default 0; } ``` 然后,在需要被拦截的方法上添加该注解: ```java @Component public class RedisService { @Autowired private RedisTemplate<String, String> redisTemplate; @RedisCacheable(key = "myKey", expire = 60) public String getValue() { return redisTemplate.opsForValue().get("myKey"); } } ``` 接下来,使用AspectJ的@Aspect注解定义一个切面类,并在该类中定义一个切点,用于匹配被@RedisCacheable注解的方法: ```java @Aspect @Component public class RedisAspect { @Autowired private RedisTemplate<String, String> redisTemplate; @Pointcut("@annotation(com.example.demo.annotation.RedisCacheable)") public void redisCacheablePointcut() {} @Around("redisCacheablePointcut()") public Object aroundRedisCacheable(ProceedingJoinPoint joinPoint) throws Throwable { MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); Method method = methodSignature.getMethod(); RedisCacheable redisCacheable = method.getAnnotation(RedisCacheable.class); String key = redisCacheable.key(); long expire = redisCacheable.expire(); String value = redisTemplate.opsForValue().get(key); if (value != null) { return value; } Object result = joinPoint.proceed(); if (result != null) { redisTemplate.opsForValue().set(key, result.toString()); if (expire > 0) { redisTemplate.expire(key, expire, TimeUnit.SECONDS); } } return result; } } ``` 在该切面类中,使用@Around注解定义一个环绕通知,在该通知中,首先获取被拦截方法上的@RedisCacheable注解,然后根据注解中的key值从Redis中获取数据。如果Redis中已经存在该数据,则直接返回;否则,执行被拦截方法,并将结果存储到Redis缓存中。 最后,启动SpringBoot应用程序,调用RedisService的getValue方法,就可以看到输出结果: ```java // 第一次调用,从数据库中获取数据,并将数据存入Redis缓存中 getValue... // 第二次调用,直接从Redis中获取数据 getValue... ``` 以上就是一个简单的SpringBoot自定义Redis注解AOP的示例。通过使用自定义注解和AOP技术,可以更加方便地实现对Redis缓存的操作,并提高应用程序的性能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值