利用HttpServletResponseWrapper劫持response输出流并保存到文件或内存数据库,实现可管理的服务端Http缓存
Wrapper包装类:
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.*;
/**
* author : ljzhang
*/
public class HttpUriCacheResponseWrapper extends HttpServletResponseWrapper {
public HttpUriCacheResponseWrapper(HttpServletResponse response) throws IOException {
super(response);
buffer = new ByteArrayOutputStream();
out = new WapperedOutputStream(buffer);
writer = new PrintWriter(new OutputStreamWriter(buffer));
}
private ByteArrayOutputStream buffer = null;
private ServletOutputStream out = null;
private PrintWriter writer = null;
@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) {
}
}
}
定义Filter:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* author : ljzhang
*/
public class HttpUriCacheFilter implements Filter {
private static Logger logger = LoggerFactory.getLogger(HttpUriCacheFilter.class);
private static Map<String,byte[]> cache = new ConcurrentHashMap<>();
FilterConfig filterConfig;
private Set<String> includedPages;
private PathMatchingResourcePatternResolver pathPatternResolver = new PathMatchingResourcePatternResolver();
public void setIncludedPages(Set<String> includedPages) {
this.includedPages = includedPages;
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
logger.info(" html cache filter init !!!");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
String ctx_path = httpServletRequest.getContextPath();
String request_uri = httpServletRequest.getRequestURI();
String action = request_uri.substring(ctx_path.length());
if (match(action)) {
logger.info(" html cache filter matched: uri [{}]",action);
ServletOutputStream out = servletResponse.getOutputStream();
byte[] data = cache.get(request_uri);
if(data == null){
logger.info(" html cache not found :uri [{}]",action);
HttpUriCacheResponseWrapper responseWrapper = new HttpUriCacheResponseWrapper((HttpServletResponse)servletResponse);
filterChain.doFilter(servletRequest,responseWrapper);
data = responseWrapper.getResponseData();
cache.put(request_uri,data);
}else{
logger.info(" html cache is found :uri [{}] ",action);
}
out.write(data);
out.flush();
}else{
filterChain.doFilter(servletRequest, servletResponse);
}
}
private boolean match(String path){
for (String includedPage : includedPages) {
if (pathPatternResolver.getPathMatcher().match(includedPage,path)) {
return true;
}
}
return false;
}
@Override
public void destroy() {
}
}
Demo代码,不代表最终实现