使用注解、切面、反射,对前端传递的参数,做统一的空格(trim)处理

使用注解、切面、反射,对前端传递的参数,做统一的空格(trim)处理

业务场景:由于目前的前后端分离,在某些情况下,前端可能没有对传入后端的字符串做出来,导致传递到后端的数据可能有偏差,两端出现空格的情况。所有我就想,怎么能够统一的对前端的传参做一个处理,让后端不用太关心前端的参数问题。

实现思路:前端的参数一般都放在请求体中,作为后端的一个入参。我们需要做的就是,把前端的参数的空格去除。所以我们需要获取到需要处理的方法的入参。拿到入参后并且要把,它的值给它改变。

实现方法:使用注解对需要处理的方法,加上注解,作为一个标志。然后通过这个标志,我们定义一个切入点。对它进行环绕增强。再利用反射,动态的去设值到原DTO中。

实现步骤

  1. 定义一个标志注解
	@Target({ElementType.METHOD,ElementType.TYPE})
	@Retention(RetentionPolicy.RUNTIME)
	@Documented
	public @interface AutoString {
	
	}
  1. 为方法加上@AutoString 注解
    @AutoString
    @ApiOperation("test01")
    @PostMapping("/test01")
    public Object test01(@RequestBody TestDto testDto){

        System.out.println(testDto);
        return testDto;
    }

    @AutoString
    @ApiOperation("test02")
    @PostMapping("/test02")
    public Object test02(@RequestBody Test02Dto test02Dto){

        System.out.println(test02Dto);
        return test02Dto;
    }

  1. 定义测试的DTO,包含一些常用的类型
public class Test02Dto {

    private String name;
    private Integer size;
    private Double weight;
    private Boolean activeFlag;
    private List<String> ids;

    @Override
    public String toString() {
        return "Test02Dto{" +
                "name='" + name + '\'' +
                ", size=" + size +
                ", weight=" + weight +
                ", activeFlag=" + activeFlag +
                ", ids=" + ids +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getSize() {
        return size;
    }

    public void setSize(Integer size) {
        this.size = size;
    }

    public Double getWeight() {
        return weight;
    }

    public void setWeight(Double weight) {
        this.weight = weight;
    }

    public Boolean getActiveFlag() {
        return activeFlag;
    }

    public void setActiveFlag(Boolean activeFlag) {
        this.activeFlag = activeFlag;
    }

    public List<String> getIds() {
        return ids;
    }

    public void setIds(List<String> ids) {
        this.ids = ids;
    }
}
  1. 通过反射对原值进行处理,为了大家阅读方便,我每行都打上了注解
package com.example.demo.aop;

import org.apache.commons.lang3.StringUtils;
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 java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import java.util.stream.Collectors;


/**
 * 系统日志,切面处理类
 *
 * @author jie
 * @date 2019/12/23 -13:36
 */
@Aspect
@Component
public class AutoStringAspect {


    // 通过 Pointcut 获取注解位置
    @Pointcut("@annotation(com.example.demo.annotation.AutoString)")
    public void stringPointCut() {

    }

    // 增强处理
    @Around("stringPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {


        //获取参数值
        Object[] paramValues = point.getArgs();
        for (Object arg : paramValues) {

            //获取类的字段
            Field[] fields = arg.getClass().getDeclaredFields();
            for (Field field : fields) {

                // 设置字段可访问, 否则无法访问private修饰的变量值
                field.setAccessible(true);

                //获取字段名
                String name = field.getName();
                // 获取字段类型
                String type = field.getGenericType().toString();

                // 拼装get set方法  例如 setName getName
                String setMethodName = "set" + name.substring(0,1).toUpperCase()+name.substring(1);
                String getMethodName = "get" + name.substring(0,1).toUpperCase()+name.substring(1);


                //通过方法名称获取对应的方法,这里是获取字段的get方法
                Method getMethod = arg.getClass().getMethod(getMethodName);

                // 判断类型是string 类型
                if ("class java.lang.String".equals(type)) {

                    // 获取set方法
                    Method setMethod = arg.getClass().getMethod(setMethodName, String.class);
                    // 通过 invoke 获取到get方法的Value值  PS: invoke()方法就是用来执行指定对象的方法
                    String value = (String) getMethod.invoke(arg);
                    // 再invoke 执行 set方法  StringUtils.trim 对空格进行处理
                    setMethod.invoke(arg, StringUtils.trim(value));
                }

                // 判断类型是List<String> 类型
                if ("java.util.List<java.lang.String>".equals(type)) {

                    Method setMethod = arg.getClass().getMethod(setMethodName, List.class);
                    List<String> valueList = (List<String>) getMethod.invoke(arg);
                    // 通过java 8 对集合中的值进行处理 ,java8 中 “::” 就是调用方法的意思
                    List<String> collect = valueList.stream().map(StringUtils::trim).collect(Collectors.toList());
                    setMethod.invoke(arg, collect);

                }
            }
        }

        return point.proceed();
    }


}

最后附上项目地址:
https://gitee.com/CurvedMirror/AutoStringTrim