Java 在SpringMVC中使用servlet过滤器将现有响应替换为新响应

Java 在SpringMVC中使用servlet过滤器将现有响应替换为新响应,java,json,spring-mvc,servlets,filter,Java,Json,Spring Mvc,Servlets,Filter,我想用使用过滤器的新响应替换现有的jsonresponse(在某些情况下)。我试图做的是从过滤器中读取现有响应(JSON)。使用新值修改它并写回响应。但结果显示了这两种反应 也就是说,我从回应中读到了什么,以及我新增了什么。但我需要用新的回应取代旧的回应。代码添加到下面 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) { try{ ByteArr

我想用使用过滤器的新响应替换现有的
json
response(在某些情况下)。我试图做的是从过滤器中读取现有响应(
JSON
)。使用新值修改它并写回响应。但结果显示了这两种反应

也就是说,我从回应中读到了什么,以及我新增了什么。但我需要用新的回应取代旧的回应。代码添加到下面

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
{
    try{
     ByteArrayOutputStream baos = new ByteArrayOutputStream();
        final PrintStream ps = new PrintStream(baos);

        chain.doFilter(request,new HttpServletResponseWrapper((HttpServletResponse)response) {
               @Override
             public ServletOutputStream getOutputStream() throws IOException {
                return new DelegatingServletOutputStream(new TeeOutputStream(super.getOutputStream(), ps)
                );
             }
          @Override
             public  PrintWriter getWriter() throws IOException {
                return new PrintWriter(new DelegatingServletOutputStream (new TeeOutputStream(super.getOutputStream(), ps))
                );
             }
          });
        /* get existing response as string*/
        String respopn=baos.toString(); 
        JSONObject json=new JSONObject(respopn);
        JSONObject dMap=new JSONObject(json.get("dataMap"));
        dMap.put("new", "newValue");
        json.put("dataMap", dMap); // Modified the old datamap with new json
        JsonMapper jsonMap=new JsonMapper();
        jsonMap.setJson(json);
        String str=jsonMap.getJson();
        byte[] responseToSend = restResponseBytes(jsonMap);
        response.getOutputStream().write(responseToSend); // write to response only the new one



    }
    catch(Exception e)
    {
        e.printStackTrace();
    }
    }


   private byte[] restResponseBytes(Object response) throws IOException {
        String serialized = new ObjectMapper().writeValueAsString(response);
        return serialized.getBytes();
    }

我觉得下面的代码片段应该可以工作。上面的问题是它被附加到现有数据中,而不是重写。我们需要创建一个用于存储数据的副本,并在处理原始ServletResponse后进行复制。希望下面的代码片段能解决您的问题

下面是主要的do过滤器方法-

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

    ServletResponseWrapperCopier capturingResponseWrapper = new ServletResponseWrapperCopier(
                (HttpServletResponse) response);

    chain.doFilter(request, capturingResponseWrapper);
    try{
        String respopn = capturingResponseWrapper.getCaptureAsString();     
        JSONObject json=new JSONObject(respopn);
        JSONObject dMap=new JSONObject(json.get("dataMap"));
        dMap.put("new", "newValue");
        json.put("dataMap", dMap); // Modified the old datamap with new json
        JsonMapper jsonMap=new JsonMapper();
        jsonMap.setJson(json);
        String str=jsonMap.getJson();
        response.getOutputStream().write(str.getBytes());
    } catch(Exception e){
        log.error("");
    }
}
下面的类用于复制上述代码段中的ServletResponse

public class ServletResponseWrapperCopier extends HttpServletResponseWrapper{

private final ByteArrayOutputStream capture;
private ServletOutputStream output;
private PrintWriter writer;

public ServletResponseWrapperCopier(HttpServletResponse response) {
    super(response);
    capture = new ByteArrayOutputStream(response.getBufferSize());
}

@Override
public ServletOutputStream getOutputStream() {
    if (writer != null) {
        throw new IllegalStateException(
                "getWriter() has already been called on this response.");
    }

    if (output == null) {
        output = new ServletOutputStream() {
            @Override
            public void write(int b) throws IOException {
                capture.write(b);
            }

            @Override
            public void flush() throws IOException {
                capture.flush();
            }

            @Override
            public void close() throws IOException {
                capture.close();
            }
        };
    }

    return output;
}

@Override
public PrintWriter getWriter() throws IOException {
    if (output != null) {
        throw new IllegalStateException(
                "getOutputStream() has already been called on this response.");
    }

    if (writer == null) {
        writer = new PrintWriter(new OutputStreamWriter(capture,
                getCharacterEncoding()));
    }

    return writer;
}

public byte[] getCaptureAsBytes() throws IOException {
    if (writer != null) {
        writer.close();
    } else if (output != null) {
        output.close();
    }

    return capture.toByteArray();
}

public String getCaptureAsString() throws IOException {
    return new String(getCaptureAsBytes(), getCharacterEncoding());
}

}

我觉得下面的代码片段应该可以工作。上面的问题是它被附加到现有数据中,而不是重写。我们需要创建一个用于存储数据的副本,并在处理原始ServletResponse后进行复制。希望下面的代码片段能解决您的问题

下面是主要的do过滤器方法-

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

    ServletResponseWrapperCopier capturingResponseWrapper = new ServletResponseWrapperCopier(
                (HttpServletResponse) response);

    chain.doFilter(request, capturingResponseWrapper);
    try{
        String respopn = capturingResponseWrapper.getCaptureAsString();     
        JSONObject json=new JSONObject(respopn);
        JSONObject dMap=new JSONObject(json.get("dataMap"));
        dMap.put("new", "newValue");
        json.put("dataMap", dMap); // Modified the old datamap with new json
        JsonMapper jsonMap=new JsonMapper();
        jsonMap.setJson(json);
        String str=jsonMap.getJson();
        response.getOutputStream().write(str.getBytes());
    } catch(Exception e){
        log.error("");
    }
}
下面的类用于复制上述代码段中的ServletResponse

