Не используйте простые таблицы HTML с типом содержимого application/vnd.ms-excel
. Тогда вы в основном обманываете Excel неправильным типом контента, который может вызвать сбой и / или предупреждения в последних версиях Excel. Он также испортит исходный HTML-код при редактировании и сохранении его в Excel. Только не делай этого.
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);
}
А внутри сервлета (да, сервлет, не используйте для этого 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());
}
Отобразите этот сервлет на что-то вроде /csv/*
и вызовите его как-то вроде http://example.com/context/csv/filename.csv
. Вот и все.
Обратите внимание, что я добавил возможность указывать символ разделителя отдельно, поскольку он может зависеть от используемой локали, будет ли Excel принимать запятую ,
или точку с запятой ;
в качестве разделителя полей CSV. Обратите внимание, что я также добавил имя файла в URL pathinfo, потому что определенный веб-браузер, разработанный командой из Редмонда, в противном случае не сохранил бы загрузку с правильным именем файла.