Spring验证器错误消息-使用AOP动态替换验证器错误消息中的占位符

目录

引言

代码实现

关键点解析

1. 切点定义

2. 后置通知

3. 自定义错误消息


引言

        在实际项目中,我们经常需要对用户输入的数据进行验证。用户在编写验证注解时,可能会使用占位符来定义错误消息,例如 @Size(min = 1, max = 100, message = "长度必须介于 {min} 与 {max} 之间")。这样的错误消息虽然灵活,但在实际显示时不够直观,无法直接告诉用户具体的错误原因。本文将展示如何通过AOP技术动态替换这些占位符,生成更加具体的错误消息。
        

代码实现

        以下是一个示例代码,展示了如何通过AOP切面动态替换验证器错误消息中的占位符:

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorContextImpl;
import org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl;
import org.springframework.stereotype.Component;

import javax.validation.ConstraintValidatorContext;
import java.util.Map;

/**
 * 验证器切面类,用于拦截验证器的验证方法并定制错误消息
 * 主要目的是为了获取验证器的默认错误消息,并根据其中的占位符替换实际的字段值
 * 从而生成更加动态和有意义的错误提示信息
 * <p>
 * 长度必须介于 {min} 与 {max} 之间  -> @Size(min = 1, max = 100, message = "长度必须介于 {min} 与 {max} 之间")
 *
 *
 * @author ds
 */
@Aspect
@Component
public class ValidatorAspect {

    /**
     * 定义切点,匹配所有执行验证的约束验证器的isValid方法
     * 这里使用了AspectJ的切点表达式来精确匹配验证方法
     *
     * @param value     被验证的值
     * @param context   验证器上下文,包含了验证过程中的上下文信息
     */
    @Pointcut(value = "execution(* javax.validation.ConstraintValidator+.isValid(Object, javax.validation.ConstraintValidatorContext)) && args(value, context)", argNames = "value,context")
    public void isValidMethod(Object value, ConstraintValidatorContext context) {
    }

    /**
     * 在验证方法返回后执行,如果验证失败,则定制错误消息
     * 通过反射和流处理来动态替换错误消息中的占位符
     *
     * @param joinPoint 切入点对象,包含了关于当前正在被拦截的方法的信息
     * @param value     被验证的值
     * @param context   验证器上下文
     * @param result    验证方法的返回值,表示验证是否成功
     */
    @AfterReturning(value = "isValidMethod(value, context)", argNames = "joinPoint,value,context,result", returning = "result")
    public void doAfterReturning(JoinPoint joinPoint, Object value, ConstraintValidatorContext context, boolean result) {
        // 如果验证失败,则定制错误消息
        if (!result) {
            // 获取约束描述符中的属性,用于替换错误消息中的占位符
            Map<String, Object> attributes = ((ConstraintDescriptorImpl<?>) ((ConstraintValidatorContextImpl) context).getConstraintDescriptor()).getAnnotationDescriptor().getAttributes();
            // 获取默认的错误消息模板
            String message = context.getDefaultConstraintMessageTemplate();
            // 使用流替换模板中的占位符,s1 为当前处理的消息字符串,entry 为属性项
            message = attributes.entrySet().stream()
                    .reduce(message,
                            (str, entry) -> str.replaceAll("{" + entry.getKey() + "}", entry.getValue().toString()),
                            // 并行流情况下的合并逻辑,这里可以直接返回 s1
                            (s1, s2) -> s1
                    );
            // 禁用默认的错误消息
            context.disableDefaultConstraintViolation();
            // 构建并添加新的错误消息
            context.buildConstraintViolationWithTemplate(message)
                    .addConstraintViolation();
        }
    }

}

关键点解析

        1. 切点定义

                @Pointcut 注解定义了一个切点,匹配所有执行验证的约束验证器的 isValid 方法。使用 execution 表达式来精确匹配方法签名,并通过 args 参数指定方法参数。

        2. 后置通知

                @AfterReturning 注解定义了一个后置通知,在验证方法返回后执行。
如果验证失败(result 为 false),则通过反射获取约束描述符中的属性,并使用 StrUtil.replace 方法动态替换错误消息中的占位符。

        3. 自定义错误消息

                context.disableDefaultConstraintViolation() 方法禁用默认的错误消息。
                context.buildConstraintViolationWithTemplate(message).addConstraintViolation() 方法构建并添加新的错误消息。 

        通过上述代码实现,我们可以动态替换验证器错误消息中的占位符,生成更加具体和友好的验证错误消息,提升用户体验。AOP技术的引入使得这一过程变得简单且高效。希望本文能为读者在实际项目中解决类似问题提供参考。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值