我正在开发一个 Java Web 应用程序,其中的文件将存储在数据库中。最初,我们通过简单地在我们的结果集上调用
getBytes
来检索已经在数据库中的文件:
byte[] bytes = resultSet.getBytes(1);
...
然后使用明显的构造函数将此字节数组转换为
DataHandler
:
dataHandler = new DataHandler(bytes, "application/octet-stream");
在我们开始尝试存储和检索更大的文件之前,这一直很有效。将整个文件内容转储到一个字节数组中,然后从中构建一个
DataHandler
只需要太多内存。
我的直接想法是使用
getBinaryStream
检索数据库中的数据流,并以某种方式以内存高效的方式将 InputStream
转换为 DataHandler
。不幸的是,似乎没有直接的方法可以将 InputStream
转换为 DataHandler
。我一直在玩的另一个想法是从InputStream
读取数据块并将它们写入OutputStream
的DataHandler
。但是......我找不到创建一个“空”DataHandler
的方法,当我调用OutputStream
...时返回非空
getOutputStream
有人做过吗?我很感激你能给我的任何帮助或引导正确的方向。
首先,创建一个辅助类,它从 InputStream 创建一个数据源:
public class InputStreamDataSource implements DataSource {
private InputStream inputStream;
public InputStreamDataSource(InputStream inputStream) {
this.inputStream = inputStream;
}
@Override
public InputStream getInputStream() throws IOException {
return inputStream;
}
@Override
public OutputStream getOutputStream() throws IOException {
throw new UnsupportedOperationException("Not implemented");
}
@Override
public String getContentType() {
return "*/*";
}
@Override
public String getName() {
return "InputStreamDataSource";
}
}
然后您可以从 InputStream 创建 DataHandler:
DataHandler dataHandler = new DataHandler(new InputStreamDataSource(inputStream))
进口:
import javax.activation.DataSource;
import java.io.OutputStream;
import java.io.InputStream;
我也遇到了这个问题。如果您的源数据是
byte[]
,Axis 已经有一个包装 InputStream 并创建 DataHandler 对象的类。这是代码
// This constructor takes byte[] as input
ByteArrayDataSource rawData = new ByteArrayDataSource(resultSet.getBytes(1));
DataHandler data = new DataHandler(rawData);
yourObject.setData(data);
相关进口
import javax.activation.DataHandler;
import org.apache.axiom.attachments.ByteArrayDataSource;
我的方法是编写一个自定义类来实现
DataSource
来包装您的 InputStream
。然后创建 DataHandler
给它创建的 DataSource
.
注意DataSource的getInputStream每次调用都要返回一个新的InputStream。这意味着您需要先将其复制到某个地方。
有关更多信息,请参阅 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4267294
bugs_ 的代码 对我不起作用。我使用 DataSource 创建 attachments 到电子邮件(从具有 inputStream 和 name 的对象)和丢失的附件内容。
看起来 Stefan 是对的,每次都必须返回一个新的 inputStream。至少在我的具体情况下。以下实现解决了这个问题:
public class InputStreamDataSource implements DataSource {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
private final String name;
public InputStreamDataSource(InputStream inputStream, String name) {
this.name = name;
try {
int nRead;
byte[] data = new byte[16384];
while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
buffer.flush();
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public String getContentType() {
return new MimetypesFileTypeMap().getContentType(name);
}
@Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(buffer.toByteArray());
}
@Override
public String getName() {
return name;
}
@Override
public OutputStream getOutputStream() throws IOException {
throw new IOException("Read-only data");
}
}
我遇到过
InputStream
从 DataSource
请求两次的情况:使用 logging handler 和 MTOM feature.
有了这个代理流解决方案,我的实现工作正常:
import org.apache.commons.io.input.CloseShieldInputStream;
import javax.activation.DataHandler;
import javax.activation.DataSource;
...
private static class InputStreamDataSource implements DataSource {
private InputStream inputStream;
@Override
public InputStream getInputStream() throws IOException {
return new CloseShieldInputStream(inputStream);
}
@Override
public OutputStream getOutputStream() throws IOException {
throw new UnsupportedOperationException("Not implemented");
}
@Override
public String getContentType() {
return "application/octet-stream";
}
@Override
public String getName() {
return "";
}
}
这是专门使用 Spring Boot org.springframework.core.io.Resource 对象的答案,我认为这是我们很多人到达这里的原因。请注意,您可能需要修改以下代码中的内容类型,因为我将 PNG 文件插入到 HTML 格式的电子邮件中。
注意:正如其他人所提到的,仅仅附加一个 InputStream 是不够的,因为它会被多次使用。只需映射到 Resource.getInputStream() 就可以了。
public class SpringResourceDataSource implements DataSource {
private Resource resource;
public SpringResourceDataSource(Resource resource) {
this.resource = resource;
}
@Override
public InputStream getInputStream() throws IOException {
return resource.getInputStream();
}
@Override
public OutputStream getOutputStream() throws IOException {
throw new UnsupportedOperationException("Not implemented");
}
@Override
public String getContentType() {
return "image/png";
}
@Override
public String getName() {
return "SpringResourceDataSource";
}
}
类的用法如下所示:
PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
Resource logoImage = pathMatchingResourcePatternResolver.getResource("/static/images/logo.png");
MimeBodyPart logoBodyPart = new MimeBodyPart();
DataSource logoFileDataSource = new SpringResourceDataSource(logoImage);
logoBodyPart.setDataHandler(new DataHandler(logoFileDataSource));
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import org.apache.commons.io.IOUtils;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
.
.
.
DataSource ds = new ByteArrayDataSource(convertHtmlToPdf("<span>html here</span>"), "application/pdf");
DataHandler dataHandler = new DataHandler(ds);
.
.
.
public static byte[] convertHtmlToPdf(String htmlString) throws IOException, DocumentException {
Document document = new Document();
ByteArrayOutputStream out = new ByteArrayOutputStream();
PdfWriter writer = PdfWriter.getInstance(document, out);
document.open();
InputStream in = IOUtils.toInputStream(htmlString);
XMLWorkerHelper.getInstance().parseXHtml(writer, document, in);
document.close();
return out.toByteArray();
}
可能的错误:元标记必须关闭。
<meta></meta>