SpringMVC Excel导入导出2.0升级版
该博客依赖1.0版本编写,只体现升级内容。1.0请参照
SpringMVC操作Excel上传下载.
升级内容介绍:
MyBatis在批量插入的时候,入参的形式多种多样,1.0版本使用List<Map<String, String>>的形式作为入参。不排除有些情况下需要使用POJO传递数据。基于此需求,研发的2.0版本,读取Excel之后返回List类型,自定义POJO的类型。
设计思想:
1、要求Excel中标题的名字和POJO中的属性名一致
(我们需要制定一些规矩,好让我们的代码能顺利的跑起来,当然这一点可能会降低用户的体验度,项目真正上线,Excel的文件模板肯定也是定好的,所以,体验上不会很差。)
2、从Excel中把标题取出
3、利用反射,获取到POJO的set方法,并执行赋值。
----------------------------------------
set方法的完整方法名如何获取?
4、利用反射获取到POJO的所有属性,并与【2、】去到的Excel中的标题比较(忽略大小写比较);
比较条件成立
将POJO的属性名首字母变大写,再拼接“set”即可的到完整的方法名。同时也可以通过方法名获取到指定的方法,然后执行传参。
话不多说,上代码
ExcelUtil.java
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.formula.functions.T;
import org.apache.poi.ss.usermodel.Cell;
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.xssf.usermodel.XSSFWorkbook;
@SuppressWarnings("hiding")
public class ExcelUtil<T> {
// 2007以前版本
public static final String XLS = ".XLS";
// 2007以后版本
public static final String XLSX = ".XLSX";
/**
* -读取excel,返回List<T>类型
* -要求Excel的标题名字要和传入的实体类的属性名保持一致
* @param suffix 文件的后缀名
* @param is 输入流
* @return
* @throws Exception
*/
@SuppressWarnings({ "unchecked", "null" })
public List<T> readExcel(String suffix, InputStream is, Class<T> clazz) throws Exception {
// 入参判断,任意一个为空则返回null
if(suffix == null || "".equals(suffix) || is == null || clazz == null) {
return null;
}
// 创建List用于封装数据
List<T> list = null;
String[] title = null;
Object obj = null;
// 获取类对象中所有的属性
Field[] fields = clazz.getDeclaredFields();
// 根据不同版本创建不同的EXCEL对象
Workbook wb = null;
if(XLS.equalsIgnoreCase(suffix)) {
wb = new HSSFWorkbook(is);
} else {
wb = new XSSFWorkbook(is);
}
// 获取第一个sheet
Sheet sheet = wb.getSheetAt(0);
// 获取最后一行(总行数)
int rowNum = sheet.getLastRowNum();
// 循环行
for(int r = 0; r <= rowNum; r++) {
// 行对象
Row row = sheet.getRow(r);
// 创建单条数据对象
if(r > 0) {
obj = clazz.newInstance();
if(list == null) {
list = new ArrayList<T>();
}
// 封装数据到list
list.add((T)obj);
}
// 每行最大的单元格数
int cellNum = row.getLastCellNum();
for(int c = 0; c < cellNum; c++) {
// 单元格对象
Cell cell = row.getCell(c);
String value = cell.getStringCellValue();
// excel第一行是标题行,将标题单独拿出放到数组中
if(r == 0) {
if(title == null) {
title = new String[cellNum];
}
title[c] = value;
// 第二行开始时数据行,将数据封装到对象中
} else {
// 属性名
String fieldName = "";
StringBuffer sb = null;
// 遍历属性,循环比较excel中读取的属性是否和类对象中的属性
for(Field field : fields) {
// 获取属性名
fieldName = field.getName();
// 忽略大小写比较excel中读取的属性是否和类对象中的相等
if(fieldName.equalsIgnoreCase(title[c])) {
sb = new StringBuffer();
// 属性名首字母大写
String firstChar = fieldName.substring(0, 1).toUpperCase();
// 属性名除首字母以外的字符
String otherChar = fieldName.substring(1);
// 拼接属性名,最后结果是属性名大写
sb.append(firstChar);
sb.append(otherChar);
break;
}
}
// 属性名构造失败时跳过当前循环
if(sb != null || !"".equals(sb.toString().trim())) {
// 构造set方法的方法名
String methodName = "set" + sb.toString();
// 根据方法名获取方法对象
Method method = clazz.getDeclaredMethod(methodName, String.class);
// 执行方法,传入参数
method.invoke(obj, value);
}
}
}
}
// 关闭资源
close(wb, is);
return list;
}
/**
* -关闭资源
* @param wb
* @param is
*/
public static void close(Workbook wb, InputStream is) {
try {
if(wb != null) {
wb.close();
}
if(is != null) {
is.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
测试类
@RequestMapping(value="/excelImport", method= {RequestMethod.POST})
public void excelImport(@RequestParam("userExcel") MultipartFile file) {
try {
// 文件的输入流(文件已经得到)
InputStream is = file.getInputStream();
// 文件名
String fileName = file.getOriginalFilename();
int index = fileName.lastIndexOf(".");
// 后缀名
String suffix = fileName.substring(index);
ExcelUtil<Users> excelUtil = new ExcelUtil<Users>();
List<Users> list = excelUtil.readExcel(suffix, is, Users.class);
for(Users user : list) {
System.out.println(user);
}
} catch (Exception e) {
e.printStackTrace();
}
}
POJO
public class Users {
String id;
String name;
String dept;
String account;
String password;
String headimg;
String gender;
String email;
String mobile;
String birthday;
String state;
String memo;
// 省略set/get
}
Exel数据
导入之后
Users [id=2, name=admin, dept=部门A, account=admin, password=admin, headimg=, gender=1, email=, mobile=, birthday=, state=1, memo=, sakujyo=1]
Users [id=402881e8578453390157845bd2730000, name=超级管理员, dept=部门A, account=superadmin, password=000000, headimg=user/402881e8578453390157845bd2730000.jpg, gender=1, email=790018823@qq.com, mobile=15238652508, birthday=2016-10-01, state=1, memo=我是superadmin, sakujyo=1]
Users [id=402881e9575c8fa101575c90a6150000, name=Peter, dept=部门B, account=admin, password=111, headimg=user/9027b570841341bfbb3617f924d26335.JPG, gender=0, email=790018823@qq.com, mobile=15238652508, birthday=2011-09-07, state=1, memo=测试数据, sakujyo=1]
Users [id=4028eedd57c0e09b0157c0e55f4f0000, name=jim, dept=部门B, account=jim, password=111, headimg=user/4028eedd57c0e09b0157c0e55f4f0000.jpg, gender=0, email=790018823@qq.com, mobile=15238652508, birthday=2016-10-05, state=1, memo=, sakujyo=1]
Users [id=4028eedd5870048a0158700e474f0003, name=aaa, dept=部门A, account=aaa, password=aaa, headimg=, gender=0, email=, mobile=, birthday=2016-11-15, state=1, memo=, sakujyo=1]
Users [id=4028eedd58715cd00158715db2ea0000, name=哦哦哦, dept=部门A, account=11, password=111, headimg=user/4028eedd58715cd00158715db2ea0000.jpg, gender=0, email=11@qq.com, mobile=, birthday=, state=1, memo=, sakujyo=1]
Users [id=ff8080815a409218015a418ca8fd0000, name=lisa, dept=部门A, account=admin1111, password=123456, headimg=, gender=0, email=790018823@qq.com, mobile=15238652508, birthday=1992-09-07, state=1, memo=, sakujyo=0]