文章目录
本文采用Apache的 POI相关API,实现对Excel和Word的文档的解析。
Apache POI 是用Java编写的免费开源的 Java API,提供对Microsoft Office格式档案读和写的功能,下载和帮助。
除了Apache POI外,Docx4j 也是一个用于创建和操作Microsoft Open XML (Word docx、Powerpoint pptx和Excel xlsx)文件的Java库。
- HSSF - 提供读写Microsoft Excel XLS格式档案的功能。
- XSSF - 提供读写Microsoft Excel OOXML XLSX格式档案的功能。
- HWPF - 提供读写Microsoft Word DOC格式档案的功能。
- HSLF - 提供读写Microsoft PowerPoint格式档案的功能。
使用到的 jar包:
- commons-fileupload-1.3.3.jar
- poi-3.16.jar
- poi-ooxml-3.16.jar
- poi-ooxml-schemas-3.16.jar
- poi-scratchpad-3.16.jar
一、JSP配置${basePath}
新建common.jsp文件,在该文件中获取当前JSP的地址bsthPath,并把它存入request中,在web.xml中添加配置,使其作用域每一个JSP文件中,这样在当前工程的所有JSP中都可以使用**EL表达式${basePath}**表示当前工程地址,方便JSP页面地址的跳转。
1、common.jsp文件
<%
String basePath = request.getScheme() + "://" + request.getServerName() + ":"
+ request.getServerPort() + request.getContextPath();
request.setAttribute("basePath", basePath);
%>
2、web.xml配置
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<include-prelude>/WEB-INF/JSP/common.jsp</include-prelude>
</jsp-property-group>
</jsp-config>
二、通用数据类和工具类
1、request参数解析结果类(通用数据类)
该类存放request流中的Form表单提交的数据。
public class ParamDto {
private Map<String, String> paramMap; // 普通参数
private Map<String, FileItem> fileMap; // 文件参数
public ParamDto() {
paramMap = new HashMap<>();
fileMap = new HashMap<>();
}
public Map<String, String> getParamMap() {return paramMap;}
public void setParamMap(Map<String, String> paramMap) {this.paramMap = paramMap;}
public Map<String, FileItem> getFileMap() {return fileMap;}
public void setFileMap(Map<String, FileItem> fileMap) {this.fileMap = fileMap;}
}
2、request参数解析工具类
从request流中解析出JSP页面中Form表单提交的参数,将普通参数存入Map<String, String> 映射内,将文件参数参数存入Map<String, FileItem> 内。
public class RequestUtil {
public static ParamDto parseParam(HttpServletRequest request) {
ParamDto result = new ParamDto(); //结果存放类
// 核心解析类
ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory());
upload.setHeaderEncoding("UTF-8");
try {
List<FileItem> fileItemList = upload.parseRequest(request);
for (FileItem fileItem : fileItemList) {
if (fileItem.isFormField()) {
// 将普通参数放置到参数传递类的映射paramMap中
result.getParamMap().put(fileItem.getFieldName(), fileItem.getString("UTF-8"));
} else {
// 将文件参数放置到参数传递类的映射fileMap中
result.getFileMap().put(fileItem.getFieldName(), fileItem);
}
}
} catch (FileUploadException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
3、文件保存工具类
为了避免用户上传同名文件,这里采用加时间戳的方法重命名,当然也可以采用UUID的方式。文件的保存使用 FileItem 的Write方法。
public class FileUtil {
public static final String SAVE_PATH = "C:/Users/Administrator/Desktop/";
public static String save(FileItem fileItem,String path) throws Exception {
String fileName = System.currentTimeMillis() + "_" + fileItem.getName();
fileItem.write(new File(path + fileName));
return fileName;
}
}
三、Excel的导入与解析
实现将Excel文件上传到Web服务器的指定地址,解析该Excel文件并显示到浏览器。
1、业务界面 JSP
<form id="mainForm" method="post" enctype="multipart/form-data" action="${basePath}/importExcel">
...
<input type="button" class="tabSub" value="导 入"
onclick="document.getElementById('mainForm').submit();" />
...
</form>
2、业务参数类
存放上面JSP传递过来的参数。具体是由request解析数据到通用数据类,再从通用数据类存放到导入Excel的参数类,便于管理和明确各类的功能。
public class ImportExcelParamDto {
private String title;
private FileItem excel;
public String getTitle() {return title;}
public void setTitle(String title) {this.title = title;}
public FileItem getExcel() {return excel;}
public void setExcel(FileItem excel) {this.excel = excel;}
}
3、业务结果类
此类是对业务处理后,结果数据的封装。
public class ImportExcelResultDto {
private String title; // Form表单提交的数据
private List<Student> studentList; // Excel解析的数据
private String msg; // 存放错误信息
public String getTitle() {return title;}
public void setTitle(String title) {this.title = title;}
public List<Student> getStudentList() {return studentList;}
public void setStudentList(List<Student> studentList) {this.studentList = studentList;}
public String getMsg() {return msg;}
public void setMsg(String msg) {this.msg = msg;}
}
4、业务实现类
根据提供业务参数:业务参数对象,实现 保存指定导入的Excel文件到服务器,和解析Excel文件,将解析结果存入业务结果对象中,用于返回 。
public class ExcelService {
public ImportExcelResultDto importExcelService(ImportExcelParamDto dto) {
// 创建导入Excel解析结果对象
ImportExcelResultDto result = new ImportExcelResultDto();
result.setTitle(dto.getTitle());
List<Student> studentList = new ArrayList<>();
result.setStudentList(studentList);
// 保存上传文件
String fileName = null;
try {
fileName = FileUtil.save(dto.getExcel(), FileUtil.SAVE_PATH);
} catch (Exception e) {
result.setMsg("保存上传文件失败啦!");
}
// 正确到获取文件名,就可以解析Excel啦
if (null != fileName) {
Workbook workbook = null;
try {
/* 可以直接传入文件流,这样用于浏览器只要求解析文件,不需要在服务器上进行保存的场景
workbook = WorkbookFactory.create(new File(dto.getExcel().getInputStream());*/
// 根据文件对象实例化工作簿
workbook = WorkbookFactory.create(new File(FileUtil.SAVE_PATH + fileName));
// 获取Excel中第0张表单, 或使用workbook.getSheet("Sheet1");拿到对应名字的表单
Sheet sheet = workbook.getSheetAt(0);
// 取得表单中有内容的总行数
int rowNum = sheet.getLastRowNum();
// 循环遍历每一行
for (int i = 1; i <= rowNum; i++) {
Row row = sheet.getRow(i); //获取第i行
Student student = new Student();
studentList.add(student);
// 以字符串方式获取该行第0列元素
student.setName(row.getCell(0).getStringCellValue());
// 以数字(double)方式获取该行第0列元素
student.setAge((int)row.getCell(1).getNumericCellValue());
// 以日期(Date)方式获取该行第0列元素
student.setTime(row.getCell(2).getDateCellValue());
}
} catch (Exception e) {
result.setMsg("解析Excel文件失败啦!");
} finally { // 这里一定要处理把workbook关闭掉,避免占用资源
if (workbook != null) {
try {
workbook.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
return result;
}
}
5、业务Servlet
对以上实现的方法进行调用,实现业务逻辑,将结果数据返回给显示的JSP。
public class ImportExcelServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 判断表单提交的enctype属性,需要“multipart/form-data”类型
if (ServletFileUpload.isMultipartContent(request)) {
// 解析request,转化为业务参数对象
ParamDto dto = RequestUtil.parseParam(request);
ImportExcelParamDto paramDto = new ImportExcelParamDto();
paramDto.setTitle(dto.getParamMap().get("title"));
paramDto.setExcel(dto.getFileMap().get("excel"));
// 实现业务逻辑,将结果数据存放到request中,返给JSP
ExcelService service = new ExcelService();
ImportExcelResultDto resultDto = service.importExcelService(paramDto);
request.setAttribute("result", resultDto);
}
// 转发给JSP,显示数据
request.getRequestDispatcher("/WEB-INF/JSP/importExcelResult.jsp").forward(request, response);
}
}
6、JSP展示业务数据
使用EL表达式和JSTL协助展示数据。
<head>
<script type="text/javascript">
function bodyInit() { // 当有错误信息,显示错误信息
if('${result.msg}') {
alert('${result.msg}');
}
}
</script>
</head>
<body style="background: #e1e9eb;" onload="bodyInit();">
<table class="tab1">
...
<td>${result.title}</td>
<c:forEach items="${result.studentList}" var="item" varStatus="s">
<tr>
<td>${s.count}</td>
<td>${item.name}</td>
<td>${item.age}</td>
<!-- fmt JSTL中的格式化标签 -->
<td><fmt:formatDate value="${item.time}" pattern="yyyy-MM-dd"/></td>
</tr>
</c:forEach>
...
</table>
...
</body>
四、Excel的导出与解析
1、业务界面 JSP
<form action="${basePath}/exportExcel" id="mainForm" method="post">
...
<input type="button" class="tabSub" value="查询" onclick="" />
<input type="button" class="tabSub" value="导出" onclick="document.getElementById('mainForm').submit();" />
...
</form>
2、业务实现类
业务参数类与导入时一致,注意将数据封装成二维的形式,方便于数据写入Excel.
导出Excel可向外留接口选择导出03版的还是07版的。
public class ExcelService {
public Workbook exportExcel(boolean isXlsx) {
Workbook workbook = null;
if (isXlsx) {
workbook = new XSSFWorkbook(); // 03版的Excel .xls
} else {
workbook = new HSSFWorkbook(); // 07版的Excel .xlsx
}
// 创建一张表单 名称:My Sheet
Sheet sheet = workbook.createSheet("My Sheet");
// 逐个遍历写入到对应的单元格
List<List<String>> content = this.getContent();
for (int i = 0; i < content.size(); i++) {
Row row = sheet.createRow(i);
List<String> rowData = content.get(i);
for (int j = 0; j < rowData.size(); j++) {
row.createCell(j).setCellValue(rowData.get(j));
}
}
return workbook;
}
}
3、业务Servlet
导出时一般不再服务器上备份Excel文件,如果需要也可以。
此Servlet没有跳转到重定向到其他界面,点击导出时的执行浏览器直接下载export.xlsx文件。
public class ExportExcelServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ExcelService service = new ExcelService();
Workbook workbook = service.exportExcel(true);
// 这个信息头告诉浏览器这个文件的名字和类型
response.setHeader("Content-Disposition", "attachment;filename=export.xlsx");
ServletOutputStream outputStream = response.getOutputStream();
// 输出流直接导出
workbook.write(outputStream);
outputStream.flush();
outputStream.close();
workbook.close();
// // 保存成文件再导出
// // 1. 先保存成文件
// FileOutputStream fileOutputStream = new FileOutputStream(SAVE_PATH + "export.xlsx");
// workbook.write(fileOutputStream);
// // 2. 再由文件导出
// FileInputStream fileInputStream = new FileInputStream(FileUtil.SAVE_PATH + "export.xlsx");
// byte[] bytes = new byte[fileInputStream.available()];
// fileInputStream.read(bytes);
// outputStream.write(bytes);
// outputStream.flush();
//
// // 3. 关闭流
// outputStream.close();
// fileInputStream.close();
// fileOutputStream.close();
// workbook.close();
}
}