|
@@ -1,5 +1,6 @@
|
|
|
package org.dromara.system.service.impl;
|
|
|
|
|
|
+import cn.hutool.core.collection.CollectionUtil;
|
|
|
import cn.hutool.core.img.FontUtil;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
|
@@ -19,6 +20,7 @@ import com.itextpdf.text.pdf.PdfWriter;
|
|
|
import jakarta.annotation.Resource;
|
|
|
import jakarta.servlet.http.HttpServletRequest;
|
|
|
import jakarta.servlet.http.HttpServletResponse;
|
|
|
+import jakarta.validation.constraints.NotNull;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.apache.commons.io.IOUtils;
|
|
|
import org.apache.commons.io.output.ByteArrayOutputStream;
|
|
@@ -33,6 +35,8 @@ import org.dromara.common.mybatis.core.page.PageQuery;
|
|
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
|
|
import org.dromara.common.redis.utils.RedisUtils;
|
|
|
import org.dromara.system.domain.GameEvent;
|
|
|
+import org.dromara.system.domain.GameEventGroup;
|
|
|
+import org.dromara.system.domain.PdfEntry;
|
|
|
import org.dromara.system.domain.bo.GameAthleteBo;
|
|
|
import org.dromara.system.domain.bo.GameEventBo;
|
|
|
import org.dromara.system.domain.bo.GameTeamBo;
|
|
@@ -40,10 +44,7 @@ import org.dromara.system.domain.bo.GenerateBibBo;
|
|
|
import org.dromara.system.domain.constant.GameEventConstant;
|
|
|
import org.dromara.system.domain.vo.*;
|
|
|
import org.dromara.system.mapper.GameEventMapper;
|
|
|
-import org.dromara.system.service.IGameAthleteService;
|
|
|
-import org.dromara.system.service.IGameEventProjectService;
|
|
|
-import org.dromara.system.service.IGameEventService;
|
|
|
-import org.dromara.system.service.IGameTeamService;
|
|
|
+import org.dromara.system.service.*;
|
|
|
import org.springframework.context.annotation.Lazy;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
@@ -54,8 +55,13 @@ import javax.imageio.ImageIO;
|
|
|
import java.awt.image.BufferedImage;
|
|
|
import java.io.*;
|
|
|
import java.util.*;
|
|
|
+import java.util.concurrent.CompletableFuture;
|
|
|
+import java.util.concurrent.ExecutorService;
|
|
|
+import java.util.concurrent.Executors;
|
|
|
import java.util.concurrent.atomic.AtomicLong;
|
|
|
import java.util.stream.Collectors;
|
|
|
+import java.util.zip.ZipEntry;
|
|
|
+import java.util.zip.ZipOutputStream;
|
|
|
|
|
|
/**
|
|
|
* 赛事基本信息Service业务层处理
|
|
@@ -80,7 +86,15 @@ public class GameEventServiceImpl implements IGameEventService {
|
|
|
private IGameEventGroupService gameEventGroupService;
|
|
|
private static final ExecutorService PDF_GENERATION_EXECUTOR =
|
|
|
Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);
|
|
|
-
|
|
|
+ // 常见图片类型的文件头(前几个字节)
|
|
|
+ private static final String[] IMAGE_HEADER_PREFIXES = {
|
|
|
+ "FFD8FF", // JPEG
|
|
|
+ "89504E47", // PNG
|
|
|
+ "47494638", // GIF
|
|
|
+ "49492A00", // TIFF (little endian)
|
|
|
+ "4D4D002A", // TIFF (big endian)
|
|
|
+ "424D" // BMP
|
|
|
+ };
|
|
|
/**
|
|
|
* 查询赛事基本信息
|
|
|
*
|
|
@@ -575,7 +589,15 @@ public class GameEventServiceImpl implements IGameEventService {
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public void generateNumberBib(HttpServletResponse response, MultipartFile bgImage, MultipartFile logo, GenerateBibBo bibParam) {
|
|
|
+ public void generateNumberBib(HttpServletResponse response,
|
|
|
+ MultipartFile bgImage, MultipartFile logo,
|
|
|
+ GenerateBibBo bibParam) {
|
|
|
+ if (bgImage!=null&&!isImage(bgImage)) {
|
|
|
+ throw new ServiceException("背景图不是图片格式");
|
|
|
+ }
|
|
|
+ if (logo!=null&&!isImage(logo)) {
|
|
|
+ throw new ServiceException("logo不是图片格式");
|
|
|
+ }
|
|
|
//1.查询当前赛事所有队员数据
|
|
|
GameAthleteBo gameAthleteBo = new GameAthleteBo();
|
|
|
Object cacheObject = RedisUtils.getCacheObject(GameEventConstant.DEFAULT_EVENT_ID);
|
|
@@ -600,6 +622,41 @@ public class GameEventServiceImpl implements IGameEventService {
|
|
|
generateBib(response, bgImage, logo, eventVo.getEventName(), gameEventGroup.getGroupName(), athleteVoList, teamNameMap, projectMap, bibParam);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 判断是否为图片
|
|
|
+ * @param file
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static boolean isImage(MultipartFile file) {
|
|
|
+ if (file == null || file.isEmpty()) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ try (InputStream is = file.getInputStream()) {
|
|
|
+ byte[] header = new byte[8]; // 读取前8字节足够判断大部分图片
|
|
|
+ int bytesRead = is.read(header);
|
|
|
+ if (bytesRead < 4) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ StringBuilder hexHeader = new StringBuilder();
|
|
|
+ for (int i = 0; i < bytesRead; i++) {
|
|
|
+ hexHeader.append(String.format("%02X", header[i] & 0xFF));
|
|
|
+ }
|
|
|
+
|
|
|
+ String headerStr = hexHeader.toString();
|
|
|
+ for (String prefix : IMAGE_HEADER_PREFIXES) {
|
|
|
+ if (headerStr.startsWith(prefix)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+
|
|
|
+ } catch (IOException e) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
/**
|
|
|
* 生成号码布并直接通过 HttpServletResponse 返回 ZIP 文件
|
|
|
*
|