1.什么是Apache POI?
Apache POI是一种流行的API,它允许程序员使用Java程序创建,修改和显示MS Office文件。这由Apache软件基金会开发使用Java分布式设计或修改Microsoft Office文件的开源库。它包含类和方法对用户输入数据或文件到MS Office文档进行解码。在我们实际的开发中,表现层的解决方案虽然有多样,但是IE浏览器已成为最多人使用的浏览器,因为大家都用Windows。在企业办公系统中,常常有客户这样子要求:你要把我们的报表直接用Excel打开(电信系统、银行系统)。或者是:我们已经习惯用Excel打印。Apache的Jakata项目的POI子项目,目前比较成熟的是HSSF接口,处理MSExcel对象。它不象我们仅仅是用csv生成的没有格式的可以由Excel转换的东西,而是真正的Excel对象,你可以控制一些属性如sheet,cell等等。ApachePOI
2.Servlet3.0上传文件
2.1在index.jsp中:
<body>
<form action="FileServlet" enctype="multipart/form-data"
method="post">
用户文件:<input type="file" name="file"><br>
<input type="submit"><br>
</form>
</body>
2.2FileServlet中:
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.UUID;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
@MultipartConfig
// 标识Servlet支持文件上传
public class FileServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
// 存储路径
String savePath = request.getServletContext().getRealPath("/upload");
// 获取上传的文件集合
Collection<Part> parts = request.getParts();
// 上传单个文件
if (parts.size() == 1) {
// Servlet3.0将multipart/form-data的POST请求封装成Part,通过Part对上传的文件进行操作。
// Part part = parts[0];//从上传的文件集合中获取Part对象
Part part = request.getPart("file");
// 通过表单file控件(<input type="file"
// name="file">)的名字直接获取Part对象
// Servlet3没有提供直接获取文件名的方法,需要从请求头中解析出来
// 获取请求头,请求头的格式:form-data; name="file"; filename="snmp4j--api.zip"
String header = part.getHeader("content-disposition");
// 获取文件名
String fileName = getFileName(header);
// 把文件写到指定路径
part.write(savePath + File.separator + fileName);
} else {
// 一次性上传多个文件
for (Part part : parts) {// 循环处理上传的文件
// 获取请求头,请求头的格式:form-data; name="file";
// filename="snmp4j--api.zip"
String header = part.getHeader("content-disposition");
// 获取文件名
String fileName = getFileName(header);
// 把文件写到指定路径
part.write(savePath + File.separator + fileName);
}
}
}
/**
* 根据请求头解析出文件名 请求头的格式:火狐和google浏览器下:form-data; name="file";
* filename="snmp4j--api.zip" IE浏览器下:form-data; name="file";
* filename="E:\snmp4j--api.zip"
*
* @param header
* 请求头
* @return 文件名
*/
public String getFileName(String header) {
/**
* String[] tempArr1 =
* header.split(";");代码执行完之后,在不同的浏览器下,tempArr1数组里面的内容稍有区别
* 火狐或者google浏览器下:
* tempArr1={form-data,name="file",filename="snmp4j--api.zip"}
* IE浏览器下:tempArr1={form-data,name="file",filename="E:\snmp4j--api.zip"}
*/
String[] tempArr1 = header.split(";");
/**
* 火狐或者google浏览器下:tempArr2={filename,"snmp4j--api.zip"}
* IE浏览器下:tempArr2={filename,"E:\snmp4j--api.zip"}
*/
String[] tempArr2 = tempArr1[2].split("=");
// 获取文件名,兼容各种浏览器的写法
String fileName = tempArr2[1].substring(
tempArr2[1].lastIndexOf("\\") + 1).replaceAll("\"", "");
//替换文件名
String result = "";
if(fileName.lastIndexOf(".")!= -1){
// 获取文件的后缀
String fileType = fileName.substring(fileName.lastIndexOf("."), fileName.length());
result = UUID.randomUUID().toString()+fileType;
}
return result;
}
}
2.3测试结果:
3.poi批量导入
3.1poi架包
上图中所需jar包都需要导入。若不导入完全中途可能会出现错误。
3.2ImportExcel文件转换成List集合工具类
import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import cn.edu.abtc.model.User;
public class ImportExcel {
public static List<User> analyExcelUserBlock(HttpServletRequest request,String fileName){
List<User> list = new ArrayList<User>();
String targetDirectory = request.getServletContext().getRealPath("/upload");
File target = new File(targetDirectory,fileName);
try {
FileInputStream fi = new FileInputStream(target);
Workbook workbook = WorkbookFactory.create(fi);
//获取第一张sheet表
Sheet sheet = workbook.getSheetAt(0);
//获取总行数
int rowCount = sheet.getPhysicalNumberOfRows();
//遍历每一行
for(int r = 1 ; r < rowCount ; r++){
User user = new User();
Row row = sheet.getRow(r);
//用户id
Cell id = row.getCell(0);
if(id != null){
//id.setCellType(Cell.CELL_TYPE_STRING);//deprecated
id.setCellType(CellType.NUMERIC);
user.setId((int)id.getNumericCellValue());
}else{
throw new Exception("excel表格数据类型不一致");
}
//用户姓名
Cell name = row.getCell(1);
if(name != null){
//id.setCellType(Cell.CELL_TYPE_STRING);//deprecated
id.setCellType(CellType.STRING);
user.setName(id.getStringCellValue());
}else{
user.setName("");
}
//用户年龄
Cell age = row.getCell(2);
if(age != null){
age.setCellType(CellType.STRING);
user.setAge(age.getStringCellValue());
}else{
user.setAge("");
}
//用户性别
Cell sex = row.getCell(3);
if(sex != null){
sex.setCellType(CellType.STRING);
user.setSex(sex.getStringCellValue());
}else{
user.setSex("");
}
list.add(user);
user = null;
}
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
}
3.3在servlet中加入以下代码:
//通过ImportExcel将上传的文件转为List
List<User> list = ImportExcel.analyExcelUserBlock(request, fileName);
for(User u:list){
System.out.println(u);
}
3.4测试结果:
3.5上传文件的模板:
3.6注意事项:
以上项目中新建了一个User.java但是本博客中没有表现出来。很多具体问题可以私聊我。
3.7POI导出excel文件
3.7.1新建一个servlet
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import cn.edu.abtc.model.User;
public class ExportServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
OutputStream out = null;
try {
//response.setContentType("application/msexcel;charset=UTF-8");
out = response.getOutputStream();
String excelName = "测试案例";
response.setHeader("Content-Disposition", "attachment;filename="+new String( excelName.getBytes("gb2312"), "ISO8859-1" )+".xls");
response.setContentType("application/msexcel;charset=UTF-8");
String[] headers = new String[]{"name","age","性别"};
exportExcel(excelName, headers, createUserList(), out, "yyyy-MM-dd");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void exportExcel(String title,String[] headers,List infos,OutputStream out,String pattern){
//声明一个工作簿
HSSFWorkbook workbook = new HSSFWorkbook();
//生成一个表格
HSSFSheet sheet = workbook.createSheet(title);
//设置表格默认列宽度为15个字符
sheet.setDefaultColumnWidth(20);
//生成一个样式,用来设置标题样式
HSSFCellStyle style = workbook.createCellStyle();
//设置这些样式
style.setFillForegroundColor(IndexedColors.GREEN.getIndex());
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
style.setBorderBottom(BorderStyle.THIN);
style.setBorderLeft(BorderStyle.THIN);
style.setBorderRight(BorderStyle.THIN);
style.setBorderTop(BorderStyle.THIN);
style.setAlignment(HorizontalAlignment.CENTER);
//生成一个字体
HSSFFont font = workbook.createFont();
font.setColor(IndexedColors.WHITE.getIndex());
font.setBold(true);
//font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
//把字体应用到当前的样式
style.setFont(font);
// 生成并设置另一个样式,用于设置内容样式
HSSFCellStyle style2 = workbook.createCellStyle();
style2.setFillForegroundColor(IndexedColors.YELLOW.getIndex());
style2.setFillPattern(FillPatternType.SOLID_FOREGROUND);
style2.setBorderBottom(BorderStyle.THIN);
style2.setBorderLeft(BorderStyle.THIN);
style2.setBorderRight(BorderStyle.THIN);
style2.setBorderTop(BorderStyle.THIN);
style2.setAlignment(HorizontalAlignment.CENTER);
style2.setVerticalAlignment(VerticalAlignment.CENTER);
// 生成另一个字体
HSSFFont font2 = workbook.createFont();
font2.setBold(true);
// 把字体应用到当前的样式
style2.setFont(font2);
//产生表格标题行
HSSFRow row = sheet.createRow(0);
for(int i = 0; i<headers.length;i++){
HSSFCell cell = row.createCell(i);
cell.setCellStyle(style);
HSSFRichTextString text = new HSSFRichTextString(headers[i]);
cell.setCellValue(text);
}
for(int i=0; i<infos.size(); i++){
User u = (User) infos.get(i);
row = sheet.createRow(i+1);
int j = 0;
if(u.getName() != null){
row.createCell(j++).setCellValue(u.getName());
}else{
row.createCell(j++).setCellValue("");
}
if(u.getAge() != null){
row.createCell(j++).setCellValue(u.getAge());
}else{
row.createCell(j++).setCellValue("");
}
if(u.getSex() != null){
row.createCell(j++).setCellValue(u.getSex());
}else{
row.createCell(j++).setCellValue("");
}
}
try {
workbook.write(out);
} catch (IOException e) {
e.printStackTrace();
}
}
public List<User> createUserList(){
List<User> list = new ArrayList<User>();
for(int i = 1 ; i < 30 ; i++){
User u = new User();
u.setName(""+i);
u.setAge(""+i*2);
if(i%2==1){
u.setSex("男");
}else{
u.setSex("女");
}
list.add(u);
u = null;
}
return list;
}
}
3.7.2测试结果
结束语:经过多次摸索测试,在查阅相关资料的情况下,终于完成了POI的批量导入和批量导出功能的实现。
在完成的过程有几个地方需要注意:
1.批量导入的过程中思路是:先将excel文件上传到服务器,本例中使用的是servlet3.0特性。然后再读取文件,将文件转换成一个List集合对象,再逐条插入数据库中。
2.再处理文件转换成List对象的时候没有考虑数据量非常大的情况,需要放在线程池中进行处理。
3.POI不同的版本有不一样的用法,需要查看所下载的POI包的文档。