springboot拦截请求参数,如去除参数emoji表情,防止数据库报错

实现这个需求有2个方法

其中一些jar包

<!-- Springboot 环境 -->

 <dependency>
            <groupId>com.vdurmont</groupId>
            <artifactId>emoji-java</artifactId>
            <version>5.1.0</version>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-io</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.8.1</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.70</version>
        </dependency>

方法一: 过滤器(Filter)

主要类:

EmojiFilter --> 过滤器
ParamsRequestWrapper -->参数过滤操作
FilterConfig -->配置filter

EmojiFilter:

public class EmojiFilter extends OncePerRequestFilter {
    
    

    private static final String POST = "POST";
    private static final String PUT = "PUT";


    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
    
    
        //只过滤post和put的请求,不然直接返回
        if (!request.getMethod().equals(POST) && !request.getMethod().equals(PUT)) {
    
    
            chain.doFilter(request, response);
            return;
        }
        //执行过滤detail
        EmojiRequestWrapper requestWrapper = new EmojiRequestWrapper(request);
        chain.doFilter(requestWrapper, response);

    }
    }
public class EmojiFilter implements Filter {
    
    

    private static final String POST = "POST";
    private static final String PUT = "PUT";

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    
    

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
    
    
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        if (!request.getMethod().equals(POST) && !request.getMethod().equals(PUT)) {
    
    
            return;
        }
        EmojiRequestWrapper requestWrapper = new EmojiRequestWrapper(request);
        chain.doFilter(requestWrapper, response);
    }
    @Override
    public void destroy() {
    
    

    }
}

EmojiRequestWrapper.java

json格式的提交
在这里插入图片描述

public class EmojisRequestWrapper extends HttpServletRequestWrapper {
    
    

    /**
     * ENCODING
     */
    private static final String ENCODING = "UTF-8";

    public EmojiRequestWrapper(HttpServletRequest request) {
    
    
        super(request);
    }

    /**
     * 字符串去除emoji的方法
     */
    private String convertEmoji2Str(String source) {
    
    
      
        if(EmojiManager.containsEmoji(source)){
    
    
         	 EmojiParser.removeAllEmojis(source);
        }
        return s;
    }

    /**
     * 重写getInputStream方法 post请求参数必须通过流才能获取到值
     */
    @Override
    public ServletInputStream getInputStream() throws IOException {
    
    
        String json = "{}";
        try (ServletInputStream stream = super.getInputStream();){
    
    
            // 非json类型,直接返回
            if (!MediaType.APPLICATION_JSON_VALUE.equals(super.getHeader(HttpHeaders.CONTENT_TYPE))
                    && !MediaType.APPLICATION_JSON_UTF8_VALUE.equals(super.getHeader(HttpHeaders.CONTENT_TYPE))) {
    
    
                return stream;
            }
            // 转化成字符串
            json = IOUtils.toString(stream, ENCODING);

            if (StringUtils.isBlank(json)) {
    
    
                return stream;
            }
        } catch (Exception e) {
    
    
            
        }
        //去除表情并返回
        String noEmojiStr = convertEmoji2Str(json);
        // 写回request
        ByteArrayInputStream bis = new ByteArrayInputStream(noEmojiStr.getBytes(ENCODING));

        return bis.read();
    }
}

可以获取提交的form表单,不是json提交
在这里插入图片描述

public class EmojiRequestWrapper extends HttpServletRequestWrapper {
    
    
    private Map<String, String[]> params = new HashMap();
    private static final String ENCODING = "UTF-8";
    private static final String CLASSTYPE = "java.lang.String";

    public EmojiRequestWrapper(HttpServletRequest request) {
    
    
        super(request);
        Map<String, String[]> requestMap = request.getParameterMap();
        String s = JSON.toJSONString(requestMap);
        if (!EmojiManager.containsEmoji(s)) {
    
    
            return;
        }
        String json = EmojiParser.removeAllEmojis(s);
        // 处理json数据,parseObject数组返回的是JSONArray,需要处理
        Map<String, JSONArray> map = JSON.parseObject(json, Map.class);
        map.forEach((k, v) -> {
    
    
            Object o = v.get(0);
            this.params.put(k, new String[] {
    
    (String) o});
        });
    }
    private  Map<String, Object> modifyParams( String json) {
    
    
        String s = convertEmoji2Str(json);
        Map map = JSON.parseObject(s, Map.class);
        return map;
    }

    @Override
    public Map getParameterMap() {
    
    
        return this.params;
    }

    @Override
    public Enumeration getParameterNames() {
    
    
        Vector l = new Vector(params.keySet());
        return l.elements();
    }

