一、准备工作:
- pom.xml 导入相应解析Excel文件依赖包
<!--解析excel-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.0.1</version>
</dependency>
- 准备一份Excel模板
- 准备SQL数据库表
二、优化点:
ExcelUtil 工具类定义为范型类,使得ExcelUtil可以解析任何Excel文件并且封装到相对应的实体类再放入LIst集合中,执行动态SQL语句插入数据库中,达到一个解析工具的多次复用。
三、代码实现:
1. Controller 层:
/**
*@ClassName: StudentController
*@Description: 上传excel
*@Params: file
*@Return:
*@Author xxw
*@Date 2020/12/15
*/
@PostMapping("/uploadExcel")
public Msg uploadExcel(@RequestParam("file")MultipartFile file) throws IOException {
String fileName = file.getOriginalFilename(); // 获取文件名
InputStream is = null;
try{
is = file.getInputStream();
List<Map> studentList = studentService.getListByExcel(is,fileName);// 获取解析后的List集合
// System.out.println(studentList.toString());
Boolean result = studentService.batchImportStuInfo(studentList); // 把数据插入数据库
if (result){
return Msg.sussess().add("info", "文件上传成功!");
}else {
return Msg.failure().add("info", "文件上传失败!");
}
}catch (Exception e){
e.printStackTrace();
} finally {
is.close();
}
return Msg.failure().add("info", "文件错误!");
}
2. Service 层:
public List<Map> getListByExcel(InputStream is,String fileName) throws IOException {
try{
List<Map> studentList = new ExcelUtil(new Student()).AnalysisExcel(is, fileName);
return studentList;
}catch (Exception e){
e.printStackTrace();
}
return new ArrayList<>();
}
public Boolean batchImportStuInfo(List<Map> list){
Integer flag = studentMapper.batchImportStuInfo(list);
if (flag > 0){
return true;
} else return false;
}
3. mapper 层:
package com.xxw.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Map;
@Repository
@Mapper
public interface StudentMapper {
// 批量导入学生信息
Integer batchImportStuInfo(List<Map> studentList);
}
4. ExcelUtil 工具类:
package com.xxw.utils;
/*
* 解析excel工具类
* */
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.*;
public class ExcelUtil<T> {
// 定义范型,这样就能传对应的实体类来封装excel数据
private T t;
public ExcelUtil(T t) {
this.t = t;
}
/**
*@ClassName: ExcelUtil
*@Description: 传入excel解析excel文件,提取出信息
*@Params: InputStream is, String fileName
*@Return:
*@Author xxw
*@Date 2020/12/15
*/
public List<Map> AnalysisExcel(InputStream is, String fileName) throws IOException {
List<Map> list = new ArrayList<>();
Workbook workbook = createWorkbookByExcelType(is, fileName); // 创建工作簿
Sheet sheet = workbook.getSheetAt(0);
Row row = null;
// 获取最大行数
int maxRowNum = sheet.getLastRowNum();
// 获取第一行
row = sheet.getRow(0);
// 获取最大列数
int maxColNum = row.getLastCellNum();
List<String> arrayList = new ArrayList<>();
Field[] declaredFields = t.getClass().getDeclaredFields();
// 把需要封装的实体类的属性名存入arrayList
for (int i = 0; i < declaredFields.length; i++) {
String name = declaredFields[i].getName();
arrayList.add(name);
}
// 循环遍历excel表格,把每条数据封装成 map集合,再放入list集合中
for (int i = 0; i <= maxRowNum; i++) {
Map<String, String> map = new HashMap<>();
row = sheet.getRow(i);
if (row != null){
for (int j = 0; j < maxColNum; j++) {
String cellData = (String)getCellFormatValue(row.getCell(j));
map.put(arrayList.get(j), cellData); // map 封装
}
list.add(map); // map存入list
}
}
return list;
}
//根据传入的文件名后缀判断是xls还是xlsx
public static Workbook createWorkbookByExcelType(InputStream inputStream,String fileName){
Workbook wb = null;
if(fileName == null){
return null;
}
String extString = fileName.substring(fileName.lastIndexOf("."));
InputStream is = null;
try {
is = inputStream;
if(".xls".equals(extString)){
return wb = new HSSFWorkbook(is); // 2003版本 .xls
}else if(".xlsx".equals(extString)){
return wb = new XSSFWorkbook(is); // 2007版本 .xlsx
}else{
return wb = null;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return wb;
}
// 用于获取表格中的数据方法
public static Object getCellFormatValue(Cell cell){
Object cellValue = null;
if(cell!=null){
//判断cell类型
switch(cell.getCellType()){
case NUMERIC:{
cellValue = String.valueOf(cell.getNumericCellValue());
break;
}
case FORMULA:{
//判断cell是否为日期格式
if(DateUtil.isCellDateFormatted(cell)){
//转换为日期格式YYYY-mm-dd
cellValue = cell.getDateCellValue();
}else{
//数字
cellValue = String.valueOf(cell.getNumericCellValue());
}
break;
}
case STRING:{
cellValue = cell.getRichStringCellValue().getString();
break;
}
default:
cellValue = "";
}
}else{
cellValue = "";
}
return cellValue;
}
}
5. Mapper.xml 映射文件:
<insert id="batchImportStuInfo" parameterType="java.util.List">
insert into student values
<foreach item="item" collection="list" separator=",">
(
#{item.id},
#{item.stuName},
#{item.sex},
#{item.cardId},
#{item.stuId},
#{item.political},
#{item.major},
#{item.classGrade},
#{item.tel},
#{item.stuStatus}
#{item.city}
)
</foreach>
</insert>
6. application.yml 配置文件:
spring:
servlet:
multipart:
max-file-size: 1000MB #上传文件大小
max-request-size: 1000MB #下载文件大小
四、 代码分析:
MultipartFile为org.springframework.web.mutipart包下的一个类,也就是说如果想使用MultipartFile这个类就必须引入spring框架,换句话说,如果想在项目中使用MultipartFile这个类,那么项目必须要使用spring框架才可以,否则无法引入这个类。MultipartFile翻译成中文来讲就是“多组件的文档”,一般来讲使用MultipartFile这个类主要是来实现以表单的形式进行文件上传功能。