public class ServletResponseWrapperCopier extends HttpServletResponseWrapper{

private final ByteArrayOutputStream capture;
private ServletOutputStream output;
private PrintWriter writer;

public ServletResponseWrapperCopier(HttpServletResponse response) {
    super(response);
    capture = new ByteArrayOutputStream(response.getBufferSize());
}

@Override
public ServletOutputStream getOutputStream() {
    if (writer != null) {
        throw new IllegalStateException(
                "getWriter() has already been called on this response.");
    }

    if (output == null) {
        output = new ServletOutputStream() {
            @Override
            public void write(int b) throws IOException {
                capture.write(b);
            }

            @Override
            public void flush() throws IOException {
                capture.flush();
            }

            @Override
            public void close() throws IOException {
                capture.close();
            }
        };
    }

    return output;
}

@Override
public PrintWriter getWriter() throws IOException {
    if (output != null) {
        throw new IllegalStateException(
                "getOutputStream() has already been called on this response.");
    }

    if (writer == null) {
        writer = new PrintWriter(new OutputStreamWriter(capture,
                getCharacterEncoding()));
    }

    return writer;
}

public byte[] getCaptureAsBytes() throws IOException {
    if (writer != null) {
        writer.close();
    } else if (output != null) {
        output.close();
    }

    return capture.toByteArray();
}

public String getCaptureAsString() throws IOException {
    return new String(getCaptureAsBytes(), getCharacterEncoding());
}

}也许这也可以考虑。 因此,首先创建一个响应包装器。(如果需要,请添加内容类型,否则可以保持原样。我的内容类型为XHTML,这促使我更改内容类型)

接下来为printwriter和ServletOutputStream创建包装器。servlet OutputStream的包装器是可选的,但这取决于您的需要。下面是实现

ByteArrayServletStream.java

public class ByteArrayServletStream extends ServletOutputStream {

    ByteArrayOutputStream baos;

    ByteArrayServletStream(ByteArrayOutputStream baos) {
        this.baos = baos;
    }

    @Override
    public void write(int param) throws IOException {
        baos.write(param);
    }

    @Override
    public boolean isReady() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public void setWriteListener(WriteListener listener) {
        // TODO Auto-generated method stub

    }

}
ByteArrayPrinter.java

/**
 * IMplemented own Printer as the new wrapper
 *
 */
public class ByteArrayPrinter {

    private ByteArrayOutputStream baos = new ByteArrayOutputStream();

    private PrintWriter pw = new PrintWriter(baos);

    private ServletOutputStream sos = new ByteArrayServletStream(baos);

    public PrintWriter getWriter() {
        return pw;
    }

    public ServletOutputStream getStream() {
        return sos;
    }

    byte[] toByteArray() {
        return baos.toByteArray();
    }
}
SwaggerFilter.java

public class SwaggerFilter implements Filter {

    final String APPLICATION_XHTML = "application/xhtml";
    final String XML_ELEMENT_START = "<Json>";
    final String XML_ELEMENT_END = "</Json>";

    @Override
    public void init(FilterConfig config) throws ServletException {
    }

    /**
     * Filter to remove the extra JSON element and render it
     */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;

        HttpServletResponse response = (HttpServletResponse) servletResponse;
        ByteArrayPrinter pw = new ByteArrayPrinter();