    @Override
    public String[] getParameterValues(String name) {
    
    

        Object v = params.get(name);
        if (v == null) {
    
    
            return null;

        } else if (v instanceof String[]) {
    
    
            return (String[]) v;
        } else if (v instanceof String) {
    
    
            return new String[]{
    
    (String) v};
        } else {
    
    
            return new String[]{
    
    v.toString()};
        }
    }


    @Override
    public String getParameter(String name) {
    
    

        Object v = params.get(name);
        if (v == null) {
    
    
            return null;
        } else if (v instanceof String[]) {
    
    
            String[] strArr = (String[]) v;
            if (strArr.length > 0) {
    
    
                return strArr[0];
            } else {
    
    
                return null;
            }

        } else if (v instanceof String) {
    
    
            return (String) v;
        } else {
    
    
            return v.toString();
        }
    }
}

可以参考这篇博客:https://www.jianshu.com/p/ab6ab47fcbd8

配置filter

第一种:FilterConfig:

@Configuration
public class FilterConfig {
    
    
    @Bean
    public FilterRegistrationBean parmsFilterRegistration() {
    
    
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new EmojiFilter());
        registration.addUrlPatterns("/*");
        registration.setName("emojiFilter");
        registration.setOrder(Integer.MAX_VALUE - 1);
        return registration;
    }
}

第二种:

@WebFilter(filterName = "emojiFilter", urlPatterns = "/*")
@Order(Integer.MAX_VALUE - 1)
public class EmojiFilter implements Filter {
    
    }

@ServletComponentScan
//Springboot 启动类 
@SpringBootApplication
public class Application{
    
    }{
    
    
}

方法二:aop (AspectJ)

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
spring:
  aop:
    auto: true
@SpringBootApplication
@EnableAspectJAutoProxy
public class Application {
    
    
}

RequestParamterAspect.java


@Aspect
@Slf4j
@Component
public class RequestParamterAspectJ {
    
    
  /**
   execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)
   modifiers-pattern : 方法的修饰符 public protected
   ret-type-patter 方法返回值类型, 比如void
   declaring-type-pattern 类的路径 com.java.
   name-pattern 方法名称 Aa()
   param-parttern 方法参数类型 如java.lang.String
   throws-pattern 方法抛出异常的类型,如Java.lang.Exception
     * 通配符,该通配符主要用于匹配单个单词,或者是以某个词为前缀或后缀的单词
    ..通配符,该通配符表示0个或多个项,主要用于declaring-type-pattern和param-pattern中,如果用于declaring-type-pattern中,则表示匹配当前包及其子包,如果用于param-pattern中,则表示匹配0个或多个参数
   * execution(public * com.spring.service.BusinessObject.businessService(java.lang.String,..))
    * */
    @Pointcut("execution(public * com.lsm.boot.controller.*Controller.*(..))")
    public void pointcut() {
    
    
    }
        /**
         * 这里只能是Around ,因为使用的是ProceedingJoinPoint
         * @param joinPoint
         * @return
         * @throws Throwable
         */
    @Around("pointcut()")
    public Object invoke(ProceedingJoinPoint joinPoint) throws Throwable {
    
     
        // 方法执行前
        Object[] args = joinPoint.getArgs();
       String json = JSON.toJSONString(args);
       //去 除 emoji
        for (Object arg : args) {
    
    
            System.out.println(arg);
        }
        // 方法执行 joinPoint.proceed()执行了目标方法
        Object proceed = joinPoint.proceed(args);

        // proceed 就是controller返回值
        System.out.println(proceed);
        return proceed;
    }
}

aop Aspect文章
https://blog.csdn.net/loveyour_1314/article/details/108850282

总结

HTTP的POST请求中如果传入的是json类型的数据的话必须要重写getInputStream()【详细看EmojisRequestWrapper.getInputStream()】,此时可以不重写getParameterMap(),getParameter(String name)之类的request的方法,直接在getInputStream()用流写回去就可以了


HTTP的POST请求中如果传入的直接是form表单,不需要重写getInputStream(),直接使用 request.getParameterMap()就可以获取到,但是需要重写getParameterMap(),getParameter(String name),不然你修改的数据无法修改回去。

参考资料
https://www.jianshu.com/p/ab6ab47fcbd8
https://zhuanlan.zhihu.com/p/81936836
https://www.cnblogs.com/timeflying/p/11523314.html
https://blog.csdn.net/HouXinLin_CSDN/article/details/108430756

猜你喜欢

转载自blog.csdn.net/loveyour_1314/article/details/108822877