第二次单击带有 StreamResource 的 Vaadin link 不起作用
Second click to Vaadin link with StreamResource doesn't work
我有一个来自另一台服务器的 InputStream(来自 JasperReports 的 PDF 文件)并且用户可以下载它。
...
VerticalLayout content;
OperationResult<InputStream> jresult;
...
final InputStream ent=jresult.getEntity();
if (ent.available()<=0) return;
Link link = new Link();
link.setCaption("Download the report");
link.setResource(new StreamResource(new StreamSource(){
private static final long serialVersionUID = 1L;
@Override
public InputStream getStream() {
return ent;
}
}, "FileName.pdf"));
content.addComponent(link);
如果打印服务器returns页面,"Download the report"会出现,用户可以点击下载PDF文件。但是第二次点击同一个 link 失败。它可能 returns 空内容。怎么了?也许我必须倒回输入流。怎么样?
那是因为您的 getStream() 方法 return 是相同的流,而流预计只会从中读取一次。一旦你消费了流中的数据,数据就不再可用了。
您可能需要先使用此方法将 InputStream 转换为字节 (taken from this SO question)
public static byte[] readFully(InputStream stream) throws IOException
{
byte[] buffer = new byte[8192];
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int bytesRead;
while ((bytesRead = stream.read(buffer)) != -1)
{
baos.write(buffer, 0, bytesRead);
}
return baos.toByteArray();
}
然后在 getStream()
方法中 return 每次新的 InputStream:
@Override
public InputStream getStream() {
return new ByteArrayInputStream(ent);
}
编辑解决方案 #2:就像@Hink 在评论中建议的那样,您也可以在 Stream 对象上调用 reset()。
我有一个来自另一台服务器的 InputStream(来自 JasperReports 的 PDF 文件)并且用户可以下载它。
...
VerticalLayout content;
OperationResult<InputStream> jresult;
...
final InputStream ent=jresult.getEntity();
if (ent.available()<=0) return;
Link link = new Link();
link.setCaption("Download the report");
link.setResource(new StreamResource(new StreamSource(){
private static final long serialVersionUID = 1L;
@Override
public InputStream getStream() {
return ent;
}
}, "FileName.pdf"));
content.addComponent(link);
如果打印服务器returns页面,"Download the report"会出现,用户可以点击下载PDF文件。但是第二次点击同一个 link 失败。它可能 returns 空内容。怎么了?也许我必须倒回输入流。怎么样?
那是因为您的 getStream() 方法 return 是相同的流,而流预计只会从中读取一次。一旦你消费了流中的数据,数据就不再可用了。
您可能需要先使用此方法将 InputStream 转换为字节 (taken from this SO question)
public static byte[] readFully(InputStream stream) throws IOException
{
byte[] buffer = new byte[8192];
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int bytesRead;
while ((bytesRead = stream.read(buffer)) != -1)
{
baos.write(buffer, 0, bytesRead);
}
return baos.toByteArray();
}
然后在 getStream()
方法中 return 每次新的 InputStream:
@Override
public InputStream getStream() {
return new ByteArrayInputStream(ent);
}
编辑解决方案 #2:就像@Hink 在评论中建议的那样,您也可以在 Stream 对象上调用 reset()。