一、流程概念
我们需要把excel通过上传得方式导入数据库,需要以下几个步骤
- 将excel上传到服务器指定文件内并重命名(upload)
- 获取到文件公共路径和别名路径
- 将上传得文件转化成输入流(poi框架)
- 通过方法,将输入流文件数值转化成List<List<Object>>对象
- 遍历excel中得值,调用一次setFieldValueByFieldName方法,就对属性赋值一次,每次循环拿到一条数据,最终得到整个数据。
- 后台调用getObjectList(file, Exam.class)。
二、conroller中的方法
@PostMapping("/upload")
public ResultJson uploadFile(MultipartFile file ) throws Exception {
List<Object> objects = ObjectList.getObjectList(file, Exam.class);
List<Exam> list = (List) objects;
boolean flag = examService.saveOrUpdateBatch(list);
if (flag) {
return ResultJson.ok();
}
return ResultJson.failure(ResultCode.NOT_UPDATE);
}
前天传过来得是二进制文件MultipartFile file
调用getObjectList方法(二进制文件,实体类对象)
package tech.niua.common.excelimport;
public class ObjectList {
/**
* 封装的将Excel文件信息转换成List<Object>的方法,需要传实体类
* @param file
* @param
* @return
* @throws Exception
*/
public static List<Object> getObjectList(MultipartFile file, Class cls) throws Exception {
//获取到了文件根路径
String filePath = NiuaConfig.getUploadPath();
// 上传并返回文件除根路径得路径 052d1c92-fc6a-4e15-a7c9-7d193c1a4bec.xlsx
String fileName = FileUploadUtils.upload(filePath, file);
//完整的上传文件的路径
fileName =filePath+ File.separator+fileName;
//把上传的文件转换成输入流(因为我们使用得是poi框架,要求使用输入流)
FileInputStream fileInputStream = new FileInputStream(new File(fileName));
//输入流 和 文件路径 作为参数传入 获取List<List<Object>>类型数据的方法中
List<List<Object>> list = ExcelUtils.getListByExcel(fileInputStream,fileName);
/**
* 将数据转换成List<Object>类型的数据
*/
//初始化标题
List<Object> firstRows = null;
//如果转换过来的数据不为空,拿到标题,在之前的方法中判断过是否为空
if (list != null && list.size() > 0) {
firstRows = list.get(0);
}
//初始化实际数据 初始化对象
List<Object> excelDate = new ArrayList<>();
//从一开始遍历,为的是拿到数据
for (int i = 1; i < list.size(); i++) {
//每一行实例化一个List<Object>数据,后面插入的也是这些
List<Object> rows = list.get(i);
//实例化对象,方便赋值(for里面是每次都改变数据,防止都访问这一个地址)
Object obj = cls.newInstance();
//对obj的每一个的字段进行赋值
for (int j = 0; j < rows.size(); j++) {
//把excel转过来的数据的每个字段的值转换成String类型
String cellVal = (String) rows.get(j);
//对obj进行赋值(对象,字段名,字段值)
ObjectList.setFieldValueByFieldName(obj, firstRows.get(j).toString().trim(), cellVal);
}
//添加进List<Object>,每个obj都是一条数据
excelDate.add(obj);
}
return excelDate;
}
public static void setFieldValueByFieldName(Object object, String fieldName, Object val) {
try {
//反射拿到实体类每个变量得对象
Field[] fields = object.getClass().getDeclaredFields();
//把实体类每个变量遍历一遍
for (int i = 0; i < fields.length; i++) {
//拿到一个对象
Field field = fields[i];
///可以访问私有
field.setAccessible(true);
//判断excel注解修饰
Excel excel = field.getAnnotation(Excel.class);
if(excel== null){
continue;
}
//如果excel转化过来的标题名和实体类字段或者实体类注解相同,说明对应上了,赋值!!
if(fieldName.equals(excel.name())||fieldName.equals(field.getName())){
//将excel中得String类型得数值,转化成对应实体类属性,把属性值set进对象
if(field.getType()== Integer.class){
//把有这个类型的要被赋值的对象和这个类型的数值当作参数,可以赋值
field.set(object,Integer.valueOf(val.toString()));
} else if(field.getType()== Long.class){
field.set(object,Long.valueOf(val.toString()));
}else if(field.getType()== LocalDateTime.class){
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime time = LocalDateTime.parse(val.toString(), df);
field.set(object,time);
}
else{
field.set(object, val);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
package tech.niua.common.excelimport;
/**
* Created by ws
* Date :2022/4/29
* Description : excel导入工具类
* Version :1.0
*/
public class ExcelUtils {
private final static String excel2003L =".xls"; //2003- 版本的excel
private final static String excel2007U =".xlsx"; //2007+ 版本的excel
/**
* @Description:获取IO流中的数据,组装成List<List<Object>>对象
* @param in,fileName
* @return
* @throws IOException
*/
public static List<List<Object>> getListByExcel(InputStream in, String fileName) throws Exception{
List<List<Object>> list = null;
//创建Excel工作薄
Workbook work = getWorkbook(in,fileName);
if(null == work){
throw new Exception("创建Excel工作薄为空!");
}
Sheet sheet = null; //页数
Row row = null; //行数
Cell cell = null; //列数
list = new ArrayList<List<Object>>();
//遍历Excel中所有的sheet
for (int i = 0; i < work.getNumberOfSheets(); i++) {
//取某个sheet
sheet = work.getSheetAt(i);
if(sheet== null){continue;}
//遍历当前sheet中的所有行
for (int j = sheet.getFirstRowNum(); j <= sheet.getLastRowNum(); j++) {
row = sheet.getRow(j);
if(row == null){continue;}
//遍历所有的列
List<Object> li = new ArrayList<Object>();
for (int y = row.getFirstCellNum(); y < row.getLastCellNum(); y++) {
cell = row.getCell(y);
li.add(getValue(cell));
}
list.add(li);
}
}
return list;
}
/**
* @Description:根据文件后缀,自适应上传文件的版本
* @param inStr,fileName
* @return
* @throws Exception
*/
public static Workbook getWorkbook(InputStream inStr, String fileName) throws Exception{
Workbook wb = null;
String fileType = fileName.substring(fileName.lastIndexOf("."));
if(excel2003L.equals(fileType)){
wb = new HSSFWorkbook(inStr); //2003-
}else if(excel2007U.equals(fileType)){
wb = new XSSFWorkbook(inStr); //2007+
}else{
throw new Exception("解析的文件格式有误!");
}
return wb;
}
/**
* @Description:对表格中数值进行格式化
* @param cell
* @return
*/
//解决excel类型问题,获得数值
public static String getValue(Cell cell) {
String value = "";
if(null == cell){
return value;
}
switch (cell.getCellType()) {
//数值型
case NUMERIC:
if (DateUtil.isCellDateFormatted(cell)) {
//如果是date类型则 ,获取该cell的date值
Date date = DateUtil.getJavaDate(cell.getNumericCellValue());
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
value = format.format(date);;
}else {// 纯数字
BigDecimal big= new BigDecimal(cell.getNumericCellValue());
value = big.toString();
//解决1234.0 去掉后面的.0
if(null!= value&&!"".equals(value.trim())){
String[] item = value.split("[.]");
if(1<item.length&&"0".equals(item[1])){
value = item[0];
}
}
}
break;
//字符串类型
case STRING:
value = cell.getStringCellValue();
break;
// 公式类型
case FORMULA:
//读公式计算值
value = String.valueOf(cell.getNumericCellValue());
if (value.equals("NaN")) {// 如果获取的数据值为非法值,则转换为获取字符串
value = cell.getStringCellValue();
}
break;
// 布尔类型
case BOOLEAN:
value = " "+ cell.getBooleanCellValue();
break;
default:
value = cell.getStringCellValue();
}
if("null".endsWith(value.trim())){
value= "";
}
return value;
}
}