SpringBoot利用filter修改response中的返回值

  1. 继承HttpServletResponseWrapper 重新覆盖Response对象,用来获取response中的返回值
package com.example.demo.wrapper;
 
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.*;
 
public class ResponseWrapper extends HttpServletResponseWrapper {
    
    
    private ByteArrayOutputStream buffer = null;
    private ServletOutputStream out = null;
    private PrintWriter writer = null;
 
    public ResponseWrapper(HttpServletResponse resp) throws IOException {
    
    
        super(resp);
        buffer = new ByteArrayOutputStream();// 真正存储数据的流
        out = new WapperedOutputStream(buffer);
        writer = new PrintWriter(new OutputStreamWriter(buffer));
    }
 
    @Override
    public ServletOutputStream getOutputStream() throws IOException {
    
    
        return out;
    }
 
    @Override
    public PrintWriter getWriter() throws UnsupportedEncodingException {
    
    
        return writer;
    }
 
    @Override
    public void flushBuffer() throws IOException {
    
    
        if (out != null) {
    
    
            out.flush();
        }
        if (writer != null) {
    
    
            writer.flush();
        }
    }
 
    @Override
    public void reset() {
    
    
        buffer.reset();
    }
 
    public byte[] getResponseData() throws IOException {
    
    
        flushBuffer();
        return buffer.toByteArray();
    }
 
    public String getContent() throws IOException {
    
    
        flushBuffer();
        return buffer.toString();
    }
 
 
    private class WapperedOutputStream extends ServletOutputStream {
    
    
        private ByteArrayOutputStream bos = null;
 
        public WapperedOutputStream(ByteArrayOutputStream stream) throws IOException {
    
    
            bos = stream;
        }
 
        @Override
        public void write(int b) throws IOException {
    
    
            bos.write(b);
        }
 
        @Override
        public void write(byte[] b) throws IOException {
    
    
            bos.write(b, 0, b.length);
        }
 
        @Override
        public void write(byte[] b, int off, int len) throws IOException {
    
    
            bos.write(b, off, len);
        }
 
        @Override
        public boolean isReady() {
    
    
            return false;
        }
 
        @Override
        public void setWriteListener(WriteListener writeListener) {
    
    
 
        }
    }
}
 

2、创建过滤器,修改response中的内容,返回

package com.example.demo.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * created with IntelliJ IDEA.
 * description: urlPatterns 是需要过滤路径,可以urlPatterns = {"/aaa","/bbb"} 配置ip或域名后的请求地址,可以具体到对应接口,只针对某个接口过滤,也可以/*针对所有
 */
@WebFilter(filterName = "myFilter", urlPatterns = "/*")
public class MyFilter implements Filter {
    
    

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    
    
        System.out.println("init...");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    
    
         ResponseWrapper responseWrapper = new ResponseWrapper((HttpServletResponse) servletResponse);
        filterChain.doFilter(servletRequest, responseWrapper);
        String contentType = responseWrapper.getContentType();
        byte[] content = responseWrapper.getResponseData();
        String str="";
        if (StringUtils.isNotBlank(contentType) && (contentType.contains(MediaType.APPLICATION_JSON_VALUE) || contentType.contains(MediaType.TEXT_HTML_VALUE))) {
    
    
           str = new String(content);
            str=str+"xiaoming";
            System.out.println("filter:"+str);
            HttpServletResponse response=(HttpServletResponse)servletResponse;
            writeResponse(response,200,str);
        }
    }
    
   public static void writeResponse(HttpServletResponse response, int status, String json) {
    
    
        try {
    
    
            response.reset();//很重要
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader("Access-Control-Allow-Methods", "*");
            response.setContentType("application/json;charset=UTF-8");
            response.setStatus(status);
            response.getWriter().write(json);
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
    }
    
    @Override
    public void destroy() {
    
    
        System.out.println("destroy...");
    }
}

3、可以代码配置过滤器,也可以注解式配置

(1)代码配置

package com.example.demo.config;
 
import com.example.demo.filter.ResponseFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
 
import java.util.ArrayList;
import java.util.List;
 
@SpringBootConfiguration
public class FilterConfig {
    
    
    @Autowired
   private ResponseFilter  responseFilter;
    @Bean
    public FilterRegistrationBean getFilterConfig(){
    
    
        FilterRegistrationBean filterRegistrationBean=new FilterRegistrationBean();
        filterRegistrationBean.setFilter(responseFilter);
        List<String> filterList=new ArrayList<>();
        filterList.add("/*");
        filterRegistrationBean.setUrlPatterns(filterList);
        return filterRegistrationBean;
    }
 
 
}

