专栏首页技术专栏自定义注解实现参数验证与业务代码解耦

自定义注解实现参数验证与业务代码解耦

  • 核心依赖
<!-- aop -->
<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>${springframework.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>${springframework.version}</version>
    </dependency>

<!-- validator -->
    <dependency>
      <groupId>javax.validation</groupId>
      <artifactId>validation-api</artifactId>
      <version>1.1.0.Final</version>
    </dependency>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-validator</artifactId>
      <version>5.2.4.Final</version>
    </dependency>
  • 验证工具类
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.mmall.exception.ParamException;
import org.apache.commons.collections.MapUtils;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

/**
 * 验证工具类
 * @author gaowenfeng 
 */
public class BeanValidator {

    private static ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();

    /**
     * 验证单个对象
     * @param t
     * @param groups
     * @param <T>
     * @return
     */
    public static <T> Map<String, String> validate(T t, Class... groups) {
        Validator validator = validatorFactory.getValidator();
        Set validateResult = validator.validate(t, groups);
        if (validateResult.isEmpty()) {
            return Collections.emptyMap();
        } else {
            LinkedHashMap errors = Maps.newLinkedHashMap();
            Iterator iterator = validateResult.iterator();
            while (iterator.hasNext()) {
                ConstraintViolation violation = (ConstraintViolation)iterator.next();
                errors.put(violation.getPropertyPath().toString(), violation.getMessage());
            }
            return errors;
        }
    }

    /**
     * 验证一个集合
     * @param collection
     * @return
     */
    public static Map<String, String> validateList(Collection<?> collection) {
        Preconditions.checkNotNull(collection);
        Iterator iterator = collection.iterator();
        Map errors;

        do {
            if (!iterator.hasNext()) {
                return Collections.emptyMap();
            }
            Object object = iterator.next();
            errors = validate(object, new Class[0]);
        } while (errors.isEmpty());

        return errors;
    }

    /**
     * 对 validate 和 validateList的封装
     * @param first
     * @param objects
     * @return
     */
    public static Map<String, String> validateObject(Object first, Object... objects) {
        if (objects != null && objects.length > 0) {
            return validateList(Lists.asList(first, objects));
        } else {
            return validate(first, new Class[0]);
        }
    }

    /**
     * 校验逻辑
     * @param param
     * @throws ParamException
     */
    public static void check(Object param) throws ParamException {
        Map<String, String> map = BeanValidator.validateObject(param);
        if (MapUtils.isNotEmpty(map)) {
            throw new ParamException(map.toString());
        }
    }
}
  • 自定义注解
import java.lang.annotation.*;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Check {
  // 需要验证的方法参数下标,默认验证第一个参数
    int checkArgPosition() default 0;
}
  • AOP切面完成对注解方法的验证代理
import com.mmall.util.BeanValidator;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * 验证切面
 * @author gaowenfeng
 */
@Component
@Aspect
@Slf4j
public class CheckAspect {

    /**
     * 切点
     */
    @Pointcut("@annotation(com.mmall.aop.Check)")
    public void checkPointCut(){}

    /**
     * 方法执行之前拦截
     * @param joinPoint
     */
    @Before("checkPointCut()")
    public void before(JoinPoint joinPoint){
        // 通过反射获取代理方法
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        Method method = signature.getMethod();
        // 获取校验参数
        Check check = method.getAnnotation(Check.class);
        Object param = joinPoint.getArgs()[check.checkArgPosition()];
        // 校验
        BeanValidator.check(param);
    }
}
  • AOP配置
SpringMVC 配置,spring-mvc.xml中加入如下配置
    <aop:aspectj-autoproxy />
SpringBoot 及 无XMLSpring配置
@Configuration
@ComponentScan("xxxx")
@EnableAspectJAutoProxy
public class AopConfig {
}
  • 测试
@Getter
@Setter
public class TestVo {

    @NotBlank
    private String msg;

    @NotNull(message = "id不可以为空")
    @Max(value = 10, message = "id 不能大于10")
    @Min(value = 0, message = "id 至少大于等于0")
    private Integer id;

    private List<String> str;
}

@RequestMapping("/validate.json")
    @ResponseBody
    @Check()
    public JsonData validate(TestVo vo) throws ParamException {
        log.info("validate");
        SysAclModuleMapper moduleMapper = ApplicationContextHelper.popBean(SysAclModuleMapper.class);
        SysAclModule module = moduleMapper.selectByPrimaryKey(1);
        log.info(JsonMapper.obj2String(module));
        return JsonData.success("test validate");
    }

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Spring Security+Spring Social+SpringBoot集成Restful可配置安全模块及代码生成器

    1.本项目主要分为core核心模块,browser浏览器模块,app模块,demo使用restful实例模块及spring-boot-api-project-s...

    Meet相识
  • JsonView 使用方法

    Meet相识
  • 慕课网Spark SQL日志分析 - 3.Spark SQL概述

    Spark SQL不仅仅有访问或者操作SQL的功能,他还提供了其他的非常丰富的操作:外部数据源,优化

    Meet相识
  • XStream、JAXB 日期(Date)、数字(Number)格式化输出xml

    XStream、Jaxb是java中用于对象xml序列化/反序列化 的经典开源项目,利用它们将对象转换成xml时,经常会遇到日期(Date)、数字按指定格式输出...

    菩提树下的杨过
  • Spring Boot:整合Shiro权限框架

    Shiro是Apache旗下的一个开源项目,它是一个非常易用的安全框架,提供了包括认证、授权、加密、会话管理等功能,与Spring Security一样属基于权...

    朝雨忆轻尘
  • 性能测试框架

    之前写过一个性能测试框架,只是针对单一的HTTP接口的测试,对于业务接口和非HTTP接口还无非适配,刚好前段时间工作中用到了,就更新了自己的测试框架,这次不再以...

    FunTester
  • MyBatis注解开发

    指的是MyBatis中SqlSession对象的缓存,当我们执行查询之后,查询的结果会同时存入到SqlSession为我们提供一块区域中。

    用户3112896
  • 12、webpack从0到1-Prefetching/Preloading

    Ewall
  • DWR的简单使用

    3 标签是dwr中重要的标签,用来描述 java(服务器端) 与 javascript (客户端)的交互方式。 其中,creator和javascript...

    qubianzhong
  • Jpa配置实体类创建时间更新时间自动赋值,@CreateDate,@LastModifiedDate

    操作数据库映射实体类时,通常需要记录createTime和updateTime,如果每个对象新增或修改去都去手工操作创建时间、更新时间,会显得比较繁琐。

    天涯泪小武

扫码关注云+社区

领取腾讯云代金券