首先说明一下我遇到的问题,公司需要做一个文件上传批量更新数据,用的是BootStarp框架,结果我发现通过BootStarp框架下载的表格文件在转换成文件流读取的时候会报错:
apache.poi.poifs.filesystem.NotOLE2FileException: Invalid header signature; read 0x6D78206C6D74683C, expected 0xE11AB1A1E011CFD0 - Your file appears not to be a valid OLE2 document
这个异常说的是excel文件表头错误。
先来看看我的项目结构:
首先这是我的maven配置文件中引入的poi Jar包,用于来解析Excel文件
<!--poi-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>3.10.1</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
下面这是用于读取文件,将excel文件中我需要的内容提取出来的帮助类
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
public class ReadExcelUtils {
private Workbook wb;
private Sheet sheet;
private Row row;
public ReadExcelUtils(String filepath) {
if (filepath == null) {
return;
}
String ext = filepath.substring(filepath.lastIndexOf("."));
try {
InputStream is = new FileInputStream(filepath);
if (".xls".equals(ext)) {
wb = new HSSFWorkbook(is);
} else if (".xlsx".equals(ext)) {
wb = new XSSFWorkbook(is);
} else {
wb = null;
}
} catch (FileNotFoundException e) {
System.out.println("FileNotFoundException" + e);
} catch (IOException e) {
System.out.println("IOException" + e);
}
}
/**
* 读取Excel表格表头的内容
*
* @param
* @return String 表头内容的数组
* @author zengwendong
*/
public String[] readExcelTitle() throws Exception {
if (wb == null) {
throw new Exception("Workbook对象为空!");
}
sheet = wb.getSheetAt(0);
row = sheet.getRow(0);
// 标题总列数
int colNum = row.getPhysicalNumberOfCells();
System.out.println("colNum:" + colNum);
String[] title = new String[colNum];
for (int i = 0; i < colNum; i++) {
// title[i] = getStringCellValue(row.getCell((short) i));
title[i] = row.getCell(i).getCellFormula();
}
return title;
}
/**
* 读取Excel数据内容
*
* @param
* @return Map 包含单元格数据内容的Map对象
* @author zengwendong
*/
public EdbitTable readExcelContent() throws Exception {
if (wb == null) {
throw new Exception("Workbook对象为空!");
}
//我自定义的对象,用来封装数据
EdbitTable edbitTable = new EdbitTable();
sheet = wb.getSheetAt(0);
// 得到总行数
int rowNum = sheet.getLastRowNum();
row = sheet.getRow(1);//从第二行读起,不读列标题
int colNum = row.getPhysicalNumberOfCells();
// 正文内容应该从第二行开始,第一行为表头的标题
for (int i = 1; i < rowNum; i++) {
row = sheet.getRow(i);
int j = 0;
while (j < colNum) {
String obj = getCellFormatValue(row.getCell(j)).toString();
//输出当前行的所有列数据
System.out.println(obj);
//以下是我个人需求获取的内容,不获取表头
if (j == 0) {
edbitTable.getId().add(Integer.parseInt(obj));
} else if (j == 10) {
if (obj.equals("拒绝")) {
//拒绝的状态0
edbitTable.getState().add("0");
} else if (obj.equals("成功")) {
//成功的状态是1
edbitTable.getState().add("1");
} else {
//其它的都是等待2
edbitTable.getState().add("2");
}
} else if (j == 11) {
//备注
edbitTable.getTextBz().add(obj);
}
j++;
}
}
return edbitTable;
}
/**
* 根据Cell类型设置数据
*
* @param cell
* @return
* @author zengwendong
*/
private Object getCellFormatValue(Cell cell) {
Object cellvalue = "";
if (cell != null) {
// 判断当前Cell的Type
switch (cell.getCellType()) {
case Cell.CELL_TYPE_NUMERIC:// 如果当前Cell的Type为NUMERIC
case Cell.CELL_TYPE_FORMULA: {
// 判断当前的cell是否为Date
if (DateUtil.isCellDateFormatted(cell)) {
// 如果是Date类型则,转化为Data格式
// data格式是带时分秒的:2013-7-10 0:00:00
// cellvalue = cell.getDateCellValue().toLocaleString();
// data格式是不带带时分秒的:2013-7-10
Date date = cell.getDateCellValue();
cellvalue = date;
} else {// 如果是纯数字
// 取得当前Cell的数值
cellvalue = String.valueOf(cell.getNumericCellValue());
}
break;
}
case Cell.CELL_TYPE_STRING:// 如果当前Cell的Type为STRING
// 取得当前的Cell字符串
cellvalue = cell.getRichStringCellValue().getString();
break;
default:// 默认的Cell值
cellvalue = "";
}
} else {
cellvalue = "";
}
return cellvalue;
}
}
下面是我用来封装我需要的内容的实体类
/**
* @ Author :chao
* @ Date :Create in 9:41 2018\12\26 0026
*/
import java.util.ArrayList;
import java.util.List;
public class EdbitTable {
private List<Integer> id = new ArrayList<Integer>(); //id列
private List<String> state= new ArrayList<String>(); //状态列, 0 拒绝 1成功 2等待
private List<String> textBz= new ArrayList<String>(); //备注
public List<Integer> getId() {
return id;
}
public void setId(List<Integer> id) {
this.id = id;
}
public List<String> getState() {
return state;
}
public void setState(List<String> state) {
this.state = state;
}
public List<String> getTextBz() {
return textBz;
}
public void setTextBz(List<String> textBz) {
this.textBz = textBz;
}
}
我当时用wps创建了一个Excel文件,两份对比并没有发现什么不同,我就很奇怪,后来在查资料的时候发现,这bootstarp导出的Excel文件!!!竟然是假的,你可以试着打开导出的Excel文件,另存为看下,是不是默认给你保存的后缀名是 htm或者html。。
当时心态就有点炸了,本来还以为自己写的代码有问题(我是个新人),结果竟然是BootStarp的埋的坑。。
后面就换了一个思维,竟然它是个假的.xsl文件,本体是个htm格式文件,不如我先给它转换成excle文件,然后再进行之前的读写操作?于是乎我的代码就多了一些
首先还是maven配置文件(加多了2个jar包):
<!--poi-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>3.10.1</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<!--Html文件转换Excel文件-->
<dependency>
<groupId>net.sourceforge.jexcelapi</groupId>
<artifactId>jxl</artifactId>
<version>2.6.12</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.8.3</version>
</dependency>
</dependencies>
最后实现功能的代码:
注意:MultipartFile fish_file 是bootstrap上传文件控件传过来的文件,
记得根据自己的储存路径变更暂存路径,我的是在服务器上的路径。
@RequestMapping(value = "/updateByFile")
@ResponseBody
public JSONObject updateByFile(@RequestParam("upFile") MultipartFile fish_file) {
JSONObject json = new JSONObject();
//文件暂存路径!
String path = "/images/demo.xls";
File filexls = new File(path);
//转成html格式
File filehtml = new File(filexls.getPath().substring(0, filexls.getPath().indexOf('.')) + ".html");
File filexlsZ = new File(path);
try {
//创建一个临时文件存放页面传过来的文件内容
FileUtils.copyInputStreamToFile(fish_file.getInputStream(), filexls);
filexls.createNewFile();
filexls.renameTo(filehtml);
//根据html文件重新生成一个真正的xls文件,并返回路径
String xlsPath = HtmlToExceUtils.toExcel(filehtml.getPath(), "roster",path);
if (xlsPath == null) {
System.out.println("错误");
} else {
try {
//创建一个读取xls文件的帮助类,根据返回的真正xls文件路径
ReadExcelUtils excelReader = new ReadExcelUtils(xlsPath);
// 对读取Excel表格内容读取存放到一个借支表格对象中
EdbitTable edbitTable = excelReader.readExcelContent();
moneyService.updateByEdbitTable(edbitTable);
} catch (Exception e) {
json.put("errorInfo", "修改失败,请检查是否打开了上传文件或文件上传格式错误!!如实在无法解决请保存错误文件并联系管理员!");
return json;
}
}
} catch (Exception e) {
json.put("errorInfo", "修改失败,请检查是否打开了上传文件或文件上传格式错误!!如实在无法解决请保存错误文件并联系管理员!");
return json;
}finally {
//判断临时文件是否存在,存在则删除
if (filexls.exists()) {
filexls.delete();
}
if (filehtml.exists()) {
filehtml.delete();
}
if (filexlsZ.exists()) {
filexlsZ.delete();
}
}
return json;
}
小白第一次写博客,写的不好请各位大神轻喷
代码可能整洁复用性有点差。。。。见谅