JSP生成Excel电子表格(XLS)下载

时间:2009-01-25 16:22:43

标签: java excel jsp tomcat export

我有这个应用程序我正在使用JSP进行开发,我希望以XLS(MS Excel格式)从数据库中导出一些数据。

是否可以在tomcat下编写一个文件,就像它是普通的Java应用程序一样,然后生成一个指向该文件的链接?或者我是否需要使用特定的API?

这样做会有权限问题吗?

6 个答案:

答案 0 :(得分:9)

虽然您可以使用JExcelAPI等完整的库,但如果您将响应MIME类型设置为“application / vnd.ms-excel”,Excel也会读取CSV和纯HTML表格。

根据电子表格的复杂程度,CSV或HTML可以在没有第三方库的情况下为您完成工作。

答案 1 :(得分:9)

不要使用带有application/vnd.ms-excel内容类型的纯HTML表格。然后,您基本上使用错误的内容类型欺骗Excel,这会导致最新Excel版本中的失败和/或警告。当您编辑并将其保存在Excel中时,它还会弄乱原始HTML源代码。只是不要这样做。

CSV反过来是一种标准格式,它可以毫无问题地享受Excel的默认支持,实际上生成简单且内存效率高。虽然有图书馆出来,但事实上你也可以轻松地在不到20行中写出一个(对于那些无法抗拒的人来说很有趣)。您只需遵守RFC 4180规范,该规范基本上只包含3条规则:

  1. 字段以逗号分隔。
  2. 如果字段中出现逗号,则该字段必须用双引号括起来。
  3. 如果字段中出现双引号,则该字段必须用双引号括起来,并且该字段中的双引号必须通过另一个双引号进行转义。
  4. 这是一个启动示例:

    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 pathinfo,因为Redmond的团队开发的某个web浏览器不会以正确的文件名保存下载。

答案 2 :(得分:3)

您可能需要一个库来操作Excel文件,例如JExcelAPI(“jxl”)或POI。我对jxl更熟悉,它肯定可以写文件。您可以通过提供URL来生成它们并存储它们,但我不会。生成的文件很痛苦。它们在形式上增加了并发性,清理过程等方面的复杂性。

如果您可以动态生成文件并通过标准servlet机制将其流式传输到客户端。

如果生成了很多次,有时候或者生成都很昂贵,那么你可以以某种方式缓存结果但是我更倾向于将它保存在内存而不是文件中。如果可以的话,我当然会避免通过URL直接链接到生成的文件。如果您通过servlet,它将允许您稍后更改您的实现。它与OO dsign中的封装概念相同。

答案 3 :(得分:1)

POI或JExcel是很好的API。我个人喜欢更好的POI,加上POI不断更新。此外,如果您有任何疑问,有关POI的在线资源比JExcel更多。但是,两者中的任何一个都做得很好。

答案 4 :(得分:0)

也许您应该考虑使用一些报告工具,并选择将文件导出为XLS格式。我的建议是JasperReports

答案 5 :(得分:0)

  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();

    }