From e1dc6930a9d217da8d87e2838208eb0e7eca2a2a Mon Sep 17 00:00:00 2001
From: zqy <2522236926@qq.com>
Date: 星期三, 31 十二月 2025 15:57:56 +0800
Subject: [PATCH] 新增mov
---
ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java | 727 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 721 insertions(+), 6 deletions(-)
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java
index 879ead8..461ee1f 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java
@@ -7,8 +7,7 @@
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.*;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -20,6 +19,7 @@
import com.ruoyi.common.utils.RenamedMultipartFile;
import com.ruoyi.common.utils.uuid.UUID;
import com.ruoyi.service.DownLoadFileService;
+import com.ruoyi.service.impl.VideoProcessService;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -36,9 +36,20 @@
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.framework.config.ServerConfig;
+
+
+import javax.imageio.ImageIO;
+
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+
/**
* 閫氱敤璇锋眰澶勭悊
- *
+ *
* @author ruoyi
*/
@RestController
@@ -52,12 +63,47 @@
@Autowired
private DownLoadFileService downLoadFileService;
+
+ @Autowired
+ private VideoProcessService videoProcessService;
+
private static final String FILE_DELIMETER = ",";
private static final Pattern CHINESE_PATTERN = Pattern.compile("[\u4e00-\u9fa5]");
+ // 缂╃暐鍥鹃厤缃�
+ @Value("${thumbnail.default-width:300}")
+ private int defaultThumbnailWidth;
-// @GetMapping("/downloadFile")
+ @Value("${thumbnail.default-height:200}")
+ private int defaultThumbnailHeight;
+
+ @Value("${thumbnail.quality:0.8}")
+ private double thumbnailQuality;
+
+ @Value("${thumbnail.cache-dir:./cache/thumbnails}")
+ private String thumbnailCacheDir;
+
+
+ @Value("${thumbnail.max-width:1920}")
+ private int maxThumbnailWidth;
+
+ @Value("${thumbnail.max-height:1080}")
+ private int maxThumbnailHeight;
+
+ @Value("${thumbnail.format:jpg}")
+ private String thumbnailFormat;
+
+ @Value("${thumbnail.keep-aspect-ratio:true}")
+ private boolean keepAspectRatio;
+
+ @Anonymous
+ @GetMapping("/generateThumbnail")
+ public AjaxResult generateThumbnail(@PathParam(value = "url") String url) throws Exception {
+
+ return AjaxResult.success( videoProcessService.generateThumbnail(url));
+ }
+ // @GetMapping("/downloadFile")
// public void fileDownload(@PathParam("path") String path, HttpServletResponse response)
// {
// path=path.substring(8);
@@ -154,7 +200,55 @@
* 閫氱敤涓婁紶璇锋眰锛堝涓級
*/
@PostMapping("/uploads")
- public AjaxResult uploadFiles(@RequestParam("files") List<MultipartFile> files) throws Exception {
+ public AjaxResult uploadFiles(@RequestParam("files") List<MultipartFile> files) throws Exception
+ {
+ //System.out.println("99999999999999999999999990000000000000000");
+ try
+ {
+ // 涓婁紶鏂囦欢璺緞
+ String filePath = RuoYiConfig.getUploadPath();
+ List<String> urls = new ArrayList<String>();
+ List<String> fileNames = new ArrayList<String>();
+ List<String> newFileNames = new ArrayList<String>();
+ List<String> originalFilenames = new ArrayList<String>();
+ // System.out.println("99999999999999999999999990000000000000000");
+ // System.out.println(files);
+ // System.out.println(files.size());
+
+ for (MultipartFile file : files)
+ {
+ // 涓婁紶骞惰繑鍥炴柊鏂囦欢鍚嶇О
+ String filename = "";
+ // System.out.println("1122123330+++++++++++++++++++++++++++++");
+
+ String fileName = FileUploadUtils.upload(filePath, file, filename);
+ String url = serverConfig.getUrl() + fileName;
+ urls.add(url);
+ fileNames.add(fileName);
+ newFileNames.add(FileUtils.getName(fileName));
+ originalFilenames.add(file.getOriginalFilename());
+ }
+ AjaxResult ajax = AjaxResult.success();
+ // System.out.println("99999999999999999999999990000000000000000");
+
+ ajax.put("urls", StringUtils.join(urls, FILE_DELIMETER));
+ ajax.put("fileNames", StringUtils.join(fileNames, FILE_DELIMETER));
+ ajax.put("newFileNames", StringUtils.join(newFileNames, FILE_DELIMETER));
+ ajax.put("originalFilenames", StringUtils.join(originalFilenames, FILE_DELIMETER));
+ // System.out.println("1122123330+++++++++++++++++++++++++++++");
+ return ajax;
+ }
+ catch (Exception e)
+ {
+ return AjaxResult.error(e.getMessage());
+ }
+ }
+
+ /**
+ * 閫氱敤涓婁紶璇锋眰锛堝涓級 灏嗕腑鏂囦慨鏀逛负鍏朵粬
+ */
+ @PostMapping("/noChinese/uploads")
+ public AjaxResult noChineseUploadFiles(@RequestParam("files") List<MultipartFile> files) throws Exception {
//System.out.println("99999999999999999999999990000000000000000");
try {
// 涓婁紶鏂囦欢璺緞
@@ -396,4 +490,625 @@
}
}
-}
\ No newline at end of file
+
+
+
+
+
+
+ // 鏀寔鐨勫浘鐗囨牸寮�
+ private static final Set<String> SUPPORTED_IMAGE_FORMATS =
+ new HashSet<>(Arrays.asList("jpg", "jpeg", "png", "gif", "bmp", "webp", "tiff")); // 缂╃暐鍥剧紦瀛�
+ private final Map<String, Long> thumbnailCache = new HashMap<>();
+
+ /**
+ * 鍔ㄦ�佺敓鎴愮缉鐣ュ浘 - 涓诲叆鍙�
+ * 鍙傛暟璇存槑锛�
+ * path: 鍥剧墖璺緞锛堝繀闇�锛�
+ * width: 缂╃暐鍥惧搴︼紙鍙�夛紝榛樿300锛�
+ * height: 缂╃暐鍥鹃珮搴︼紙鍙�夛紝榛樿200锛�
+ * mode: 鐢熸垚妯″紡锛堝彲閫夛紝crop=瑁佸壀锛宻cale=缂╂斁锛岄粯璁cale锛�
+ * quality: 鍥剧墖璐ㄩ噺锛堝彲閫夛紝0-1锛岄粯璁�0.8锛�
+ * format: 杈撳嚭鏍煎紡锛堝彲閫夛紝jpg/png绛夛紝榛樿jpg锛�
+ */
+ @Anonymous
+ @GetMapping("/thumbnail")
+ public void generateThumbnail(
+ @RequestParam("path") String imagePath,
+ @RequestParam(value = "width", required = false) Integer width,
+ @RequestParam(value = "height", required = false) Integer height,
+ @RequestParam(value = "mode", defaultValue = "scale") String mode,
+ @RequestParam(value = "quality", required = false) Double quality,
+ @RequestParam(value = "format", required = false) String format,
+
+ HttpServletResponse response) {
+
+ try {
+ // 1. 鍙傛暟楠岃瘉鍜岃缃粯璁ゅ��
+ String decodedPath = URLDecoder.decode(imagePath, "UTF-8").replace("/profile","");
+
+ int targetWidth = width != null ? Math.min(width, maxThumbnailWidth) : defaultThumbnailWidth;
+ int targetHeight = height != null ? Math.min(height, maxThumbnailHeight) : defaultThumbnailHeight;
+ double targetQuality = quality != null ? Math.max(0.1, Math.min(1.0, quality)) : thumbnailQuality;
+ String targetFormat = format != null && SUPPORTED_IMAGE_FORMATS.contains(format.toLowerCase())
+ ? format.toLowerCase() : thumbnailFormat;
+
+ // 2. 瀹夊叏妫�鏌�
+ if (!FileUtils.checkAllowDownload(decodedPath)) {
+ response.sendError(HttpServletResponse.SC_FORBIDDEN, "绂佹璁块棶璇ヨ矾寰�");
+ return;
+ }
+
+ // 3. 鑾峰彇鍘熷浘鏂囦欢
+ String fullPath = RuoYiConfig.getProfile() + decodedPath;
+ File originalFile = new File(fullPath);
+
+ if (!originalFile.exists()) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND, "鍥剧墖涓嶅瓨鍦�: " + decodedPath);
+ return;
+ }
+
+ if (!isImageFile(originalFile)) {
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST, "涓嶆槸鍥剧墖鏂囦欢: " + originalFile.getName());
+ return;
+ }
+
+
+
+ // 5. 鐢熸垚缂╃暐鍥�
+ BufferedImage thumbnail = generateThumbnailImage(
+ originalFile, targetWidth, targetHeight, mode, targetQuality, targetFormat
+ );
+
+ if (thumbnail == null) {
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "鐢熸垚缂╃暐鍥惧け璐�");
+ return;
+ }
+
+ // 7. 杈撳嚭缂╃暐鍥�
+ sendThumbnailResponse(thumbnail, targetFormat, targetQuality, response);
+
+ } catch (Exception e) {
+ log.error("鐢熸垚缂╃暐鍥惧け璐�: path={}, error={}", imagePath, e.getMessage(), e);
+ try {
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "鐢熸垚缂╃暐鍥惧け璐�: " + e.getMessage());
+ } catch (IOException ex) {
+ log.error("鍙戦�侀敊璇搷搴斿け璐�", ex);
+ }
+ }
+ }
+
+ /**
+ * 鎵归噺鐢熸垚缂╃暐鍥� - 閫氳繃閫楀彿鍒嗛殧鐨勮矾寰�
+ * 鍙傛暟璇存槑锛�
+ * paths: 鐢ㄩ�楀彿鍒嗛殧鐨勫浘鐗囪矾寰勫垪琛紙蹇呴渶锛�
+ * width: 缂╃暐鍥惧搴︼紙鍙�夛紝榛樿300锛�
+ * height: 缂╃暐鍥鹃珮搴︼紙鍙�夛紝榛樿200锛�
+ * mode: 鐢熸垚妯″紡锛堝彲閫夛紝crop=瑁佸壀锛宻cale=缂╂斁锛岄粯璁cale锛�
+ * quality: 鍥剧墖璐ㄩ噺锛堝彲閫夛紝0-1锛岄粯璁�0.8锛�
+ * format: 杈撳嚭鏍煎紡锛堝彲閫夛紝jpg/png绛夛紝榛樿jpg锛�
+ */
+ @Anonymous
+ @PostMapping("/batchThumbnailByPaths")
+ public AjaxResult generateBatchThumbnailByPaths(
+ @RequestParam("paths") String imagePaths,
+ @RequestParam(value = "width", required = false) Integer width,
+ @RequestParam(value = "height", required = false) Integer height,
+ @RequestParam(value = "mode", defaultValue = "scale") String mode,
+ @RequestParam(value = "quality", required = false) Double quality,
+ @RequestParam(value = "format", required = false) String format) {
+
+ List<Map<String, Object>> results = new ArrayList<>();
+ List<String> thumbnailUrls = new ArrayList<>(); // 瀛樺偍鎵�鏈夌缉鐣ュ浘URL
+
+ try {
+ // 1. 鍒嗗壊璺緞
+ String[] pathArray = imagePaths.split(",");
+ if (pathArray.length == 0) {
+ return AjaxResult.error("鍥剧墖璺緞涓嶈兘涓虹┖");
+ }
+
+ // 2. 璁剧疆鍘嬬缉鍙傛暟
+ int targetWidth = width != null ? Math.min(width, maxThumbnailWidth) : defaultThumbnailWidth;
+ int targetHeight = height != null ? Math.min(height, maxThumbnailHeight) : defaultThumbnailHeight;
+ double targetQuality = quality != null ? Math.max(0.1, Math.min(1.0, quality)) : thumbnailQuality;
+ String targetFormat = format != null && SUPPORTED_IMAGE_FORMATS.contains(format.toLowerCase())
+ ? format.toLowerCase() : thumbnailFormat;
+
+ int successCount = 0;
+ int failCount = 0;
+
+ // 3. 澶勭悊姣忎釜璺緞
+ for (String path : pathArray) {
+ Map<String, Object> result = new HashMap<>();
+ String trimmedPath = path.trim();
+
+ if (trimmedPath.isEmpty()) {
+ continue;
+ }
+
+ result.put("originalPath", trimmedPath);
+
+ try {
+ // 瑙g爜璺緞
+ String decodedPath = URLDecoder.decode(trimmedPath, "UTF-8").replace("/profile","");
+
+ // 瀹夊叏妫�鏌�
+ if (!FileUtils.checkAllowDownload(decodedPath)) {
+ result.put("success", false);
+ result.put("error", "绂佹璁块棶璇ヨ矾寰�");
+ result.put("code", 403);
+ results.add(result);
+ failCount++;
+ continue;
+ }
+
+ // 鑾峰彇鍘熷浘
+ String fullPath = RuoYiConfig.getProfile() + decodedPath;
+ File originalFile = new File(fullPath);
+
+ if (!originalFile.exists()) {
+ result.put("success", false);
+ result.put("error", "鍥剧墖涓嶅瓨鍦�");
+ result.put("code", 404);
+ results.add(result);
+ failCount++;
+ continue;
+ }
+
+ if (!isImageFile(originalFile)) {
+ result.put("success", false);
+ result.put("error", "涓嶆槸鍥剧墖鏂囦欢");
+ result.put("code", 400);
+ results.add(result);
+ failCount++;
+ continue;
+ }
+
+ // 鐢熸垚缂╃暐鍥綰RL
+ String thumbnailUrl = buildThumbnailUrlWithParams(
+ trimmedPath, targetWidth, targetHeight, mode, targetQuality, targetFormat
+ );
+
+ result.put("success", true);
+ result.put("thumbnailUrl", thumbnailUrl);
+ result.put("originalUrl", serverConfig.getUrl() + decodedPath);
+ result.put("fileName", originalFile.getName());
+ result.put("code", 200);
+
+ // 灏嗘垚鍔熺殑缂╃暐鍥綰RL娣诲姞鍒板垪琛�
+ thumbnailUrls.add(thumbnailUrl);
+
+ // 鑾峰彇鍥剧墖淇℃伅
+ BufferedImage originalImage = ImageIO.read(originalFile);
+ if (originalImage != null) {
+ result.put("originalWidth", originalImage.getWidth());
+ result.put("originalHeight", originalImage.getHeight());
+ }
+
+ // 鍘嬬缉鍙傛暟
+
+ Map<String, Object> compressParams = new HashMap<>();
+ compressParams.put("width", targetWidth);
+ compressParams.put("height", targetHeight);
+ compressParams.put("mode", mode);
+ compressParams.put("quality", targetQuality);
+ compressParams.put("format", targetFormat);
+
+ result.put("compressParams", compressParams);
+
+ successCount++;
+
+ } catch (Exception e) {
+ log.error("澶勭悊缂╃暐鍥捐姹傚け璐�: {}", trimmedPath, e);
+ result.put("success", false);
+ result.put("error", e.getMessage());
+ result.put("code", 500);
+ failCount++;
+ }
+
+ results.add(result);
+ }
+
+ // 4. 鏋勫缓杩斿洖缁撴灉
+ Map<String, Object> responseData = new HashMap<>();
+ responseData.put("results", results);
+
+ // 灏嗘墍鏈夋垚鍔熺殑缂╃暐鍥綰RL鐢ㄩ�楀彿杩炴帴
+ if (!thumbnailUrls.isEmpty()) {
+ responseData.put("thumbnailUrls", String.join(",", thumbnailUrls));
+ } else {
+ responseData.put("thumbnailUrls", "");
+ }
+
+ // 姹囨�讳俊鎭�
+ Map<String, Object> summary = new HashMap<>();
+ summary.put("total", pathArray.length);
+ summary.put("success", successCount);
+ summary.put("fail", failCount);
+ Map<String, Object> compressParams = new HashMap<>();
+ compressParams.put("width", targetWidth);
+ compressParams.put("height", targetHeight);
+ compressParams.put("mode", mode);
+ compressParams.put("quality", targetQuality);
+ compressParams.put("format", targetFormat);
+
+ summary.put("compressParams", compressParams);
+
+ responseData.put("summary", summary);
+
+ return AjaxResult.success(
+ String.format("鎵归噺澶勭悊瀹屾垚锛屾垚鍔�%s涓紝澶辫触%s涓�", successCount, failCount),
+ responseData
+ );
+
+ } catch (Exception e) {
+ log.error("鎵归噺鐢熸垚缂╃暐鍥惧け璐�", e);
+ return AjaxResult.error("鎵归噺澶勭悊澶辫触: " + e.getMessage());
+ }
+ }
+
+
+ /**
+ * 鎵归噺鐢熸垚缂╃暐鍥惧苟鐩存帴鍘嬬缉鍥剧墖 - 杩斿洖鍘嬬缉鍚庣殑鍥剧墖淇℃伅
+ */
+ @Anonymous
+ @PostMapping("/batchCompressImages")
+ public void batchCompressImages(
+ @RequestParam("paths") String imagePaths,
+ @RequestParam(value = "width", required = false) Integer width,
+ @RequestParam(value = "height", required = false) Integer height,
+ @RequestParam(value = "mode", defaultValue = "scale") String mode,
+ @RequestParam(value = "quality", required = false) Double quality,
+ @RequestParam(value = "format", required = false) String format,
+ HttpServletResponse response) {
+
+ try {
+ // 1. 鍒嗗壊璺緞
+ String[] pathArray = imagePaths.split(",");
+ if (pathArray.length == 0) {
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST, "鍥剧墖璺緞涓嶈兘涓虹┖");
+ return;
+ }
+
+ // 2. 璁剧疆鍘嬬缉鍙傛暟
+ int targetWidth = width != null ? Math.min(width, maxThumbnailWidth) : defaultThumbnailWidth;
+ int targetHeight = height != null ? Math.min(height, maxThumbnailHeight) : defaultThumbnailHeight;
+ double targetQuality = quality != null ? Math.max(0.1, Math.min(1.0, quality)) : thumbnailQuality;
+ String targetFormat = format != null && SUPPORTED_IMAGE_FORMATS.contains(format.toLowerCase())
+ ? format.toLowerCase() : thumbnailFormat;
+
+ // 3. 鐢熸垚ZIP鍘嬬缉鍖�
+ response.setContentType("application/zip");
+ response.setHeader("Content-Disposition", "attachment; filename=\"compressed_images.zip\"");
+
+ try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
+ int processedCount = 0;
+
+ for (String path : pathArray) {
+ String trimmedPath = path.trim();
+ if (trimmedPath.isEmpty()) {
+ continue;
+ }
+
+ try {
+ // 瑙g爜璺緞
+ String decodedPath = URLDecoder.decode(trimmedPath, "UTF-8").replace("/profile","");
+
+ // 瀹夊叏妫�鏌�
+ if (!FileUtils.checkAllowDownload(decodedPath)) {
+ log.warn("绂佹璁块棶璺緞: {}", decodedPath);
+ continue;
+ }
+
+ // 鑾峰彇鍘熷浘
+ String fullPath = RuoYiConfig.getProfile() + decodedPath;
+ File originalFile = new File(fullPath);
+
+ if (!originalFile.exists() || !isImageFile(originalFile)) {
+ log.warn("鍥剧墖涓嶅瓨鍦ㄦ垨涓嶆槸鍥剧墖鏂囦欢: {}", decodedPath);
+ continue;
+ }
+
+ // 鐢熸垚缂╃暐鍥�
+ BufferedImage thumbnail = generateThumbnailImage(
+ originalFile, targetWidth, targetHeight, mode, targetQuality, targetFormat
+ );
+
+ if (thumbnail != null) {
+ // 娣诲姞鍒癦IP
+ String fileName = getFileNameWithoutExtension(originalFile.getName()) +
+ "_" + targetWidth + "x" + targetHeight +
+ "." + targetFormat;
+
+ ZipEntry zipEntry = new ZipEntry(fileName);
+ zipOut.putNextEntry(zipEntry);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ImageIO.write(thumbnail, targetFormat, baos);
+ zipOut.write(baos.toByteArray());
+
+ zipOut.closeEntry();
+ processedCount++;
+ }
+
+ } catch (Exception e) {
+ log.error("澶勭悊鍥剧墖澶辫触: {}", trimmedPath, e);
+ }
+ }
+
+ if (processedCount == 0) {
+ response.reset(); // 娓呯┖鍝嶅簲
+ response.setContentType("application/json");
+ response.getWriter().write("{\"code\": 500, \"msg\": \"娌℃湁鍥剧墖澶勭悊鎴愬姛\"}");
+ }
+
+ } catch (Exception e) {
+ log.error("鐢熸垚鍘嬬缉鍖呭け璐�", e);
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "鐢熸垚鍘嬬缉鍖呭け璐�");
+ }
+
+ } catch (Exception e) {
+ log.error("鎵归噺鍘嬬缉鍥剧墖澶辫触", e);
+ try {
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "澶勭悊澶辫触: " + e.getMessage());
+ } catch (IOException ex) {
+ log.error("鍙戦�侀敊璇搷搴斿け璐�", ex);
+ }
+ }
+ }
+
+ /**
+ * 鑾峰彇鍥剧墖淇℃伅锛堝寘鍚缉鐣ュ浘URL锛�
+ */
+ @Anonymous
+ @GetMapping("/imageInfo")
+ public AjaxResult getImageInfo(
+ @RequestParam("path") String imagePath,
+ @RequestParam(value = "width", required = false) Integer width,
+ @RequestParam(value = "height", required = false) Integer height) {
+
+ try {
+ String decodedPath = URLDecoder.decode(imagePath, "UTF-8");
+
+ // 瀹夊叏妫�鏌�
+ if (!FileUtils.checkAllowDownload(decodedPath)) {
+ return AjaxResult.error("绂佹璁块棶璇ヨ矾寰�");
+ }
+
+ // 鑾峰彇鍘熷浘
+ String fullPath = RuoYiConfig.getProfile() + decodedPath;
+ File originalFile = new File(fullPath);
+
+ if (!originalFile.exists()) {
+ return AjaxResult.error("鍥剧墖涓嶅瓨鍦�");
+ }
+
+ if (!isImageFile(originalFile)) {
+ return AjaxResult.error("涓嶆槸鍥剧墖鏂囦欢");
+ }
+
+ // 璇诲彇鍥剧墖淇℃伅
+ BufferedImage image = ImageIO.read(originalFile);
+ if (image == null) {
+ return AjaxResult.error("鏃犳硶璇诲彇鍥剧墖");
+ }
+
+ // 鏋勫缓杩斿洖淇℃伅
+ Map<String, Object> info = new HashMap<>();
+ info.put("originalUrl", serverConfig.getUrl() + decodedPath);
+ info.put("originalPath", decodedPath);
+ info.put("fileName", originalFile.getName());
+ info.put("fileSize", originalFile.length());
+ info.put("fileType", getFileExtension(originalFile.getName()));
+ info.put("width", image.getWidth());
+ info.put("height", image.getHeight());
+ info.put("lastModified", originalFile.lastModified());
+
+ // 鏋勫缓缂╃暐鍥綰RL
+ int targetWidth = width != null ? width : defaultThumbnailWidth;
+ int targetHeight = height != null ? height : defaultThumbnailHeight;
+
+ String thumbnailUrl = buildThumbnailUrl(decodedPath, targetWidth, targetHeight);
+ info.put("thumbnailUrl", thumbnailUrl);
+
+ // 涓嶅悓灏哄鐨勭缉鐣ュ浘URL
+ info.put("smallThumbnailUrl", buildThumbnailUrl(decodedPath, 150, 100));
+ info.put("mediumThumbnailUrl", buildThumbnailUrl(decodedPath, 300, 200));
+ info.put("largeThumbnailUrl", buildThumbnailUrl(decodedPath, 600, 400));
+
+ return AjaxResult.success("鑾峰彇鎴愬姛", info);
+
+ } catch (Exception e) {
+ log.error("鑾峰彇鍥剧墖淇℃伅澶辫触: {}", imagePath, e);
+ return AjaxResult.error("鑾峰彇澶辫触: " + e.getMessage());
+ }
+ }
+
+
+
+ /**
+ * 妫�鏌ユ槸鍚︿负鍥剧墖鏂囦欢
+ */
+ private boolean isImageFile(File file) {
+ if (file == null || !file.exists()) {
+ return false;
+ }
+
+ String fileName = file.getName().toLowerCase();
+ String extension = getFileExtension(fileName);
+
+ return SUPPORTED_IMAGE_FORMATS.contains(extension);
+ }
+
+ /**
+ * 鑾峰彇鏂囦欢鎵╁睍鍚�
+ */
+ private String getFileExtension(String fileName) {
+ if (StringUtils.isEmpty(fileName)) {
+ return "";
+ }
+
+ int lastDot = fileName.lastIndexOf('.');
+ if (lastDot > 0 && lastDot < fileName.length() - 1) {
+ return fileName.substring(lastDot + 1).toLowerCase();
+ }
+ return "";
+ }
+
+
+ /**
+ * 鐢熸垚缂╃暐鍥�
+ */
+ private BufferedImage generateThumbnailImage(File originalFile, int width, int height,
+ String mode, double quality, String format) {
+
+ try {
+ BufferedImage originalImage = ImageIO.read(originalFile);
+ if (originalImage == null) {
+ return null;
+ }
+
+ int originalWidth = originalImage.getWidth();
+ int originalHeight = originalImage.getHeight();
+
+ // 璁$畻鐩爣灏哄
+ int targetWidth = width;
+ int targetHeight = height;
+
+ if (keepAspectRatio && mode.equals("scale")) {
+ // 淇濇寔瀹介珮姣旂缉鏀�
+ double widthRatio = (double) width / originalWidth;
+ double heightRatio = (double) height / originalHeight;
+ double ratio = Math.min(widthRatio, heightRatio);
+
+ targetWidth = (int) (originalWidth * ratio);
+ targetHeight = (int) (originalHeight * ratio);
+ } else if (mode.equals("crop")) {
+ // 瑁佸壀妯″紡
+ double widthRatio = (double) width / originalWidth;
+ double heightRatio = (double) height / originalHeight;
+ double ratio = Math.max(widthRatio, heightRatio);
+
+ int cropWidth = (int) (width / ratio);
+ int cropHeight = (int) (height / ratio);
+
+ // 灞呬腑瑁佸壀
+ int cropX = (originalWidth - cropWidth) / 2;
+ int cropY = (originalHeight - cropHeight) / 2;
+
+ BufferedImage cropped = originalImage.getSubimage(
+ Math.max(0, cropX),
+ Math.max(0, cropY),
+ Math.min(cropWidth, originalWidth - cropX),
+ Math.min(cropHeight, originalHeight - cropY)
+ );
+
+ originalImage = cropped;
+ }
+
+ // 鍒涘缓鐩爣鍥剧墖
+ BufferedImage thumbnail = new BufferedImage(targetWidth, targetHeight,
+ format.equals("png") ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB);
+
+ // 缁樺埗缂╃暐鍥�
+ Graphics2D g2d = thumbnail.createGraphics();
+ g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
+ RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+ g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
+ RenderingHints.VALUE_RENDER_QUALITY);
+ g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_ON);
+
+ g2d.drawImage(originalImage, 0, 0, targetWidth, targetHeight, null);
+ g2d.dispose();
+
+ return thumbnail;
+
+ } catch (Exception e) {
+ log.error("鐢熸垚缂╃暐鍥惧け璐�: {}", originalFile.getAbsolutePath(), e);
+ return null;
+ }
+ }
+
+
+ /**
+ * 鍙戦�佺缉鐣ュ浘鍝嶅簲
+ */
+ private void sendThumbnailResponse(BufferedImage thumbnail, String format,
+ double quality, HttpServletResponse response) throws IOException {
+
+ response.setContentType("image/" + format);
+ response.setHeader("Cache-Control", "public, max-age=31536000"); // 缂撳瓨1骞�
+ response.setHeader("X-Thumbnail-Cache", "MISS");
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ImageIO.write(thumbnail, format, baos);
+
+ byte[] imageBytes = baos.toByteArray();
+ response.setContentLength(imageBytes.length);
+ response.getOutputStream().write(imageBytes);
+ }
+
+ /**
+ * 鏋勫缓缂╃暐鍥綰RL
+ */
+ private String buildThumbnailUrl(String imagePath, int width, int height) {
+ try {
+ return serverConfig.getUrl() + "/common/thumbnail?" +
+ "path=" + URLEncoder.encode(imagePath, "UTF-8") +
+ "&width=" + width +
+ "&height=" + height;
+ } catch (UnsupportedEncodingException e) {
+ return "";
+ }
+ }
+
+
+ /**
+ * 鏋勫缓甯﹀弬鏁扮殑缂╃暐鍥綰RL
+ */
+ private String buildThumbnailUrlWithParams(String imagePath, int width, int height,
+ String mode, double quality, String format)
+ throws UnsupportedEncodingException {
+
+ StringBuilder url = new StringBuilder();
+ url.append(serverConfig.getUrl()).append("/common/thumbnail?");
+ url.append("path=").append(URLEncoder.encode(imagePath, "UTF-8"));
+ url.append("&width=").append(width);
+ url.append("&height=").append(height);
+ url.append("&mode=").append(mode);
+ url.append("&quality=").append(quality);
+ url.append("&format=").append(format);
+
+ return url.toString();
+ }
+
+ /**
+ * 鑾峰彇涓嶅甫鎵╁睍鍚嶇殑鏂囦欢鍚�
+ */
+ private String getFileNameWithoutExtension(String fileName) {
+ if (fileName == null) {
+ return "";
+ }
+
+ int lastDot = fileName.lastIndexOf('.');
+ if (lastDot > 0) {
+ return fileName.substring(0, lastDot);
+ }
+
+ return fileName;
+ }
+ /**
+ * 缂╃暐鍥捐姹傚弬鏁扮被
+ */
+ @Data
+ static class ThumbnailRequest {
+ private String path; // 鍥剧墖璺緞
+ private Integer width; // 瀹藉害
+ private Integer height; // 楂樺害
+ private String mode; // 妯″紡锛歴cale/crop
+ private Double quality; // 璐ㄩ噺锛�0-1
+ private String format; // 鏍煎紡
+ }
+}
--
Gitblit v1.9.1