前言:在实际工作中,遇到了数据导入问题。我这里使用了Hutool工作包的excel导入方法,下面是实现代码。
代码实现:
controller层:
@PostMapping("/uploadFile")
public JSONObject upload(@RequestParam("file")MultipartFile file) throws IOException {
JSONObject result = this.dataSharingDylwhzService.upload(file);
return result;
}
service层:
/**
* 文件上传(使用hutool进行批量上传,适用于小批量的数据上传,如果上传的excel大于10MB,则会报错内存溢出错误,使用easyExcel技术即可解决)
* @param file: 上传的文件
* @return
*/
@Override
@Transactional
public JSONObject upload(MultipartFile file) throws IOException {
//获取当前用户名
String userName = SwbUserSecurityUtil.getInstance().getSwbUser().getUserName();
//获取当前时间
Date date = new Date();
//创建一个存放返回结果的对象
JSONObject result = new JSONObject();
AjaxBackData ajax = null;
// 通过文件获取输入流
InputStream in = file.getInputStream();
// 调用 hutool 方法读取数据 默认调用第一个sheet
ExcelReader reader = ExcelUtil.getReader(in);
try {
//对上传的文件进行验证
if (Objects.isNull(file) || Objects.isNull(file.isEmpty())){
ajax = new AjaxBackData(false,"上传文件不能为空,请重新上传!");
}else { //上传的文件无误,可以上传
//忽略第一行头(第一行是中文的情况),直接读取表的内容
List<List<Object>> list = reader.read(1);
//创建一个新的ArrayList
List<DataSharingDylwhz> dylwhzList = CollUtil.newArrayList();
//循环遍历数据
for (List<Object> row : list) {
DataSharingDylwhz dylwhz = new DataSharingDylwhz();
dylwhz.setId(IdUtil.simpleUUID()); //使用UUID对象用于生成主键
dylwhz.setSbny(row.get(1).toString());
dylwhz.setNyzwrs(Integer.valueOf(row.get(2).toString()));
dylwhz.setYgzwrs(Integer.valueOf(row.get(3).toString()));
dylwhz.setNyzzzwrs(Integer.valueOf(row.get(4).toString()));
dylwhz.setCreateName(userName);
dylwhz.setCreateTime(date);
dylwhzList.add(dylwhz);
}
//循环遍历dylwhzList集合,找出数据库中是否有已经存在的数据
for (DataSharingDylwhz dylwhz : dylwhzList) {
String sbny = dylwhz.getSbny();
//判断上报年月是不为null或空则查询删除数据
if (StringUtils.isNotBlank(sbny)){
//通过这几个条件判断数据库中是否存在该数据
List<String> ids = this.dataSharingDylwhzDao.getDataIdsByCondition(sbny);
//如果数据库中存在,则删除数据库中存在的数据
if (!ids.isEmpty()){
this.dataSharingDylwhzDao.deleteByIds(ids);
}
}
}
//批量插入数据
log.info("===== 开始插入数据 =====");
long startTime = System.currentTimeMillis();
//创建一个集合,用于临时存放数据
ArrayList<DataSharingDylwhz> temporaryList = new ArrayList<>();
//循环插入全部数据,每1000条数据往临时集合中存放一次,然后执行批量插入方法,之后清空临时集合,以此往复
for (int i = 0; i < dylwhzList.size(); i++){
//将当前数据添加到临时集合中
temporaryList.add(dylwhzList.get(i));
//每1000次执行一次批量插入操作
if ((i + 1) % 1000 == 0){
//批量插入方法
this.dataSharingDylwhzDao.batchSave(temporaryList);
//清空临时集合
temporaryList.clear();
}
}
//处理剩余的数据(不足1000条的情况)
if (!temporaryList.isEmpty()) {
this.dataSharingDylwhzDao.batchSave(temporaryList);
}
//插入数据用时
long spendTime = System.currentTimeMillis() - startTime;
log.info("===== 成功插入" + dylwhzList.size() + "条数据,耗时:" + spendTime + "毫秒");
ajax = new AjaxBackData(true, "上传成功!");
}
}catch (UncategorizedSQLException e){
SQLException sqlException = e.getSQLException();
int errorCode = sqlException.getErrorCode();
if (errorCode == 12899){
ajax = new AjaxBackData(false, "上传失败,请检查数据内容大小,修改后重试!");
}
e.printStackTrace();
}catch (DataIntegrityViolationException e){
Throwable cause = e.getCause();
//instanceof 是一个关键字,用于测试一个对象是否是一个类的实例或者是该类的子类的实例
if (cause instanceof SQLException){
SQLException sqlException = (SQLException) cause;
int errorCode = sqlException.getErrorCode();
if (errorCode == 1722){
ajax = new AjaxBackData(false, "上传失败,请检查数据格式,修改后重试!");
}
}else {
ajax = new AjaxBackData(false, "上传出现异常,请稍后重试!");
}
e.printStackTrace();
}catch (Exception e){
ajax = new AjaxBackData(false, "上传失败,请稍后重试!");
e.printStackTrace();
}finally {
//关闭流对象
reader.close();
in.close();
}
result.put("ajax", ajax);
return result;
}
控制台输出:
===== 开始插入数据 =====
===== 成功插入15562条数据,耗时:5000毫秒
这段代码的核心是:
ExcelReader reader = ExcelUtil.getReader(in);
使用 Hutool中的ExcelUtil.getReader()方法将实体Excel文件转换为Hutool封装的ExcelReader对象。后续可以通过这个对象读取excel文件的内容。
注意:
当上传的excel数据量过大时(大于10MB),就不能使用这个方法了,因为这个方法会读取Excel会非常缓慢,在内存中加载大量数据,尤其是当整个文件的内容都被加载到内存中时,可能会导致内存不足。抛出java.lang.OutOfMemoryError: GC overhead limit exceeded异常并造成内存溢出错误。那么当我们在上传大批量的数据时,可以考虑使用easyExcel插件处理。