        // Create a wrapper
        HttpServletResponse wrappedResp = new HttpServletResponseWrapper(response) {

            @Override
            public void setContentType(final String type) {
                super.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
            }

            @Override
            public PrintWriter getWriter() {
                return pw.getWriter();
            }

            // set the outputstream content type to JSON
            @Override
            public ServletOutputStream getOutputStream() throws IOException {
                ServletResponse response = this.getResponse();

                String ct = (response != null) ? response.getContentType() : null;
                if (ct != null && ct.contains(APPLICATION_XHTML)) {
                    response.setContentType(ct + AppConstants.CONSTANT_COMMA + MediaType.APPLICATION_JSON_UTF8_VALUE);
                }
                return pw.getStream();
            }

        };
        chain.doFilter(httpRequest, wrappedResp);

        byte[] bytes = pw.toByteArray();
        String respBody = new String(bytes);
        if (respBody.startsWith(XML_ELEMENT_START)) {

            // Instead of using substring made use of stream to identify any occurence of <Json> xml element
            List<String> xmlStringList = Stream.of(respBody).filter((s1) -> s1.contains(XML_ELEMENT_START))
                    // filter the string. Split it by mapping to new arraylist by space
                    .map((stringBeforeSplit) -> Arrays.asList(stringBeforeSplit.split(AppConstants.CONSTANT_SPACE)))
                    // create a new stream of array list strings
                    .flatMap((stringArrayAfterSplit) -> {
                        StringBuffer concatenateStringStream = new StringBuffer();
                        stringArrayAfterSplit.forEach(item -> {

                            concatenateStringStream.append(item);

                        });
                        // remove the <JSON> xml element and return the values
                        return Stream
                                .of(concatenateStringStream.toString().trim()
                                        .replace(XML_ELEMENT_START, AppConstants.CONSTANT_NO_SPACE)
                                        .replace(XML_ELEMENT_END, AppConstants.CONSTANT_NO_SPACE));
                        // collect it as a new list of strings with the xmlelement - <JSON> removed
                    }).collect(Collectors.toList());

            // Join the list to make it one
            String finalString = String.join(AppConstants.CONSTANT_NO_SPACE, xmlStringList);

            // write to the outputstream with JSON mediatype
            response.getOutputStream().write(finalString.getBytes());
        } else {
            response.getOutputStream().write(bytes);
        }

    }

    @Override
    public void destroy() {
    }

}
公共类SwaggerFilter实现过滤器{
最终字符串APPLICATION\u XHTML=“APPLICATION/XHTML”;
最后一个字符串XML_元素_START=“”;
最后一个字符串XML_元素_END=“”;
@凌驾
public void init(FilterConfig config)抛出ServletException{
}
/**
*筛选以删除额外的JSON元素并呈现它
*/
@凌驾
public void doFilter(ServletRequest ServletRequest、ServletResponse ServletResponse、FilterChain链)
抛出IOException、ServletException{
HttpServletRequest httpRequest=(HttpServletRequest)servletRequest;
HttpServletResponse=(HttpServletResponse)servletResponse;
ByteArrayPrinter pw=新的ByteArrayPrinter();
//创建一个包装器
HttpServletResponse wrappedResp=新的HttpServletResponseWrapper(响应){
@凌驾
公共void setContentType(最终字符串类型){
setContentType(MediaType.APPLICATION\uJSON\uUTF8\u值);
}
@凌驾
公共PrintWriter getWriter(){
返回pw.getWriter();
}
//将outputstream内容类型设置为JSON
@凌驾
公共ServletOutputStream getOutputStream()引发IOException{
ServletResponse=this.getResponse();
字符串ct=(response!=null)?response.getContentType():null;
if(ct!=null&&ct.contains(应用程序\u XHTML)){
response.setContentType(ct+AppConstants.CONSTANT\u逗号+MediaType.APPLICATION\u JSON\u UTF8\u值);
}
返回pw.getStream();
}
};
链式过滤器(httpRequest,wrappedResp);
byte[]bytes=pw.toByteArray();
String respBody=新字符串(字节);
if(respBody.startsWith(XML_元素_开始)){
//使用流来标识xml元素的任何出现,而不是使用子字符串
List xmlStringList=Stream.of(respBody).filter((s1)->s1.contains(XML\u ELEMENT\u START))
//筛选字符串。通过按空格映射到新的arraylist将其拆分
.map((StringBeforeSpilt)->array.asList(StringBeforeSpilt.split(AppConstants.CONSTANT_SPACE)))
//创建新的数组列表字符串流
.flatMap((stringArrayAfterSplit)->{
StringBuffer concatenateStringStream=新的StringBuffer();
stringArrayAfterSplit.forEach(项目->{
concatenateStringStream.append(项);
});
//删除xml元素并返回值
回流
.of(concatenateStringStream.toString().trim())
.replace(XML\u元素\u开始,AppConstants.CONSTANT\u无空间)
.replace(XML_元素_END,AppConstants.CONSTANT_NO_空格));
//将其收集为xmlelement-removed的新字符串列表
}).collect(Collectors.toList());
//加入列表,使其成为一个
String finalString=String.join(AppConstants.CONSTANT\u NO\u空格,xmlStringList);
//使用JSON mediatype写入outputstream
response.getOutputStream().write(finalString.getBytes());
}否则{
response.getOutputStream().write(字节);
}
}
@凌驾
公共空间销毁(){
}
}

