2009-01-25 44 views
5

Tôi có ứng dụng này tôi đang phát triển trong JSP và tôi muốn xuất một số dữ liệu từ cơ sở dữ liệu trong XLS (định dạng MS Excel).JSP tạo bảng tính Excel (XLS) để tải xuống

Có thể theo tomcat để chỉ viết một tệp như thể đó là một ứng dụng Java bình thường và sau đó tạo liên kết tới tệp này? Hay tôi cần sử dụng một API cụ thể cho nó?

Tôi có gặp sự cố về quyền khi thực hiện việc này không?

Trả lời

9

Trong khi bạn có thể sử dụng thư viện chính thức như JExcelAPI, Excel cũng sẽ đọc bảng CSV và HTML thuần túy miễn là bạn đã đặt kiểu MIME trả lời thành "application/vnd.ms-excel".

Tùy thuộc vào mức độ phức tạp của bảng tính, CSV hoặc HTML có thể thực hiện công việc cho bạn mà không cần thư viện của bên thứ ba.

+0

+1 cho mẹo "HTML thuần túy"; trong nhiều trường hợp, điều này sẽ thực hiện công việc và rất đơn giản. – Jonik

+1

giữ cho nó đơn giản thường là cách tốt nhất. Câu trả lời hay: – SWD

3

Có thể bạn sẽ cần một thư viện để thao tác các tệp Excel, như JExcelAPI ("jxl") hoặc POI. Tôi quen thuộc hơn với jxl và nó chắc chắn có thể ghi các tập tin. Bạn có thể tạo chúng và lưu trữ chúng bằng cách cung cấp một URL cho chúng nhưng tôi sẽ không. Các tệp được tạo ra là một nỗi đau. Chúng thêm biến chứng dưới dạng đồng thời, quá trình dọn dẹp, v.v.

Nếu bạn có thể tạo tệp trực tiếp và truyền trực tiếp đến máy khách thông qua các cơ chế servlet tiêu chuẩn.

Nếu nó được tạo ra nhiều, có thể thời gian hoặc thế hệ là tốn kém sau đó bạn có thể cache kết quả bằng cách nào đó nhưng tôi muốn có nhiều hơn để giữ nó trong bộ nhớ hơn là một tập tin. Tôi chắc chắn sẽ tránh, nếu bạn có thể, liên kết trực tiếp đến tập tin được tạo ra bởi URL. Nếu bạn đi qua một servlet nó sẽ cho phép bạn thay đổi impleemntation của bạn sau này. Đó là khái niệm encapsualtion giống như trong OO dsign.

0

có thể bạn nên xem xét sử dụng một số công cụ báo cáo có tùy chọn xuất tệp sang định dạng XLS. Đề nghị của tôi là JasperReports

8

Không sử dụng các bảng HTML thuần túy với loại nội dung application/vnd.ms-excel. Sau đó, bạn về cơ bản lừa Excel với một loại nội dung sai sẽ gây ra thất bại và/hoặc cảnh báo trong các phiên bản Excel mới nhất. Nó cũng sẽ làm lộn xộn nguồn HTML gốc khi bạn chỉnh sửa và lưu nó trong Excel. Đừng làm thế.

CSV lần lượt là định dạng chuẩn được hỗ trợ mặc định từ Excel mà không gặp bất kỳ sự cố nào và thực tế là dễ dàng và hiệu quả về bộ nhớ để tạo. Mặc dù có thư viện, bạn có thể dễ dàng viết một trong ít hơn 20 dòng (vui cho những người không thể cưỡng lại). Bạn chỉ cần tuân thủ thông số RFC 4180 về cơ bản chỉ chứa 3 quy tắc:

  1. Các trường được phân tách bằng dấu phẩy.
  2. Nếu dấu phẩy xảy ra trong một trường, thì trường phải được bao quanh bởi dấu ngoặc kép.
  3. Nếu báo giá kép xảy ra trong một trường, thì trường phải được bao quanh bởi dấu ngoặc kép và dấu ngoặc kép trong trường phải được thoát bằng dấu ngoặc kép khác.

Dưới đây là một ví dụ Kickoff:

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

Dưới đây là một ví dụ làm thế nào bạn có thể sử dụng nó:

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

Và bên trong một Servlet (vâng, Servlet, không sử dụng JSP cho điều này !) về cơ bản bạn có thể làm:

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

Lập bản đồ servlet này trên thứ gì đó e /csv/* và gọi nó là một cái gì đó như http://example.com/context/csv/filename.csv. Đó là tất cả. Lưu ý rằng tôi đã thêm khả năng xác định riêng biệt ký tự tách biệt, vì nó có thể phụ thuộc vào ngôn ngữ được sử dụng cho dù Excel sẽ chấp nhận dấu phẩy , hoặc dấu chấm phẩy ; làm dấu tách trường CSV. Lưu ý rằng tôi cũng đã thêm tên tệp vào đường dẫn URL, vì một trình duyệt web nhất định được phát triển bởi một nhóm ở Redmond nếu không sẽ không lưu tệp tải xuống với tên tệp thích hợp.

+0

Bạn có kinh nghiệm với "Excel sẽ chấp nhận dấu phẩy hoặc dấu chấm phẩy" để chia sẻ? –

+1

@Thor: Nếu dấu phân tách bên phải được sử dụng, Excel sẽ mở nó tự động trong các ô bên phải. Dấu phân tách phụ thuộc vào cấu hình và ngôn ngữ Excel (mặc định). Ví dụ, ở châu Âu, nó thường là dấu chấm phẩy. Vì vậy, nó thực sự phụ thuộc vào đối tượng mục tiêu của bạn mà tách để lựa chọn trong quá trình xuất khẩu. Người dùng cuối có cách khác để nhập thủ công và chỉ định dấu phân tách. – BalusC

+0

Tên tệp không hỗ trợ tiếng Trung, tôi sử dụng tên tệp tĩnh = "下载 物品", nhưng tên tệp được tải xuống có url ánh xạ, nói xxx.do trong springmvc hoặc đường dẫn ánh xạ trên servlet. Làm thế nào để hỗ trợ tên tập tin Trung Quốc? – Jaskey

1

POI hoặc JExcel là các API tốt. Cá nhân tôi thích POI tốt hơn, cộng với POI được cập nhật liên tục. Hơn nữa, có nhiều tài nguyên trực tuyến về POI hơn JExcel trong trường hợp bạn có bất kỳ câu hỏi nào. Tuy nhiên, cả hai đều làm một công việc tuyệt vời.

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

    } 
Các vấn đề liên quan