屏蔽词过滤器 2

简介: 屏蔽词过滤器

屏蔽词过滤器 1:https://developer.aliyun.com/article/1379261

然后是过滤器中需要的过滤请求的封装好的request

package com.ruben.simplescaffold.filter.wrappers;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.ruben.simplescaffold.utils.sensitive.SensitiveWordUtils;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
/**
 * 封装请求
 *
 * @author <achao1441470436@gmail.com>
 * @since 2021/8/7 21:50
 */
public class RequestWrapper extends HttpServletRequestWrapper {
    private final Map<String, String[]> parameterMap;
    private final byte[] body;
    public RequestWrapper(HttpServletRequest request, SensitiveWordUtils sensitiveWordUtils, Map<String, String[]> parameterMap, String bodyString) {
        super(request);
        if (sensitiveWordUtils == null) {
            this.parameterMap = Optional.ofNullable(parameterMap).orElseGet(super::getParameterMap);
            queryStringPutParameterMap(super.getQueryString());
            this.body = Optional.ofNullable(bodyString).orElseGet(() -> BodyHelper.getBodyString(request)).getBytes(StandardCharsets.UTF_8);
        } else {
            String paramString = JSON.toJSONString(Optional.ofNullable(parameterMap).orElseGet(super::getParameterMap));
            paramString = sensitiveWordUtils.replaceSensitiveWord(paramString, SensitiveWordUtils.MAX_MATCH_TYPE, SensitiveWordUtils.REPLACE_CHAR);
            this.parameterMap = JSON.parseObject(paramString, new TypeReference<Map<String, String[]>>() {
            });
            Optional.ofNullable(super.getQueryString()).ifPresent(queryString -> queryStringPutParameterMap(sensitiveWordUtils.replaceSensitiveWord(queryString, SensitiveWordUtils.MAX_MATCH_TYPE, SensitiveWordUtils.REPLACE_CHAR)));
            this.body = sensitiveWordUtils.replaceSensitiveWord(Optional.ofNullable(bodyString).orElseGet(() -> BodyHelper.getBodyString(request)), SensitiveWordUtils.MAX_MATCH_TYPE, SensitiveWordUtils.REPLACE_CHAR).getBytes(StandardCharsets.UTF_8);
        }
    }
    @Override
    public String getParameter(String name) {
        String[] values = parameterMap.get(name);
        if (Objects.isNull(values) || values.length == 0) {
            return null;
        }
        return values[0];
    }
    @Override
    public Map<String, String[]> getParameterMap() {
        if (parameterMap == null) {
            return super.getParameterMap();
        }
        return parameterMap;
    }
    @Override
    public Enumeration<String> getParameterNames() {
        if (parameterMap == null) {
            return super.getParameterNames();
        }
        return new Vector<>(parameterMap.keySet()).elements();
    }
    @Override
    public String[] getParameterValues(String name) {
        if (parameterMap == null) {
            return super.getParameterValues(name);
        }
        return parameterMap.get(name);
    }
    @Override
    public BufferedReader getReader() {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }
    @Override
    public ServletInputStream getInputStream() {
        final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body);
        return new ServletInputStream() {
            @Override
            public int read() {
                return byteArrayInputStream.read();
            }
            @Override
            public boolean isFinished() {
                return false;
            }
            @Override
            public boolean isReady() {
                return false;
            }
            @Override
            public void setReadListener(ReadListener arg0) {
            }
        };
    }
    @Override
    public String getHeader(String name) {
        return super.getHeader(name);
    }
    @Override
    public Enumeration<String> getHeaderNames() {
        return super.getHeaderNames();
    }
    @Override
    public Enumeration<String> getHeaders(String name) {
        return super.getHeaders(name);
    }
    private void queryStringPutParameterMap(String queryString) {
        if (queryString != null && queryString.trim().length() > 0) {
            String[] params = queryString.split("&");
            for (String param : params) {
                int splitIndex = param.indexOf("=");
                if (splitIndex == -1) {
                    continue;
                }
                String key = param.substring(0, splitIndex);
                if (!this.parameterMap.containsKey(key)) {
                    if (splitIndex < param.length()) {
                        String value = param.substring(splitIndex + 1);
                        this.parameterMap.put(key, new String[]{value});
                    }
                }
            }
        }
    }
    public static class BodyHelper {
        /**
         * 获取请求Body
         *
         * @param request
         * @return
         */
        public static String getBodyString(ServletRequest request) {
            StringBuilder sb = new StringBuilder();
            InputStream inputStream = null;
            BufferedReader reader = null;
            try {
                inputStream = request.getInputStream();
                reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
                String line = "";
                while ((line = reader.readLine()) != null) {
                    sb.append(line);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return sb.toString();
        }
    }
}

还有个获取响应结果的封装好的response,虽然此处我们没用到,但如果我们要获取filter中的响应体执行过滤,也可以用这个

package com.ruben.simplescaffold.filter.wrappers;
import lombok.SneakyThrows;
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
/**
 * 过滤器获取响应结果
 *
 * @author <achao1441470436@gmail.com>
 * @since 2021/7/29 10:13
 */
public class ResponseWrapper extends HttpServletResponseWrapper {
    private ByteArrayOutputStream buffer = null;
    private ServletOutputStream outputStream = null;
    private PrintWriter writer = null;
    /**
     * Constructs a response adaptor wrapping the given response.
     *
     * @param response The response to be wrapped
     * @throws IllegalArgumentException if the response is null
     */
    @SneakyThrows
    public ResponseWrapper(HttpServletResponse response) {
        super(response);
        buffer = new ByteArrayOutputStream();
        outputStream = new WrapperOutputStream(buffer);
        writer = new PrintWriter(new OutputStreamWriter(buffer, StandardCharsets.UTF_8));
    }
    /**
     * The default behavior of this method is to return getOutputStream() on the
     * wrapped response object.
     */
    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        return outputStream;
    }
    /**
     * The default behavior of this method is to return getWriter() on the
     * wrapped response object.
     */
    @Override
    public PrintWriter getWriter() throws IOException {
        return writer;
    }
    /**
     * The default behavior of this method is to call flushBuffer() on the
     * wrapped response object.
     */
    @Override
    @SneakyThrows
    public void flushBuffer() {
        if (outputStream != null) {
            outputStream.flush();
        }
        if (writer != null) {
            writer.flush();
        }
    }
    /**
     * The default behavior of this method is to call reset() on the wrapped
     * response object.
     */
    @Override
    public void reset() {
        buffer.reset();
    }
    /**
     * Get response content
     *
     * @param charset HttpServletResponse#getCharacterEncoding()
     * @return response content
     */
    @SneakyThrows
    public String getResponseData(String charset) {
        // 将out、writer中的数据强制输出到WrapperResponse的buffer里面,否则取不到数据
        flushBuffer();
        return buffer.toString(StandardCharsets.UTF_8.displayName());
    }
    /**
     * 内部类,对ServletOutputStream进行包装,指定输出流的输出端
     */
    private static class WrapperOutputStream extends ServletOutputStream {
        private ByteArrayOutputStream bos = null;
        public WrapperOutputStream(ByteArrayOutputStream stream) throws IOException {
            bos = stream;
        }
        /**
         * Writes the specified byte to this output stream. The general
         * contract for <code>write</code> is that one byte is written
         * to the output stream. The byte to be written is the eight
         * low-order bits of the argument <code>b</code>. The 24
         * high-order bits of <code>b</code> are ignored.
         * <p>
         * Subclasses of <code>OutputStream</code> must provide an
         * implementation for this method.
         *
         * @param b the <code>byte</code>.
         * @throws IOException if an I/O error occurs. In particular,
         *                     an <code>IOException</code> may be thrown if the
         *                     output stream has been closed.
         */
        @Override
        public void write(int b) throws IOException {
            bos.write(b);
        }
        /**
         * Checks if a non-blocking write will succeed. If this returns
         * <code>false</code>, it will cause a callback to
         * {@link WriteListener#onWritePossible()} when the buffer has emptied. If
         * this method returns <code>false</code> no further data must be written
         * until the contain calls {@link WriteListener#onWritePossible()}.
         *
         * @return <code>true</code> if data can be written, else <code>false</code>
         * @since Servlet 3.1
         */
        @Override
        public boolean isReady() {
            return false;
        }
        /**
         * Sets the {@link WriteListener} for this {@link ServletOutputStream} and
         * thereby switches to non-blocking IO. It is only valid to switch to
         * non-blocking IO within async processing or HTTP upgrade processing.
         *
         * @param listener The non-blocking IO write listener
         * @throws IllegalStateException If this method is called if neither
         *                               async nor HTTP upgrade is in progress or
         *                               if the {@link WriteListener} has already
         *                               been set
         * @throws NullPointerException  If listener is null
         * @since Servlet 3.1
         */
        @Override
        public void setWriteListener(WriteListener listener) {
        }
    }
}

