我试图将Vaadin 8 FileDropTarget与Tomcat服务器一起使用。示例代码有点长,但它可能适合这里:
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;
import com.vaadin.server.StreamVariable;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Label;
import com.vaadin.ui.Notification;
import com.vaadin.ui.ProgressBar;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.dnd.FileDropTarget;
import hu.dynaxpress.base.mvc.DynaAbstractController;
@SuppressWarnings({ "serial", "rawtypes" })
public class FileStreamController extends DynaAbstractController {
private VerticalLayout layout;
private ProgressBar progress;
@Override
protected void onInit() {
super.onInit();
System.err.println("FileStreamController.onInit");
}
@Override
protected void onEnter() {
System.err.println("FileStreamController.onEnter");
// https://vaadin.com/docs/v8/framework/components/components-upload.html
layout = new VerticalLayout();
final Label infoLabel = new Label("DROP A FILE ON THIS TEXT");
infoLabel.setWidth(240.0f, Unit.PIXELS);
final VerticalLayout dropPane = new VerticalLayout(infoLabel);
dropPane.setComponentAlignment(infoLabel, Alignment.MIDDLE_CENTER);
dropPane.addStyleName("drop-area");
dropPane.setSizeUndefined();
dropPane.setWidth("100%");
progress = new ProgressBar();
progress.setIndeterminate(false);
progress.setVisible(false);
progress.setWidth("100%");
dropPane.addComponent(progress);
layout.addComponent(dropPane);
new FileDropTarget<>(dropPane, fileDropEvent -> {
final long fileSizeLimit = 20 * 1024 * 1024 * 1024; // 20GB
fileDropEvent.getFiles().forEach(html5File -> {
// html5File.getFileSize() always returns zero, but why?
if (false && ( html5File.getFileSize() > fileSizeLimit) ) {
Notification.show(
"File rejected. Max size=" +fileSizeLimit+ ", actual="+html5File.getFileSize(),
Notification.Type.WARNING_MESSAGE);
} else {
Label lbl = new Label(html5File.getFileName() + " size=" + html5File.getFileSize() + " " + html5File.getType());
lbl.setWidth("100%");
layout.addComponent(lbl);
final StreamVariable streamVariable = new StreamVariable() {
@Override
public OutputStream getOutputStream() {
try {
return new FileOutputStream("F:\\"+html5File.getFileName());
} catch (FileNotFoundException e) {
e.printStackTrace();
throw new Error("F:\\"+html5File.getFileName());
}
}
@Override
public boolean listenProgress() { return false; }
@Override
public void onProgress(final StreamingProgressEvent event) {
progress.setValue(
event.getBytesReceived() / event.getContentLength()
);
}
@Override
public void streamingStarted(
final StreamingStartEvent event) {
progress.setVisible(true);
progress.setCaption(event.getFileName());
}
@Override
public void streamingFinished(
final StreamingEndEvent event) {
progress.setVisible(false);
}
@Override
public void streamingFailed(final StreamingErrorEvent event) {
progress.setVisible(false);
}
@Override
public boolean isInterrupted() { return false; }
};
html5File.setStreamVariable(streamVariable);
progress.setVisible(true);
}
});
});
setCompositionRoot(layout);
}
}
此代码有效,但它具有可怕的性能。在此MWE中,程序将所有删除的文件写入F:\驱动器。它是一个闪存驱动器(我想模拟流式大文件,看看随着时间的推移消耗了多少内存)。但是我发现这个程序在20秒内写出了一个40MB的文件。那是2MB / sec的速度。服务器在localhost上运行,源文件和目标F:驱动器都在我的本地计算机上。如果我只是将同一个文件复制到驱动器上,则只需不到2秒钟。
我也尝试过另一个(非常慢)的闪存驱动器,并且有类似的结果。当tomcat正在流式传输文件时,它的速度要慢10到20倍。
有没有办法让它更快?我究竟做错了什么?我没有看到任何加快速度的方法,因为流式传输发生在组件内部。
第二个重要(无相关)问题是为什么我无法获得文件大小?请参阅代码中的注释:&#34; html5File.getFileSize()始终返回零,但为什么?&#34;我从firefox调试器检查了POST头,浏览器在发送实际文件数据之前,在JSON / RPC调用中发送文件的大小。因此,服务器应该在第一个字节到达之前知道文件大小。