From b1ce87e284eb4056ae7a69a8c53002669076e669 Mon Sep 17 00:00:00 2001 From: Mlxa0324 Date: Mon, 28 Nov 2022 03:03:21 +0800 Subject: [PATCH] =?UTF-8?q?excel=20=E6=89=B9=E9=87=8F=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ibeetl/admin/core/util/BeanUtil.java | 33 ++++++ .../excel/DictExcelSelectorServiceImpl.java | 1 + .../excel/ExcelSelectorDataWriteHandler.java | 2 +- .../java/cn/jlw/util/excel/ExcelUtil.java | 32 +++++- .../util/excel/MyExcelCellDataListener.java | 79 -------------- .../MyValidateExcelCellDataListener.java | 100 ++++++++++++++++++ ...penCourseMergeResourcesQuestionImport.java | 23 ++-- ...ourseMergeResourcesQuestionController.java | 28 +++-- 8 files changed, 198 insertions(+), 100 deletions(-) delete mode 100644 web/src/main/java/cn/jlw/util/excel/MyExcelCellDataListener.java create mode 100644 web/src/main/java/cn/jlw/util/excel/MyValidateExcelCellDataListener.java diff --git a/admin-core/src/main/java/com/ibeetl/admin/core/util/BeanUtil.java b/admin-core/src/main/java/com/ibeetl/admin/core/util/BeanUtil.java index 38192844..00bb1020 100644 --- a/admin-core/src/main/java/com/ibeetl/admin/core/util/BeanUtil.java +++ b/admin-core/src/main/java/com/ibeetl/admin/core/util/BeanUtil.java @@ -1,6 +1,7 @@ package com.ibeetl.admin.core.util; +import cn.hutool.core.bean.copier.CopyOptions; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.RandomUtil; @@ -128,4 +129,36 @@ public class BeanUtil extends cn.hutool.core.bean.BeanUtil { return result; } + + /** + * 单个对象中的属性,循环拷贝到集合中 + * @param o 单个对象 + * @param list 集合 + * @param copyOptions 属性拷贝选项 + * @param + * @param + */ + public static void beanPropertyCopyToList(T o, Collection list, CopyOptions copyOptions) { + for (R r : list) { + copyProperties(o, r, copyOptions); + } + } + + /** + * 单个对象中的属性,循环拷贝到集合中 + * @param o 单个对象 + * @param list 集合 + * @param fieldMapping 属性映射关系 + * @param filterCopyNames 过滤字段 + * @param + * @param + */ + public static void beanPropertyCopyToList(T o, Collection list, Map fieldMapping, String... filterCopyNames) { + CopyOptions copyOptions = CopyOptions.create() + .setPropertiesFilter((field, s) -> Arrays.asList(filterCopyNames).contains(field.getName())) + .setFieldMapping(fieldMapping); + for (R r : list) { + copyProperties(o, r, copyOptions); + } + } } diff --git a/web/src/main/java/cn/jlw/util/excel/DictExcelSelectorServiceImpl.java b/web/src/main/java/cn/jlw/util/excel/DictExcelSelectorServiceImpl.java index e995d851..c44707d6 100644 --- a/web/src/main/java/cn/jlw/util/excel/DictExcelSelectorServiceImpl.java +++ b/web/src/main/java/cn/jlw/util/excel/DictExcelSelectorServiceImpl.java @@ -29,6 +29,7 @@ public class DictExcelSelectorServiceImpl implements ExcelSelectorService { if (CollUtil.isEmpty(list)) { return null; } + return list.stream().map(CoreDict::getName).toArray(String[]::new); } } diff --git a/web/src/main/java/cn/jlw/util/excel/ExcelSelectorDataWriteHandler.java b/web/src/main/java/cn/jlw/util/excel/ExcelSelectorDataWriteHandler.java index 15203f32..4d40aefc 100644 --- a/web/src/main/java/cn/jlw/util/excel/ExcelSelectorDataWriteHandler.java +++ b/web/src/main/java/cn/jlw/util/excel/ExcelSelectorDataWriteHandler.java @@ -58,7 +58,7 @@ public class ExcelSelectorDataWriteHandler implements SheetWriteHandler { Name category1Name = workbook.createName(); category1Name.setNameName(hiddenName); //3 A1:A代表隐藏域创建第N列createCell(N)时。以A1列开始A行数据获取下拉数组 - category1Name.setRefersToFormula(hiddenName + "!A1:A" + (deptList.length + endRow)); + category1Name.setRefersToFormula(hiddenName + "!A2:A" + (deptList.length + endRow)); DataValidationConstraint constraint = helper.createFormulaListConstraint(hiddenName); CellRangeAddressList addressList = new CellRangeAddressList(startRow, endRow, k, k); diff --git a/web/src/main/java/cn/jlw/util/excel/ExcelUtil.java b/web/src/main/java/cn/jlw/util/excel/ExcelUtil.java index 3a969f0b..a9d421c7 100644 --- a/web/src/main/java/cn/jlw/util/excel/ExcelUtil.java +++ b/web/src/main/java/cn/jlw/util/excel/ExcelUtil.java @@ -2,6 +2,7 @@ package cn.jlw.util.excel; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.StrUtil; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.ExcelReader; @@ -24,6 +25,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.Field; import java.net.URLEncoder; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; @@ -315,15 +317,39 @@ public class ExcelUtil { return selectedMap; } + /** + * 获取下拉的map + * + * @param clazz 类class + * @return java.util.Map + * @author mlx + */ + public static HashSet getSelectedIndexSet(Class clazz) { + HashSet set = new HashSet<>(); + Field[] fields = clazz.getDeclaredFields(); + for (Field field : fields) { + if (!field.isAnnotationPresent(ExcelSelector.class) || !field.isAnnotationPresent(ExcelProperty.class)) { + continue; + } + ExcelSelector excelSelector = field.getAnnotation(ExcelSelector.class); + ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class); + + if (excelSelector != null) { + set.add(excelProperty.index()); + } + } + return set; + } + public static T longValuesOf(String text) { - return (T) Long.valueOf(Objects.requireNonNull(text.split(ID_SEPARATOR)[1], text + "字段,必须要有___ID:的分隔符")); + return (T) Long.valueOf(Objects.requireNonNull(text.split(ID_SEPARATOR), text + "字段,必须要有___ID:的分隔符")[1]); } public static T bigDecimalValuesOf(String text) { - return (T) Long.valueOf(Objects.requireNonNull(text.split(ID_SEPARATOR)[1], text + "字段,必须要有___ID:的分隔符")); + return (T) NumberUtil.toBigDecimal(Objects.requireNonNull(text.split(ID_SEPARATOR), text + "字段,必须要有___ID:的分隔符")[1]); } public static T integerValuesOf(String text) { - return (T) Integer.valueOf(Objects.requireNonNull(text.split(ID_SEPARATOR)[1], text + "字段,必须要有___ID:的分隔符")); + return (T) Integer.valueOf(Objects.requireNonNull(text.split(ID_SEPARATOR), text + "字段,必须要有___ID:的分隔符")[1]); } } diff --git a/web/src/main/java/cn/jlw/util/excel/MyExcelCellDataListener.java b/web/src/main/java/cn/jlw/util/excel/MyExcelCellDataListener.java deleted file mode 100644 index e30011bd..00000000 --- a/web/src/main/java/cn/jlw/util/excel/MyExcelCellDataListener.java +++ /dev/null @@ -1,79 +0,0 @@ -package cn.jlw.util.excel; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.map.MapUtil; -import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.ReflectUtil; -import cn.hutool.core.util.StrUtil; -import com.alibaba.excel.context.AnalysisContext; -import com.alibaba.excel.exception.ExcelDataConvertException; -import com.alibaba.excel.read.listener.ReadListener; -import com.alibaba.excel.read.metadata.holder.ReadRowHolder; -import lombok.Data; -import lombok.extern.slf4j.Slf4j; - -import java.lang.reflect.Field; -import java.util.Arrays; -import java.util.List; -import java.util.Map; - -@Data -@Slf4j -public class MyExcelCellDataListener implements ReadListener { - - /** - * 数据集合 - */ - private List data = CollUtil.newArrayList(); - - private Map failMap = MapUtil.newHashMap(16); - - @Override - public void invoke(T bean, AnalysisContext context) { - boolean emptyRow = true; - List fieldList = Arrays.asList(ReflectUtil.getFields(bean.getClass())); - for (Field field : fieldList) { - field.setAccessible(true); - try { - Object fieldValue = field.get(bean); - if (fieldValue instanceof String) { - if (StrUtil.isNotBlank((String) fieldValue)) { - emptyRow = false; - break; - } - } - if (ObjectUtil.isNotNull(fieldValue)) { - emptyRow = false; - break; - } - } catch (IllegalAccessException e) { - log.error(e.getMessage(), e); - } - } - if (!emptyRow) { - // 不处理空数据行 - data.add(bean); - ReadRowHolder readRowHolder = context.readRowHolder(); - log.info("rowIndex: {}, rowType: {}", readRowHolder.getRowIndex(), readRowHolder.getRowType()); - } - } - - @Override - public void onException(Exception exception, AnalysisContext context) { - log.error(exception.getMessage(), exception); - if (exception instanceof ExcelDataConvertException) { - ExcelDataConvertException e = (ExcelDataConvertException) exception; - ExcelFailRecord excelFailRecord = new ExcelFailRecord(); - excelFailRecord.setRow(e.getRowIndex()); - excelFailRecord.setColumn(e.getColumnIndex()); - excelFailRecord.setFailMessage(e.getCause().getMessage()); - - failMap.put(e.getRowIndex(), excelFailRecord); - } - } - - @Override - public void doAfterAllAnalysed(AnalysisContext analysisContext) { - log.info("Excel Deal Finish"); - } -} diff --git a/web/src/main/java/cn/jlw/util/excel/MyValidateExcelCellDataListener.java b/web/src/main/java/cn/jlw/util/excel/MyValidateExcelCellDataListener.java new file mode 100644 index 00000000..9f436c59 --- /dev/null +++ b/web/src/main/java/cn/jlw/util/excel/MyValidateExcelCellDataListener.java @@ -0,0 +1,100 @@ +package cn.jlw.util.excel; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.ReflectUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.exception.ExcelDataConvertException; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.read.metadata.holder.ReadRowHolder; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.Field; +import java.util.List; +import java.util.Map; + +/** + * 我的通用Excel检查格式,监听器 + * @param + * @author mlx + */ +@Data +@Slf4j +public class MyValidateExcelCellDataListener implements ReadListener { + + /** + * 数据集合 + */ + private List data = CollUtil.newArrayList(); + + private Map failMap = MapUtil.newHashMap(16); + + @Override + public void invoke(T bean, AnalysisContext context) { + + if (context.readSheetHolder().getSheetName().contains("hidden")) { + return; + } + + // 第几行 + Integer rowIndex = context.readRowHolder().getRowIndex(); + int emptyColumnCount = 0; + Field[] fields = ReflectUtil.getFields(bean.getClass()); + for (int columnIndex = 0; columnIndex < fields.length; columnIndex++) { + Field field = fields[columnIndex]; field.setAccessible(true); + try { + Object fieldValue = field.get(bean); + // 空值判断 + if (ObjectUtil.isEmpty(fieldValue)) { + putFailMap(rowIndex, columnIndex, "存在空值"); + emptyColumnCount++; + } + // 重复值判断,判断规则所有属性进行对比,需要调用对象的ToString方法, 建议重写一下 + boolean isRepeat = data.stream().anyMatch(item -> item.toString().equals(bean.toString())); + if (isRepeat) { + putFailMap(rowIndex, columnIndex, "数据重复"); + emptyColumnCount++; + } + } catch (IllegalAccessException e) { + log.error(e.getMessage(), e); + } + } + + if (emptyColumnCount == 0) { + // 不处理空数据行 + data.add(bean); + ReadRowHolder readRowHolder = context.readRowHolder(); + log.info("rowIndex: {}, rowType: {}", readRowHolder.getRowIndex(), readRowHolder.getRowType()); + } + } + + @Override + public void onException(Exception exception, AnalysisContext context) { + log.error(exception.getMessage(), exception); + if (exception instanceof ExcelDataConvertException) { + ExcelDataConvertException e = (ExcelDataConvertException) exception; + + Integer rowIndex = e.getRowIndex(); Integer columnIndex = e.getColumnIndex(); + putFailMap(rowIndex, columnIndex, "输入格式错误,类型转换异常"); + } + } + + private void putFailMap(Integer rowIndex, Integer columnIndex, String message) { + ExcelFailRecord excelFailRecord = new ExcelFailRecord(); + int newRowIndex = rowIndex + 1; + int newColumnIndex = columnIndex + 1; + excelFailRecord.setRow(newRowIndex); + excelFailRecord.setColumn(newColumnIndex); + excelFailRecord.setFailMessage(StrUtil.format("Excel中第{}行第{}列数据,{}", newRowIndex, newColumnIndex, message)); + + failMap.put(rowIndex, excelFailRecord); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext analysisContext) { + log.info("Excel Deal Finish"); + } +} diff --git a/web/src/main/java/com/ibeetl/jlw/entity/TeacherOpenCourseMergeResourcesQuestionImport.java b/web/src/main/java/com/ibeetl/jlw/entity/TeacherOpenCourseMergeResourcesQuestionImport.java index 7c025baf..785b5c3f 100644 --- a/web/src/main/java/com/ibeetl/jlw/entity/TeacherOpenCourseMergeResourcesQuestionImport.java +++ b/web/src/main/java/com/ibeetl/jlw/entity/TeacherOpenCourseMergeResourcesQuestionImport.java @@ -1,14 +1,19 @@ package com.ibeetl.jlw.entity; import lombok.Data; +import lombok.ToString; -import static cn.jlw.util.excel.ExcelUtil.*; +import java.math.BigDecimal; + +import static cn.jlw.util.excel.ExcelUtil.integerValuesOf; +import static cn.jlw.util.excel.ExcelUtil.longValuesOf; /** * 开课-题库管理-离线 导入实体 * @author lx */ @Data +@ToString public class TeacherOpenCourseMergeResourcesQuestionImport { //开课ID @@ -25,7 +30,7 @@ public class TeacherOpenCourseMergeResourcesQuestionImport { //分值 - private String questionScore ; + private BigDecimal questionScore ; //题干 @@ -69,14 +74,14 @@ public class TeacherOpenCourseMergeResourcesQuestionImport { .teacherOpenCourseMergeCourseInfoId(longValuesOf(importPojo.getTeacherOpenCourseMergeCourseInfoId())) .teacherOpenCourseId(longValuesOf(importPojo.getTeacherOpenCourseId())) .questionType(integerValuesOf(importPojo.getTeacherOpenCourseId())) - .questionScore(bigDecimalValuesOf(importPojo.getTeacherOpenCourseId())) + .questionScore(importPojo.getQuestionScore()) .questionStem(importPojo.getQuestionStem()) - .questionOptionA(importPojo.getQuestionOptionA()) - .questionOptionB(importPojo.getQuestionOptionB()) - .questionOptionC(importPojo.getQuestionOptionC()) - .questionOptionD(importPojo.getQuestionOptionD()) - .questionOptionE(importPojo.getQuestionOptionE()) - .questionAnswer(importPojo.getQuestionAnswer()) + .questionOptionA(importPojo.getQuestionOptionA().toUpperCase()) + .questionOptionB(importPojo.getQuestionOptionB().toUpperCase()) + .questionOptionC(importPojo.getQuestionOptionC().toUpperCase()) + .questionOptionD(importPojo.getQuestionOptionD().toUpperCase()) + .questionOptionE(importPojo.getQuestionOptionE().toUpperCase()) + .questionAnswer(importPojo.getQuestionAnswer().toUpperCase()) .questionAnalysis(importPojo.getQuestionAnalysis()) .questionStatus(1) .build(); diff --git a/web/src/main/java/com/ibeetl/jlw/web/TeacherOpenCourseMergeResourcesQuestionController.java b/web/src/main/java/com/ibeetl/jlw/web/TeacherOpenCourseMergeResourcesQuestionController.java index 8d1432a1..6fb9447e 100644 --- a/web/src/main/java/com/ibeetl/jlw/web/TeacherOpenCourseMergeResourcesQuestionController.java +++ b/web/src/main/java/com/ibeetl/jlw/web/TeacherOpenCourseMergeResourcesQuestionController.java @@ -3,16 +3,20 @@ package com.ibeetl.jlw.web; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.lang.Assert; +import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; import cn.jlw.Interceptor.GetFile; import cn.jlw.Interceptor.RFile; import cn.jlw.Interceptor.SCoreUser; import cn.jlw.util.ToolUtils; import cn.jlw.util.excel.ExcelUtil; +import cn.jlw.util.excel.MyValidateExcelCellDataListener; import cn.jlw.validate.ValidateConfig; import com.ibeetl.admin.core.annotation.Function; import com.ibeetl.admin.core.entity.CoreUser; import com.ibeetl.admin.core.file.FileService; +import com.ibeetl.admin.core.util.BeanUtil; import com.ibeetl.admin.core.util.TimeTool; import com.ibeetl.admin.core.web.JsonResult; import com.ibeetl.jlw.entity.FileEntity; @@ -501,20 +505,28 @@ public class TeacherOpenCourseMergeResourcesQuestionController extends BaseContr */ @SneakyThrows @PostMapping(API + "/importBatchTemplate.do") - public void importBatchTemplate(MultipartFile file) { + public JsonResult importBatchTemplate(MultipartFile file) { - Assert.notNull(getUser(), "请登录后再操作"); + CoreUser user = getUser(); + Assert.notNull(user, "请登录后再操作"); Assert.isNull(getStudent(), "学生无法访问该接口"); // 输出 Excel - List list = - ExcelUtil.readExcelNotContainHeader(file, TeacherOpenCourseMergeResourcesQuestionImport.class); + MyValidateExcelCellDataListener listener = new MyValidateExcelCellDataListener<>(); + + ExcelUtil.readExcelNotContainHeader(file, TeacherOpenCourseMergeResourcesQuestionImport.class, listener); // 类型转换 - List options = list.stream() + List options = listener.getData().stream() .map(TeacherOpenCourseMergeResourcesQuestionImport::pojo).collect(Collectors.toList()); - for (Object option : options) { - System.out.println(option); - } + // 判断错误的结果集 + Assert.isTrue(MapUtil.isEmpty(listener.getFailMap()), JSONUtil.toJsonStr(listener.getFailMap())); + + // 只复制用户ID和组织ID + BeanUtil.beanPropertyCopyToList(user, options, MapUtil.of("id", "userId"), "userId", "orgId"); + + teacherOpenCourseMergeResourcesQuestionService.insertBatch(options); + + return JsonResult.successMessage("导入成功!"); } }