服务端参数校验(二):SpringMVC项目的参数校验

news/2024/7/8 5:21:06

项目参见:

https://gitee.com/xxssyyyyssxx/validation

compile "top.jfunc.validation:validation-core:1.0.1"
compile "top.jfunc.validation:validation-spring:1.0.1"

上文提供了参数校验工具,但是如果我们把参数校验跟正常业务逻辑放一起,势必会严重影响代码的可读性。站在Spring巨人的肩头上,利用AOP+注解实现参数校验和正常业务逻辑的解耦。

首先定义校验器Validator,使用者需要实现此接口实现自己的校验逻辑,并把其放入Spring容器,也由于此可以注入Spring容器中的组件供其使用。校验器Validator能够拿到被校验方法的输入参数。

public interface Validator {
    /**
     * 对传入的参数进行校验
     * @param params 传入的参数
     * @throws IllegalArgumentException 参数校验不过抛出异常
     */
    void validate(Object[] params) throws IllegalArgumentException;
}

比如:

/**
 * 注册校验
 * @author xiongshiyan at 2019/9/28 , contact me with email yanshixiong@126.com or phone 15208384257
 */
@Component
public class StoreRegisterValidator implements Validator {
    @Autowired
    private MemberService memberService;
    @Override
    public void validate(Object[] params) throws IllegalArgumentException {
        JSONObject jsonObject = JSON.parseObject(params[0].toString());

        ValidateValue.with(jsonObject.getString("name")).notNull("名字不允许为空")
                .and(jsonObject.getString("idCard")).notNull("身份证不允许为空")
                .and(jsonObject.getString("cardFront")).notNull("身份证正面照片不允许为空")
                .and(jsonObject.getString("cardBack")).notNull("身份证反面照片不允许为空");

        Member byPhone = memberService.findByPhone(jsonObject.getString("phone"));
        if(null != byPhone){
            throw new IllegalArgumentException("此号码已经存在,不允许重复注册");
        }
    }
}

再定义注解Validated,方法标注了此注解表示要进行参数校验。此注解指定使用哪些Validator进行校验。

/**
 * 添加了此注解就表示要进行参数校验
 * @author xiongshiyan at 2018/11/2 , contact me with email yanshixiong@126.com or phone 15208384257
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Validated {
    Class<? extends Validator>[] value();
}

在需要参数校验的方法上标注该注解:

@RequestMapping(value = "/register",method ={ RequestMethod.POST})
@Validated(StoreRegisterValidator.class)
public ResponseMsg register(@RequestBody String body){
    。。。。
}

再定义切面,在切入点之前调用注解指定的校验器的校验方法,传入参数,当校验失败的时候就抛出IllegalArgumentException异常:

/**
 * @author xiongshiyan
 * 示例:参数校验切面
 * 使用者可以通过定义自己的切面,在调用方法之前调用{@see ValidateUtil#validateJoinPointParams}
 */
@Aspect
@Component
public class ParamValidateAspect implements Ordered , ApplicationContextAware{
    private ApplicationContext applicationContext;


    @Pointcut("execution(public * top.jfunc.validation.controller..*.*(..))")
    public void webParamValid(){}

    @Around(value = "webParamValid()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        ValidateUtil.validateJoinPointParams(applicationContext , pjp);
        return pjp.proceed();
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public int getOrder() {
        return 0;
    }
}
public class ValidateUtil {
    /**
     * 在切面方法前调用此方法,根据注解{@link Validated}指定的{@link Validator}校验方法的参数
     * @param applicationContext ApplicationContext
     * @param pjp JoinPoint 在此切入点之前调用
     */
    public static void validateJoinPointParams(ApplicationContext applicationContext , JoinPoint pjp) {
        //目标方法
        Method method = AnnotationUtil.getMethod(pjp);
        Validated validated = AnnotationUtil.getValidated(method);
        //存在@Validated注解
        if(null != validated){
            Class<? extends Validator>[] validatorClasses = validated.value();
            for (Class<? extends Validator> validatorClass : validatorClasses) {
                Validator validator = applicationContext.getBean(validatorClass);
                validator.validate(pjp.getArgs());
            }
        }
    }
}

 


http://www.niftyadmin.cn/n/3568776.html

相关文章

关于类初始化的一个诡异问题

圣思园张龙老师关于类加载器的一个例子。 这个打印的是1,1 这个打印的是1,0 造成以上的区别的原因就在于&#xff1a;类加载的时候先准备&#xff08;静态变量赋默认值&#xff09;&#xff0c;然后初始化&#xff08;赋值或者静态代码块&#xff09;&#xff0c;实例化。 类的…

记录定时任务迁移xxl-job的过程和理解

一般定时任务使用的是基于quartz或者spring-scheduler的&#xff0c;能够满足大部分的开发需求。但是像手动执行一次&#xff0c;执行情况监测&#xff0c;进程阻塞停止等维护需求就显得无能为力了。无意间在gitee.com上发现了一个很好满足以上需求的项目&#xff0c;来自许雪里…

vsftpd 安装过程记录

使用yum安装&#xff0c;执行安装命令&#xff1a;yum install -y vsftpd 安装FTP服务器 创建FTP用户和FTP的目录,并修改FTP目录的权限给FTP用户 创建用户: 重置密码: 创建FTP目录&#xff1a; 授权FTP目录权限给camera用户: 修改目录用户组执行权限&#xff1a; 进入/et…

NFS网络的搭建和迁移

以前的NFS服务器在192.168.0.50 ${oldserverip}&#xff0c;在新机器192.168.0.100 ${newserverip}上安装NFS服务&#xff0c;迁移数据到新主机上&#xff0c;然后启动NFS服务&#xff0c;其他的客户端全部重新挂载到新的NFS网络。 保持挂载目录和以前完全一样&#xff1a; 以…

lduan Exchange 2013 部署(二)

转载于:https://blog.51cto.com/tblduan/1899182

从使用os.system)在python命令(重定向标准输入输出

从使用os.system&#xff09;在python命令&#xff08;重定向标准输入输出 python 标准输出stdout stdio os.system通常我可以通过改变sys.stdout的值在python更改标准输出。然而&#xff0c;这似乎只影响打印那么&#xff0c;有没有什么办法可以抑制方案是通过使用os.system在…

OutputStream与PrintWriter的使用与区别

1.OutputStream 使用步骤&#xff1a; 获取输出流设置中文将字符串转换成字节数组调用outputStream.write()这里只贴出doGet方法的内容&#xff1a; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {/…

如果mysql的自增主键达到最大值会发生什么?

如果mysql的自增主键达到最大值会发生什么&#xff1f;比如主键类型设为int&#xff0c;其最大值为&#xff1a;2147483647&#xff0c;如果此时我们再往其中写入数据&#xff0c;就会发生异常&#xff1a; Duplicate entry 2147483647 for key PRIMARY 也即写不进去了。如果…