13

我意识到这是一个先有鸡还是先有蛋的问题,并且不可能准确地解决呈现页面所花费的时间(或响应的大小)并将该数字插入页面本身而不影响任何一项措施。不过,我正在寻找一种方法将任一数字部分插入 JSF/Facelets/Seam 应用程序的页面中。

例如,在 .jsf 页面的底部某处:

<!-- page size: 10.3Kb -->
<!-- render time: 0.2s -->

我遇到过 JSFUnit 的JSFTimer,它真的很方便。但是,阶段侦听器方法不允许将 RENDER_RESPONSE 阶段的结果插入到页面中。也不知道如何访问到目前为止编码的响应的大小。

是否有一种快速而肮脏的方法可以在 RENDER_RESPONSE 结束时或之后连接到某种后处理事件,并将两个数字都注入到即将呈现的页面中?解决这个问题的一种方法可能是通过 servlet 过滤器,但我正在寻找更简单的方法;也许是 Seam 或 Facelets 的一个技巧......

谢谢,
-A

4

3 回答 3

23

这是Apache Commons IO CountingOutputStream的完美用例。您需要创建一个Filter用于将响应的HttpServletResponseWrapper替换OutputStream为该响应的,并替换Writer应该包装被包装的OutputStream. 然后HttpServletResponseWrapper在请求范围内获取实例,以便您可以getByteCount()CountingOutputStream.

这是一个启动示例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.
    }

}

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();
    }

}

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();
    }

}

您可以在任何(甚至非 JSF)页面中使用它,如下所示:

<!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 -->
于 2010-07-11T01:36:27.180 回答
2

我写了一篇博客文章,解释了如何创建一个拦截器来测量每个方法调用你的接缝组件在哪里使用。

您可以在此处找到博客文章。您需要向下滚动到第二部分。

基本上,您需要做的就是注释您想要测量的方法 @MeasureCalls,它会自动被拦截器拾取

@Name("fooBean")
@MeasureCalls
public class FooBean

输出将是这样的,显示以毫秒为单位的时间以及每个方法被调用的次数:

284.94 ms   1   FooBean.getRandomDroplets()
284.56 ms   1   GahBean.getRandomDroplets()
201.60 ms   2   SohBean.searchRatedDoodlesWithinHead()
185.94 ms   1   FroBean.doSearchPopular()
157.63 ms   1   FroBean.doSearchRecent()
 42.34 ms   1   FooBean.fetchMostRecentYodel()
 41.94 ms   1   GahBean.getMostRecentYodel()
 15.89 ms   1   FooBean.getNoOfYodels()
 15.00 ms   1   GahBean.getNoOfYodels()
  9.14 ms   1   SohBean.mainYodels()
  1.11 ms   2   SohBean.trackHoorayEvent()
  0.32 ms   1   FroBean.reset()
  0.22 ms  43   NohBean.thumbPicture()
  0.03 ms  18   FooBean.getMostRecentYodels()
  0.01 ms   1   NohBean.profilePicture()
  0.01 ms   1   FroBean.setToDefault()
  0.01 ms   1   FroBean.getRecentMarker() 
于 2011-01-21T15:53:30.567 回答
0

或者有一个异步 Javascript 调用在服务器准备好后从服务器获取响应时间和大小?将其视为在页面加载完成并且值已准备好插入后执行的回调。

于 2010-07-10T21:16:51.383 回答