(2)注解配置 在Application 启动类 添加 ​​@ServletComponentScan​​ 注解
注:MyFilter 一定要在 ​​@ServletComponentScan​​ 的扫描范围内

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

@ServletComponentScan
@SpringBootApplication
public class Application {
    
    

    public static void main(String[] args) {
    
    
        SpringApplication.run(Application.class, args);
    }
}

延展可以针对filter过滤路径下的返回值修改,比如敏感词操作:
4、在MyFilter内的doFilter 获取到 str 即 返回值内容后可以将其传递到敏感词的工具类下,进行敏感词替换。
注意:contentType 是 MediaType.TEXT_HTML_VALUE 类型则不要转换 json转换报错,如要剔除

package com.util;


import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 敏感词处理 - DFA算法实现
 *
 * @author jeff
 * @since 2018/3/15
 */
public class SensitiveWordUtil {
    
    

    /**
     * 敏感词匹配规则
     */
    public static final int MinMatchTYpe = 1;      //最小匹配规则,如:敏感词库["中国","中国人"],语句:"我是中国人",匹配结果:我是[中国]人
    public static final int MaxMatchType = 2;      //最大匹配规则,如:敏感词库["中国","中国人"],语句:"我是中国人",匹配结果:我是[中国人]

    /**
     * 敏感词集合
     */
    public static HashMap sensitiveWordMap;

    /**
     * 初始化敏感词库,构建DFA算法模型
     *
     * @param sensitiveWordSet 敏感词库
     */
    public static synchronized void init(Set<String> sensitiveWordSet) {
    
    
        initSensitiveWordMap(sensitiveWordSet);
    }

    /**
     * 初始化敏感词库,构建DFA算法模型
     *
     * @param sensitiveWordSet 敏感词库
     */
    private static void initSensitiveWordMap(Set<String> sensitiveWordSet) {
    
    
        //初始化敏感词容器,减少扩容操作
        sensitiveWordMap = new HashMap(sensitiveWordSet.size());
        String key;
        Map nowMap;
        Map<String, String> newWorMap;
        //迭代sensitiveWordSet
        Iterator<String> iterator = sensitiveWordSet.iterator();
        while (iterator.hasNext()) {
    
    
            //关键字
            key = iterator.next();
            nowMap = sensitiveWordMap;
            for (int i = 0; i < key.length(); i++) {
    
    
                //转换成char型
                char keyChar = key.charAt(i);
                //库中获取关键字
                Object wordMap = nowMap.get(keyChar);
                //如果存在该key,直接赋值,用于下一个循环获取
                if (wordMap != null) {
    
    
                    nowMap = (Map) wordMap;
                } else {
    
    
                    //不存在则,则构建一个map,同时将isEnd设置为0,因为他不是最后一个
                    newWorMap = new HashMap<>();
                    //不是最后一个
                    newWorMap.put("isEnd", "0");
                    nowMap.put(keyChar, newWorMap);
                    nowMap = newWorMap;
                }

                if (i == key.length() - 1) {
    
    
                    //最后一个
                    nowMap.put("isEnd", "1");
                }
            }
        }
    }

    /**
     * 判断文字是否包含敏感字符
     *
     * @param txt       文字
     * @param matchType 匹配规则 1:最小匹配规则,2:最大匹配规则
     * @return 若包含返回true,否则返回false
     */
    public static boolean contains(String txt, int matchType) {
    
    
        boolean flag = false;
        for (int i = 0; i < txt.length(); i++) {
    
    
            int matchFlag = checkSensitiveWord(txt, i, matchType); //判断是否包含敏感字符
            if (matchFlag > 0) {
    
        //大于0存在,返回true
                flag = true;
            }
        }
        return flag;
    }

    /**
     * 判断文字是否包含敏感字符
     *
     * @param txt 文字
     * @return 若包含返回true,否则返回false
     */
    public static boolean contains(String txt) {
    
    
        return contains(txt, MaxMatchType);
    }

    /**
     * 获取文字中的敏感词
     *
     * @param txt       文字
     * @param matchType 匹配规则 1:最小匹配规则,2:最大匹配规则
     * @return
     */
    public static Set<String> getSensitiveWord(String txt, int matchType) {
    
    
        Set<String> sensitiveWordList = new HashSet<>();

        for (int i = 0; i < txt.length(); i++) {
    
    
            //判断是否包含敏感字符
            int length = checkSensitiveWord(txt, i, matchType);
            if (length > 0) {
    
    //存在,加入list中
                sensitiveWordList.add(txt.substring(i, i + length));
                i = i + length - 1;//减1的原因,是因为for会自增
            }
        }

        return sensitiveWordList;
    }

