From 1f45d782a7dd5d4ce9062db8ed1cf86928196821 Mon Sep 17 00:00:00 2001 From: jianjun Date: Fri, 21 Aug 2020 14:00:36 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=86=E8=AF=84=E4=BB=B7=E6=8C=87=E6=A0=87?= =?UTF-8?q?=E4=BD=93=E7=B3=BBexcel=E5=AF=BC=E5=85=A5=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tools/utils/UniqueIdGenerator.java | 81 ++++++ .../com/epmet/dto/screen/IndexDictDTO.java | 97 +++++++ .../com/epmet/dto/screen/IndexGroupDTO.java | 92 ++++++ .../epmet/dto/screen/IndexGroupDetailDTO.java | 92 ++++++ .../screen/IndexGroupDetailTemplateDTO.java | 92 ++++++ .../data-statistical-server/pom.xml | 19 ++ .../epmet/controller/IndexDictController.java | 68 +++++ .../com/epmet/dao/screen/IndexDictDao.java | 34 +++ .../com/epmet/dao/screen/IndexGroupDao.java | 33 +++ .../epmet/dao/screen/IndexGroupDetailDao.java | 33 +++ .../screen/IndexGroupDetailTemplateDao.java | 35 +++ .../dao/screen/IndexGroupTemplateDao.java | 34 +++ .../epmet/entity/screen/IndexDictEntity.java | 53 ++++ .../entity/screen/IndexGroupDetailEntity.java | 60 ++++ .../IndexGroupDetailTemplateEntity.java | 65 +++++ .../epmet/entity/screen/IndexGroupEntity.java | 58 ++++ .../screen/IndexGroupTemplateEntity.java | 53 ++++ .../epmet/model/IndexExcelDataListener.java | 272 ++++++++++++++++++ .../main/java/com/epmet/model/IndexModel.java | 26 ++ .../epmet/model/ParseIndexExcelResult.java | 54 ++++ .../service/screen/IndexDictService.java | 34 +++ .../screen/IndexGroupDetailService.java | 31 ++ .../IndexGroupDetailTemplateService.java | 34 +++ .../service/screen/IndexGroupService.java | 31 ++ .../screen/IndexGroupTemplateService.java | 34 +++ .../screen/impl/IndexDictServiceImpl.java | 43 +++ .../impl/IndexGroupDetailServiceImpl.java | 36 +++ .../IndexGroupDetailTemplateServiceImpl.java | 42 +++ .../screen/impl/IndexGroupServiceImpl.java | 35 +++ .../impl/IndexGroupTemplateServiceImpl.java | 43 +++ .../java/com/epmet/util/ExcelListener.java | 17 ++ .../java/com/epmet/util/TestFileUtil.java | 35 +++ .../resources/mapper/screen/IndexDictDao.xml | 8 + .../resources/mapper/screen/IndexGroupDao.xml | 7 + .../mapper/screen/IndexGroupDetailDao.xml | 6 + .../screen/IndexGroupDetailTemplateDao.xml | 9 + .../mapper/screen/IndexGroupTemplateDao.xml | 8 + .../com/epmet/stats/test/model/DemoData.java | 17 ++ .../stats/test/model/DemoDataListener.java | 84 ++++++ .../epmet/stats/test/read/ConverterData.java | 30 ++ .../test/read/ConverterDataListener.java | 48 ++++ .../read/CustomStringStringConverter.java | 59 ++++ .../com/epmet/stats/test/read/DemoDAO.java | 15 + .../com/epmet/stats/test/read/DemoData.java | 17 ++ .../stats/test/read/DemoDataListener.java | 97 +++++++ .../com/epmet/stats/test/read/ReadTest.java | 70 +++++ .../epmet/stats/test/util/TestFileUtil.java | 35 +++ ...评价指标体系算法需求-备注.xlsx | Bin 0 -> 59391 bytes 48 files changed, 2276 insertions(+) create mode 100644 epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/utils/UniqueIdGenerator.java create mode 100644 epmet-module/data-statistical/data-statistical-client/src/main/java/com/epmet/dto/screen/IndexDictDTO.java create mode 100644 epmet-module/data-statistical/data-statistical-client/src/main/java/com/epmet/dto/screen/IndexGroupDTO.java create mode 100644 epmet-module/data-statistical/data-statistical-client/src/main/java/com/epmet/dto/screen/IndexGroupDetailDTO.java create mode 100644 epmet-module/data-statistical/data-statistical-client/src/main/java/com/epmet/dto/screen/IndexGroupDetailTemplateDTO.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/controller/IndexDictController.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/dao/screen/IndexDictDao.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/dao/screen/IndexGroupDao.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/dao/screen/IndexGroupDetailDao.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/dao/screen/IndexGroupDetailTemplateDao.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/dao/screen/IndexGroupTemplateDao.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/entity/screen/IndexDictEntity.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/entity/screen/IndexGroupDetailEntity.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/entity/screen/IndexGroupDetailTemplateEntity.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/entity/screen/IndexGroupEntity.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/entity/screen/IndexGroupTemplateEntity.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/model/IndexExcelDataListener.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/model/IndexModel.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/model/ParseIndexExcelResult.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/IndexDictService.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/IndexGroupDetailService.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/IndexGroupDetailTemplateService.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/IndexGroupService.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/IndexGroupTemplateService.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/impl/IndexDictServiceImpl.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/impl/IndexGroupDetailServiceImpl.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/impl/IndexGroupDetailTemplateServiceImpl.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/impl/IndexGroupServiceImpl.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/impl/IndexGroupTemplateServiceImpl.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/util/ExcelListener.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/util/TestFileUtil.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/main/resources/mapper/screen/IndexDictDao.xml create mode 100644 epmet-module/data-statistical/data-statistical-server/src/main/resources/mapper/screen/IndexGroupDao.xml create mode 100644 epmet-module/data-statistical/data-statistical-server/src/main/resources/mapper/screen/IndexGroupDetailDao.xml create mode 100644 epmet-module/data-statistical/data-statistical-server/src/main/resources/mapper/screen/IndexGroupDetailTemplateDao.xml create mode 100644 epmet-module/data-statistical/data-statistical-server/src/main/resources/mapper/screen/IndexGroupTemplateDao.xml create mode 100644 epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/model/DemoData.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/model/DemoDataListener.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/read/ConverterData.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/read/ConverterDataListener.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/read/CustomStringStringConverter.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/read/DemoDAO.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/read/DemoData.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/read/DemoDataListener.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/read/ReadTest.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/util/TestFileUtil.java create mode 100644 epmet-module/data-statistical/data-statistical-server/src/test/java/resources/评价指标体系算法需求-备注.xlsx diff --git a/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/utils/UniqueIdGenerator.java b/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/utils/UniqueIdGenerator.java new file mode 100644 index 0000000000..fcefbdf2ca --- /dev/null +++ b/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/utils/UniqueIdGenerator.java @@ -0,0 +1,81 @@ +package com.epmet.commons.tools.utils; + + +import org.apache.commons.lang3.StringUtils; + +import java.util.Date; +import java.util.Random; +import java.util.concurrent.atomic.AtomicLong; + +/** + * 唯一ID生成器 + */ +public class UniqueIdGenerator { + + private static UniqueValue uniqueValue = new UniqueValue(); + private static String middle; + static { + String threadCode = StringUtils.right(String.valueOf(Math.abs(System.nanoTime()+"".hashCode())), 2); + middle = StringUtils.leftPad(threadCode, 2, "0"); + } + + /** + * 唯一时间值 + */ + private static class UniqueValue { + + private AtomicLong uniqueValue = new AtomicLong(0L); + private volatile String currentTime = DateUtils.format(new Date(), DateUtils.DATE_TIME_NO_SPLIT); + private volatile String lastTime = currentTime; + + /** + * 获取当前时间:yyyyMMddHHmmSS + * 如果到了下一秒,则唯一值从0开始 + * + * @return + */ + public String getCurrentTime() { + currentTime = DateUtils.format(new Date(), DateUtils.DATE_TIME_NO_SPLIT); + if (!currentTime.equals(lastTime)) { + lastTime = currentTime; + Random random = new Random(); + uniqueValue.set(Long.valueOf(random.nextInt(10))); + } + return currentTime; + } + + public String getCurrentValue() { + return StringUtils.leftPad(String.valueOf(uniqueValue.incrementAndGet()), 5, "0"); + } + } + + /** + * 生成一个24位唯一ID + * 15位时间+2位中间值(防止多服务冲突)+2个线程code+5位秒级递增值 + * + * @return + */ + public static String generate() { + StringBuilder builder = new StringBuilder(32); + builder.append(uniqueValue.getCurrentTime()) + .append(middle) + .append(getUniqueThreadCode()) + .append(uniqueValue.getCurrentValue()); + + return builder.toString(); + } + + public static String getUniqueThreadCode() { + String threadCode = StringUtils.left(String.valueOf(Thread.currentThread().hashCode()), 2); + return StringUtils.leftPad(threadCode, 2, "0"); + } + + public static void main(String[] args) throws InterruptedException { + + System.out.println(UniqueIdGenerator.uniqueValue.currentTime); + System.out.println(UniqueIdGenerator.middle); + System.out.println(UniqueIdGenerator.getUniqueThreadCode()); + System.out.println(uniqueValue.getCurrentValue()); + + } +} diff --git a/epmet-module/data-statistical/data-statistical-client/src/main/java/com/epmet/dto/screen/IndexDictDTO.java b/epmet-module/data-statistical/data-statistical-client/src/main/java/com/epmet/dto/screen/IndexDictDTO.java new file mode 100644 index 0000000000..7ca7e42117 --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-client/src/main/java/com/epmet/dto/screen/IndexDictDTO.java @@ -0,0 +1,97 @@ +/** + * Copyright 2018 人人开源 https://www.renren.io + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.epmet.dto.screen; + +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + + +/** + * 评价指标字典 + * + * @author generator generator@elink-cn.com + * @since v1.0.0 2020-08-19 + */ +@Data +public class IndexDictDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + private String id; + + /** + * 指标编码(唯一) + */ + private String indexCode; + + /** + * 指标名 + */ + private String indexName; + + /** + * 指标描述 + */ + private String indexDesc; + + /** + * 父级指标id,如果是一级指标,PID=0 + */ + private String pid; + + /** + * 指标级别(1,2,3,4,5) + */ + private String level; + + /** + * 删除标识 0.未删除 1.已删除 + */ + private Integer delFlag; + + /** + * 乐观锁 + */ + private Integer revision; + + /** + * 创建人 + */ + private String createdBy; + + /** + * 创建时间 + */ + private Date createdTime; + + /** + * 更新人 + */ + private String updatedBy; + + /** + * 更新时间 + */ + private Date updatedTime; + +} \ No newline at end of file diff --git a/epmet-module/data-statistical/data-statistical-client/src/main/java/com/epmet/dto/screen/IndexGroupDTO.java b/epmet-module/data-statistical/data-statistical-client/src/main/java/com/epmet/dto/screen/IndexGroupDTO.java new file mode 100644 index 0000000000..19ee948d15 --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-client/src/main/java/com/epmet/dto/screen/IndexGroupDTO.java @@ -0,0 +1,92 @@ +/** + * Copyright 2018 人人开源 https://www.renren.io + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.epmet.dto.screen; + +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + + +/** + * 客户指标分组 + * + * @author generator generator@elink-cn.com + * @since v1.0.0 2020-08-19 + */ +@Data +public class IndexGroupDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + private String id; + + /** + * 客户id + */ + private String customerId; + + /** + * 指标id + */ + private String indexCode; + + /** + * 是否启用:启用:enable 禁用:disabled + */ + private String status; + + /** + * 当前指标关联的上一级指标分组,如果没有上一级,则为0 + */ + private String parentIndexGroupId; + + /** + * 删除标识 0.未删除 1.已删除 + */ + private Integer delFlag; + + /** + * 乐观锁 + */ + private Integer revision; + + /** + * 创建人 + */ + private String createdBy; + + /** + * 创建时间 + */ + private Date createdTime; + + /** + * 更新人 + */ + private String updatedBy; + + /** + * 更新时间 + */ + private Date updatedTime; + +} \ No newline at end of file diff --git a/epmet-module/data-statistical/data-statistical-client/src/main/java/com/epmet/dto/screen/IndexGroupDetailDTO.java b/epmet-module/data-statistical/data-statistical-client/src/main/java/com/epmet/dto/screen/IndexGroupDetailDTO.java new file mode 100644 index 0000000000..e6335250eb --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-client/src/main/java/com/epmet/dto/screen/IndexGroupDetailDTO.java @@ -0,0 +1,92 @@ +/** + * Copyright 2018 人人开源 https://www.renren.io + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.epmet.dto.screen; + +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + +/** + * 客户指标详情 + * + * @author generator generator@elink-cn.com + * @since v1.0.0 2020-08-19 + */ +@Data +public class IndexGroupDetailDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + private String id; + + /** + * index_group.id + */ + private String indexGroupId; + + /** + * 指标id + */ + private String indexCode; + + /** + * 权重(同一组权重总和=1) + */ + private BigDecimal weight; + + /** + * 是否启用:启用:enable 禁用:disabled + */ + private String status; + + /** + * 删除标识 0.未删除 1.已删除 + */ + private Integer delFlag; + + /** + * 乐观锁 + */ + private Integer revision; + + /** + * 创建人 + */ + private String createdBy; + + /** + * 创建时间 + */ + private Date createdTime; + + /** + * 更新人 + */ + private String updatedBy; + + /** + * 更新时间 + */ + private Date updatedTime; + +} \ No newline at end of file diff --git a/epmet-module/data-statistical/data-statistical-client/src/main/java/com/epmet/dto/screen/IndexGroupDetailTemplateDTO.java b/epmet-module/data-statistical/data-statistical-client/src/main/java/com/epmet/dto/screen/IndexGroupDetailTemplateDTO.java new file mode 100644 index 0000000000..e82b7b4588 --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-client/src/main/java/com/epmet/dto/screen/IndexGroupDetailTemplateDTO.java @@ -0,0 +1,92 @@ +/** + * Copyright 2018 人人开源 https://www.renren.io + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.epmet.dto.screen; + +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + +/** + * 客户指标详情 + * + * @author generator generator@elink-cn.com + * @since v1.0.0 2020-08-19 + */ +@Data +public class IndexGroupDetailTemplateDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + private String id; + + /** + * index_group.id + */ + private String indexGroupId; + + /** + * 指标id + */ + private String indexCode; + + /** + * 权重(同一组权重总和=1) + */ + private BigDecimal weight; + + /** + * 是否启用:启用:enable 禁用:disabled + */ + private String status; + + /** + * 删除标识 0.未删除 1.已删除 + */ + private Integer delFlag; + + /** + * 乐观锁 + */ + private Integer revision; + + /** + * 创建人 + */ + private String createdBy; + + /** + * 创建时间 + */ + private Date createdTime; + + /** + * 更新人 + */ + private String updatedBy; + + /** + * 更新时间 + */ + private Date updatedTime; + +} \ No newline at end of file diff --git a/epmet-module/data-statistical/data-statistical-server/pom.xml b/epmet-module/data-statistical/data-statistical-server/pom.xml index cf116c4fb7..95c74f75d1 100644 --- a/epmet-module/data-statistical/data-statistical-server/pom.xml +++ b/epmet-module/data-statistical/data-statistical-server/pom.xml @@ -74,6 +74,25 @@ 2.0.0 compile + + + + + org.apache.poi + poi + 3.17 + + + + org.apache.poi + poi-ooxml + 3.17 + + + com.alibaba + easyexcel + 2.2.6 + diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/controller/IndexDictController.java b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/controller/IndexDictController.java new file mode 100644 index 0000000000..217867ea32 --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/controller/IndexDictController.java @@ -0,0 +1,68 @@ +package com.epmet.controller; + +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.epmet.commons.tools.utils.Result; +import com.epmet.model.IndexExcelDataListener; +import com.epmet.model.IndexModel; +import com.epmet.service.screen.IndexDictService; +import com.epmet.service.screen.IndexGroupDetailTemplateService; +import com.epmet.service.screen.IndexGroupTemplateService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.io.InputStream; + +/** + * @author liujianjun + */ +@RequestMapping("indexdict") +@RestController +@Slf4j +public class IndexDictController { + + @Autowired + private IndexDictService indexDictService; + @Autowired + private IndexGroupTemplateService indexGroupTemplateService; + @Autowired + private IndexGroupDetailTemplateService indexGroupDetailTemplateService; + + /** + * url:http://localhost:8108/data/stats/indexdict/initFromExcel + * desc:从excel初始化指标,分组,权重 + * + * @param file + * @return + */ + @PostMapping("initFromExcel") + public Result testTx(@RequestPart("file") MultipartFile file) { + ExcelReader excelReader = null; + try { + InputStream inputStream = null; + try { + inputStream = file.getInputStream(); + } catch (IOException e) { + return new Result().error("读取文件失败"); + } + excelReader = EasyExcel.read(inputStream).build(); + // 这里为了简单 所以注册了 同样的head 和Listener 自己使用功能必须不同的Listener + ReadSheet readSheet = EasyExcel.readSheet(1).head(IndexModel.class) + .registerReadListener(new IndexExcelDataListener(indexDictService, indexGroupTemplateService, indexGroupDetailTemplateService)) + .build(); + excelReader.read(readSheet); + } finally { + if (excelReader != null) { + excelReader.finish(); + } + } + return new Result<>(); + } +} diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/dao/screen/IndexDictDao.java b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/dao/screen/IndexDictDao.java new file mode 100644 index 0000000000..7aa2ab9733 --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/dao/screen/IndexDictDao.java @@ -0,0 +1,34 @@ +/** + * Copyright 2018 人人开源 https://www.renren.io + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.epmet.dao.screen; + +import com.epmet.commons.mybatis.dao.BaseDao; +import com.epmet.entity.screen.IndexDictEntity; +import org.apache.ibatis.annotations.Mapper; + +/** + * 评价指标字典 + * + * @author generator generator@elink-cn.com + * @since v1.0.0 2020-08-19 + */ +@Mapper +public interface IndexDictDao extends BaseDao { + + int deleteAll(); +} \ No newline at end of file diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/dao/screen/IndexGroupDao.java b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/dao/screen/IndexGroupDao.java new file mode 100644 index 0000000000..10033b7456 --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/dao/screen/IndexGroupDao.java @@ -0,0 +1,33 @@ +/** + * Copyright 2018 人人开源 https://www.renren.io + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.epmet.dao.screen; + +import com.epmet.commons.mybatis.dao.BaseDao; +import com.epmet.entity.screen.IndexGroupEntity; +import org.apache.ibatis.annotations.Mapper; + +/** + * 客户指标分组 + * + * @author generator generator@elink-cn.com + * @since v1.0.0 2020-08-19 + */ +@Mapper +public interface IndexGroupDao extends BaseDao { + +} \ No newline at end of file diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/dao/screen/IndexGroupDetailDao.java b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/dao/screen/IndexGroupDetailDao.java new file mode 100644 index 0000000000..1a7dd4a0a8 --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/dao/screen/IndexGroupDetailDao.java @@ -0,0 +1,33 @@ +/** + * Copyright 2018 人人开源 https://www.renren.io + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.epmet.dao.screen; + +import com.epmet.commons.mybatis.dao.BaseDao; +import com.epmet.entity.screen.IndexGroupDetailEntity; +import org.apache.ibatis.annotations.Mapper; + +/** + * 客户指标详情 + * + * @author generator generator@elink-cn.com + * @since v1.0.0 2020-08-19 + */ +@Mapper +public interface IndexGroupDetailDao extends BaseDao { + +} \ No newline at end of file diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/dao/screen/IndexGroupDetailTemplateDao.java b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/dao/screen/IndexGroupDetailTemplateDao.java new file mode 100644 index 0000000000..cfe5270615 --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/dao/screen/IndexGroupDetailTemplateDao.java @@ -0,0 +1,35 @@ +/** + * Copyright 2018 人人开源 https://www.renren.io + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.epmet.dao.screen; + + +import com.epmet.commons.mybatis.dao.BaseDao; +import com.epmet.entity.screen.IndexGroupDetailTemplateEntity; +import org.apache.ibatis.annotations.Mapper; + +/** + * 客户指标详情 + * + * @author generator generator@elink-cn.com + * @since v1.0.0 2020-08-19 + */ +@Mapper +public interface IndexGroupDetailTemplateDao extends BaseDao { + + int deleteAll(); +} \ No newline at end of file diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/dao/screen/IndexGroupTemplateDao.java b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/dao/screen/IndexGroupTemplateDao.java new file mode 100644 index 0000000000..6f64a61349 --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/dao/screen/IndexGroupTemplateDao.java @@ -0,0 +1,34 @@ +/** + * Copyright 2018 人人开源 https://www.renren.io + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.epmet.dao.screen; + +import com.epmet.commons.mybatis.dao.BaseDao; +import com.epmet.entity.screen.IndexGroupTemplateEntity; +import org.apache.ibatis.annotations.Mapper; + +/** + * 默认指标分组 + * + * @author generator generator@elink-cn.com + * @since v1.0.0 2020-08-19 + */ +@Mapper +public interface IndexGroupTemplateDao extends BaseDao { + + int deleteAll(); +} \ No newline at end of file diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/entity/screen/IndexDictEntity.java b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/entity/screen/IndexDictEntity.java new file mode 100644 index 0000000000..2ea5745dba --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/entity/screen/IndexDictEntity.java @@ -0,0 +1,53 @@ +/** + * Copyright 2018 人人开源 https://www.renren.io + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.epmet.entity.screen; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.epmet.commons.mybatis.entity.BaseEpmetEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 评价指标字典 + * + * @author generator generator@elink-cn.com + * @since v1.0.0 2020-08-19 + */ +@Data +@EqualsAndHashCode(callSuper=false) +@TableName("index_dict") +public class IndexDictEntity extends BaseEpmetEntity { + + private static final long serialVersionUID = 1L; + + /** + * 指标名 + */ + private String indexName; + + /** + * 指标描述 + */ + private String indexDesc; + + /** + * 指标级别(1,2,3,4,5) + */ + private String level; + +} diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/entity/screen/IndexGroupDetailEntity.java b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/entity/screen/IndexGroupDetailEntity.java new file mode 100644 index 0000000000..e17ba9b2b2 --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/entity/screen/IndexGroupDetailEntity.java @@ -0,0 +1,60 @@ +/** + * Copyright 2018 人人开源 https://www.renren.io + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.epmet.entity.screen; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.epmet.commons.mybatis.entity.BaseEpmetEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; + +/** + * 客户指标详情 + * + * @author generator generator@elink-cn.com + * @since v1.0.0 2020-08-19 + */ +@Data +@EqualsAndHashCode(callSuper=false) +@TableName("index_group_detail") +public class IndexGroupDetailEntity extends BaseEpmetEntity { + + private static final long serialVersionUID = 1L; + + /** + * index_group.id + */ + private String indexGroupId; + + /** + * 指标id + */ + private String indexId; + + /** + * 权重(同一组权重总和=1) + */ + private BigDecimal weight; + + /** + * 是否启用:启用:enable 禁用:disabled + */ + private String status; + +} diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/entity/screen/IndexGroupDetailTemplateEntity.java b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/entity/screen/IndexGroupDetailTemplateEntity.java new file mode 100644 index 0000000000..569cda48d9 --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/entity/screen/IndexGroupDetailTemplateEntity.java @@ -0,0 +1,65 @@ +/** + * Copyright 2018 人人开源 https://www.renren.io + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.epmet.entity.screen; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.epmet.commons.mybatis.entity.BaseEpmetEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; + +/** + * 客户指标详情 + * + * @author generator generator@elink-cn.com + * @since v1.0.0 2020-08-19 + */ +@Data +@EqualsAndHashCode(callSuper=false) +@TableName("index_group_detail_template") +public class IndexGroupDetailTemplateEntity extends BaseEpmetEntity { + + private static final long serialVersionUID = 1L; + + /** + * index_group.id + */ + private String indexGroupId; + + /** + * 指标id + */ + private String indexId; + + /** + * 权重(同一组权重总和=1) + */ + private BigDecimal weight; + + /** + * 是否启用:启用:enable 禁用:disabled + */ + private String status; + + /** + * 阈值 如果是百分比 则为除以100以后的值 + */ + private BigDecimal threshold; + +} diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/entity/screen/IndexGroupEntity.java b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/entity/screen/IndexGroupEntity.java new file mode 100644 index 0000000000..24df1ef18a --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/entity/screen/IndexGroupEntity.java @@ -0,0 +1,58 @@ +/** + * Copyright 2018 人人开源 https://www.renren.io + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.epmet.entity.screen; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.epmet.commons.mybatis.entity.BaseEpmetEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 客户指标分组 + * + * @author generator generator@elink-cn.com + * @since v1.0.0 2020-08-19 + */ +@Data +@EqualsAndHashCode(callSuper=false) +@TableName("index_group") +public class IndexGroupEntity extends BaseEpmetEntity { + + private static final long serialVersionUID = 1L; + + /** + * 客户id + */ + private String customerId; + + /** + * 指标id + */ + private String indexId; + + /** + * 是否启用:启用:enable 禁用:disabled + */ + private String status; + + /** + * 当前指标关联的上一级指标分组,如果没有上一级,则为0 + */ + private String parentIndexGroupId; + +} diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/entity/screen/IndexGroupTemplateEntity.java b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/entity/screen/IndexGroupTemplateEntity.java new file mode 100644 index 0000000000..3348ebdeda --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/entity/screen/IndexGroupTemplateEntity.java @@ -0,0 +1,53 @@ +/** + * Copyright 2018 人人开源 https://www.renren.io + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.epmet.entity.screen; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.epmet.commons.mybatis.entity.BaseEpmetEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 客户指标分组 + * + * @author generator generator@elink-cn.com + * @since v1.0.0 2020-08-19 + */ +@Data +@EqualsAndHashCode(callSuper=false) +@TableName("index_group_template") +public class IndexGroupTemplateEntity extends BaseEpmetEntity { + + private static final long serialVersionUID = 1L; + + /** + * 指标id + */ + private String indexId; + + /** + * 是否启用:启用:enable 禁用:disabled + */ + private String status; + + /** + * 当前指标关联的上一级指标分组,如果没有上一级,则为0 + */ + private String parentIndexGroupId; + +} diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/model/IndexExcelDataListener.java b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/model/IndexExcelDataListener.java new file mode 100644 index 0000000000..76f0897890 --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/model/IndexExcelDataListener.java @@ -0,0 +1,272 @@ +package com.epmet.model; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.fastjson.JSON; +import com.epmet.commons.tools.utils.UniqueIdGenerator; +import com.epmet.entity.screen.IndexDictEntity; +import com.epmet.entity.screen.IndexGroupDetailTemplateEntity; +import com.epmet.entity.screen.IndexGroupTemplateEntity; +import com.epmet.service.screen.IndexDictService; +import com.epmet.service.screen.IndexGroupDetailTemplateService; +import com.epmet.service.screen.IndexGroupTemplateService; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +/** + * 读取转换异常 + * + * @author Jiaju Zhuang + */ +public class IndexExcelDataListener extends AnalysisEventListener { + private static final Logger LOGGER = LoggerFactory.getLogger(IndexExcelDataListener.class); + /** + * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收 + */ + private static volatile boolean isGroup = false; + ; + AtomicInteger total = new AtomicInteger(0); + Map indexDicMap = new HashMap<>(); + Map indexGroupMap = new HashMap<>(); + Map indexGroupDetailMap = new HashMap<>(); + List indexModelList = new ArrayList<>(); + private String preWheight; + + private Integer wheightSum = 0; + /** + * 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。 + */ + private IndexDictService indexDictService; + + private IndexGroupTemplateService indexGroupTemplateService; + + private IndexGroupDetailTemplateService indexGroupDetailTemplateService; + + + /** + * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来 + * + * @param indexDictService + */ + public IndexExcelDataListener(IndexDictService indexDictService, IndexGroupTemplateService indexGroupTemplateService, IndexGroupDetailTemplateService indexGroupDetailTemplateService) { + this.indexDictService = indexDictService; + this.indexGroupTemplateService = indexGroupTemplateService; + this.indexGroupDetailTemplateService = indexGroupDetailTemplateService; + } + + /** + * 这个每一条数据解析都会来调用 + * + * @param data one row value. Is is same as {@link AnalysisContext#readRowHolder()} + * @param context + */ + @Override + public void invoke(IndexModel data, AnalysisContext context) { + if (data == null || data.getIsUsed() == null || data.getIsUsed() != 1) { + return; + } + + //合并单元格的 权重 处理 + String weight = data.getWeight(); + if (StringUtils.isNotBlank(weight)) { + weight = weight.replace("%", ""); + data.setWeight(weight); + preWheight = data.getWeight(); + } else { + data.setWeight(preWheight); + } + LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data)); + + IndexDictEntity entity = new IndexDictEntity(); + IndexDictEntity entity2 = new IndexDictEntity(); + IndexDictEntity entity3 = new IndexDictEntity(); + IndexDictEntity entity4 = new IndexDictEntity(); + IndexDictEntity entity5 = new IndexDictEntity(); + + indexModelList.add(data); + buildIndexDicEntity(data, entity, entity2, entity3, entity4, entity5); + + buildIndexGroupEntity(); + + total.addAndGet(1); + + + // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM + /*if (isGroup) { + saveData(); + // 存储完成清理 list + list.clear(); + }*/ + } + + private void buildIndexGroupEntity() { + List collect = indexModelList.stream().sorted(Comparator.comparing(IndexModel::getLevel1Index)).collect(Collectors.toList()); + collect.forEach(index -> { + if (index.getLevel1Index().equals("党员相关")) { + IndexDictEntity indexDictEntity = indexDicMap.get(index.getLevel1Index()); + String level1GroupId = UniqueIdGenerator.generate(); + IndexGroupTemplateEntity group1 = indexGroupMap.get(index.getLevel1Index()); + if (group1 == null) { + group1 = new IndexGroupTemplateEntity(); + group1.setIndexId(indexDictEntity.getId()); + group1.setParentIndexGroupId("0"); + group1.setId(level1GroupId); + indexGroupMap.put(index.getLevel1Index(), group1); + } + + String level4Index = index.getLevel4Index(); + indexDictEntity = indexDicMap.get(level4Index); + String level2GroupId = UniqueIdGenerator.generate(); + + IndexGroupTemplateEntity group2 = indexGroupMap.get(level4Index); + IndexGroupDetailTemplateEntity templateEntity = null; + if (group2 == null) { + group2 = new IndexGroupTemplateEntity(); + group2.setIndexId(indexDictEntity.getId()); + group2.setParentIndexGroupId(level1GroupId); + group2.setId(level2GroupId); + indexGroupMap.put(level4Index, group2); + //构建 分组明细 + templateEntity = indexGroupDetailMap.get(level4Index); + if (templateEntity == null) { + buildIndexGroupDetail(indexDictEntity, index, group1.getId(), 2); + } + } + indexDictEntity = indexDicMap.get(index.getLevel5Index()); + + templateEntity = indexGroupDetailMap.get(index.getLevel5Index()); + if (templateEntity == null) { + buildIndexGroupDetail(indexDictEntity, index, group2.getId(), 5); + } + } else { + //todo 测试完去掉 + //if ("街道相关".equals(index.getLevel1Index())) { + IndexDictEntity indexDictEntity = indexDicMap.get(index.getLevel1Index()); + String level1GroupId = UniqueIdGenerator.generate(); + IndexGroupTemplateEntity group1 = indexGroupMap.get(index.getLevel1Index()); + if (group1 == null) { + group1 = new IndexGroupTemplateEntity(); + group1.setIndexId(indexDictEntity.getId()); + group1.setParentIndexGroupId("0"); + group1.setId(level1GroupId); + indexGroupMap.put(index.getLevel1Index(), group1); + } + + String level2Index = index.getLevel2Index(); + indexDictEntity = indexDicMap.get(level2Index); + String level2GroupId = UniqueIdGenerator.generate(); + + IndexGroupTemplateEntity group2 = indexGroupMap.get(level2Index); + IndexGroupDetailTemplateEntity templateEntity = null; + if (group2 == null) { + group2 = new IndexGroupTemplateEntity(); + group2.setIndexId(indexDictEntity.getId()); + group2.setParentIndexGroupId(level1GroupId); + group2.setId(level2GroupId); + indexGroupMap.put(level2Index, group2); + //构建 分组明细 + templateEntity = indexGroupDetailMap.get(level2Index); + if (templateEntity == null) { + buildIndexGroupDetail(indexDictEntity, index, group1.getId(), 2); + } + } + indexDictEntity = indexDicMap.get(index.getLevel5Index()); + + templateEntity = indexGroupDetailMap.get(index.getLevel5Index()); + if (templateEntity == null) { + buildIndexGroupDetail(indexDictEntity, index, group2.getId(), 5); + } + } + //} + }); + LOGGER.info("所有指标分组数据解析完成:{}", JSON.toJSONString(indexGroupMap.values())); + LOGGER.info("所有指标分组明细数据解析完成:{}", JSON.toJSONString(indexGroupDetailMap.values())); + } + + private void buildIndexGroupDetail(IndexDictEntity indexDictEntity, IndexModel index, String groupId, Integer level) { + IndexGroupDetailTemplateEntity templateEntity; + templateEntity = new IndexGroupDetailTemplateEntity(); + templateEntity.setIndexGroupId(groupId); + templateEntity.setIndexId(indexDictEntity.getId()); + + if (level == 5) { + String level5WeightStr = index.getLevel5Weight().replace("%", ""); + templateEntity.setWeight(new BigDecimal(level5WeightStr).divide(new BigDecimal(100), 4, RoundingMode.HALF_UP)); + indexGroupDetailMap.put(index.getLevel5Index(), templateEntity); + } else { + indexGroupDetailMap.put(indexDictEntity.getIndexName(), templateEntity); + templateEntity.setWeight(new BigDecimal(index.getWeight()).divide(new BigDecimal(100), 4, RoundingMode.HALF_UP)); + } + templateEntity.setId(UniqueIdGenerator.generate()); + if (StringUtils.isNotBlank(index.getThreshold())) { + String thresholdStr = index.getThreshold().replace("%", ""); + templateEntity.setThreshold(new BigDecimal(thresholdStr).divide(new BigDecimal(100), 4, RoundingMode.HALF_UP)); + } + } + + private void buildIndexDicEntity(IndexModel data, IndexDictEntity entity, IndexDictEntity entity2, IndexDictEntity entity3, IndexDictEntity entity4, IndexDictEntity entity5) { + if (!indexDicMap.containsKey(data.getLevel1Index())) { + entity.setId(UniqueIdGenerator.generate()); + entity.setIndexName(data.getLevel1Index()); + entity.setLevel("1"); + indexDicMap.put(data.getLevel1Index(), entity); + } + if (!indexDicMap.containsKey(data.getLevel2Index())) { + entity2.setId(UniqueIdGenerator.generate()); + entity2.setIndexName(data.getLevel2Index()); + entity2.setLevel("2"); + indexDicMap.put(data.getLevel2Index(), entity2); + } + if (!indexDicMap.containsKey(data.getLevel3Index())) { + entity3.setId(UniqueIdGenerator.generate()); + entity3.setIndexName(data.getLevel3Index()); + entity3.setLevel("3"); + indexDicMap.put(data.getLevel3Index(), entity3); + } + if (!indexDicMap.containsKey(data.getLevel4Index())) { + entity4.setId(UniqueIdGenerator.generate()); + entity4.setIndexName(data.getLevel4Index()); + entity4.setLevel("4"); + indexDicMap.put(data.getLevel4Index(), entity4); + } + if (!indexDicMap.containsKey(data.getLevel5Index())) { + entity5.setId(UniqueIdGenerator.generate()); + entity5.setIndexName(data.getLevel5Index()); + entity5.setLevel("5"); + indexDicMap.put(data.getLevel5Index(), entity5); + } + } + + /** + * 所有数据解析完成了 都会来调用 + * + * @param context + */ + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + // 这里也要保存数据,确保最后遗留的数据也存储到数据库 + saveData(); + LOGGER.info("所有数据解析完成!total:{}", total.intValue()); + } + + /** + * 加上存储数据库 + */ + private void saveData() { + LOGGER.info("{}条数据,开始存储数据库!", indexDicMap.size()); + indexDictService.deleteAndInsertBatch(indexDicMap.values()); + + buildIndexGroupEntity(); + + indexGroupTemplateService.deleteAndInsertBatch(indexGroupMap.values()); + indexGroupDetailTemplateService.deleteAndInsertBatch(indexGroupDetailMap.values()); + LOGGER.info("存储数据库成功!指标:{}个,分组:{}个,详情:{}个", indexDicMap.values().size(), indexGroupMap.values().size(), indexGroupDetailMap.values().size()); + } +} diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/model/IndexModel.java b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/model/IndexModel.java new file mode 100644 index 0000000000..f264a2c39e --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/model/IndexModel.java @@ -0,0 +1,26 @@ +package com.epmet.model; + +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.Data; + +@Data +public class IndexModel { + @ExcelProperty(value = "一级指标") + private String level1Index; + @ExcelProperty(value = "二级指标") + private String level2Index; + @ExcelProperty(value = "三级指标") + private String level3Index; + @ExcelProperty(value = "四级指标") + private String level4Index; + @ExcelProperty(value = "五级指标") + private String level5Index; + @ExcelProperty(value = "是否采用") + private Integer isUsed; + @ExcelProperty(value = "权重") + private String weight; + @ExcelProperty(value = "五级权重") + private String level5Weight; + @ExcelProperty(value = "阈值") + private String threshold; +} diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/model/ParseIndexExcelResult.java b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/model/ParseIndexExcelResult.java new file mode 100644 index 0000000000..17b4fa0634 --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/model/ParseIndexExcelResult.java @@ -0,0 +1,54 @@ +package com.epmet.model; + +import lombok.Data; + +import java.io.Serializable; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +@Data +public class ParseIndexExcelResult implements Serializable { + private String id; + private String groupId; + /** + * 当前指标关联的上一级指标分组,如果没有上一级,则为0 + */ + private String parentIndexGroupId; + /** + * 指标编码(唯一) + */ + private String indexCode; + + /** + * 指标名 + */ + private String indexName; + + /** + * 指标描述 + */ + private String indexDesc; + + /** + * 指标级别(1,2,3,4,5) + */ + private String level; + + private Set children = new HashSet<>(); + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ParseIndexExcelResult that = (ParseIndexExcelResult) o; + return indexCode.equals(that.indexCode) && + indexName.equals(that.indexName) && + level.equals(that.level); + } + + @Override + public int hashCode() { + return Objects.hash(indexCode, indexName, indexDesc, level); + } +} diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/IndexDictService.java b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/IndexDictService.java new file mode 100644 index 0000000000..9e3b4f83ed --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/IndexDictService.java @@ -0,0 +1,34 @@ +/** + * Copyright 2018 人人开源 https://www.renren.io + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.epmet.service.screen; + +import com.epmet.commons.mybatis.service.BaseService; +import com.epmet.entity.screen.IndexDictEntity; + +import java.util.Collection; + +/** + * 评价指标字典 + * + * @author generator generator@elink-cn.com + * @since v1.0.0 2020-08-19 + */ +public interface IndexDictService extends BaseService { + + Boolean deleteAndInsertBatch(Collection values); +} \ No newline at end of file diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/IndexGroupDetailService.java b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/IndexGroupDetailService.java new file mode 100644 index 0000000000..ea03e298a1 --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/IndexGroupDetailService.java @@ -0,0 +1,31 @@ +/** + * Copyright 2018 人人开源 https://www.renren.io + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.epmet.service.screen; + +import com.epmet.commons.mybatis.service.BaseService; +import com.epmet.entity.screen.IndexGroupDetailEntity; + +/** + * 客户指标详情 + * + * @author generator generator@elink-cn.com + * @since v1.0.0 2020-08-19 + */ +public interface IndexGroupDetailService extends BaseService { + +} \ No newline at end of file diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/IndexGroupDetailTemplateService.java b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/IndexGroupDetailTemplateService.java new file mode 100644 index 0000000000..3b0c48f7f9 --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/IndexGroupDetailTemplateService.java @@ -0,0 +1,34 @@ +/** + * Copyright 2018 人人开源 https://www.renren.io + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.epmet.service.screen; + +import com.epmet.commons.mybatis.service.BaseService; +import com.epmet.entity.screen.IndexGroupDetailTemplateEntity; + +import java.util.Collection; + +/** + * 客户指标详情 + * + * @author generator generator@elink-cn.com + * @since v1.0.0 2020-08-19 + */ +public interface IndexGroupDetailTemplateService extends BaseService { + + Boolean deleteAndInsertBatch(Collection values); +} \ No newline at end of file diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/IndexGroupService.java b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/IndexGroupService.java new file mode 100644 index 0000000000..f2ee989bea --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/IndexGroupService.java @@ -0,0 +1,31 @@ +/** + * Copyright 2018 人人开源 https://www.renren.io + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.epmet.service.screen; + +import com.epmet.commons.mybatis.service.BaseService; +import com.epmet.entity.screen.IndexGroupEntity; + +/** + * 客户指标分组 + * + * @author generator generator@elink-cn.com + * @since v1.0.0 2020-08-19 + */ +public interface IndexGroupService extends BaseService { + +} \ No newline at end of file diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/IndexGroupTemplateService.java b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/IndexGroupTemplateService.java new file mode 100644 index 0000000000..1f23716176 --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/IndexGroupTemplateService.java @@ -0,0 +1,34 @@ +/** + * Copyright 2018 人人开源 https://www.renren.io + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.epmet.service.screen; + +import com.epmet.commons.mybatis.service.BaseService; +import com.epmet.entity.screen.IndexGroupTemplateEntity; + +import java.util.Collection; + +/** + * 默认指标分组 + * + * @author generator generator@elink-cn.com + * @since v1.0.0 2020-08-19 + */ +public interface IndexGroupTemplateService extends BaseService { + + Boolean deleteAndInsertBatch(Collection values); +} \ No newline at end of file diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/impl/IndexDictServiceImpl.java b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/impl/IndexDictServiceImpl.java new file mode 100644 index 0000000000..16e4815226 --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/impl/IndexDictServiceImpl.java @@ -0,0 +1,43 @@ +/** + * Copyright 2018 人人开源 https://www.renren.io + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.epmet.service.screen.impl; + +import com.epmet.commons.mybatis.service.impl.BaseServiceImpl; +import com.epmet.dao.screen.IndexDictDao; +import com.epmet.entity.screen.IndexDictEntity; +import com.epmet.service.screen.IndexDictService; +import org.springframework.stereotype.Service; + +import java.util.Collection; + +/** + * 评价指标字典 + * + * @author generator generator@elink-cn.com + * @since v1.0.0 2020-08-19 + */ +@Service +public class IndexDictServiceImpl extends BaseServiceImpl implements IndexDictService { + + + @Override + public Boolean deleteAndInsertBatch(Collection values) { + int n = baseDao.deleteAll(); + return this.insertBatch(values,10); + } +} \ No newline at end of file diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/impl/IndexGroupDetailServiceImpl.java b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/impl/IndexGroupDetailServiceImpl.java new file mode 100644 index 0000000000..db9fe1f411 --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/impl/IndexGroupDetailServiceImpl.java @@ -0,0 +1,36 @@ +/** + * Copyright 2018 人人开源 https://www.renren.io + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.epmet.service.screen.impl; + +import com.epmet.commons.mybatis.service.impl.BaseServiceImpl; +import com.epmet.dao.screen.IndexGroupDetailDao; +import com.epmet.entity.screen.IndexGroupDetailEntity; +import com.epmet.service.screen.IndexGroupDetailService; +import org.springframework.stereotype.Service; + +/** + * 客户指标详情 + * + * @author generator generator@elink-cn.com + * @since v1.0.0 2020-08-19 + */ +@Service +public class IndexGroupDetailServiceImpl extends BaseServiceImpl implements IndexGroupDetailService { + + +} \ No newline at end of file diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/impl/IndexGroupDetailTemplateServiceImpl.java b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/impl/IndexGroupDetailTemplateServiceImpl.java new file mode 100644 index 0000000000..081f94ef3c --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/impl/IndexGroupDetailTemplateServiceImpl.java @@ -0,0 +1,42 @@ +/** + * Copyright 2018 人人开源 https://www.renren.io + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.epmet.service.screen.impl; + +import com.epmet.commons.mybatis.service.impl.BaseServiceImpl; +import com.epmet.dao.screen.IndexGroupDetailTemplateDao; +import com.epmet.entity.screen.IndexGroupDetailTemplateEntity; +import com.epmet.service.screen.IndexGroupDetailTemplateService; +import org.springframework.stereotype.Service; + +import java.util.Collection; + +/** + * 客户指标详情 + * + * @author generator generator@elink-cn.com + * @since v1.0.0 2020-08-19 + */ +@Service +public class IndexGroupDetailTemplateServiceImpl extends BaseServiceImpl implements IndexGroupDetailTemplateService { + + @Override + public Boolean deleteAndInsertBatch(Collection values) { + baseDao.deleteAll(); + return this.insertBatch(values, 10); + } +} \ No newline at end of file diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/impl/IndexGroupServiceImpl.java b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/impl/IndexGroupServiceImpl.java new file mode 100644 index 0000000000..5d12ec33d1 --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/impl/IndexGroupServiceImpl.java @@ -0,0 +1,35 @@ +/** + * Copyright 2018 人人开源 https://www.renren.io + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.epmet.service.screen.impl; + +import com.epmet.commons.mybatis.service.impl.BaseServiceImpl; +import com.epmet.dao.screen.IndexGroupDao; +import com.epmet.entity.screen.IndexGroupEntity; +import com.epmet.service.screen.IndexGroupService; +import org.springframework.stereotype.Service; + +/** + * 客户指标分组 + * + * @author generator generator@elink-cn.com + * @since v1.0.0 2020-08-19 + */ +@Service +public class IndexGroupServiceImpl extends BaseServiceImpl implements IndexGroupService { + +} \ No newline at end of file diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/impl/IndexGroupTemplateServiceImpl.java b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/impl/IndexGroupTemplateServiceImpl.java new file mode 100644 index 0000000000..058cf911eb --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/service/screen/impl/IndexGroupTemplateServiceImpl.java @@ -0,0 +1,43 @@ +/** + * Copyright 2018 人人开源 https://www.renren.io + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.epmet.service.screen.impl; + +import com.epmet.commons.mybatis.service.impl.BaseServiceImpl; +import com.epmet.dao.screen.IndexGroupTemplateDao; +import com.epmet.entity.screen.IndexGroupTemplateEntity; +import com.epmet.service.screen.IndexGroupTemplateService; +import org.springframework.stereotype.Service; + +import java.util.Collection; + +/** + * 客户指标分组 + * + * @author generator generator@elink-cn.com + * @since v1.0.0 2020-08-19 + */ +@Service +public class IndexGroupTemplateServiceImpl extends BaseServiceImpl implements IndexGroupTemplateService { + + @Override + public Boolean deleteAndInsertBatch(Collection values) { + + baseDao.deleteAll(); + return this.insertBatch(values, 10); + } +} \ No newline at end of file diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/util/ExcelListener.java b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/util/ExcelListener.java new file mode 100644 index 0000000000..e8ad7cbe66 --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/util/ExcelListener.java @@ -0,0 +1,17 @@ +package com.epmet.util; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import org.apache.poi.ss.formula.functions.T; + +public class ExcelListener extends AnalysisEventListener { + @Override + public void invoke(T t, AnalysisContext analysisContext) { + + } + + @Override + public void doAfterAllAnalysed(AnalysisContext analysisContext) { + System.out.println(analysisContext); + } +} diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/util/TestFileUtil.java b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/util/TestFileUtil.java new file mode 100644 index 0000000000..865e691e80 --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/util/TestFileUtil.java @@ -0,0 +1,35 @@ +package com.epmet.util; + +import java.io.File; +import java.io.InputStream; + +public class TestFileUtil { + + public static InputStream getResourcesFileInputStream(String fileName) { + return Thread.currentThread().getContextClassLoader().getResourceAsStream("" + fileName); + } + + public static String getPath() { + return TestFileUtil.class.getResource("/").getPath(); + } + + public static File createNewFile(String pathName) { + File file = new File(getPath() + pathName); + if (file.exists()) { + file.delete(); + } else { + if (!file.getParentFile().exists()) { + file.getParentFile().mkdirs(); + } + } + return file; + } + + public static File readFile(String pathName) { + return new File(getPath() + pathName); + } + + public static File readUserHomeFile(String pathName) { + return new File(System.getProperty("user.home") + File.separator + pathName); + } +} diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/resources/mapper/screen/IndexDictDao.xml b/epmet-module/data-statistical/data-statistical-server/src/main/resources/mapper/screen/IndexDictDao.xml new file mode 100644 index 0000000000..a91513e1d5 --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/main/resources/mapper/screen/IndexDictDao.xml @@ -0,0 +1,8 @@ + + + + + + delete from index_dict + + \ No newline at end of file diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/resources/mapper/screen/IndexGroupDao.xml b/epmet-module/data-statistical/data-statistical-server/src/main/resources/mapper/screen/IndexGroupDao.xml new file mode 100644 index 0000000000..06f0cf0198 --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/main/resources/mapper/screen/IndexGroupDao.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/resources/mapper/screen/IndexGroupDetailDao.xml b/epmet-module/data-statistical/data-statistical-server/src/main/resources/mapper/screen/IndexGroupDetailDao.xml new file mode 100644 index 0000000000..b7854f3338 --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/main/resources/mapper/screen/IndexGroupDetailDao.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/resources/mapper/screen/IndexGroupDetailTemplateDao.xml b/epmet-module/data-statistical/data-statistical-server/src/main/resources/mapper/screen/IndexGroupDetailTemplateDao.xml new file mode 100644 index 0000000000..ddb138771e --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/main/resources/mapper/screen/IndexGroupDetailTemplateDao.xml @@ -0,0 +1,9 @@ + + + + + + + delete from index_group_detail_template + + \ No newline at end of file diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/resources/mapper/screen/IndexGroupTemplateDao.xml b/epmet-module/data-statistical/data-statistical-server/src/main/resources/mapper/screen/IndexGroupTemplateDao.xml new file mode 100644 index 0000000000..d527876c4d --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/main/resources/mapper/screen/IndexGroupTemplateDao.xml @@ -0,0 +1,8 @@ + + + + + + delete from index_group_template + + \ No newline at end of file diff --git a/epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/model/DemoData.java b/epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/model/DemoData.java new file mode 100644 index 0000000000..234e66cb58 --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/model/DemoData.java @@ -0,0 +1,17 @@ +package com.epmet.stats.test.model; + +import lombok.Data; + +import java.util.Date; + +/** + * 基础数据类.这里的排序和excel里面的排序一致 + * + * @author Jiaju Zhuang + **/ +@Data +public class DemoData { + private String string; + private Date date; + private Double doubleData; +} diff --git a/epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/model/DemoDataListener.java b/epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/model/DemoDataListener.java new file mode 100644 index 0000000000..d218327ad1 --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/model/DemoDataListener.java @@ -0,0 +1,84 @@ +package com.epmet.stats.test.model; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.fastjson.JSON; +import com.epmet.dao.screen.ScreenCustomerAgencyDao; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; + +/** + * 模板的读取类 + * + * @author Jiaju Zhuang + */ +// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去 +public class DemoDataListener extends AnalysisEventListener { + private static final Logger LOGGER = LoggerFactory.getLogger(DemoDataListener.class); + /** + * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收 + */ + private static final int BATCH_COUNT = 5; + List list = new ArrayList(); + /** + * 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。 + */ + private ScreenCustomerAgencyDao demoDAO; + + public DemoDataListener() { + // 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数 + demoDAO = null; + } + + /** + * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来 + * + * @param demoDAO + */ + public DemoDataListener(ScreenCustomerAgencyDao demoDAO) { + this.demoDAO = demoDAO; + } + + /** + * 这个每一条数据解析都会来调用 + * + * @param data + * one row value. Is is same as {@link AnalysisContext#readRowHolder()} + * @param context + */ + @Override + public void invoke(DemoData data, AnalysisContext context) { + LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data)); + list.add(data); + // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM + if (list.size() >= BATCH_COUNT) { + saveData(); + // 存储完成清理 list + list.clear(); + } + } + + /** + * 所有数据解析完成了 都会来调用 + * + * @param context + */ + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + // 这里也要保存数据,确保最后遗留的数据也存储到数据库 + saveData(); + LOGGER.info("所有数据解析完成!"); + } + + /** + * 加上存储数据库 + */ + private void saveData() { + LOGGER.info("{}条数据,开始存储数据库!", list.size()); + //demoDAO.save(list); + LOGGER.info("存储数据库成功!"); + } +} diff --git a/epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/read/ConverterData.java b/epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/read/ConverterData.java new file mode 100644 index 0000000000..9a9be1642d --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/read/ConverterData.java @@ -0,0 +1,30 @@ +package com.epmet.stats.test.read; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.format.DateTimeFormat; +import com.alibaba.excel.annotation.format.NumberFormat; +import lombok.Data; + +/** + * 基础数据类.这里的排序和excel里面的排序一致 + * + * @author Jiaju Zhuang + **/ +@Data +public class ConverterData { + /** + * 我自定义 转换器,不管数据库传过来什么 。我给他加上“自定义:” + */ + @ExcelProperty(converter = CustomStringStringConverter.class) + private String string; + /** + * 这里用string 去接日期才能格式化。我想接收年月日格式 + */ + @DateTimeFormat("yyyy年MM月dd日HH时mm分ss秒") + private String date; + /** + * 我想接收百分比的数字 + */ + @NumberFormat("#.##%") + private String doubleData; +} diff --git a/epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/read/ConverterDataListener.java b/epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/read/ConverterDataListener.java new file mode 100644 index 0000000000..7c28d41fe8 --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/read/ConverterDataListener.java @@ -0,0 +1,48 @@ +package com.epmet.stats.test.read; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.fastjson.JSON; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; + +/** + * 模板的读取类 + * + * @author Jiaju Zhuang + */ +public class ConverterDataListener extends AnalysisEventListener { + private static final Logger LOGGER = LoggerFactory.getLogger(ConverterDataListener.class); + /** + * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收 + */ + private static final int BATCH_COUNT = 5; + List list = new ArrayList(); + + @Override + public void invoke(ConverterData data, AnalysisContext context) { + LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data)); + list.add(data); + if (list.size() >= BATCH_COUNT) { + saveData(); + list.clear(); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + saveData(); + LOGGER.info("所有数据解析完成!"); + } + + /** + * 加上存储数据库 + */ + private void saveData() { + LOGGER.info("{}条数据,开始存储数据库!", list.size()); + LOGGER.info("存储数据库成功!"); + } +} diff --git a/epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/read/CustomStringStringConverter.java b/epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/read/CustomStringStringConverter.java new file mode 100644 index 0000000000..584e563a77 --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/read/CustomStringStringConverter.java @@ -0,0 +1,59 @@ +package com.epmet.stats.test.read; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +/** + * String and string converter + * + * @author Jiaju Zhuang + */ +public class CustomStringStringConverter implements Converter { + @Override + public Class supportJavaTypeKey() { + return String.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + /** + * 这里读的时候会调用 + * + * @param cellData + * NotNull + * @param contentProperty + * Nullable + * @param globalConfiguration + * NotNull + * @return + */ + @Override + public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return "自定义:" + cellData.getStringValue(); + } + + /** + * 这里是写的时候会调用 不用管 + * + * @param value + * NotNull + * @param contentProperty + * Nullable + * @param globalConfiguration + * NotNull + * @return + */ + @Override + public CellData convertToExcelData(String value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return new CellData(value); + } + +} diff --git a/epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/read/DemoDAO.java b/epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/read/DemoDAO.java new file mode 100644 index 0000000000..bf09288f59 --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/read/DemoDAO.java @@ -0,0 +1,15 @@ +package com.epmet.stats.test.read; + +import java.util.List; + +/** + * 假设这个是你的DAO存储。当然还要这个类让spring管理,当然你不用需要存储,也不需要这个类。 + * + * @author Jiaju Zhuang + **/ +public class DemoDAO { + + public void save(List list) { + // 如果是mybatis,尽量别直接调用多次insert,自己写一个mapper里面新增一个方法batchInsert,所有数据一次性插入 + } +} diff --git a/epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/read/DemoData.java b/epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/read/DemoData.java new file mode 100644 index 0000000000..ceb3dd37ca --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/read/DemoData.java @@ -0,0 +1,17 @@ +package com.epmet.stats.test.read; + +import lombok.Data; + +import java.util.Date; + +/** + * 基础数据类.这里的排序和excel里面的排序一致 + * + * @author Jiaju Zhuang + **/ +@Data +public class DemoData { + private String string; + private Date date; + private Double doubleData; +} diff --git a/epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/read/DemoDataListener.java b/epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/read/DemoDataListener.java new file mode 100644 index 0000000000..539f1903b0 --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/read/DemoDataListener.java @@ -0,0 +1,97 @@ +package com.epmet.stats.test.read; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.fastjson.JSON; +import com.epmet.model.IndexModel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * 模板的读取类 + * + * @author Jiaju Zhuang + */ +// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去 +public class DemoDataListener extends AnalysisEventListener { + private static final Logger LOGGER = LoggerFactory.getLogger(DemoDataListener.class); + /** + * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收 + */ + private static final int BATCH_COUNT = 5; + List list = new ArrayList(); + AtomicInteger total = new AtomicInteger(0); + + private String preWheight; + /** + * 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。 + */ + private DemoDAO demoDAO; + + public DemoDataListener() { + // 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数 + demoDAO = new DemoDAO(); + } + + /** + * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来 + * + * @param demoDAO + */ + public DemoDataListener(DemoDAO demoDAO) { + this.demoDAO = demoDAO; + } + + /** + * 这个每一条数据解析都会来调用 + * + * @param data + * one row value. Is is same as {@link AnalysisContext#readRowHolder()} + * @param context + */ + @Override + public void invoke(IndexModel data, AnalysisContext context) { + if (data == null || data.getIsUsed() == null || data.getIsUsed() != 1){ + return; + } + if ( data.getWeight() != null){ + preWheight = data.getWeight(); + }else{ + data.setWeight(preWheight); + } + LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data)); + list.add(data); + total.addAndGet(1); + // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM + if (list.size() >= BATCH_COUNT) { + saveData(); + // 存储完成清理 list + list.clear(); + } + } + + /** + * 所有数据解析完成了 都会来调用 + * + * @param context + */ + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + // 这里也要保存数据,确保最后遗留的数据也存储到数据库 + saveData(); + LOGGER.info("所有数据解析完成!total:{}",total.intValue()); + } + + /** + * 加上存储数据库 + */ + private void saveData() { + LOGGER.info("{}条数据,开始存储数据库!", list.size()); + //demoDAO.save(list); + LOGGER.info("存储数据库成功!"); + } +} diff --git a/epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/read/ReadTest.java b/epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/read/ReadTest.java new file mode 100644 index 0000000000..85ee1e7806 --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/read/ReadTest.java @@ -0,0 +1,70 @@ +package com.epmet.stats.test.read; + +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.epmet.model.IndexModel; +import com.epmet.util.TestFileUtil; +import org.junit.Ignore; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.FileNotFoundException; + + +/** + * 读的常见写法 + * + * @author Jiaju Zhuang + */ +@Ignore +public class ReadTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(ReadTest.class); + + + + /** + * 读多个或者全部sheet,这里注意一个sheet不能读取多次,多次读取需要重新读取文件 + *

+ * 1. 创建excel对应的实体对象 参照{@link DemoData} + *

+ * 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener} + *

+ * 3. 直接读即可 + */ + @Test + public void repeatedRead() throws FileNotFoundException { + String fileName = ""; + /* String fileName = TestFileUtil.getPath() + File.separator + "评价指标体系算法需求-备注.xlsx"; + // 读取全部sheet + // 这里需要注意 DemoDataListener的doAfterAllAnalysed 会在每个sheet读取完毕后调用一次。然后所有sheet都会往同一个DemoDataListener里面写 + EasyExcel.read(fileName, IndexModel.class, new DemoDataListener()).doReadAll(); +*/ + // 读取部分sheet + String excelName = "评价指标体系算法需求-备注.xlsx"; + fileName = TestFileUtil.getPath() + File.separator + excelName; + //fileName = this.getClass().getResource(File.separator).getPath().concat(excelName); + ExcelReader excelReader = null; + try { + //ExcelImportUtil.importExcel(null); + + //EasyExcel.read(new FileInputStream(new File(fileName)),IndexModel.class); + excelReader = EasyExcel.read(fileName).build(); + // 这里为了简单 所以注册了 同样的head 和Listener 自己使用功能必须不同的Listener + ReadSheet readSheet1 = + EasyExcel.readSheet(0).head(IndexModel.class).registerReadListener(new DemoDataListener()).build(); + ReadSheet readSheet2 = + EasyExcel.readSheet(1).head(IndexModel.class).registerReadListener(new DemoDataListener()).build(); + // 这里注意 一定要把sheet1 sheet2 一起传进去,不然有个问题就是03版的excel 会读取多次,浪费性能 + excelReader.read(readSheet2); + } finally { + if (excelReader != null) { + // 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的 + excelReader.finish(); + } + } + } +} diff --git a/epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/util/TestFileUtil.java b/epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/util/TestFileUtil.java new file mode 100644 index 0000000000..5035e52046 --- /dev/null +++ b/epmet-module/data-statistical/data-statistical-server/src/test/java/com/epmet/stats/test/util/TestFileUtil.java @@ -0,0 +1,35 @@ +package com.epmet.stats.test.util; + +import java.io.File; +import java.io.InputStream; + +public class TestFileUtil { + + public static InputStream getResourcesFileInputStream(String fileName) { + return Thread.currentThread().getContextClassLoader().getResourceAsStream("" + fileName); + } + + public static String getPath() { + return TestFileUtil.class.getResource("/").getPath(); + } + + public static File createNewFile(String pathName) { + File file = new File(getPath() + pathName); + if (file.exists()) { + file.delete(); + } else { + if (!file.getParentFile().exists()) { + file.getParentFile().mkdirs(); + } + } + return file; + } + + public static File readFile(String pathName) { + return new File(getPath() + pathName); + } + + public static File readUserHomeFile(String pathName) { + return new File(System.getProperty("user.home") + File.separator + pathName); + } +} diff --git a/epmet-module/data-statistical/data-statistical-server/src/test/java/resources/评价指标体系算法需求-备注.xlsx b/epmet-module/data-statistical/data-statistical-server/src/test/java/resources/评价指标体系算法需求-备注.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..592e740466e97361226da2745174eb8dcb4754fd GIT binary patch literal 59391 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 literal 0 HcmV?d00001