最后是测试用的controller

package com.ruben.simplescaffold.controller.rest;
import com.ruben.simplescaffold.pojo.common.Result;
import com.ruben.simplescaffold.pojo.dto.CommonDTO;
import org.springframework.web.bind.annotation.*;
/**
 * 测试控制层
 *
 * @author <achao1441470436@gmail.com>
 * @since 2021/8/7 22:58
 */
@RestController
@RequestMapping("test")
public class TestController {
    @PostMapping
    public Result testBody(@RequestBody CommonDTO commonDTO) {
        return Result.ok().data(commonDTO);
    }
    @GetMapping
    public Result testQueryParam(CommonDTO commonDTO) {
        return Result.ok().data(commonDTO);
    }
    @GetMapping("{path}")
    public Result testPath(@PathVariable String path) {
        return Result.ok().data(path);
    }
}

这里还用到两个类,一个响应结果Result,一个CommonDTOCommonDTO大伙可以使用Map代替下

package com.ruben.simplescaffold.pojo.common;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import org.springframework.http.HttpStatus;
import java.util.HashMap;
import java.util.Optional;
/**
 * 自定义返回响应
 *
 * @author <achao1441470436@gmail.com>
 * @since 2021/6/23 10:40
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(fluent = true)
@EqualsAndHashCode(callSuper = true)
public class Result extends HashMap<String, Object> {
    public static final String DATA_KEY = "data";
    private static final long serialVersionUID = 8639693790921600208L;
    /**
     * 成功状态
     */
    private Boolean success;
    /**
     * 消息
     */
    private String msg;
    /**
     * 状态码
     */
    private Integer code;
    public static Result ok() {
        return httpStatus(HttpStatus.OK);
    }
    public static Result error(String msg) {
        return httpStatus(HttpStatus.INTERNAL_SERVER_ERROR).msg(msg);
    }
    public static Result paramError() {
        return httpStatus(HttpStatus.BAD_REQUEST);
    }
    public static Result notLogin() {
        return httpStatus(HttpStatus.UNAUTHORIZED);
    }
    public static Result httpStatus(HttpStatus httpStatus) {
        httpStatus = Optional.ofNullable(httpStatus).orElse(HttpStatus.OK);
        HttpStatus.Series series = httpStatus.series();
        return new Result().success(httpStatus.is2xxSuccessful()).msg(series.name()).code(HttpStatus.OK.value());
    }
    /**
     * 放入key和value
     *
     * @param key   键
     * @param value 值
     * @return com.kuang.honghaisyweb.pojo.common.Result
     * @author <achao1441470436@gmail.com>
     * @since 2021/6/23 17:07
     */
    @Override
    public Result put(String key, Object value) {
        super.put(key, value);
        return this;
    }
    /**
     * 返回数据
     *
     * @param value 数据
     * @return com.kuang.honghaisyweb.pojo.common.Result
     * @author <achao1441470436@gmail.com>
     * @since 2021/6/23 17:07
     */
    public Result data(Object value) {
        this.put(DATA_KEY, value);
        return this;
    }
}

