Jsf 如何将响应大小和时间插入页面本身(至少部分插入)?

Jsf 如何将响应大小和时间插入页面本身(至少部分插入)?,jsf,servlets,httpresponse,Jsf,Servlets,Httpresponse,我意识到这是一个鸡和蛋的问题,不可能准确地解决呈现页面所需的时间(或响应的大小),并在不影响任何一个度量的情况下将该数字插入页面本身。尽管如此,我仍在寻找一种在JSF/Facelets/Seam应用程序的页面中部分插入任意一个数字的方法 例如,在.jsf页面底部的某个地方: <!-- page size: 10.3Kb --> <!-- render time: 0.2s --> 我遇到过JSF单元,它非常方便。但是,阶段侦听器方法不允许将RENDER_响应阶段的结

我意识到这是一个鸡和蛋的问题,不可能准确地解决呈现页面所需的时间(或响应的大小),并在不影响任何一个度量的情况下将该数字插入页面本身。尽管如此,我仍在寻找一种在JSF/Facelets/Seam应用程序的页面中部分插入任意一个数字的方法

例如,在.jsf页面底部的某个地方:

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

我遇到过JSF单元,它非常方便。但是,阶段侦听器方法不允许将RENDER_响应阶段的结果插入到页面中。也不确定如何访问到目前为止编码的响应的大小

在RENDER_响应结束时或之后,是否有一种快速而肮脏的方式连接到某种后处理事件,并将这两个数字都注入即将呈现的页面?实现这一点的一种方法可能是通过servlet过滤器,但我正在寻找更简单的方法;也许是缝线或小脸孔的把戏

谢谢,

-一个

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

这是一个完美的应用程序用例。您需要创建一个
过滤器
,该过滤器用于将响应的
OutputStream
替换为该过滤器,并替换
Writer
,Writer也应包装包装的
OutputStream
。然后在请求范围中获取
HttpServletResponseWrapper
实例,以便可以从
CountingOutputStream
获取
getByteCount()

下面是
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 -->

计数演示
你好,世界

我写了一篇博客文章,解释了如何创建一个拦截器,用于测量使用seam组件的每个方法调用

你可以找到这篇博文。 您需要向下滚动到第二部分

基本上,您所需要做的就是注释您想要测量的方法
@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() 

虽然我很想避免使用过滤器,但这似乎是最好的方法。谢谢你的建议!这里有一些需要注意的事情:1)使用Seam,过滤器很容易用注释设置,例如:@Scope(APPLICATION)@Name(“org.myorg.countingFilter”)@BypassInterceptors@Filter(around=“org.jboss.Seam.web.ajax4jsfFilter”)countingFilter 2)由于上面提到的鸡/蛋问题,数字并不完全准确。在JSF下,ViewState被排除在字节数之外,字节数可能是一个重要的数字。这同样适用于渲染时间。这两个都很好,足以描绘一幅粗略的画面。又是很棒的东西。但是,我有几个回发请求,它们正在生成几个响应。如何找到正确的响应,即我想要分析的响应?@Kawu:相应地更改筛选器的URL模式,使其仅在所需的URL上运行。部分(AJAX)请求/响应如何?它似乎显示了正确的一个,但我想确保它不是巧合。@Kawu:Ajax请求通过
Faces-Request
头的存在来识别,头的值为
Partial/Ajax
。看起来很方便。您的
toString()
:有一个
类#getSimpleName()
String#format()
@Shervin,谢谢您的解决方案。我尝试将它与CDIBeans(无Seam框架)一起使用,它几乎可以工作,但我不明白加载完成后如何显示统计信息?或者您经常在控制台中打印更新的控制台?当多页应用程序加载完成时,是否有办法确定?非常感谢。