Spring Boot 下,敏感词及特殊字符过滤处理方式

原创
2019/04/26 14:02
阅读数 1.3W

背景:

技术采用的是 Spring Boot ,请求方法主要为 POST, 请求使用较多的注解为 @RequestBody

 

交付测试人员进行测试,测试人员在对模糊搜索模块进行了各种特殊字符的搜索,以至于敏感词和特殊字符均会入库。

对于我这样有情怀的开发者而言,是不能容忍的。

上来就是干!

 

主要采用  @ControllerAdvice(basePackages = "com.my") 的方式,对用户提交的数据做处理。

以下是示例代码,不影响笔者要言表的功能实现:

/**
 * @author Ryan
 * @date 2019/4/25 18:41
 */
@ControllerAdvice(basePackages = "com.ytkj")
public class EscapeSensitiveWordFilter implements RequestBodyAdvice {


    @Override
    public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        return true;
    }


    @Override
    public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
        return inputMessage;
    }

    @Override
    public Object afterBodyRead(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        if(o != null){
            SensitiveWordUtils.apply(o);
        }
        return o;
    }

    @Override
    public Object handleEmptyBody(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {

        return o;
    }
}

 

由于我们主要针对提交的数据做处理,主要入口在  SensitiveWordUtils.apply(o);  这里的 “Object ” 参数,其实也就是我们 Controller 方法参数中,打了 @RequestBody 的实体。我们可以直接在这里,使用一些手段做处理即可。

 

这里的手段,也只能使用反射了(如果读者有什么好的方案可以告诉我)。

1. 字符串替换;

2. 自定义抛出运行时异常;

 

这样做的另外一个好处就是,可以在这里统一管理敏感词。

如果你使用 replaceAll 的话,统一管理上就比较费劲了。

最后,笔者把自己写的反射放在下面,仅供参考,敏感词替换部分写了一个“测试“ 作为要替换入口的标记。

欢迎各界大佬来扶正!

 

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * @author Ryan
 * @date 2019/4/26 12:40
 */
public class SensitiveWordUtils {


    /**
     * @param result
     * @return
     */
    public static Object apply(Object result) {
        if (result == null) {
            return null;
        }

        objectParse(result);

        return result;
    }



    /**
     * @param obj
     */
    public static void objectParse(Object obj) {
        List<Field> allField = findAllField(obj);
        for (Field field : allField) {
            field.setAccessible(true);
            Class<?> typeClazz = field.getType();
            matchFieldType(obj, field, typeClazz);
        }
    }

    public static List<Field> findAllField(Object object){
        List<Field> result = new ArrayList<>();

        Class<?> clazz = object.getClass();
        while (true) {
            clazz = clazz.getSuperclass();
            if (clazz == Object.class) {
                break;
            }

            Field[] declaredFields = clazz.getDeclaredFields();
            result.addAll(Arrays.asList(declaredFields));
        }
        return result;
    }


    /**
     * @param obj
     * @param field
     * @param clazz
     */
    public static <T> void matchFieldType(Object obj, Field field, T clazz) {
        try {
            T param = (T) field.get(obj);
            if(param == null){
                return;
            }

            if (clazz == List.class) {
                List p = (List)param;
                for (Object o : p) {
                    objectParse(o);
                }
            } else if (clazz == String.class) {
                setValue(obj, field, "测试");
            } else if (clazz == Map.class) {
                Map map = (Map)param;
                for (Object o : map.keySet()) {
                    objectParse(o);
                }
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     *
     * @param object
     * @param field
     * @param param
     * @throws IllegalAccessException
     */
    public static void setValue(Object object, Field field, Object param) throws IllegalAccessException {
        if(!field.isAccessible()){
            throw new IllegalAccessException("modify the field fail.");
        }

        field.set(object, param);
    }
}

这里的 SensitiveWordUtils 还有很大的优化点,我在这里没有目前只是看看效果,写的很粗糙,望大神不要喷。

 

读者自行实现一下,我说一下优化点:

  1. 缓存 object 的 String.class 类型的 Field 或者 methodName; 在第一次加载的时候,缓存进去;放到 ConcurrentHashMap<ObjectType,  List<StringField>>  , 是不是感觉清爽了好多;
  2. 过滤出来 String 类型的 Field ,其他的类型酌情考虑;
  3. 等臣妾的再想想;

 

展开阅读全文
打赏
0
4 收藏
分享
加载中
更多评论
打赏
0 评论
4 收藏
0
分享
返回顶部
顶部