Browse Source

fix:添加文件校验

wenkai 2 days ago
parent
commit
42761d811a

+ 1 - 1
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/controller/NumberController.java

@@ -58,7 +58,7 @@ public class NumberController {
     @PostMapping("/generateBib")
     public void generateNumberBib(HttpServletResponse response,
                                   @RequestPart("bgImage") MultipartFile bgImage,
-                                  @RequestPart("logo") MultipartFile logo,
+                                  @RequestPart(name = "logo") MultipartFile logo,
                                   GenerateBibBo bibParam) {
         gameEventService.generateNumberBib(response, bgImage, logo, bibParam);
     }

+ 63 - 6
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/GameEventServiceImpl.java

@@ -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 文件
      *