一、首先。我们使用到的是apache的开源框架《poi》
1、导入相应的依赖包
2、连接数据库的框架可自行选择,下文使用的是mybatis-plus
Maven
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>4.1.2</version>
</dependency>
Gradle
compile 'org.apache.poi:poi:4.1.2'
compile 'org.apache.poi:poi-ooxml:4.1.2'
compile 'org.apache.poi:poi-ooxml-schemas:4.1.2'
excel导入数据到数据库原理。
- 当我们拿到excel表格,我们第一步应该先读取excel里面的数据信息。
- 通过特定的方法将读出来的数据封装到对象中。
- 每一行表示一个对象,每一列表示一个对象中的每一个字段属性。
- 当有多行时我们需要使用
List<Object>
(Object是对应excel表格数据的实体类对象)来存取对象- 拿到对象数组后,我们可以通过遍历得到,每一个对象,再通过mybatis将对象导入到数据库
知道了原理,有了思路。我们就可以开始干活了。
1、先拿到excel文件,我们使用MultipartFile接受文件。
2、拿到文件后。通过文件得到一个输入流
3、通过poi对excel进行解析,将表格中的每个数据通过for
循环得到。
demo案例:(内附注释)
先了解到我们需要保存哪些字段。
根据字段。创建对应的实体类。
实体类
public class BuiPatientInfo{
private static final long serialVersionUID = 1L;
/**
* 患者姓名
*/
@TableField("patient_name")
private String patientName;
/**
* 加密存储,不可反编译、列表不显示
*/
@TableField("patient_identity")
private String patientIdentity;
/**
* 就诊卡号
*/
@TableField("healing_Id")
private String healingId;
/**
* (性别)自动从身份证中截取
*/
@TableField("patient_sex")
private Integer patientSex;
/**
* (出生年月)自动从身份证中截取
*/
@TableField("patient_birthDate")
private LocalDate patientBirthdate;
/**
* 其他信息说明
*/
@TableField("else_Info")
private String elseInfo;
/**
* 创建人ID
*/
@TableField("create_id")
private Long createId;
/**
* 创建时间
*/
@TableField("create_time")
private LocalDateTime createTime;
/**
* 最后修改时间
*/
@TableField("update_time")
private LocalDateTime updateTime;
@TableField("patient_state")
private Integer patientState;
}
- 以下代码包含了对excel文件的检验是否合法。excel是哪年版的。
数据导入解析工具类
package com.mosukj.util;
import com.mosukj.manage.entity.BuiPatientInfo;
import com.spire.ms.System.DateTime;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
/**
* @author xjt
* @version 1.0
*/
public class ReadPatientExcelUtil {
//总行数
private static int totalRows = 0;
//总条数
private static int totalCells = 0;
//错误信息接收器
private static String errorMsg;
/**
* 读EXCEL文件,获取信息集合
* @return
*/
public static List<BuiPatientInfo> getExcelInfo(MultipartFile mFile) {
String fileName = mFile.getOriginalFilename();//获取文件名
try {
if (!validateExcel(fileName)) {// 验证文件名是否合格
return null;
}
boolean isExcel2003 = true;// 根据文件名判断文件是2003版本还是2007版本
if (isExcel2007(fileName)) {
isExcel2003 = false;
}
List<BuiPatientInfo> userList = createExcel(mFile.getInputStream(), isExcel2003);
return userList;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 根据excel里面的内容读取客户信息
* @param is 输入流
* @param isExcel2003 excel是2003还是2007版本
* @return
* @throws IOException
*/
public static List<BuiPatientInfo> createExcel(InputStream is, boolean isExcel2003) {
try{
Workbook wb = null;
if (isExcel2003) {// 当excel是2003时,创建excel2003
wb = new HSSFWorkbook(is);
} else {// 当excel是2007时,创建excel2007
wb = new XSSFWorkbook(is);
}
List<BuiPatientInfo> userList = readExcelValue(wb);// 读取Excel里面客户的信息
return userList;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* 读取Excel里面客户的信息
* @param wb
* @return
*/
private static List<BuiPatientInfo> readExcelValue(Workbook wb) {
//默认会跳过第一行标题
// 得到第一个shell
Sheet sheet = wb.getSheetAt(0);
// 得到Excel的行数
totalRows = sheet.getPhysicalNumberOfRows();
// 得到Excel的列数(前提是有行数)
if (totalRows > 1 && sheet.getRow(0) != null) {
totalCells = sheet.getRow(0).getPhysicalNumberOfCells();
}
List<BuiPatientInfo> userList = new ArrayList<BuiPatientInfo>();
// 循环Excel行数
for (int r = 1; r < totalRows; r++) {
Row row = sheet.getRow(r);
if (row == null){
continue;
}
BuiPatientInfo user = new BuiPatientInfo();
// 循环Excel的列
for (int c = 0; c < totalCells-1; c++) {
Cell cell = row.getCell(c);
if (null != cell) {
if (c == 0) { //第一列
//如果是纯数字,将单元格类型转为String
if(cell.getCellTypeEnum() == CellType.NUMERIC){
cell.setCellType(CellType.STRING);
}
user.setPatientName(cell.getStringCellValue());//将单元格数据赋值给user
}
else if (c == 1){
if(cell.getCellTypeEnum() == CellType.NUMERIC){
cell.setCellType(CellType.STRING);
}
user.setPatientIdentity(cell.getStringCellValue());
}
else if (c == 2){
if(cell.getCellTypeEnum() == CellType.NUMERIC){
cell.setCellType(CellType.STRING);
}
String stringCellValue = cell.getStringCellValue();
user.setHealingId(stringCellValue);
}
else if (c == 3){
if(cell.getCellTypeEnum() == CellType.NUMERIC){
cell.setCellType(CellType.STRING);
}
user.setElseInfo(String.valueOf(cell.getStringCellValue()));
}
}
}
//将excel解析出来的数据赋值给对象添加到list中
user.setUpdateTime(LocalDateTime.now());
user.setPatientBirthdate(IdentityUtil.getPatientBirth(user.getPatientIdentity())); //拿到身份中好通过已经写好的通过身份证信息获取出生年月工具类
user.setPatientSex(IdentityUtil.getPatientSex(user.getPatientIdentity())); //通过省份证号,获取男女信息工具类
user.setPatientState(1); //当前实体类字段是固定的,不是excel数据中的。每个对象都可以再遍历完后增加固定属性值
user.setCreateId(2L);
user.setCreateTime(LocalDateTime.now());
// 添加到list
userList.add(user);
}
return userList;
}
/**
* 验证EXCEL文件
*
* @param filePath
* @return
*/
public static boolean validateExcel(String filePath) {
if (filePath == null || !(isExcel2003(filePath) || isExcel2007(filePath))) {
errorMsg = "文件名不是excel格式";
return false;
}
return true;
}
// @描述:是否是2003的excel,返回true是2003
public static boolean isExcel2003(String filePath) {
return filePath.matches("^.+\\.(?i)(xls)$");
}
//@描述:是否是2007的excel,返回true是2007
public static boolean isExcel2007(String filePath) {
return filePath.matches("^.+\\.(?i)(xlsx)$");
}
}
调用getExcelInfo可以得到一个对象数组。
之后就方便导入数据库了
我拿到数组对象后的处理方式:
实例业务接口如下
@PostMapping("/excelExport")
public void test(HttpServletRequest request,HttpServletResponse response,@RequestParam(value="file",required = false) MultipartFile file){
long startTime = System.currentTimeMillis();
List<String> list = new ArrayList();
Map<String,Object> res = new HashMap<>();
int row=1;
int rowSuccess=0;
Integer errorCount=0;
QueryWrapper<BuiPatientInfo> wrapper;
// ReadExcel readExcel = new ReadExcel();
List<BuiPatientInfo> excelInfo = ReadPatientExcelUtil.getExcelInfo(file);
for (BuiPatientInfo patientInfo : excelInfo) {
// System.out.println(patientInfo);
wrapper=new QueryWrapper<>();
row++;
patientInfo.setHealingId(patientInfo.getHealingId());
wrapper.eq("healing_Id", patientInfo.getHealingId());
wrapper.ne("patient_state", 9);
//业务代码,通过患者id查询数据库中式否有该患者,如果已存在,则不保存,跳过该患者
int patientCount = buiPatientInfoService.getBaseMapper().getPatientCount(wrapper);
if (patientCount>0){
list.add("在第"+row+"行的<"+patientInfo.getHealingId()+">患者已存在!!");
errorCount++;
}else {
boolean save = buiPatientInfoService.save(patientInfo);
if (save){
rowSuccess++;
}
}
}
if (list.size()>0){
res.put("log", list);
}
res.put("success", "导入数据成功条数:"+rowSuccess);
res.put("error", "导入数据失败条数:"+errorCount);
long endTime = System.currentTimeMillis();
String time = String.valueOf((endTime - startTime) / 1000);
res.put("time", "导入数据用时:"+time+"秒");
renderResult(response, res);
}
renderResult()是封装好的返回前端数据的一个工具类,如需了解,请异步我的另一篇文章
封装好的返回前端数据工具类详情(传送门)
excel模板
以上从excel获取数据导入到数据库为静态的导入,动态获取字段导入到数据库请移步笔者其他文章链接:动态导入数据到数据库。(注意,excel模板为固定字段,每一列对应工具类里面的获取第1/2/3…)
- 调用成功后返回。导入失败数据所在的行号,并注释姓名(根据需要可修改)。
- 成功导入条数。
- 导入用时
- 导入成功数、导入失败数
有疑问欢迎大家评论区讨论交流!乐意解答。