From 7c4a10482326ef418dd9e0713fda3761e665accb Mon Sep 17 00:00:00 2001
From: 疯狂的狮子Li <15040126243@163.com>
Date: 星期五, 26 十一月 2021 16:40:42 +0800
Subject: [PATCH] !113 add 新增 excel 导入支持开启 Validator 数据验证 Merge pull request !113 from Yjoioooo/auto-5403234-dev-1637903026810
---
ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestDemoController.java | 25 +++
ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java | 14 ++
ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelListener.java | 116 +++++++++++++++++++
ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelResult.java | 40 ++++++
ruoyi-ui/src/views/demo/demo/index.vue | 67 +++++++++++
ruoyi-demo/src/main/java/com/ruoyi/demo/domain/bo/TestDemoImportVo.java | 66 +++++++++++
6 files changed, 325 insertions(+), 3 deletions(-)
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 0000000..5705e94
--- /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 <T>
+ */
+public class ExcelListener<T> extends AnalysisEventListener<T> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ExcelListener.class);
+ /** 鏁版嵁瀵硅薄list */
+ private final List<T> list = new ArrayList<>();
+ /** 閿欒淇℃伅鍒楄〃 */
+ private final List<String> errorList = new ArrayList<>();
+ /** 閬囧埌寮傚父鏄惁璺冲嚭瀵煎叆锛岄粯璁や负鏄� */
+ private Boolean skipException = Boolean.TRUE;
+ /** 鏄惁Validator妫�楠岋紝榛樿涓烘槸 */
+ private Boolean isValidate = Boolean.TRUE;
+ /**
+ * 瀵煎叆鍥炴墽
+ */
+ private final ExcelResult<T> 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("绗瑊}琛�-绗瑊}鍒楄В鏋愬紓甯�<br/>", excelDataConvertException.getRowIndex() + 1,
+ excelDataConvertException.getColumnIndex() + 1);
+ LOGGER.error(errMsg);
+ }
+ if (exception instanceof ConstraintViolationException) {
+ ConstraintViolationException constraintViolationException = (ConstraintViolationException)exception;
+ Set<ConstraintViolation<?>> 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<Integer, String> headMap, AnalysisContext context) {
+ LOGGER.debug("瑙f瀽鍒颁竴鏉″ご鏁版嵁:{}", 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<T> getList() {
+ return list;
+ }
+
+ public ExcelResult<T> 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 0000000..3e17548
--- /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<T> {
+
+ /** 鏁版嵁瀵硅薄list
+ */
+ private List<T> list;
+ /** 閿欒淇℃伅鍒楄〃 */
+ private List<String> errorList;
+
+ /**
+ * 鑾峰彇瀵煎叆鍥炴墽
+ * @return 瀵煎叆鍥炴墽
+ */
+ public String getAnalysis() {
+ int successCount = list.size();
+ int errorCount = errorList.size();
+ if (successCount == 0) {
+ return "璇诲彇澶辫触锛屾湭瑙f瀽鍒版暟鎹�";
+ } else {
+ if (errorList.size() == 0) {
+ return StrUtil.format("鎭枩鎮紝鍏ㄩ儴璇诲彇鎴愬姛锛佸叡{}鏉�", successCount);
+ } else {
+ return StrUtil.format("閮ㄥ垎璇诲彇鎴愬姛锛屽叾涓垚鍔焮}鏉★紝澶辫触{}鏉★紝閿欒淇℃伅濡備笅锛�<br/>{}",
+ successCount,
+ errorCount,
+ CollUtil.join(errorList, "<br/>"));
+ }
+
+ }
+ }
+}
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 0775ce5..8802a54 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.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 @@
return EasyExcel.read(is).head(clazz).autoCloseStream(false).sheet().doReadSync();
}
+
+ /**
+ * 瀵筫xcel琛ㄥ崟榛樿绗竴涓储寮曞悕杞崲鎴恖ist锛圗asyExcel锛�
+ *
+ * @param is 杈撳叆娴�
+ * @return 杞崲鍚庨泦鍚�
+ */
+ public static <T> ExcelResult<T> importExcel(InputStream is, Class<T> clazz, boolean isValidate, boolean skipException) {
+ ExcelListener<T> listener = new ExcelListener<>(isValidate, skipException);
+ EasyExcel.read(is, clazz, listener).sheet().doRead();
+ return listener.getExcelResult();
+ }
+
/**
* 瀵筶ist鏁版嵁婧愬皢鍏堕噷闈㈢殑鏁版嵁瀵煎叆鍒癳xcel琛ㄥ崟锛圗asyExcel锛�
*
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 7b70360..0307d13 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 @@
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<Void> importData(@RequestPart("file") MultipartFile file) throws Exception {
+ ExcelResult<TestDemoImportVo> excelResult = ExcelUtil.importExcel(file.getInputStream(), TestDemoImportVo.class, true, true);
+ List<TestDemoImportVo> volist = excelResult.getList();
+ List<TestDemo> 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 0000000..2150cdf
--- /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 9ff0e47..c6a2cdf 100644
--- a/ruoyi-ui/src/views/demo/demo/index.vue
+++ b/ruoyi-ui/src/views/demo/demo/index.vue
@@ -73,6 +73,16 @@
</el-col>
<el-col :span="1.5">
<el-button
+ type="info"
+ plain
+ icon="el-icon-upload2"
+ size="mini"
+ @click="handleImport"
+ v-hasPermi="['demo:demo:import']"
+ >瀵煎叆</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
type="warning"
plain
icon="el-icon-download"
@@ -164,11 +174,34 @@
<el-button @click="cancel">鍙� 娑�</el-button>
</div>
</el-dialog>
+ <!-- 鐢ㄦ埛瀵煎叆瀵硅瘽妗� -->
+ <el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
+ <el-upload
+ ref="upload"
+ :limit="1"
+ accept=".xlsx, .xls"
+ :headers="upload.headers"
+ :action="upload.url + '?updateSupport=' + upload.updateSupport"
+ :disabled="upload.isUploading"
+ :on-progress="handleFileUploadProgress"
+ :on-success="handleFileSuccess"
+ :auto-upload="false"
+ drag
+ >
+ <i class="el-icon-upload"></i>
+ <div class="el-upload__text">灏嗘枃浠舵嫋鍒版澶勶紝鎴�<em>鐐瑰嚮涓婁紶</em></div>
+ </el-upload>
+ <div slot="footer" class="dialog-footer">
+ <el-button type="primary" @click="submitFileForm">纭� 瀹�</el-button>
+ <el-button @click="upload.open = false">鍙� 娑�</el-button>
+ </div>
+ </el-dialog>
</div>
</template>
<script>
import { listDemo, pageDemo, getDemo, delDemo, addDemo, updateDemo } from "@/api/demo/demo";
+import {getToken} from "@/utils/auth";
export default {
name: "Demo",
@@ -198,6 +231,19 @@
open: false,
// 鍒涘缓鏃堕棿鏃堕棿鑼冨洿
daterangeCreateTime: [],
+ // 鐢ㄦ埛瀵煎叆鍙傛暟
+ upload: {
+ // 鏄惁鏄剧ず寮瑰嚭灞傦紙鐢ㄦ埛瀵煎叆锛�
+ open: false,
+ // 寮瑰嚭灞傛爣棰橈紙鐢ㄦ埛瀵煎叆锛�
+ title: "",
+ // 鏄惁绂佺敤涓婁紶
+ isUploading: false,
+ // 璁剧疆涓婁紶鐨勮姹傚ご閮�
+ headers: { Authorization: "Bearer " + getToken() },
+ // 涓婁紶鐨勫湴鍧�
+ url: process.env.VUE_APP_BASE_API + "/demo/demo/importData"
+ },
// 鏌ヨ鍙傛暟
queryParams: {
pageNum: 1,
@@ -353,11 +399,32 @@
this.loading = false;
});
},
+ /** 瀵煎叆鎸夐挳鎿嶄綔 */
+ handleImport() {
+ this.upload.title = "鐢ㄦ埛瀵煎叆";
+ this.upload.open = true;
+ },
/** 瀵煎嚭鎸夐挳鎿嶄綔 */
handleExport() {
this.download('demo/demo/export', {
...this.queryParams
}, `demo_${new Date().getTime()}.xlsx`)
+ },
+ // 鏂囦欢涓婁紶涓鐞�
+ handleFileUploadProgress(event, file, fileList) {
+ this.upload.isUploading = true;
+ },
+ // 鏂囦欢涓婁紶鎴愬姛澶勭悊
+ handleFileSuccess(response, file, fileList) {
+ this.upload.open = false;
+ this.upload.isUploading = false;
+ this.$refs.upload.clearFiles();
+ this.$alert(response.msg, "瀵煎叆缁撴灉", { dangerouslyUseHTMLString: true });
+ this.getList();
+ },
+ // 鎻愪氦涓婁紶鏂囦欢
+ submitFileForm() {
+ this.$refs.upload.submit();
}
}
};
--
Gitblit v1.9.3