使用SpringAop做Controller层null值校验

距离上次写博客已经有一段时间了,想到有很多技术点比较散又容易忘记,所以决定写点博客把这些都记下来

主要功能: 实现单属性,自定义对象和Map的null值校验处理

注意事项: 如果是SpringBoot 1.5的版本需要在pom文件加一下配置


            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.3</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <compilerArgs>
                        <arg>-parameters</arg>
                    </compilerArgs>
                </configuration>
            </plugin>

1.主要类: 主要有两个类 一个是AOP类 另外一个是自定义注解

AOP类防止表单验证类

package com.example.auctionapp.aop;

import com.example.auctionapp.annotation.ObjectNotNull;
import com.example.auctionapp.core.Result;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import javax.validation.constraints.NotNull;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.HashMap;
import java.util.Map;

/**
 * Controller防空校验
 *
 * @author 安能
 * @version 1.0.7
 * @date 2019年7月29日10:59:33
 */
@Aspect
@Component
@Slf4j
public class VerifyAspect {


    /**
     * 使用@Pointcut定义一个切入点,可以是一个规则表达式,比如下例中某个package下的所有函数,也可以是一个注解等。
     * public表示访问权限是公有方法,第一个*表示返回类型,第二 *表示类名,第三个*表示方法(..)表示任何参数,包含子包
     */
    @Pointcut("execution(public * com.example.auctionapp.controller.*.*(..))")
    public void webLog() {
    }

    /**
     * 环绕通知,环绕增强,相当于MethodInterceptor
     *
     * @param point
     * @return
     */
    @Around("webLog()")
    public Result doAround(ProceedingJoinPoint point) throws Throwable {

        Result result;

        Class<?> targetClass = point.getTarget().getClass();
        String methodName = point.getSignature().getName();
        Object[] args = point.getArgs();
        Map<String, String> dataMap = new HashMap<>(16);
        for (Method method : targetClass.getMethods()) {
            if (methodName.equals(method.getName())) {

                Parameter[] parameters = method.getParameters();
                for (int i = 0; i < parameters.length; i++) {

                    Class<?> aClass = parameters[i].getType();
                    ClassLoader classLoader = aClass.getClassLoader();
                    if (classLoader != null) {
                        boolean isObjectNotNull = parameters[i].isAnnotationPresent(ObjectNotNull.class);


                        if (isObjectNotNull) {

                            ObjectNotNull annotation = parameters[i].getAnnotation(ObjectNotNull.class);
                            String[] value = annotation.value();

                            Field[] fields = aClass.getDeclaredFields();

                            for (String v : value) {
                                for (Field field : fields) {
                                    field.setAccessible(true);
                                    if (v.equals(field.getName())) {
                                        if (field.get(args[i]) == null) {
                                            dataMap.put(field.getName(),"不能为空!");
                                        }
                                    }
                                }
                            }
                        }
                        //            非自定义类
                    } else {

                        boolean isObjectNotNull = parameters[i].isAnnotationPresent(ObjectNotNull.class);

                        if (isObjectNotNull) {

                            ObjectNotNull annotation = parameters[i].getAnnotation(ObjectNotNull.class);
                            String[] values = annotation.value();
                            if (args[i] instanceof Map) {
                                for (String value : values) {
                                    Map map = (Map) args[i];
                                    if (null == map.get(value)) {
                                        dataMap.put(value,"不能为空!");
                                    }
                                }
                            }
                        }

                        boolean isNotNull = parameters[i].isAnnotationPresent(NotNull.class);
                        if (isNotNull) {
                            if (args[i] == null) {
                                dataMap.put(parameters[i].getName(),"不能为空!");
                            }
                        }
                    }

                }
            }
        }
        if (dataMap.size() > 0) {
            return Result.success(
                    dataMap);
        }
        result = (Result) point.proceed();

        return result;

    }
}

自定义注解类

package com.example.auctionapp.annotation;


import java.lang.annotation.*;

/**
 * 防对象空注解,value为字符串数组,每个字符串对应类中的每个字段
 *
 * @author 安能
 * @date 2019年7月30日13:24:25
 */
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ObjectNotNull {

    /**
     * 字符串数组,每个字符串对应类中的每个字段
     *
     * @return 防空数组
     */
    String[] value() default "";
}

2.返回结果类: result可以自由设置统一返回封装类

返回结果不演示过多没有什么意义,仅供参考!

package com.ms.auction.utils.respons;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;

/**
 * 统一API响应结果封装
 * 不要单独使用Result会编译出错,使用ResultBuilder方法调用 Result为返回
 *
 * @author 安能
 * @date 2019年6月24日10:56:38
 */
@Builder(access = AccessLevel.MODULE)
@EqualsAndHashCode()
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Getter
@ApiModel(value = "Result对象", description = "统一响应")
public final class Result<T> {

    /**
     * 状态码
     */
    @ApiModelProperty(value = "状态码")
    private int code;

    /**
     * 响应消息
     */
    @ApiModelProperty(value = "响应消息")
    private String message;

    /**
     * 响应数据
     */
    @ApiModelProperty(value = "响应数据")
    private T data;


}

3.controller演示类

可以防止单属性,自定义对象和Map类的为空校验

package com.example.auctionapp.controller;


import com.example.auctionapp.annotation.ObjectNotNull;
import com.example.auctionapp.annotation.WebLog;
import com.example.auctionapp.core.Result;
import com.example.auctionapp.core.ResultGenerator;
import com.example.auctionapp.entity.Account;
import com.example.auctionapp.service.IAccountService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.util.Map;

/**
 * <p>
 * 账户 前端控制器
 * </p>
 *
 * @author 安能
 * @since 2019-05-06
 */
@RestController
@RequestMapping("/account")
@Slf4j
public class AccountController {


    @Resource
    IAccountService accountService;



   
    @GetMapping("u")
    public Result updatePayPassword(@NotNull String name, @ObjectNotNull({"type","password"}) Account account,
                                    @ObjectNotNull({"age","a"}) @RequestParam(required = false) Map map) {

        return Result.errorInfo("123");
    }

4.使用postMan效果演示

      1. 正常不缺参数情况下

         2. 缺少单属性参数

       3.缺少自定义对象属性

      4. 缺少Map属性 

 

看到这里的同学也应该体验到了乐趣,代码写的有粗糙没有结构的,有兴趣的话可以优化一下

不懂的同学欢迎留言评论

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值