JSP生成Excel电子表格(XLS)进行下载
我有我在JSP中开发的这个应用程序,我希望从XLS(MS Excel格式)的数据库中导出一些数据。
是否有可能在tomcat下编写一个文件,就像它是一个普通的Java应用程序,然后生成一个链接到这个文件? 或者我需要使用特定的API吗?
这样做的时候我会有权限问题吗?
虽然可以使用像JExcelAPI这样的完整库,但是如果您将响应MIMEtypes设置为“application / vnd.ms-excel”,Excel也将读取CSV和纯HTML表格。
根据电子表格的复杂程度,CSV或HTML可以在没有第三方库的情况下为您完成这项工作。
不要将纯HTML表格与application/vnd.ms-excel
内容types一起使用。 那么你基本上是用错误的内容types来欺骗Excel,这会在最新的Excel版本中导致失败和/或警告。 当您编辑并保存在Excel中时,它也会混淆原始的HTML源代码。 只是不要这样做。
CSV反过来是一个标准格式,它可以在没有任何问题的情况下享受Excel的默认支持,而且实际上很容易和高效的生成。 虽然有图书馆,但事实上也可以很容易地写出一个不到20行(对于那些无法抗拒的人)。 你只需要遵守基本上只包含3条规则的RFC 4180规范:
- 字段用逗号分隔。
- 如果在一个字段中出现逗号,则该字段必须用双引号包围。
- 如果在一个字段中出现双引号,则该字段必须用双引号包围,并且该字段中的双引号必须用另一个双引号转义。
这是一个开球的例子:
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
那样调用它。 就这样。
请注意,我添加了可能性来单独指定分隔符,因为它可能取决于所使用的语言环境,而不pipeExcel是接受逗号还是分号;
作为CSV字段分隔符。 请注意,我还将文件名添加到URL pathinfo中,因为由Redmond中的团队开发的某个Web浏览器不会使用正确的文件名保存下载。
您可能需要一个库来操作Excel文件,如JExcelAPI (“jxl”)或POI 。 我更熟悉jxl,它当然可以写文件。 你可以生成它们并通过向它们提供一个URL来存储它们,但我不会。 生成的文件是一个痛苦。 他们在并发,清理过程等方面增加了复杂性。
如果您可以即时生成文件并通过标准servlet机制将其stream式传输到客户端。
如果它产生了很多,可能是时代或代价昂贵,那么你可以caching结果不知何故,但我更倾向于保存在内存中,而不是作为一个文件。 如果可以的话,我一定会避免,通过URL直接链接到生成的文件。 如果你通过一个servlet,它会允许你稍后改变你的实现。 这与OOdevise中的封装概念是一样的。
也许你应该考虑使用一些报告工具,将文件导出为XLS格式。 我的build议是JasperReports
POI或JExcel是很好的API。 我个人喜欢更好的POI,加上POI不断更新。 此外,如果您有任何疑问,网上有关于POI的资源比JExcel更多。 但是,两者中的任何一个都做得很好。
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(); }