| 
									
										
										
										
											2025-09-08 17:01:50 +08:00
										 |  |  |  | package com.yj.earth.business.controller;
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | import cn.hutool.core.io.FileUtil;
 | 
					
						
							|  |  |  |  | import cn.hutool.core.util.IdUtil;
 | 
					
						
							| 
									
										
										
										
											2025-09-16 11:41:45 +08:00
										 |  |  |  | import com.drew.imaging.ImageMetadataReader;
 | 
					
						
							|  |  |  |  | import com.drew.imaging.ImageProcessingException;
 | 
					
						
							|  |  |  |  | import com.drew.metadata.Directory;
 | 
					
						
							|  |  |  |  | import com.drew.metadata.Metadata;
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | import java.io.*;
 | 
					
						
							|  |  |  |  | import java.nio.file.Files;
 | 
					
						
							|  |  |  |  | import java.nio.file.Path;
 | 
					
						
							|  |  |  |  | import java.nio.file.Paths;
 | 
					
						
							|  |  |  |  | import java.util.*;
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-08 17:01:50 +08:00
										 |  |  |  | import cn.hutool.crypto.digest.DigestUtil;
 | 
					
						
							|  |  |  |  | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 | 
					
						
							|  |  |  |  | import com.baomidou.mybatisplus.core.metadata.IPage;
 | 
					
						
							|  |  |  |  | import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 | 
					
						
							|  |  |  |  | import com.yj.earth.business.domain.FileInfo;
 | 
					
						
							|  |  |  |  | import com.yj.earth.business.service.FileInfoService;
 | 
					
						
							|  |  |  |  | import com.yj.earth.common.util.ApiResponse;
 | 
					
						
							| 
									
										
										
										
											2025-09-16 11:41:45 +08:00
										 |  |  |  | import com.yj.earth.common.util.JsonMapConverter;
 | 
					
						
							| 
									
										
										
										
											2025-09-08 17:01:50 +08:00
										 |  |  |  | import com.yj.earth.vo.FileInfoVo;
 | 
					
						
							|  |  |  |  | import io.swagger.v3.oas.annotations.Operation;
 | 
					
						
							|  |  |  |  | import io.swagger.v3.oas.annotations.Parameter;
 | 
					
						
							|  |  |  |  | import io.swagger.v3.oas.annotations.tags.Tag;
 | 
					
						
							|  |  |  |  | import jakarta.servlet.http.HttpServletResponse;
 | 
					
						
							|  |  |  |  | import org.springframework.beans.BeanUtils;
 | 
					
						
							|  |  |  |  | import org.springframework.beans.factory.annotation.Value;
 | 
					
						
							|  |  |  |  | import org.springframework.http.HttpHeaders;
 | 
					
						
							| 
									
										
										
										
											2025-09-16 11:41:45 +08:00
										 |  |  |  | import org.springframework.util.DigestUtils;
 | 
					
						
							| 
									
										
										
										
											2025-09-08 17:01:50 +08:00
										 |  |  |  | import org.springframework.web.bind.annotation.*;
 | 
					
						
							|  |  |  |  | import org.springframework.web.multipart.MultipartFile;
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | import javax.annotation.Resource;
 | 
					
						
							| 
									
										
										
										
											2025-09-16 11:41:45 +08:00
										 |  |  |  | import java.io.InputStream;
 | 
					
						
							| 
									
										
										
										
											2025-09-08 17:01:50 +08:00
										 |  |  |  | import java.net.URLEncoder;
 | 
					
						
							|  |  |  |  | import java.nio.charset.StandardCharsets;
 | 
					
						
							| 
									
										
										
										
											2025-09-16 11:41:45 +08:00
										 |  |  |  | import java.util.HashMap;
 | 
					
						
							|  |  |  |  | import java.util.Map;
 | 
					
						
							| 
									
										
										
										
											2025-09-08 17:01:50 +08:00
										 |  |  |  | import java.util.stream.Collectors;
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | @Tag(name = "文件数据管理")
 | 
					
						
							|  |  |  |  | @RestController
 | 
					
						
							|  |  |  |  | @RequestMapping("/fileInfo")
 | 
					
						
							|  |  |  |  | public class FileInfoController {
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     @Resource
 | 
					
						
							|  |  |  |  |     private FileInfoService fileInfoService;
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     @Value("${file.upload.path}")
 | 
					
						
							|  |  |  |  |     private String uploadPath;
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 获取项目根目录
 | 
					
						
							|  |  |  |  |     private String getProjectRootPath() {
 | 
					
						
							|  |  |  |  |         return System.getProperty("user.dir");
 | 
					
						
							|  |  |  |  |     }
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 获取完整的上传目录路径
 | 
					
						
							|  |  |  |  |     private String getFullUploadPath() {
 | 
					
						
							|  |  |  |  |         // 拼接项目根目录和配置的上传路径
 | 
					
						
							|  |  |  |  |         return getProjectRootPath() + File.separator + uploadPath;
 | 
					
						
							|  |  |  |  |     }
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     @Operation(summary = "文件上传")
 | 
					
						
							|  |  |  |  |     @PostMapping("/upload")
 | 
					
						
							|  |  |  |  |     public ApiResponse uploadFiles(@Parameter(description = "上传的文件数组", required = true) @RequestParam("files") MultipartFile[] files) throws IOException {
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // 校验文件数组是否为空
 | 
					
						
							|  |  |  |  |         if (files == null || files.length == 0) {
 | 
					
						
							|  |  |  |  |             return ApiResponse.failure("上传文件不能为空");
 | 
					
						
							|  |  |  |  |         }
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // 获取完整的上传目录路径
 | 
					
						
							|  |  |  |  |         String fullUploadPath = getFullUploadPath();
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         List<FileInfoVo> fileInfoVoList = new ArrayList<>();
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // 遍历处理每个文件
 | 
					
						
							|  |  |  |  |         for (MultipartFile file : files) {
 | 
					
						
							|  |  |  |  |             // 跳过空文件
 | 
					
						
							|  |  |  |  |             if (file.isEmpty()) {
 | 
					
						
							|  |  |  |  |                 continue;
 | 
					
						
							|  |  |  |  |             }
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             // 获取原始文件名和后缀
 | 
					
						
							|  |  |  |  |             String originalFilename = file.getOriginalFilename();
 | 
					
						
							|  |  |  |  |             String fileSuffix = FileUtil.extName(originalFilename);
 | 
					
						
							|  |  |  |  |             String contentType = file.getContentType();
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             // 生成唯一文件名、避免重复
 | 
					
						
							|  |  |  |  |             String uniqueFileName = IdUtil.simpleUUID() + "." + fileSuffix;
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             // 创建文件存储目录(如果不存在则自动创建)
 | 
					
						
							|  |  |  |  |             File uploadDir = new File(fullUploadPath);
 | 
					
						
							|  |  |  |  |             FileUtil.mkdir(uploadDir);
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             // 构建完整文件路径
 | 
					
						
							|  |  |  |  |             String filePath = fullUploadPath + File.separator + uniqueFileName;
 | 
					
						
							|  |  |  |  |             File destFile = new File(filePath);
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             // 使用Hutool工具类保存文件
 | 
					
						
							|  |  |  |  |             FileUtil.writeBytes(file.getBytes(), destFile);
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             // 计算文件MD5(用于校验文件完整性)
 | 
					
						
							|  |  |  |  |             String fileMd5 = DigestUtil.md5Hex(destFile);
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             // 查询有没有文件名一样并且 MD5 也一样的数据
 | 
					
						
							|  |  |  |  |             LambdaQueryWrapper<FileInfo> queryWrapper = new LambdaQueryWrapper<>();
 | 
					
						
							|  |  |  |  |             queryWrapper.eq(FileInfo::getFileName, originalFilename).eq(FileInfo::getFileMd5, fileMd5);
 | 
					
						
							|  |  |  |  |             if (fileInfoService.count(queryWrapper) > 0) {  // 修复了此处的bug、添加了queryWrapper参数
 | 
					
						
							|  |  |  |  |                 return ApiResponse.failure("已存在文件名相同且内容完全一致的文件");
 | 
					
						
							|  |  |  |  |             }
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             // 保存文件信息到数据库
 | 
					
						
							|  |  |  |  |             FileInfo fileInfo = new FileInfo();
 | 
					
						
							|  |  |  |  |             fileInfo.setFileName(originalFilename);
 | 
					
						
							|  |  |  |  |             fileInfo.setFileSuffix(fileSuffix);
 | 
					
						
							|  |  |  |  |             fileInfo.setContentType(contentType);
 | 
					
						
							|  |  |  |  |             fileInfo.setFileSize(file.getSize());
 | 
					
						
							|  |  |  |  |             fileInfo.setFilePath(uniqueFileName);  // 只保存相对文件名、不保存完整路径
 | 
					
						
							|  |  |  |  |             fileInfo.setFileMd5(fileMd5);
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             // 保存文件信息并获取ID
 | 
					
						
							|  |  |  |  |             fileInfoService.save(fileInfo);
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             // 构建并设置预览URL和下载URL
 | 
					
						
							|  |  |  |  |             String previewUrl = "/fileInfo/preview/" + fileInfo.getId();
 | 
					
						
							|  |  |  |  |             String downloadUrl = "/fileInfo/download/" + fileInfo.getId();
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             FileInfoVo fileInfoVo = new FileInfoVo();
 | 
					
						
							|  |  |  |  |             BeanUtils.copyProperties(fileInfo, fileInfoVo);
 | 
					
						
							|  |  |  |  |             fileInfoVo.setPreviewUrl(previewUrl);
 | 
					
						
							|  |  |  |  |             fileInfoVo.setDownloadUrl(downloadUrl);
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             fileInfoVoList.add(fileInfoVo);
 | 
					
						
							|  |  |  |  |         }
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (fileInfoVoList.isEmpty()) {
 | 
					
						
							|  |  |  |  |             return ApiResponse.failure("未成功上传任何文件");
 | 
					
						
							|  |  |  |  |         }
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         return ApiResponse.success(fileInfoVoList);
 | 
					
						
							|  |  |  |  |     }
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     @Operation(summary = "文件下载")
 | 
					
						
							|  |  |  |  |     @GetMapping("/download/{id}")
 | 
					
						
							|  |  |  |  |     public void downloadFile(@Parameter(description = "文件ID", required = true) @PathVariable String id, HttpServletResponse response) throws IOException {
 | 
					
						
							|  |  |  |  |         // 根据ID查询文件信息
 | 
					
						
							|  |  |  |  |         FileInfo fileInfo = fileInfoService.getById(id);
 | 
					
						
							|  |  |  |  |         if (fileInfo == null) {
 | 
					
						
							|  |  |  |  |             response.setStatus(HttpServletResponse.SC_NOT_FOUND);
 | 
					
						
							|  |  |  |  |             return;
 | 
					
						
							|  |  |  |  |         }
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // 构建完整文件路径
 | 
					
						
							|  |  |  |  |         String fullPath = getFullUploadPath() + File.separator + fileInfo.getFilePath();
 | 
					
						
							|  |  |  |  |         File file = new File(fullPath);
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // 校验文件是否存在
 | 
					
						
							|  |  |  |  |         if (!file.exists()) {
 | 
					
						
							|  |  |  |  |             response.setStatus(HttpServletResponse.SC_NOT_FOUND);
 | 
					
						
							|  |  |  |  |             return;
 | 
					
						
							|  |  |  |  |         }
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // 设置响应头
 | 
					
						
							|  |  |  |  |         response.setContentType(fileInfo.getContentType());
 | 
					
						
							|  |  |  |  |         response.setContentLengthLong(fileInfo.getFileSize());
 | 
					
						
							|  |  |  |  |         String encodedFileName = URLEncoder.encode(fileInfo.getFileName(), StandardCharsets.UTF_8.name());
 | 
					
						
							|  |  |  |  |         response.setHeader(HttpHeaders.CONTENT_DISPOSITION,
 | 
					
						
							|  |  |  |  |                 "attachment; filename=\"" + encodedFileName + "\"; filename*=UTF-8''" + encodedFileName);
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // 使用 Hutool 工具类复制文件流到响应输出流
 | 
					
						
							|  |  |  |  |         try (OutputStream os = response.getOutputStream()) {
 | 
					
						
							|  |  |  |  |             FileUtil.writeToStream(file, os);
 | 
					
						
							|  |  |  |  |         }
 | 
					
						
							|  |  |  |  |     }
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     @Operation(summary = "文件预览")
 | 
					
						
							|  |  |  |  |     @GetMapping("/preview/{id}")
 | 
					
						
							| 
									
										
										
										
											2025-09-16 11:41:45 +08:00
										 |  |  |  |     public void previewFile(@Parameter(description = "文件ID", required = true) @PathVariable String id, HttpServletResponse response) throws IOException {
 | 
					
						
							| 
									
										
										
										
											2025-09-08 17:01:50 +08:00
										 |  |  |  |         // 根据ID查询文件信息
 | 
					
						
							|  |  |  |  |         FileInfo fileInfo = fileInfoService.getById(id);
 | 
					
						
							|  |  |  |  |         if (fileInfo == null) {
 | 
					
						
							|  |  |  |  |             response.setStatus(HttpServletResponse.SC_NOT_FOUND);
 | 
					
						
							|  |  |  |  |             return;
 | 
					
						
							|  |  |  |  |         }
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // 构建完整文件路径
 | 
					
						
							|  |  |  |  |         String fullPath = getFullUploadPath() + File.separator + fileInfo.getFilePath();
 | 
					
						
							|  |  |  |  |         File file = new File(fullPath);
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // 校验文件是否存在
 | 
					
						
							|  |  |  |  |         if (!file.exists()) {
 | 
					
						
							|  |  |  |  |             response.setStatus(HttpServletResponse.SC_NOT_FOUND);
 | 
					
						
							|  |  |  |  |             return;
 | 
					
						
							|  |  |  |  |         }
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // 设置响应头(不设置 attachment、让浏览器直接显示)
 | 
					
						
							|  |  |  |  |         response.setContentType(fileInfo.getContentType());
 | 
					
						
							|  |  |  |  |         response.setContentLengthLong(fileInfo.getFileSize());
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // 使用 Hutool 工具类复制文件流到响应输出流
 | 
					
						
							|  |  |  |  |         try (OutputStream os = response.getOutputStream()) {
 | 
					
						
							|  |  |  |  |             FileUtil.writeToStream(file, os);
 | 
					
						
							|  |  |  |  |         }
 | 
					
						
							|  |  |  |  |     }
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-16 11:41:45 +08:00
										 |  |  |  |     public String handleLocationImageUpload(MultipartFile file) {
 | 
					
						
							|  |  |  |  |         try {
 | 
					
						
							|  |  |  |  |             // 校验文件是否为空
 | 
					
						
							|  |  |  |  |             if (file.isEmpty()) {
 | 
					
						
							|  |  |  |  |                 throw new IllegalArgumentException("上传文件不能为空");
 | 
					
						
							|  |  |  |  |             }
 | 
					
						
							|  |  |  |  |             // 获取文件基本信息
 | 
					
						
							|  |  |  |  |             String originalFilename = file.getOriginalFilename();
 | 
					
						
							|  |  |  |  |             String fileSuffix = FileUtil.extName(originalFilename);
 | 
					
						
							|  |  |  |  |             String contentType = file.getContentType();
 | 
					
						
							|  |  |  |  |             // 验证是否为图片文件
 | 
					
						
							|  |  |  |  |             if (contentType == null || !contentType.startsWith("image/")) {
 | 
					
						
							|  |  |  |  |                 throw new IllegalArgumentException("请上传图片文件");
 | 
					
						
							|  |  |  |  |             }
 | 
					
						
							|  |  |  |  |             // 获取完整的上传目录路径
 | 
					
						
							|  |  |  |  |             Path fullUploadPath = Paths.get(getFullUploadPath());
 | 
					
						
							|  |  |  |  |             // 生成唯一文件名
 | 
					
						
							|  |  |  |  |             String uniqueFileName = UUID.randomUUID().toString().replaceAll("-", "") + "." + fileSuffix;
 | 
					
						
							|  |  |  |  |             // 创建文件存储目录
 | 
					
						
							|  |  |  |  |             Files.createDirectories(fullUploadPath);
 | 
					
						
							|  |  |  |  |             // 构建完整文件路径并保存文件
 | 
					
						
							|  |  |  |  |             Path destFilePath = fullUploadPath.resolve(uniqueFileName);
 | 
					
						
							|  |  |  |  |             // 先将文件保存到目标位置
 | 
					
						
							|  |  |  |  |             file.transferTo(destFilePath);
 | 
					
						
							|  |  |  |  |             // 计算文件MD5(使用已保存的文件)
 | 
					
						
							|  |  |  |  |             String fileMd5 = calculateFileMd5(destFilePath.toFile());
 | 
					
						
							|  |  |  |  |             // 检查文件是否已存在
 | 
					
						
							|  |  |  |  |             LambdaQueryWrapper<FileInfo> queryWrapper = new LambdaQueryWrapper<>();
 | 
					
						
							|  |  |  |  |             queryWrapper.eq(FileInfo::getFileName, originalFilename)
 | 
					
						
							|  |  |  |  |                     .eq(FileInfo::getFileMd5, fileMd5);
 | 
					
						
							|  |  |  |  |             if (fileInfoService.count(queryWrapper) > 0) {
 | 
					
						
							|  |  |  |  |                 throw new IllegalStateException("已存在相同的图片文件");
 | 
					
						
							|  |  |  |  |             }
 | 
					
						
							|  |  |  |  |             // 提取图片元数据(使用已保存的文件,避免使用临时文件)
 | 
					
						
							|  |  |  |  |             Map<String, Object> metadata;
 | 
					
						
							|  |  |  |  |             try (InputStream is = Files.newInputStream(destFilePath)) {
 | 
					
						
							|  |  |  |  |                 metadata = extractImageMetadata(is);
 | 
					
						
							|  |  |  |  |             }
 | 
					
						
							|  |  |  |  |             // 保存文件信息到数据库
 | 
					
						
							|  |  |  |  |             FileInfo fileInfo = new FileInfo();
 | 
					
						
							|  |  |  |  |             fileInfo.setFileName(originalFilename);
 | 
					
						
							|  |  |  |  |             fileInfo.setFileSuffix(fileSuffix);
 | 
					
						
							|  |  |  |  |             fileInfo.setContentType(contentType);
 | 
					
						
							|  |  |  |  |             fileInfo.setFileSize(file.getSize());
 | 
					
						
							|  |  |  |  |             fileInfo.setFilePath(uniqueFileName);
 | 
					
						
							|  |  |  |  |             fileInfo.setFileMd5(fileMd5);
 | 
					
						
							|  |  |  |  |             fileInfoService.save(fileInfo);
 | 
					
						
							|  |  |  |  |             // 构建并返回结果
 | 
					
						
							|  |  |  |  |             Map<String, Object> result = new HashMap<>();
 | 
					
						
							|  |  |  |  |             result.put("previewUrl", "/fileInfo/preview/" + fileInfo.getId());
 | 
					
						
							|  |  |  |  |             result.put("downloadUrl", "/fileInfo/download/" + fileInfo.getId());
 | 
					
						
							|  |  |  |  |             result.put("metadata", metadata);
 | 
					
						
							|  |  |  |  |             return JsonMapConverter.mapToJson(result);
 | 
					
						
							|  |  |  |  |         } catch (IOException e) {
 | 
					
						
							|  |  |  |  |             throw new RuntimeException("文件上传失败: " + e.getMessage(), e);
 | 
					
						
							|  |  |  |  |         }
 | 
					
						
							|  |  |  |  |     }
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /**
 | 
					
						
							|  |  |  |  |      * 计算文件的 MD5
 | 
					
						
							|  |  |  |  |      */
 | 
					
						
							|  |  |  |  |     private String calculateFileMd5(File file) throws IOException {
 | 
					
						
							|  |  |  |  |         try (InputStream is = new FileInputStream(file)) {
 | 
					
						
							|  |  |  |  |             return DigestUtils.md5DigestAsHex(is);
 | 
					
						
							|  |  |  |  |         }
 | 
					
						
							|  |  |  |  |     }
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /**
 | 
					
						
							|  |  |  |  |      * 提取图片的EXIF元数据(包括定位信息)
 | 
					
						
							|  |  |  |  |      */
 | 
					
						
							|  |  |  |  |     private Map<String, Object> extractImageMetadata(InputStream inputStream) {
 | 
					
						
							|  |  |  |  |         try {
 | 
					
						
							|  |  |  |  |             Map<String, Object> result = new HashMap<>();
 | 
					
						
							|  |  |  |  |             Metadata metadata = ImageMetadataReader.readMetadata(inputStream);
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             // 遍历所有元数据目录
 | 
					
						
							|  |  |  |  |             for (Directory directory : metadata.getDirectories()) {
 | 
					
						
							|  |  |  |  |                 String directoryName = directory.getName();
 | 
					
						
							|  |  |  |  |                 Map<String, String> directoryTags = new HashMap<>();
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                 // 提取当前目录下的所有标签
 | 
					
						
							|  |  |  |  |                 for (com.drew.metadata.Tag tag : directory.getTags()) {
 | 
					
						
							|  |  |  |  |                     directoryTags.put(tag.getTagName(), tag.getDescription());
 | 
					
						
							|  |  |  |  |                 }
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                 // 存储当前目录的所有标签
 | 
					
						
							|  |  |  |  |                 if (!directoryTags.isEmpty()) {
 | 
					
						
							|  |  |  |  |                     result.put(directoryName, directoryTags);
 | 
					
						
							|  |  |  |  |                 }
 | 
					
						
							|  |  |  |  |             }
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             return result;
 | 
					
						
							|  |  |  |  |         } catch (ImageProcessingException | IOException e) {
 | 
					
						
							|  |  |  |  |             return Collections.emptyMap();
 | 
					
						
							| 
									
										
										
										
											2025-09-08 17:01:50 +08:00
										 |  |  |  |         }
 | 
					
						
							|  |  |  |  |     }
 | 
					
						
							|  |  |  |  | }
 |