我遇到过类似的问题,建议您使用 Servlet Filters 来解决它。
Servlet 过滤器是 Java 类,可在 Servlet 编程中使用,在客户端访问后端资源之前拦截来自客户端的请求,或者在将来自服务器的响应发送回客户端之前对其进行操作。
您的过滤器必须实现 javax.servlet.Filter 接口并重写三个方法:
public void doFilter (ServletRequest, ServletResponse, FilterChain)
每当由于客户端请求链末端的资源而导致请求/响应对通过链时,都会调用此方法。
public void init(FilterConfig filterConfig)
在过滤器投入使用之前调用,并设置过滤器的配置对象。
public void destroy()
过滤器停止使用后调用。
可以使用任意数量的过滤器,并且执行顺序将与它们在 web.xml 中定义的顺序相同。
web.xml:
...
<filter>
<filter-name>restResponseFilter</filter-name>
<filter-class>
com.package.filters.ResponseFilter
</filter-class>
</filter>
<filter>
<filter-name>anotherFilter</filter-name>
<filter-class>
com.package.filters.AnotherFilter
</filter-class>
</filter>
...
因此,此过滤器获取控制器响应,将其转换为 String,将其作为 feild 添加到 RestResponse 类对象(带有状态和消息字段),将其对象序列化为 Json 并将完整响应发送到客户端。
响应过滤器类:
public final class ResponseFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
ResponseWrapper responseWrapper = new ResponseWrapper((HttpServletResponse) response);
chain.doFilter(request, responseWrapper);
String responseContent = new String(responseWrapper.getDataStream());
RestResponse fullResponse = new RestResponse(/*status*/, /*message*/,responseContent);
byte[] responseToSend = restResponseBytes(fullResponse);
response.getOutputStream().write(responseToSend);
}
@Override
public void destroy() {
}
private byte[] restResponseBytes(RestResponse response) throws IOException {
String serialized = new ObjectMapper().writeValueAsString(response);
return serialized.getBytes();
}
}
chain.doFilter(request, responseWrapper) 方法调用链中的下一个过滤器,或者如果调用过滤器是链中的最后一个过滤器,则调用 servlet 逻辑。
HTTP Servlet 响应包装器使用自定义 Servlet 输出流,该输出流允许包装器在 Servlet 完成写出响应数据后对其进行操作。通常,在 servlet 输出流关闭后(本质上是在 servlet 提交它之后),无法执行此操作。这就是对 ServletOutputStream 类实现特定于过滤器的扩展的原因。
过滤ServletOutputStream类:
public class FilterServletOutputStream extends ServletOutputStream {
DataOutputStream output;
public FilterServletOutputStream(OutputStream output) {
this.output = new DataOutputStream(output);
}
@Override
public void write(int arg0) throws IOException {
output.write(arg0);
}
@Override
public void write(byte[] arg0, int arg1, int arg2) throws IOException {
output.write(arg0, arg1, arg2);
}
@Override
public void write(byte[] arg0) throws IOException {
output.write(arg0);
}
}
要使用 FilterServletOutputStream 类,应该实现一个可以充当响应对象的类。该包装器对象将代替 servlet 生成的原始响应发送回客户端。
响应包装类:
public class ResponseWrapper extends HttpServletResponseWrapper {
ByteArrayOutputStream output;
FilterServletOutputStream filterOutput;
HttpResponseStatus status = HttpResponseStatus.OK;
public ResponseWrapper(HttpServletResponse response) {
super(response);
output = new ByteArrayOutputStream();
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
if (filterOutput == null) {
filterOutput = new FilterServletOutputStream(output);
}
return filterOutput;
}
public byte[] getDataStream() {
return output.toByteArray();
}
}
我认为这种方法将很好地解决您的问题。
如果有不清楚的地方,请提出问题,如果我错了,请纠正我。