    /**
     * 获取文字中的敏感词
     *
     * @param txt 文字
     * @return
     */
    public static Set<String> getSensitiveWord(String txt) {
    
    
        return getSensitiveWord(txt, MaxMatchType);
    }

    /**
     * 替换敏感字字符
     *
     * @param txt         文本
     * @param replaceChar 替换的字符,匹配的敏感词以字符逐个替换,如 语句:我爱中国人 敏感词:中国人,替换字符:*, 替换结果:我爱***
     * @param matchType   敏感词匹配规则
     * @return
     */
    public static String replaceSensitiveWord(String txt, char replaceChar, int matchType) {
    
    
        String resultTxt = txt;
        //获取所有的敏感词
        Set<String> set = getSensitiveWord(txt, matchType);
        Iterator<String> iterator = set.iterator();
        String word;
        String replaceString;
        while (iterator.hasNext()) {
    
    
            word = iterator.next();
            replaceString = getReplaceChars(replaceChar, word.length());
            resultTxt = resultTxt.replaceAll(word, replaceString);
        }

        return resultTxt;
    }

    /**
     * 替换敏感字字符
     *
     * @param txt         文本
     * @param replaceChar 替换的字符,匹配的敏感词以字符逐个替换,如 语句:我爱中国人 敏感词:中国人,替换字符:*, 替换结果:我爱***
     * @return
     */
    public static String replaceSensitiveWord(String txt, char replaceChar) {
    
    
        return replaceSensitiveWord(txt, replaceChar, MaxMatchType);
    }

    /**
     * 替换敏感字字符
     *
     * @param txt        文本
     * @param replaceStr 替换的字符串,匹配的敏感词以字符逐个替换,如 语句:我爱中国人 敏感词:中国人,替换字符串:[屏蔽],替换结果:我爱[屏蔽]
     * @param matchType  敏感词匹配规则
     * @return
     */
    public static String replaceSensitiveWord(String txt, String replaceStr, int matchType) {
    
    
        String resultTxt = txt;
        //获取所有的敏感词
        Set<String> set = getSensitiveWord(txt, matchType);
        Iterator<String> iterator = set.iterator();
        String word;
        while (iterator.hasNext()) {
    
    
            word = iterator.next();
            resultTxt = resultTxt.replaceAll(word, replaceStr);
        }

        return resultTxt;
    }

    /**
     * 替换敏感字字符
     *
     * @param txt        文本
     * @param replaceStr 替换的字符串,匹配的敏感词以字符逐个替换,如 语句:我爱中国人 敏感词:中国人,替换字符串:[屏蔽],替换结果:我爱[屏蔽]
     * @return
     */
    public static String replaceSensitiveWord(String txt, String replaceStr) {
    
    
        return replaceSensitiveWord(txt, replaceStr, MaxMatchType);
    }

    /**
     * 获取替换字符串
     *
     * @param replaceChar
     * @param length
     * @return
     */
    private static String getReplaceChars(char replaceChar, int length) {
    
    
        String resultReplace = String.valueOf(replaceChar);
        for (int i = 1; i < length; i++) {
    
    
            resultReplace += replaceChar;
        }

        return resultReplace;
    }

    /**
     * 检查文字中是否包含敏感字符,检查规则如下:<br>
     *
     * @param txt
     * @param beginIndex
     * @param matchType
     * @return 如果存在,则返回敏感词字符的长度,不存在返回0
     */
    private static int checkSensitiveWord(String txt, int beginIndex, int matchType) {
    
    
        //敏感词结束标识位:用于敏感词只有1位的情况
        boolean flag = false;
        //匹配标识数默认为0
        int matchFlag = 0;
        char word;
        Map nowMap = sensitiveWordMap;
        for (int i = beginIndex; i < txt.length(); i++) {
    
    
            word = txt.charAt(i);
            //获取指定key
            nowMap = (Map) nowMap.get(word);
            if (nowMap != null) {
    
    //存在,则判断是否为最后一个
                //找到相应key,匹配标识+1
                matchFlag++;
                //如果为最后一个匹配规则,结束循环,返回匹配标识数
                if ("1".equals(nowMap.get("isEnd"))) {
    
    
                    //结束标志位为true
                    flag = true;
                    //最小规则,直接返回,最大规则还需继续查找
                    if (MinMatchTYpe == matchType) {
    
    
                        break;
                    }
                }
            } else {
    
    //不存在,直接返回
                break;
            }
        }
        if (matchFlag < 2 || !flag) {
    
    //长度必须大于等于1,为词
            matchFlag = 0;
        }
        return matchFlag;
    }

