Java 如何防止有人在Vaadin 8中快速点击文件下载器按钮?

Java 如何防止有人在Vaadin 8中快速点击文件下载器按钮?,java,vaadin,vaadin8,Java,Vaadin,Vaadin8,使用来自的代码,我们有: 此示例代码的问题在于,有人可能会开始不停地快速单击下载按钮,而动态创建的文件将以用户可以单击的速度生成。有没有一种方法可以设置一个限制器,即在x次之后阻止用户下载?另外,如果您快速单击该限制器,您会得到一个错误,特别是一个DefaultErrorHandler 至少我希望有一种方法可以防止有人下载该文件超过x次。最好还有类似于downloadButton.disableOnClick()的东西但我似乎找不到在下载完成后重新启用的方法,因为下载完成时没有钩子通知您,但主要

使用来自的代码,我们有:

此示例代码的问题在于,有人可能会开始不停地快速单击
下载按钮
,而动态创建的文件将以用户可以单击的速度生成。有没有一种方法可以设置一个限制器,即在x次之后阻止用户下载?另外,如果您快速单击该限制器,您会得到一个错误,特别是一个
DefaultErrorHandler


至少我希望有一种方法可以防止有人下载该文件超过x次。最好还有类似于
downloadButton.disableOnClick()的东西
但我似乎找不到在下载完成后重新启用的方法,因为下载完成时没有钩子通知您,但主要目标是阻止某人连续下载50次。

以下是一个在下载50次后禁用按钮的解决方案。我将按钮作为参数添加到createResource。如果它将保持在同一类中,则不一定需要该参数

int downloaded = 0;
private StreamResource createResource(Button downloadButton) {
    return new StreamResource(new StreamSource() {
        @Override
        public InputStream getStream() {
            downloaded++;
            if (downloaded > 50)
            {
                downloadButton.setEnabled(false);
            }
            .. generate your InputStream
        }
    }, "myImage.png");
}
免责声明:我正在使用Vaadin7,但语法似乎没有改变。

为此:

但我似乎找不到在下载完成后重新启用的方法,因为没有钩子在下载完成时通知您

不,据我所知,没有钩子可以让浏览器的下载功能从客户端告诉Vaadin dowload何时准备好了

但是,可能是服务器端解决方案

我相信您可以从
StreamResource
创建
Resource
,并在后者中实现:

@Override
public InputStream getStream() {
    return s;
}
当流
s
关闭时,可以认为下载已准备就绪。但是,
InputStream.close()
也没有钩子。为此,您可以为
InputStream
实现包装器实现,如:

@Slf4j
@RequiredArgsConstructor
public class CloseNotifyingInputStream extends InputStream  {

    @FunctionalInterface
    public static interface InputStreamCloseListener {
        public void onInputStreamClose(CloseNotifyingInputStream closeNotifyingInputStream);
    }

    private final InputStream wrappedStream;
    private final InputStreamCloseListener closeListener;

    @Override
    public synchronized int read() throws IOException {
        return wrappedStream.read();
    }

    @Override
    public void close() throws IOException  {
        log.info("Download complete, closing stream");
        closeListener.onInputStreamClose(this);
        wrappedStream.close();          
        super.close();
    }
}
使用这种包装器,您可以在回调函数的帮助下得到一个通知,然后处理您决定实现的任何按钮逻辑

最后,您在
getStream()
中的
s
将如下所示:

new CloseNotifyingInputStream(getTheActualInputStream(),
            cnis -> log.info("Handling the btn logic")
);
`

Viritin(Vaadin add-on)DownloadButton现在支持在内容发送到客户端时执行逻辑。要显示这些信息,您需要启用推送功能,或者在UI中添加轮询间隔

请参阅项目测试源中的示例代码。它使用按钮的disableOnClick功能,但在内容写入浏览器后重新启用按钮:


当您在单击后禁用按钮时?主要问题是如何防止有人连续下载50x。忽略这一点,不是如何重新启用按钮,而是何时重新启用?下载完成时,没有挂钩可以让您知道。是否可以阻止下载10秒钟,然后重新启用它?这不是真的,因为我们确实有一些人需要稍微调整报告设置(更改日期)并重新运行它。基本上,我是在试图防止有人通过点击同一个生成的报告来发送垃圾邮件。这与我现在所做的非常接近。问题是,我以50为例,它还可以防止人们意外双击,等等。双击可以通过阻止按钮一段时间来禁用。1可以解决这个问题。但我认为比尔霍斯的解决方案更好,更像你正在寻找的!
new CloseNotifyingInputStream(getTheActualInputStream(),
            cnis -> log.info("Handling the btn logic")
);