最后是屏蔽词文本

屏蔽词1号
屏蔽词2号
屏蔽词3号

以及测试案例:

可以看到bodyparam传参都替换成了*号,urlpath传参也替换成了0

完整源码:https://gitee.com/VampireAchao/simple-scaffold.git

相关文章
|
Java 容器
28JavaWeb基础 - 过滤器
28JavaWeb基础 - 过滤器
53 0
|
2天前
|
存储 缓存 安全
常用过滤器介绍
常用过滤器介绍
|
28天前
|
Java 数据挖掘 Android开发
如何添加一个过滤器
如何添加一个过滤器
|
6月前
|
Python
过滤器
过滤器
27 2
|
6月前
|
存储 Java 数据库
整合切面,参数拦截+过滤
整合切面,参数拦截+过滤
|
6月前
|
Java 数据安全/隐私保护
Filter概述、执行流程、拦截路径配置及过滤器链
Filter概述、执行流程、拦截路径配置及过滤器链
82 0
|
12月前
|
JSON 数据格式
屏蔽词过滤器 1
屏蔽词过滤器
124 0
过滤器简介--操作步骤--过滤器生命周期--过滤器匹配规则-- 过滤器链
过滤器简介--操作步骤--过滤器生命周期--过滤器匹配规则-- 过滤器链
62 0
|
监控 Java 数据库连接
过滤器的应用
在上一篇博客中,我们简单的学习了一下面向切面编程,而过滤器就是对这一思想的应用。那如何在项目中使用呢?
|
前端开发 Java 应用服务中间件
GetWay网关过滤器工厂与全局过滤器
GatewayFilter是网关中提供的一种过滤器,可以对进入网关的请求和微服务返回的响应做处理:
351 0