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:
- Các trường được phân tách bằng dấu phẩy.
- 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.
- 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.
+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
giữ cho nó đơn giản thường là cách tốt nhất. Câu trả lời hay: – SWD