瀏覽器根據響應頭 Content-Type 決定如何處理內容:
▸ application/msword → 調用 Word / WPS 打開 .doc
▸ application/vnd.ms-excel → 調用 Excel / WPS 打開 .xls
▸ application/vnd.openxmlformats-officedocument.wordprocessingml.document → .docx
▸ application/vnd.openxmlformats-officedocument.spreadsheetml.sheet → .xlsx
<!-- 輸出 Word 97-2003 (.doc) --> <%@ page contentType="application/msword;charset=UTF-8" %> <!-- 輸出 Excel 97-2003 (.xls) --> <%@ page contentType="application/vnd.ms-excel;charset=UTF-8" %> <!-- 現代格式 .docx --> <%@ page contentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document;charset=UTF-8" %> <!-- 現代格式 .xlsx --> <%@ page contentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8" %>
<%@ page contentType="application/vnd.ms-excel;charset=UTF-8" %>
<%@ page import="java.util.*,java.text.*" %>
<%
response.setHeader("Content-Disposition", "attachment; filename=users_" + new SimpleDateFormat("yyyyMMdd").format(new Date()) + ".xls");
%>
<table border="1">
<tr><th>ID</th><th>姓名</th><th>郵箱</th><th>註冊時間</th></tr>
<%
List<User> users = (List<User>) request.getAttribute("userList");
if (users != null) {
for (User u : users) {
%>
<tr>
<td><%= u.getId() %></td>
<td><%= u.getName() %></td>
<td><%= u.getEmail() %></td>
<td><%= new SimpleDateFormat("yyyy-MM-dd HH:mm").format(u.getRegTime()) %></td>
</tr>
<%
}
}
%>
</table>
| 問題 | 解決 |
|---|---|
| 中文亂碼 | 頁面 charset=UTF-8、數據庫連接 characterEncoding=utf8、JSP pageEncoding="UTF-8" |
| 文件名中文 | filename*=UTF-8''%E6%96%87%E4%BB%B6.xls (RFC 5987) 或雙重編碼兼容舊瀏覽器 |
| 大數據量導出 | JSP 輸出易 OOM,**改用 Servlet + SXSSF (POI 流式寫入) 直接寫 response.getOutputStream()** |
| 樣式/公式/合併儲存格 | HTML 表格不支持,**必須用 Apache POI 生成真實 .xlsx/.xls 二進制** |
| 瀏覽器直接打開而非下載 | 加 Content-Disposition: attachment; filename=... 強制下載 |
@WebServlet("/export/users.xlsx")
public class UserExcelExportServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
resp.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
resp.setHeader("Content-Disposition", "attachment; filename=users_" + LocalDate.now() + ".xlsx");
try (SXSSFWorkbook wb = new SXSSFWorkbook(100); // 內存保留 100 行,其餘寫臨時文件
ServletOutputStream out = resp.getOutputStream()) {
Sheet sheet = wb.createSheet("用戶列表");
Row header = sheet.createRow(0);
String[] cols = {"ID", "姓名", "郵箱", "註冊時間"};
for (int i = 0; i < cols.length; i++) header.createCell(i).setCellValue(cols[i]);
List<User> users = userService.findAll(); // 或分頁查詢
int rowNum = 1;
for (User u : users) {
Row row = sheet.createRow(rowNum++);
row.createCell(0).setCellValue(u.getId());
row.createCell(1).setCellValue(u.getName());
row.createCell(2).setCellValue(u.getEmail());
row.createCell(3).setCellValue(u.getRegTime().toString());
}
wb.write(out); // 直接寫響應流
out.flush();
}
}
}
JSP 設置 contentType 導出 Office 文件是**快速原型/小數據量**的權宜之計:本質是輸出 HTML 表格,瀏覽器勉強識別為 Word/Excel。**缺陷**:無樣式控制、無公式、大數據 OOM、非標準格式。生產環境**必須使用 Apache POI (SXSSF/XSSF) 生成真實二進制文件**,配合 Content-Disposition: attachment 強制下載,支持百萬行導出、樣式、公式、圖表、簽名等企業級需求。