也许这也可以考虑。 因此,首先创建一个响应包装器。(如果需要,请添加内容类型,否则可以保持原样。我的内容类型为XHTML,这促使我更改内容类型)

接下来为printwriter和ServletOutputStream创建包装器。servlet OutputStream的包装器是可选的,但这取决于您的需要。下面是实现

ByteArrayServletStream.java

public class ByteArrayServletStream extends ServletOutputStream {

    ByteArrayOutputStream baos;

    ByteArrayServletStream(ByteArrayOutputStream baos) {
        this.baos = baos;
    }

    @Override
    public void write(int param) throws IOException {
        baos.write(param);
    }

    @Override
    public boolean isReady() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public void setWriteListener(WriteListener listener) {
        // TODO Auto-generated method stub

    }

}
ByteArrayPrinter.java

/**
 * IMplemented own Printer as the new wrapper
 *
 */
public class ByteArrayPrinter {

    private ByteArrayOutputStream baos = new ByteArrayOutputStream();

    private PrintWriter pw = new PrintWriter(baos);

    private ServletOutputStream sos = new ByteArrayServletStream(baos);

    public PrintWriter getWriter() {
        return pw;
    }

    public ServletOutputStream getStream() {
        return sos;
    }

    byte[] toByteArray() {
        return baos.toByteArray();
    }
}
SwaggerFilter.java

public class SwaggerFilter implements Filter {

    final String APPLICATION_XHTML = "application/xhtml";
    final String XML_ELEMENT_START = "<Json>";
    final String XML_ELEMENT_END = "</Json>";

    @Override
    public void init(FilterConfig config) throws ServletException {
    }

    /**
     * Filter to remove the extra JSON element and render it
     */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;

        HttpServletResponse response = (HttpServletResponse) servletResponse;
        ByteArrayPrinter pw = new ByteArrayPrinter();

        // Create a wrapper
        HttpServletResponse wrappedResp = new HttpServletResponseWrapper(response) {

            @Override
            public void setContentType(final String type) {
                super.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
            }

            @Override
            public PrintWriter getWriter() {
                return pw.getWriter();
            }

            // set the outputstream content type to JSON
            @Override
            public ServletOutputStream getOutputStream() throws IOException {
                ServletResponse response = this.getResponse();

                String ct = (response != null) ? response.getContentType() : null;
                if (ct != null && ct.contains(APPLICATION_XHTML)) {
                    response.setContentType(ct + AppConstants.CONSTANT_COMMA + MediaType.APPLICATION_JSON_UTF8_VALUE);
                }
                return pw.getStream();
            }

        };
        chain.doFilter(httpRequest, wrappedResp);

        byte[] bytes = pw.toByteArray();
        String respBody = new String(bytes);
        if (respBody.startsWith(XML_ELEMENT_START)) {

            // Instead of using substring made use of stream to identify any occurence of <Json> xml element
            List<String> xmlStringList = Stream.of(respBody).filter((s1) -> s1.contains(XML_ELEMENT_START))
                    // filter the string. Split it by mapping to new arraylist by space
                    .map((stringBeforeSplit) -> Arrays.asList(stringBeforeSplit.split(AppConstants.CONSTANT_SPACE)))
                    // create a new stream of array list strings
                    .flatMap((stringArrayAfterSplit) -> {
                        StringBuffer concatenateStringStream = new StringBuffer();
                        stringArrayAfterSplit.forEach(item -> {

                            concatenateStringStream.append(item);

                        });
                        // remove the <JSON> xml element and return the values
                        return Stream
                                .of(concatenateStringStream.toString().trim()
                                        .replace(XML_ELEMENT_START, AppConstants.CONSTANT_NO_SPACE)
                                        .replace(XML_ELEMENT_END, AppConstants.CONSTANT_NO_SPACE));
                        // collect it as a new list of strings with the xmlelement - <JSON> removed
                    }).collect(Collectors.toList());

            // Join the list to make it one
            String finalString = String.join(AppConstants.CONSTANT_NO_SPACE, xmlStringList);

            // write to the outputstream with JSON mediatype
            response.getOutputStream().write(finalString.getBytes());
        } else {
            response.getOutputStream().write(bytes);
        }

    }

    @Override
    public void destroy() {
    }

}
公共类招摇过市过滤器i