diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelListener.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelListener.java new file mode 100644 index 000000000..5705e94da --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelListener.java @@ -0,0 +1,116 @@ +package com.ruoyi.common.utils.poi; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.exception.ExcelAnalysisException; +import com.alibaba.excel.exception.ExcelDataConvertException; +import com.alibaba.fastjson.JSON; +import com.ruoyi.common.utils.ValidatorUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import javax.validation.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 公共excel监听类 + * @param + */ +public class ExcelListener extends AnalysisEventListener { + + private static final Logger LOGGER = LoggerFactory.getLogger(ExcelListener.class); + /** 数据对象list */ + private final List list = new ArrayList<>(); + /** 错误信息列表 */ + private final List errorList = new ArrayList<>(); + /** 遇到异常是否跳出导入,默认为是 */ + private Boolean skipException = Boolean.TRUE; + /** 是否Validator检验,默认为是 */ + private Boolean isValidate = Boolean.TRUE; + /** + * 导入回执 + */ + private final ExcelResult excelResult = new ExcelResult<>(); + + public ExcelListener() { + + } + + public ExcelListener(boolean isValidate, boolean skipException) { + this.isValidate = isValidate; + this.skipException = skipException; + } + + /** + * 处理异常 + * + * @param exception ExcelDataConvertException + * @param context excel上下文 + */ + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + // 如果是某一个单元格的转换异常 能获取到具体行号 + // 如果要获取头的信息 配合doAfterAllAnalysedHeadMap使用 + String errMsg = null; + if (exception instanceof ExcelDataConvertException) { + ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception; + errMsg = StrUtil.format("第{}行-第{}列解析异常
", excelDataConvertException.getRowIndex() + 1, + excelDataConvertException.getColumnIndex() + 1); + LOGGER.error(errMsg); + } + if (exception instanceof ConstraintViolationException) { + ConstraintViolationException constraintViolationException = (ConstraintViolationException)exception; + Set> constraintViolations = constraintViolationException.getConstraintViolations(); + String constraintViolationsMsg= CollUtil.join(constraintViolations + .stream() + .map(ConstraintViolation::getMessage) + .collect(Collectors.toList()), + ","); + errMsg = StrUtil.format("第{}行数据校验异常:{}", context.readRowHolder().getRowIndex() + 1, + constraintViolationsMsg); + LOGGER.error(errMsg); + } + errorList.add(errMsg); + if (!skipException){ + throw new ExcelAnalysisException(errMsg); + } + } + + @Override + public void invokeHeadMap(Map headMap, AnalysisContext context) { + LOGGER.debug("解析到一条头数据:{}", JSON.toJSONString(headMap)); + } + + @Override + public void invoke(T data, AnalysisContext context) { + if (isValidate) { + ValidatorUtils.validate(data); + } + list.add(data); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + excelResult.setList(list); + excelResult.setErrorList(errorList); + LOGGER.debug("所有数据解析完成!"); + } + + /** + * 获取导入数据 + * @return 导入数据 + */ + public List getList() { + return list; + } + + public ExcelResult getExcelResult() { + return excelResult; + } + +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelResult.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelResult.java new file mode 100644 index 000000000..3e17548ad --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelResult.java @@ -0,0 +1,40 @@ +package com.ruoyi.common.utils.poi; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +@Data +public class ExcelResult { + + /** 数据对象list + */ + private List list; + /** 错误信息列表 */ + private List errorList; + + /** + * 获取导入回执 + * @return 导入回执 + */ + public String getAnalysis() { + int successCount = list.size(); + int errorCount = errorList.size(); + if (successCount == 0) { + return "读取失败,未解析到数据"; + } else { + if (errorList.size() == 0) { + return StrUtil.format("恭喜您,全部读取成功!共{}条", successCount); + } else { + return StrUtil.format("部分读取成功,其中成功{}条,失败{}条,错误信息如下:
{}", + successCount, + errorCount, + CollUtil.join(errorList, "
")); + } + + } + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java index 0775ce57c..8802a546a 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java @@ -6,6 +6,7 @@ import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy import com.ruoyi.common.convert.ExcelBigNumberConvert; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.file.FileUtils; +import org.apache.poi.ss.formula.functions.T; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; @@ -30,6 +31,19 @@ public class ExcelUtil { return EasyExcel.read(is).head(clazz).autoCloseStream(false).sheet().doReadSync(); } + + /** + * 对excel表单默认第一个索引名转换成list(EasyExcel) + * + * @param is 输入流 + * @return 转换后集合 + */ + public static ExcelResult importExcel(InputStream is, Class clazz, boolean isValidate, boolean skipException) { + ExcelListener listener = new ExcelListener<>(isValidate, skipException); + EasyExcel.read(is, clazz, listener).sheet().doRead(); + return listener.getExcelResult(); + } + /** * 对list数据源将其里面的数据导入到excel表单(EasyExcel) * diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestDemoController.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestDemoController.java index 7b7036030..0307d13f4 100644 --- a/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestDemoController.java +++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestDemoController.java @@ -1,27 +1,31 @@ package com.ruoyi.demo.controller; +import cn.hutool.core.bean.BeanUtil; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.annotation.RepeatSubmit; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.core.validate.AddGroup; import com.ruoyi.common.core.validate.EditGroup; import com.ruoyi.common.core.validate.QueryGroup; import com.ruoyi.common.enums.BusinessType; import com.ruoyi.common.utils.ValidatorUtils; +import com.ruoyi.common.utils.poi.ExcelResult; import com.ruoyi.common.utils.poi.ExcelUtil; +import com.ruoyi.demo.domain.TestDemo; import com.ruoyi.demo.domain.bo.TestDemoBo; +import com.ruoyi.demo.domain.bo.TestDemoImportVo; import com.ruoyi.demo.domain.vo.TestDemoVo; import com.ruoyi.demo.service.ITestDemoService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; +import io.swagger.annotations.*; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletResponse; import javax.validation.constraints.NotEmpty; @@ -65,6 +69,21 @@ public class TestDemoController extends BaseController { return iTestDemoService.customPageList(bo); } + @ApiOperation("导入测试单表") + @ApiImplicitParams({ + @ApiImplicitParam(name = "file", value = "导入文件", dataType = "java.io.File", required = true), + }) + @Log(title = "测试单表", businessType = BusinessType.IMPORT) + @PreAuthorize("@ss.hasPermi('demo:demo:import')") + @PostMapping("/importData") + public AjaxResult importData(@RequestPart("file") MultipartFile file) throws Exception { + ExcelResult excelResult = ExcelUtil.importExcel(file.getInputStream(), TestDemoImportVo.class, true, true); + List volist = excelResult.getList(); + List list = BeanUtil.copyToList(volist, TestDemo.class); + iTestDemoService.saveAll(list); + return AjaxResult.success(excelResult.getAnalysis()); + } + /** * 导出测试单表列表 */ diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/bo/TestDemoImportVo.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/bo/TestDemoImportVo.java new file mode 100644 index 000000000..2150cdfe7 --- /dev/null +++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/bo/TestDemoImportVo.java @@ -0,0 +1,66 @@ +package com.ruoyi.demo.domain.bo; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.ruoyi.common.core.domain.BaseEntity; +import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.core.validate.EditGroup; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * 测试单表业务对象 test_demo + * + * @author Lion Li + * @date 2021-07-26 + */ + +@Data +@ApiModel("测试单表业务对象") +public class TestDemoImportVo { + + + /** + * 部门id + */ + @ApiModelProperty("部门id") + @NotNull(message = "部门id不能为空") + @ExcelProperty(value = "部门id") + private Long deptId; + + /** + * 用户id + */ + @ApiModelProperty("用户id") + @NotNull(message = "用户id不能为空") + @ExcelProperty(value = "用户id") + private Long userId; + + /** + * 排序号 + */ + @ApiModelProperty("排序号") + @NotNull(message = "排序号不能为空") + @ExcelProperty(value = "排序号") + private Long orderNum; + + /** + * key键 + */ + @ApiModelProperty("key键") + @NotBlank(message = "key键不能为空") + @ExcelProperty(value = "key键") + private String testKey; + + /** + * 值 + */ + @ApiModelProperty("值") + @NotBlank(message = "值不能为空") + @ExcelProperty(value = "值") + private String value; +} diff --git a/ruoyi-ui/src/views/demo/demo/index.vue b/ruoyi-ui/src/views/demo/demo/index.vue index 9ff0e4755..c6a2cdffc 100644 --- a/ruoyi-ui/src/views/demo/demo/index.vue +++ b/ruoyi-ui/src/views/demo/demo/index.vue @@ -71,6 +71,16 @@ v-hasPermi="['demo:demo:remove']" >删除 + + 导入 + 取 消 + + + + +
将文件拖到此处,或点击上传
+
+ +