    /**
     * 检测敏感词
     * @param text 需要检测的内容
     * @param path 敏感词字典路径
     */
    public static boolean wordFilter(String text,String path){
    
    
        HashSet<String> sensitiveWordSet = getTxt(path);
        String str = del(text);
        if(sensitiveWordSet==null){
    
    
            System.out.println("error");
        }else {
    
    
            //初始化敏感词库
            SensitiveWordUtil.init(sensitiveWordSet);
            //是否含有关键字
            boolean result = SensitiveWordUtil.contains(str);
            result = SensitiveWordUtil.contains(str, SensitiveWordUtil.MaxMatchType);
            return result;
        }
        return true;
    }


//    public static void main(String[] args) {
    
    
//        HashSet<String> sensitiveWordSet = getTxt("");
//        if(sensitiveWordSet==null){
    
    
//            System.out.println("error");
//        }else {
    
    
//        //初始化敏感词库
//        SensitiveWordUtil.init(sensitiveWordSet);
//        System.out.println("敏感词的数量:" + SensitiveWordUtil.sensitiveWordMap.size());
//        String string = "靖国神社";
//        System.out.println("待检测语句字数:" + string.length());
//        //是否含有关键字
//        boolean result = SensitiveWordUtil.contains(string);
//        result = SensitiveWordUtil.contains(string, SensitiveWordUtil.MaxMatchType);
//        System.out.println(result);
//
//        //获取语句中的敏感词
        Set<String> set = SensitiveWordUtil.getSensitiveWord(string);
        System.out.println("语句中包含敏感词的个数为:" + set.size() + "。包含:" + set);
        set = SensitiveWordUtil.getSensitiveWord(string, SensitiveWordUtil.MaxMatchType);
        System.out.println("语句中包含敏感词的个数为:" + set.size() + "。包含:" + set);
//
//        //替换语句中的敏感词
        String filterStr = SensitiveWordUtil.replaceSensitiveWord(string, '*');
        System.out.println(filterStr);
        filterStr = SensitiveWordUtil.replaceSensitiveWord(string, '*', SensitiveWordUtil.MaxMatchType);
        System.out.println(filterStr);

        String filterStr2 = SensitiveWordUtil.replaceSensitiveWord(string, "[*敏感词*]");
        System.out.println(filterStr2);
        filterStr2 = SensitiveWordUtil.replaceSensitiveWord(string, "[*敏感词*]", SensitiveWordUtil.MaxMatchType);
        System.out.println(filterStr2);
//        }
//
//    }


    /**
     * 获取txt字典敏感词库
     * @return
     */
        public static   HashSet<String> getTxt(String readerPath) {
    
    
            //创建字符缓冲输入流对象
            BufferedReader br = null;
            try {
    
    
                br = new BufferedReader(new FileReader(readerPath));
                //创建ArrayList集合对象
                HashSet<String> array = new HashSet<>();
                //调用字符缓冲输入流对象的方法读数据
                String line;
                while ((line=br.readLine())!=null) {
    
    
                    //把读取到的字符串数据存储到集合中
                    array.add(line);
                }
                //释放资源
                br.close();
                return array;
            } catch (FileNotFoundException e) {
    
    
                e.printStackTrace();
            } catch (IOException e) {
    
    
                e.printStackTrace();
            }
                return null;
        }
    /**
     * 去除字符串中的空格以及特殊字符
     */
    private static String del(String str){
    
    
        str = str.replaceAll(" ", "");//去除空格
        Pattern p = Pattern.compile("[`~☆★!@#$%^&*()+=|{}':;,\\[\\]》·.<>/?~!@#¥%……()——+|{}【】‘;:”“’。,、?]");//去除特殊字符
        Matcher m = p.matcher(str);
        str = m.replaceAll("").trim().replace(" ", "").replace("\\", "");//将匹配的特殊字符转变为空
        return str;
    }
}

5、在初始化的时候springboot可以采用@postConstruct初始化 这样就可以在类下添加方法调用敏感词工具类下的初始化方法,进行敏感词初始化,剩下的就是需要在哪里做敏感词就可以在webFilter添加路径,或者自己手动调用敏感词工具类。

猜你喜欢

转载自blog.csdn.net/yangyang_VV/article/details/127897754