记录万级数据Excel导入优化
实现方式:Poi+数据校验+多线程+异步批量分组插入
poi依赖
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>3.9</version>
</dependency>
参数校验:非空,或正则校验
class DownloadTemplateVO extends IExcelModel{
//卡
@Excel(name="号")
@NotBlank(message = "号不能为空")
@BeanProperty
var no:String =_
//登记时间
@Excel(name="登记时间" ,format = "yyyy-MM-dd hh:mm:ss")
@BeanProperty
@NotNull
var enterTime:Date =_
//失败原因 用于设置失败原因
// @Excel(name="失败原因")
@BeanProperty
var errorMsg:String =_
}
controller
@PostMapping(value = Array("/importExcel"), produces = Array(MediaType.MULTIPART_FORM_DATA_VALUE))
def importExcel(entityVO: CardVO, @RequestParam("multipartFile") multipartFile: MultipartFile,
request: HttpServletRequest, response: HttpServletResponse) {
//获取文件后缀
val suffix = multipartFile.getOriginalFilename().substring(multipartFile.getOriginalFilename().lastIndexOf(".") + 1)
//文件格式
val EXT_FILE_NAME = "xlsx"
if (!EXT_FILE_NAME.equals(suffix)) {
return write(response, BaseResponse.error("文件格式不正确"))
}
val importParams: ImportParams = new ImportParams()
// 需要验证
importParams.setNeedVerify(true);
val list = new java.util.ArrayList[SuccessCardVO]()
val result: ExcelImportResult[DownloadTemplateVO] = ExcelImportUtil.importExcelMore(multipartFile.getInputStream,
classOf[DownloadTemplateVO], importParams)
//验证通过List
val successList: util.List[DownloadTemplateVO] = result.getList
val saveList=new CopyOnWriteArrayList[Card]()
//创建线程池
val executor=Executors.newFixedThreadPool(1000)
//记录成功、失败数
val successTotal=new java.util.concurrent.atomic.AtomicInteger()
val failTotal=new java.util.concurrent.atomic.AtomicInteger()
successList.forEach(
downloadTemplateVo => {
val thread=new Thread(){
override def run(): Unit ={
val hdqryCard = hdqryService.getEntityByCardNo(downloadTemplateVo.cardNo)
//查询数据库不存在 失败数自增
if(hdqryCard==null){
failTotal.incrementAndGet()
}
val card: Card = new Card
copyHdqryCardEntityToCardEntity(hdqryCard, card)
card.setCardNo(downloadTemplateVo.cardNo)
card.setOperationUserId(getOptId.toString)
card.setEnterTime(entityVO.enterTime)
val createTime = new Date()
card.setCreateTime(createTime)
card.setIsTimeout("0")
card.setIsInform("0")
card.setCardTreatmentState("0")
saveList.add(card)
//成功数自增
successTotal.incrementAndGet()
val successCardVO = new SuccessCardVO
BeanUtils.copyProperties(downloadTemplateVo, successCardVO)
successCardVO.setCreateTime(createTime)
successCardVO.setResult("上传成功")
list.add(successCardVO)
}
}
executor.submit(thread)
})
//关闭线程池
executor.shutdown()
//异步批量插入
service.saveList(saveList)
//验证失败List
val failList: util.List[DownloadTemplateVO] = result.getFailList
failList.forEach(
downloadTemplateVo => {
val s = new SuccessCardVO
BeanUtils.copyProperties(downloadTemplateVo, s)
val failWorkbook = result.getFailWorkbook
val sheet = failWorkbook.getSheetAt(0)
//遍历获取失败原因
for (a <- 1 until sheet.getPhysicalNumberOfRows) {
val row = sheet.getRow(a)
val cell = row.getCell(row.getLastCellNum - 1)
if (cell != null && cell != "") {
cell.setCellType(CellType.STRING)
val value = cell.getStringCellValue()
s.setResult(value)
}
}
list.add(s)
}
)
val re = new util.HashMap[String, Object]()
re.put("result", list)
re.put("total", list.size().toString)
re.put("successTotal",successList.size().toString)
re.put("failTotal",failList.size().toString)
write(response, BaseResponse.success(re))
}
}
//异步批量插入 启动类添加注解 @EnableAsync
@Async
def saveList(list: List[Card]): BaseResponse[Any] = {
//在这里将数组拆分成多个数组插入 代码省略
mapper.insertList(list)
BaseResponse.success()
}

浙公网安备 33010602011771号