Questo è un caso d'uso perfetto per il Apache Commons IOCountingOutputStream
. È necessario creare un Filter
che utilizzi HttpServletResponseWrapper
per sostituire lo OutputStream
della risposta con questo e sostituisca anche lo Writer
che dovrebbe avvolgere l'involucro OutputStream
. Quindi acquisire l'istanza HttpServletResponseWrapper
nell'ambito della richiesta in modo da poter ottenere getByteCount()
da CountingOutputStream
.
Ecco un esempio calcio d'inizio della CountingFilter
:
public class CountingFilter implements Filter {
@Override
public void init(FilterConfig arg0) throws ServletException {
// NOOP.
}
@Override
public void doFilter(ServletRequest request, final ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletResponse httpres = (HttpServletResponse) response;
CountingServletResponse counter = new CountingServletResponse(httpres);
HttpServletRequest httpreq = (HttpServletRequest) request;
httpreq.setAttribute("counter", counter);
chain.doFilter(request, counter);
counter.flushBuffer(); // Push the last bits containing HTML comment.
}
@Override
public void destroy() {
// NOOP.
}
}
Il CountingServletResponse
:
public class CountingServletResponse extends HttpServletResponseWrapper {
private final long startTime;
private final CountingServletOutputStream output;
private final PrintWriter writer;
public CountingServletResponse(HttpServletResponse response) throws IOException {
super(response);
startTime = System.nanoTime();
output = new CountingServletOutputStream(response.getOutputStream());
writer = new PrintWriter(output, true);
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
return output;
}
@Override
public PrintWriter getWriter() throws IOException {
return writer;
}
@Override
public void flushBuffer() throws IOException {
writer.flush();
}
public long getElapsedTime() {
return System.nanoTime() - startTime;
}
public long getByteCount() throws IOException {
flushBuffer(); // Ensure that all bytes are written at this point.
return output.getByteCount();
}
}
Il CountingServletOutputStream
:
public class CountingServletOutputStream extends ServletOutputStream {
private final CountingOutputStream output;
public CountingServletOutputStream(ServletOutputStream output) {
this.output = new CountingOutputStream(output);
}
@Override
public void write(int b) throws IOException {
output.write(b);
}
@Override
public void flush() throws IOException {
output.flush();
}
public long getByteCount() {
return output.getByteCount();
}
}
è possibile utilizzarlo in qualsiasi (anche non-JSF pagina come segue:
<!DOCTYPE html>
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<title>Counting demo</title>
</h:head>
<h:body>
<h1>Hello World</h1>
</h:body>
</html>
<!-- page size: #{counter.byteCount/1000}KB -->
<!-- render time: #{counter.elapsedTime/1000000}ms -->
Per quanto volessi evitare i filtri, questo sembra l'approccio migliore. Grazie per il suggerimento! Ecco alcune cose da tenere a mente: 1) con Seam, i filtri sono piuttosto facili da configurare con annotazioni, ad esempio: @Scope (APPLICATION) @Name ("org.myorg.countingFilter") @BypassInterceptors @Filter (circa = "org.jboss.seam.web.ajax4jsfFilter") CountingFilter 2) a causa di problemi di pollo/uova annotati sopra i numeri non sono completamente accurati. Sotto JSF, ViewState viene escluso dal byteCount, che può essere un numero significativo. Lo stesso vale per il rendering del tempo. Entrambi sono abbastanza buoni per un'immagine approssimativa però. – anikitin
Ancora cose fantastiche. Tuttavia, ho diverse richieste di postback, che generano diverse risposte. Come trovo la risposta corretta, cioè quella che intendevo per profilo? – Kawu
@Kawu: modifica il pattern URL del filtro in modo che venga eseguito solo sugli URL desiderati. – BalusC