我有这个在 JSP 中开发的应用程序,我希望以 XLS(MS Excel 格式)从数据库中导出一些数据。
在tomcat下是否可以像普通Java应用程序一样编写文件,然后生成指向该文件的链接?还是我需要为此使用特定的 API?
这样做时我会遇到权限问题吗?
虽然您可以使用像JExcelAPI这样的完整库,但如果您将响应 MIME 类型设置为“application/vnd.ms-excel”之类的内容,Excel 还将读取 CSV 和纯 HTML 表格。
根据电子表格需要的复杂程度,CSV 或 HTML 可以在没有第三方库的情况下为您完成这项工作。
不要使用带有application/vnd.ms-excel
内容类型的纯 HTML 表格。然后,您基本上是在用错误的内容类型欺骗 Excel,这将导致最新 Excel 版本中的失败和/或警告。当您在 Excel 中编辑和保存原始 HTML 源代码时,它也会弄乱它。只是不要那样做。
反过来,CSV 是一种标准格式,它可以毫无问题地从 Excel 中获得默认支持,并且实际上生成起来很容易且节省内存。尽管有库,但实际上您也可以轻松地在不到 20 行中编写一个(对于那些无法抗拒的人来说很有趣)。您只需要遵守RFC 4180规范,它基本上只包含 3 条规则:
这是一个启动示例:
public static <T> void writeCsv (List<List<T>> csv, char separator, OutputStream output) throws IOException {
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(output, "UTF-8"));
for (List<T> row : csv) {
for (Iterator<T> iter = row.iterator(); iter.hasNext();) {
String field = String.valueOf(iter.next()).replace("\"", "\"\"");
if (field.indexOf(separator) > -1 || field.indexOf('"') > -1) {
field = '"' + field + '"';
}
writer.append(field);
if (iter.hasNext()) {
writer.append(separator);
}
}
writer.newLine();
}
writer.flush();
}
这是一个如何使用它的示例:
public static void main(String[] args) throws IOException {
List<List<String>> csv = new ArrayList<List<String>>();
csv.add(Arrays.asList("field1", "field2", "field3"));
csv.add(Arrays.asList("field1,", "field2", "fie\"ld3"));
csv.add(Arrays.asList("\"field1\"", ",field2,", ",\",\",\""));
writeCsv(csv, ',', System.out);
}
在 Servlet 内部(是的,Servlet,不要为此使用 JSP!)您基本上可以这样做:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String filename = request.getPathInfo().substring(1);
List<List<Object>> csv = someDAO().findCsvContentFor(filename);
response.setHeader("content-type", "text/csv");
response.setHeader("content-disposition", "attachment;filename=\"" + filename + "\"");
writeCsv(csv, ';', response.getOutputStream());
}
将此 servlet 映射到类似的东西上/csv/*
并将其调用为类似http://example.com/context/csv/filename.csv
. 就这样。
请注意,我添加了单独指定分隔符的可能性,因为它可能取决于使用的语言环境,Excel 是否接受逗号,
或分号;
作为 CSV 字段分隔符。请注意,我还将文件名添加到 URL 路径信息中,因为由 Redmond 的团队开发的某个网络浏览器不会使用正确的文件名保存下载。
您可能需要一个库来操作 Excel 文件,例如JExcelAPI ("jxl") 或POI。我对jxl比较熟悉,它当然可以写文件。您可以通过向它们提供 URL 来生成和存储它们,但我不会。生成的文件很痛苦。它们在并发、清理过程等方面增加了复杂性。
如果您可以动态生成文件并通过标准 servlet 机制将其流式传输到客户端。
如果它生成了很多次,或者生成很昂贵,那么您可以以某种方式缓存结果,但我更倾向于将其保存在内存中而不是作为文件。如果可以的话,我当然会避免通过 URL 直接链接到生成的文件。如果您通过一个 servlet,它将允许您稍后更改您的实施。这与 OO 设计中的封装概念相同。
POI 或 JExcel 是很好的 API。我个人喜欢更好的 POI,而且 POI 会不断更新。此外,如果您有任何问题,网上有比 JExcel 更多的关于 POI 的资源。但是,两者中的任何一个都做得很好。
也许您应该考虑使用一些报告工具,可以选择将文件导出为 XLS 格式。我的建议是 JasperReports
try {
String absoluteDiskPath = test.xls";
File f = new File(absoluteDiskPath);
response.setContentType("application/xlsx");
response.setHeader("Content-Disposition", "attachment; filename=" + absoluteDiskPath);
String name = f.getName().substring(f.getName().lastIndexOf("/") + 1, f.getName().length());
InputStream in = new FileInputStream(f);
out.clear(); //clear outputStream prevent illegalStateException write binary data to outputStream
ServletOutputStream outs = response.getOutputStream();
int bit = 256;
int i = 0;
try {
while ((bit) >= 0) {
bit = in.read();
outs.write(bit);
}
outs.flush();
outs.close();
in.close();
} catch (IOException ioe) {
ioe.printStackTrace();
} finally {
try {
if(outs != null)
outs.close();
if(in != null)
in.close();
}catch (Exception ioe2) {
ioe2.printStackTrace();
}
}
} catch (Exception ex) {
ex.printStackTrace();
}