From ed1564e307855b00c5ec2e038ea8e5e30a682c22 Mon Sep 17 00:00:00 2001 From: cwchen <1048842385@qq.com> Date: Tue, 20 Aug 2024 12:12:22 +0800 Subject: [PATCH] =?UTF-8?q?=E8=87=AA=E6=B5=8B=E9=97=AE=E9=A2=98=E4=BF=AE?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/constant/BusinessConstants.java | 5 + .../common/core/utils/ImportExcelUtils.java | 88 ++++++++++++++---- .../utils/SpringThreadPoolConfig.java | 65 +++++++++++++ ...ot.autoconfigure.AutoConfiguration.imports | 3 +- .../service/impl/PersonMgeServiceImpl.java | 31 +++++- .../main/resources/download/person_model.xlsx | Bin 49195 -> 49218 bytes 6 files changed, 171 insertions(+), 21 deletions(-) create mode 100644 bonus-common/bonus-common-security/src/main/java/com/bonus/common/security/utils/SpringThreadPoolConfig.java diff --git a/bonus-common/bonus-common-core/src/main/java/com/bonus/common/core/constant/BusinessConstants.java b/bonus-common/bonus-common-core/src/main/java/com/bonus/common/core/constant/BusinessConstants.java index 2640c22..4534469 100644 --- a/bonus-common/bonus-common-core/src/main/java/com/bonus/common/core/constant/BusinessConstants.java +++ b/bonus-common/bonus-common-core/src/main/java/com/bonus/common/core/constant/BusinessConstants.java @@ -134,6 +134,11 @@ public class BusinessConstants { * 每页显示记录数 */ public static final String PAGE_SIZE = "pageSize"; + public static final String JPGE = "image/jpeg"; + public static final String PNG = "image/png"; + public static final String JPG = "image/jpg"; + + public final static Integer CELL_1 = 1; public final static Integer CELL_2 = 2; diff --git a/bonus-common/bonus-common-core/src/main/java/com/bonus/common/core/utils/ImportExcelUtils.java b/bonus-common/bonus-common-core/src/main/java/com/bonus/common/core/utils/ImportExcelUtils.java index 8f938b1..0a0a8d6 100644 --- a/bonus-common/bonus-common-core/src/main/java/com/bonus/common/core/utils/ImportExcelUtils.java +++ b/bonus-common/bonus-common-core/src/main/java/com/bonus/common/core/utils/ImportExcelUtils.java @@ -89,7 +89,7 @@ public class ImportExcelUtils { int colNum = sheet.getRow(1).getLastCellNum(); if (Objects.equals(className, BusinessConstants.PERSON_IMPORT_VO)) { return colNum == 9; - }else if(Objects.equals(className, BusinessConstants.Gt_IMPORT_VO)){ + } else if (Objects.equals(className, BusinessConstants.Gt_IMPORT_VO)) { return colNum == 4; } return false; @@ -113,7 +113,7 @@ public class ImportExcelUtils { if (row.getRowNum() < 2) { continue; } - }else if(Objects.equals(mClass.getSimpleName(), BusinessConstants.Gt_IMPORT_VO)){ + } else if (Objects.equals(mClass.getSimpleName(), BusinessConstants.Gt_IMPORT_VO)) { if (row.getRowNum() < 2) { continue; } @@ -131,9 +131,9 @@ public class ImportExcelUtils { JSONObject obj = new JSONObject(); obj.put("rowNo", row.getRowNum() + 1); if (Objects.equals(mClass.getSimpleName(), BusinessConstants.PERSON_IMPORT_VO)) { - setExcelToString(5, row); + setExcelToString(9, row); obj = setPersonObjData(row, obj, filename); - }else if (Objects.equals(mClass.getSimpleName(), BusinessConstants.Gt_IMPORT_VO)) { + } else if (Objects.equals(mClass.getSimpleName(), BusinessConstants.Gt_IMPORT_VO)) { setExcelToString(5, row); obj = setGtObjData(row, obj, filename); } @@ -244,22 +244,32 @@ public class ImportExcelUtils { if (part instanceof XSSFDrawing) { XSSFDrawing drawing = (XSSFDrawing) part; List shapes = drawing.getShapes(); - for (XSSFShape shape : shapes) { - XSSFPicture picture = (XSSFPicture) shape; - XSSFClientAnchor anchor = picture.getPreferredSize(); - CTMarker marker = anchor.getFrom(); - Row row = sheet.getRow(marker.getRow()); - if (row == null) { - continue; + try { + if (!(shape instanceof XSSFPicture)) { + throw new RuntimeException("模版中包含非图片(jpeg、jpg、png)的文件,请仔细检查"); + } + XSSFPicture picture = (XSSFPicture) shape; + boolean isImage = isXlsxImage(picture.getPictureData()); + if (!isImage) { + throw new RuntimeException("模版中包含非图片(jpeg、jpg、png)的文件,请仔细检查"); + } + XSSFClientAnchor anchor = picture.getPreferredSize(); + CTMarker marker = anchor.getFrom(); + Row row = sheet.getRow(marker.getRow()); + if (row == null) { + continue; + } + String keyName = null; + if (Objects.equals(className, BusinessConstants.PERSON_IMPORT_VO)) { + keyName = setKey(picture, row, BusinessConstants.PERSON_IMPORT_VO); + } else { + keyName = ""; + } + map.put(keyName, picture.getPictureData()); + } catch (Exception e) { + throw new RuntimeException("模版中包含非图片(jpeg、jpg、png)的文件,请仔细检查"); } - String keyName = null; - if (Objects.equals(className, BusinessConstants.PERSON_IMPORT_VO)) { - keyName = setKey(picture, row, BusinessConstants.PERSON_IMPORT_VO); - } else { - keyName = ""; - } - map.put(keyName, picture.getPictureData()); } } } @@ -281,6 +291,10 @@ public class ImportExcelUtils { for (HSSFShape shape : list) { if (shape instanceof HSSFPicture) { HSSFPicture picture = (HSSFPicture) shape; + boolean isImage = isXlsImage(picture.getPictureData()); + if (!isImage) { + throw new RuntimeException("模版中包含非图片(jpeg、jpg、png)的文件,请仔细检查"); + } int pictureIndex = ((HSSFPicture) shape).getPictureIndex(); if (pictureIndex != -1) { HSSFClientAnchor cAnchor = picture.getClientAnchor(); @@ -361,4 +375,42 @@ public class ImportExcelUtils { } } } + + /** + * Xls判断文件是否是png、jpg格式 + * + * @param pictureData + * @return boolean + * @author cwchen + * @date 2024/8/20 11:17 + */ + private static boolean isXlsImage(HSSFPictureData pictureData) { + String mimeType = pictureData.getMimeType(); + System.err.println(mimeType); + if (Objects.equals(mimeType, BusinessConstants.JPGE) || + Objects.equals(mimeType, BusinessConstants.JPG) || + Objects.equals(mimeType, BusinessConstants.PNG)) { + return true; + } + return false; + } + + /** + * Xlsx 判断文件是否是png、jpg格式 + * + * @param pictureData + * @return boolean + * @author cwchen + * @date 2024/8/20 11:29 + */ + private static boolean isXlsxImage(XSSFPictureData pictureData) { + String mimeType = pictureData.getMimeType(); + System.err.println(mimeType); + if (Objects.equals(mimeType, BusinessConstants.JPGE) || + Objects.equals(mimeType, BusinessConstants.JPG) || + Objects.equals(mimeType, BusinessConstants.PNG)) { + return true; + } + return false; + } } diff --git a/bonus-common/bonus-common-security/src/main/java/com/bonus/common/security/utils/SpringThreadPoolConfig.java b/bonus-common/bonus-common-security/src/main/java/com/bonus/common/security/utils/SpringThreadPoolConfig.java new file mode 100644 index 0000000..1a4284f --- /dev/null +++ b/bonus-common/bonus-common-security/src/main/java/com/bonus/common/security/utils/SpringThreadPoolConfig.java @@ -0,0 +1,65 @@ +package com.bonus.common.security.utils; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.ThreadPoolExecutor; + +/** + * @author cw chen + * @description TODO + * @date 2022-08-22 14:42 + */ +@EnableAsync +@Configuration +public class SpringThreadPoolConfig { + /** + * 核心线程数(默认线程数) + */ + private int corePoolSize = 20; + + /** + * 最大线程数 + */ + private int maxPoolSize = 20; + + /** + * 允许线程空闲时间(单位:默认为秒) + */ + private int keepAliveTime = 10; + + /** + * 缓冲队列数 + */ + private int queueCapacity = 200; + + /** + * 线程池名前缀 + */ + private String threadNamePrefix = "custom-executor-"; + + @Bean("testTaskExecutor") + public ThreadPoolTaskExecutor taskExecutor1() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + //设置核心线程数 + executor.setCorePoolSize(corePoolSize); + //设置最大线程数 + executor.setMaxPoolSize(maxPoolSize); + //线程池所使用的缓冲队列 + executor.setQueueCapacity(queueCapacity); + //等待任务在关机时完成--表明等待所有线程执行完 + executor.setWaitForTasksToCompleteOnShutdown(true); + // 等待时间 (默认为0,此时立即停止),并没等待xx秒后强制停止 + executor.setKeepAliveSeconds(keepAliveTime); + // 线程名称前缀 + executor.setThreadNamePrefix(threadNamePrefix); + // 线程池对拒绝任务的处理策略 + executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + // 初始化 + executor.initialize(); + return executor; + } + +} diff --git a/bonus-common/bonus-common-security/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/bonus-common/bonus-common-security/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index 7a457ea..9b7fbe5 100644 --- a/bonus-common/bonus-common-security/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/bonus-common/bonus-common-security/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -4,4 +4,5 @@ com.bonus.common.security.service.TokenService com.bonus.common.security.aspect.PreAuthorizeAspect com.bonus.common.security.aspect.InnerAuthAspect com.bonus.common.security.handler.GlobalExceptionHandler -com.bonus.common.security.utils.ValidatorsUtils \ No newline at end of file +com.bonus.common.security.utils.ValidatorsUtils +com.bonus.common.security.utils.SpringThreadPoolConfig \ No newline at end of file diff --git a/bonus-modules/bonus-bracelet/src/main/java/com/bonus/bracelet/service/impl/PersonMgeServiceImpl.java b/bonus-modules/bonus-bracelet/src/main/java/com/bonus/bracelet/service/impl/PersonMgeServiceImpl.java index 57383a8..6f37528 100644 --- a/bonus-modules/bonus-bracelet/src/main/java/com/bonus/bracelet/service/impl/PersonMgeServiceImpl.java +++ b/bonus-modules/bonus-bracelet/src/main/java/com/bonus/bracelet/service/impl/PersonMgeServiceImpl.java @@ -36,6 +36,7 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.interceptor.TransactionAspectSupport; @@ -48,7 +49,10 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.InputStream; +import java.math.BigDecimal; import java.util.*; +import java.util.concurrent.Callable; +import java.util.concurrent.Future; import java.util.stream.Collectors; /** @@ -71,6 +75,9 @@ public class PersonMgeServiceImpl implements IPersonMgeService { @Resource(name = "ValidatorsUtils") private ValidatorsUtils validatorsUtils; + @Resource(name = "testTaskExecutor") + private ThreadPoolTaskExecutor testTaskExecutor; + @Resource private RemoteFileService remoteFileService; @@ -84,12 +91,11 @@ public class PersonMgeServiceImpl implements IPersonMgeService { public List getPersonLists(BraceletParamsDto dto) { dto.setSourceType(BusinessConstants.RESOURCE_TYPE_USER); List list = new ArrayList<>(); - int num = 0; try { list = mapper.getPersonLists(dto); for (PersonVo vo : list) { vo = handleData(vo); - num = mapper.getCertificateNum(vo.getId()); + int num = mapper.getCertificateNum(vo.getId()); vo.setCertificateNum(num); } } catch (Exception e) { @@ -515,6 +521,7 @@ public class PersonMgeServiceImpl implements IPersonMgeService { /** * 判断安全帽编号、马甲编号 是否重复 + * * @param list * @param value * @return boolean @@ -575,6 +582,26 @@ public class PersonMgeServiceImpl implements IPersonMgeService { return vo; } + /** + * 获取图片的base64 + * + * @param filePath + * @return String + * @author cwchen + * @date 2024/8/20 9:18 + */ + public String getImageBase64(String filePath) { + R result = remoteFileService.getImgBase64(filePath, SecurityConstants.INNER); + if (result != null && result.getCode() == HttpStatus.SUCCESS && result.getData() != null) { + String jsonString = JSON.toJSONString(result.getData()); + JSONObject item = JSON.parseObject(jsonString); + String base64 = item.getString("url"); + return base64; + } + return null; + } + + /** * 资源文件赋值 * diff --git a/bonus-modules/bonus-bracelet/src/main/resources/download/person_model.xlsx b/bonus-modules/bonus-bracelet/src/main/resources/download/person_model.xlsx index 088653c032cc096dad6bffe13c643917b9bb5172..c7c65e99b731ae70cf512acd326e3abf3d91866e 100644 GIT binary patch delta 3694 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 B)!+aC delta 3649 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