在实际的开发过程中,经常会需要客户端输入一些字符串,比如账号、密码,都是以字符串的形式传给后端的。
客户端传给后端的字符串可以说五花八门,""," "," 123456","123456 "," 123456 "等等。
这就导致后端拿到字符串之后需要做两次操作,第一次判空,第二次去除前后空格。
public String test(String str) {
if (str != null) {
str = str.trim();
}
return str;
}
这样的后果是,当需要客户端传送许多文本的时候(POST请求发送大量数据),去除空格的代码就会变得很冗余。
public String test(Class class) {
if (class.p1 != null) {
class.p1 = class.p1.trim();
}
if (class.p2 != null) {
class.p2 = class.p2.trim();
}
if (class.p3 != null) {
class.p3 = class.p3.trim();
}
// 其余去空代码
...
return class;
}
使用AOP可以在方法的执行前先统一对字符串去空格,这样在业务逻辑代码里面就不需要对字符串进行去空格操作了。
/**
* Created with IntelliJ IDEA.
*
* @auther: lkz
* @date: 2021/02/28
* @version: 1.0
* @description:
*/
@Component
@Aspect
public class TrimAspect {
// 定义切点
// 记录后台接口的操作记录
// 拦截Controller所在的包
@Pointcut("execution(* com.xxx.xxx.controller.*.*(..))")
public void excudeService() {
}
@Around("excudeService()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
// 数据校验注解优先于此AOP执行
//重点 这里就是获取@RequestBody参数的关键 调试的情况下 可以看到arr变量已经获取到了请求的参数
Object[] arr = pjp.getArgs();
for (int i = 0; i < arr.length; ++i) {
if (arr[i] instanceof HttpServletRequest) { // 特殊处理
HttpServletRequest request = (HttpServletRequest) arr[i];
Map<String, String[]> m = request.getParameterMap();
Map<String, String[]> newM = new HashMap<String, String[]>();
if (m != null) {
for (Map.Entry<String, String[]> entry : m.entrySet()) {
String key = entry.getKey();
String[] value = entry.getValue();
if (value == null) continue;
for (int j = 0; j < value.length; ++j) {
String temp = value[i].trim();
value[i] = temp.length() == 0 ? null : temp;
}
newM.put(key, value);
}
}
// 因为我们无法去改变getParameterMap的返回值
// 所以对里面的值去除空格是无效的
// 但是我们可以把参数的值去除空格之后把值放入setAttribute里面
// 这样request对象就携带了去除空格之后的值
request.setAttribute("The-result-after-removing-the-space", newM);
arr[i] = request;
} else {
// 考虑到类里面还有类 这里采用递归的方式处理
arr[i] = dfs(arr[i].getClass(), arr[i]);
}
}
// 把 arr 放回去即可改变参数的值
return pjp.proceed(arr);
}
private Object dfs(Class<?> aClass, Object object) throws IllegalAccessException {
if (object == null) return null;
// 如果是Java的基本数据类型就不需要继续递归了
if (isPrimitive(aClass)) {
if (object instanceof String) {
String temp = ((String) object).trim();
return temp.length() == 0 ? null : temp;
}
return object;
}
// 返回类所有字段
// 注意: 会返回静态字段
// 不要在Dto、Vo定义静态属性
// 没有获取父类属性 可通过 “object.getClass().getSuperclass()” 获取
for (Field item : object.getClass().getDeclaredFields()) {
// static 和 final 修饰的字段忽略
if (Modifier.isStatic(item.getModifiers()) || Modifier.isStatic(item.getModifiers())) {
continue;
}
// 设置可见性
item.setAccessible(true);
// 递归处理
item.set(object, dfs(item.getType(), item.get(object)));
}
return object;
}
// 判断是否为Java的基本类型或包装类
// java.lang.* java.util.* 存放着Java的基本数据类型的包装类和集合类
// 基本数据类型和包装类是JVM虚拟机运行需要的类,已嵌入到JVM内核
// 不需要继承ClassLoader 用户自定义的需要
private boolean isPrimitive(Class<?> aClass) {
return aClass != null && aClass.getClassLoader() == null;
}
}
通过了这个AOP之后的字符串都是已经去除前后空格的了,之后的业务代码根据需要去判断字符串是否为空就可以了。上述代码对空格字符串的处理是,把空格字符串的那个字段置为null。可以自己根据需求去修改。
public String test(Class class) {
if (class.p1 != null) {
// 已经不需要了
// class.p1 = class.p1.trim();
}
if (class.p2 != null) {
// 已经不需要了
// class.p2 = class.p2.trim();
}
if (class.p3 != null) {
// 已经不需要了
// class.p3 = class.p3.trim();
}
// 其余去空代码
...
return class;
}
// " " 会变成null
String temp = value[i].trim();
value[i] = temp.length() == 0 ? null : temp;
这个AOP还有一个不足的地方是没有考虑到父类,只向下处理了子类,没有向上处理父类。
可以通过 “object.getClass().getSuperclass()” 获取父类,然后加以改进。
不过,一般Controller层接受参数的类不会很复杂,有父类一般也就只有一层,不需要用到递归,向上处理一层就可以了。