实力有限,想一步写出操作excel的代码做不到,只能一步一步开始写,从最基本的开始
首先是ajax完成excel上传,controller获取excel,暂时先不做后缀名的校验不区分两个版本的excel
<body>
<div class="easyui-panel" title="Upload" style="width:100%;height:auto">
<form enctype="multipart/form-data" method="post" id="upload">
<input type="file" name="uploadFile" id="uploadFile"
accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel "/>
<input type="button" id="btn" value="上传"/>
</form>
</div>
<script type="text/javascript">
$(function(){
$("#btn").click(function(){
var formdata=new FormData();
formdata.append("uploadFile",$('#uploadFile')[0].files[0])
console.log(formdata.get("uploadFile"));
$.ajax({
url:"../user/testUpExcel",
data:formdata,
type:"post",
dataType:"json",
processData:false,
contentType:false,
success:function(json){
if(json.code==100){
alert("上传成功");
}else{
alert(json.code);
}
},
error:function(){
alert("上传出错");
}
})
})
})
</script>
</body>
@RequestMapping(value="/testUpExcel",method=RequestMethod.POST)
@ResponseBody
public Msg uploadExcel(
MultipartFile uploadFile,
HttpServletRequest request) throws Exception, IOException {
//上传到本地磁盘
String realPath="E:\\upload\\temp\\excel\\";
//获取原始图片的拓展名-------暂时不判断后缀名
String originalFilename = uploadFile.getOriginalFilename();
//封装上传文件位置的全路径,就是硬盘路径+文件名
File targetFile = new File(realPath,originalFilename);
//使用MultipartFile接口中的方法,把本地文件上传到已经封装好的文件位置的全路径就是上面的targetFile
uploadFile.transferTo(targetFile);
FileInputStream stream=new FileInputStream(targetFile);
HSSFWorkbook workbook=new HSSFWorkbook(stream);
for(Sheet sheet:workbook) {
for (Row row : sheet)
{
for (Cell cell : row)
{
System.out.print(cell + "\t");
}
System.out.println();
}
}
return Msg.success();
}
成功读取到excel中的数据
mqb0 FALSE 43884.46119959491 0.0
mqb1 FALSE 43884.46120081018 1.0
mqb2 FALSE 43884.46120081018 2.0
mqb3 FALSE 43884.46120081018 3.0
mqb4 FALSE 43884.46120082176 4.0
mqb0---- FALSE 43884.46120082176 0-----
mqb1---- FALSE 43884.46120082176 1-----
mqb2---- FALSE 43884.46120082176 2-----
mqb3---- FALSE 43884.46120082176 3-----
mqb4---- FALSE 43884.461200833335 4-----
将excel中的数据读取出来之后封装成bean
目前最容易想到的方法就是将实体的每个属性与cell对应起来,然后赋值,先实现这种方式,等后面改进
假设我定义了一个类:TTT。里面4个属性包含了最常用的几个类型
public class TTT {
String name;
Boolean sex;
Date birthday;
Integer num;
public TTT() {}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Boolean getSex() {
return sex;
}
public void setSex(Boolean sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Integer getNum() {
return num;
}
public void setNum(Integer num) {
this.num = num;
}
@Override
public String toString() {
return "TTT [name=" + name + ", sex=" + sex + ", birthday=" + birthday + ", num=" + num + "]";
}
}
还是按照刚才的 jsp+jq上传文件,但是controller有了一些改变,这里的代码应该写在service里的,现在就不管了
大概步骤就是接收文件 uploadFile,保存到 realPath中 ,然后读取该文件,创建workbook,sheet,row,cell,直接三重循环遍历每个sheet的每个row的每个cell,row(0)跳过,因为这一行是标题行
@RequestMapping(value="/testUpExcel",method=RequestMethod.POST)
@ResponseBody
public Msg uploadExcel(
MultipartFile uploadFile,
HttpServletRequest request) throws Exception, IOException {
//上传到本地磁盘
String realPath="E:\\upload\\temp\\excel\\";
//获取原始图片的拓展名-------暂时不判断后缀名
String originalFilename = uploadFile.getOriginalFilename();
//封装上传文件位置的全路径,就是硬盘路径+文件名
File targetFile = new File(realPath,originalFilename);
//使用MultipartFile接口中的方法,把本地文件上传到已经封装好的文件位置的全路径就是上面的targetFile
uploadFile.transferTo(targetFile);
FileInputStream stream=new FileInputStream(targetFile);
HSSFWorkbook workbook=new HSSFWorkbook(stream);
TTT tt = new TTT();
List<TTT> list=new ArrayList<>();
HSSFSheet sheet=null;
HSSFRow row=null;
HSSFCell cell=null;
for(int i=0;i<workbook.getNumberOfSheets();i++) {//获取每个sheet
sheet=workbook.getSheetAt(i);
for(int j=0;j<sheet.getPhysicalNumberOfRows();j++) {//获取每个row
if(j==0) continue;
row=sheet.getRow(j);
for(int k=0;k<row.getPhysicalNumberOfCells();k++) {//获取每个cell
cell=row.getCell(k);
try {
if(k==0) {
tt.setName(ExcelUtil.getValueByCellStyle(cell));
}
else if(k==1) {
tt.setSex(Boolean.valueOf(ExcelUtil.getValueByCellStyle(cell)));
}
else if(k==2) {
Date d=new Date(ExcelUtil.getValueByCellStyle(cell));
tt.setBirthday(d);
}
else if(k==3) {
String doubleStr=ExcelUtil.getValueByCellStyle(cell);
String intStr=doubleStr.substring(0, doubleStr.indexOf("."));
tt.setNum(Integer.parseInt(intStr));
}
}catch(Exception e) {
System.out.println("数据封装出错");
}
}
System.out.println("第"+j+"个row处理完毕");
list.add(tt);
}
System.out.println("第"+i+"个sheet处理完毕");
}
for(TTT t:list) {
System.out.println(t.toString());
}
return Msg.success();
}
封装完两个TTT遍历输出看下结果,可以看到封装成功了
TTT [name=hff, sex=true, birthday=Tue Feb 02 14:00:00 CST 1999, num=22]
TTT [name=hff, sex=true, birthday=Tue Feb 02 14:00:00 CST 1999, num=22]
controller的三重循环中有一个自定义的工具类,用来根据cell的style来获取对应的值,不然日期这个值不好处理
这里对于日期的模板我只判断了一个,需要的话可以判断多个,我设置的excel日期类型2001/12/12就是 m/d/yy这种的
还有一点:cell.getNumericCellValue() 获取的值是double类型,有两个小数点,在转int时注意要把两个小数截掉
package com.mqb.utils;
import org.apache.poi.ss.usermodel.Cell;
public class ExcelUtil {
public static String getValueByCellStyle(Cell cell) {
String value="";
switch(cell.getCellTypeEnum()) {
case STRING:
value=cell.getStringCellValue();
break;
case BOOLEAN:
value=String.valueOf(cell.getBooleanCellValue());
break;
case NUMERIC:
String str=cell.getCellStyle().getDataFormatString();
if("m/d/yy".equals(str)) {
value=cell.getDateCellValue().toString();
}else {
value=String.valueOf(cell.getNumericCellValue());
}
break;
default:
break;
}
return value;
}
}
----------------------
初步的功能已经完成,后续再加入 xls 和 xlsx的判断就可以实现大致的读取excel的功能,但是没有对excel进行校验,比如excel的第一列是否是name,如果有一列String属性的之和name这列换了下,我现在无法发现。
下一步思考解决这个问题
再想多点,再接下来尝试写一个通用的封装bean的方法。
听说POI+反射可以很好的解决问题,学习中