资源相关
This commit is contained in:
		| @ -2,6 +2,17 @@ package com.yj.earth.business.controller; | ||||
|  | ||||
| import cn.hutool.core.io.FileUtil; | ||||
| import cn.hutool.core.util.IdUtil; | ||||
| 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.*; | ||||
|  | ||||
| import cn.hutool.crypto.digest.DigestUtil; | ||||
| import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | ||||
| import com.baomidou.mybatisplus.core.metadata.IPage; | ||||
| @ -9,6 +20,7 @@ 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; | ||||
| import com.yj.earth.common.util.JsonMapConverter; | ||||
| import com.yj.earth.vo.FileInfoVo; | ||||
| import io.swagger.v3.oas.annotations.Operation; | ||||
| import io.swagger.v3.oas.annotations.Parameter; | ||||
| @ -17,17 +29,16 @@ import jakarta.servlet.http.HttpServletResponse; | ||||
| import org.springframework.beans.BeanUtils; | ||||
| import org.springframework.beans.factory.annotation.Value; | ||||
| import org.springframework.http.HttpHeaders; | ||||
| import org.springframework.util.DigestUtils; | ||||
| import org.springframework.web.bind.annotation.*; | ||||
| import org.springframework.web.multipart.MultipartFile; | ||||
|  | ||||
| import javax.annotation.Resource; | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
| import java.io.OutputStream; | ||||
| import java.io.InputStream; | ||||
| import java.net.URLEncoder; | ||||
| import java.nio.charset.StandardCharsets; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
| import java.util.stream.Collectors; | ||||
|  | ||||
| @Tag(name = "文件数据管理") | ||||
| @ -168,11 +179,7 @@ public class FileInfoController { | ||||
|  | ||||
|     @Operation(summary = "文件预览") | ||||
|     @GetMapping("/preview/{id}") | ||||
|     public void previewFile( | ||||
|             @Parameter(description = "文件ID", required = true) | ||||
|             @PathVariable String id, | ||||
|             HttpServletResponse response) throws IOException { | ||||
|  | ||||
|     public void previewFile(@Parameter(description = "文件ID", required = true) @PathVariable String id, HttpServletResponse response) throws IOException { | ||||
|         // 根据ID查询文件信息 | ||||
|         FileInfo fileInfo = fileInfoService.getById(id); | ||||
|         if (fileInfo == null) { | ||||
| @ -200,42 +207,100 @@ public class FileInfoController { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Operation(summary = "文件列表") | ||||
|     @GetMapping("/list") | ||||
|     public ApiResponse getFileList( | ||||
|             @Parameter(description = "页码", required = true) Integer pageNum, | ||||
|             @Parameter(description = "每页条数", required = true) Integer pageSize, | ||||
|             @Parameter(description = "文件名称") String fileName) { | ||||
|  | ||||
|         // 创建分页对象 | ||||
|         Page<FileInfo> page = new Page<>(pageNum, pageSize); | ||||
|         // 构建查询条件 | ||||
|         LambdaQueryWrapper<FileInfo> queryWrapper = new LambdaQueryWrapper<>(); | ||||
|         if (fileName != null && !fileName.isEmpty()) { | ||||
|             queryWrapper.like(FileInfo::getFileName, fileName); | ||||
|     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); | ||||
|         } | ||||
|         // 按创建时间倒序排列、最新上传的文件在前 | ||||
|         queryWrapper.orderByDesc(FileInfo::getCreatedAt); | ||||
|     } | ||||
|  | ||||
|         // 执行分页查询 | ||||
|         IPage<FileInfo> fileInfoPage = fileInfoService.page(page, queryWrapper); | ||||
|     /** | ||||
|      * 计算文件的 MD5 | ||||
|      */ | ||||
|     private String calculateFileMd5(File file) throws IOException { | ||||
|         try (InputStream is = new FileInputStream(file)) { | ||||
|             return DigestUtils.md5DigestAsHex(is); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|         // 转换为VO对象并设置URL | ||||
|         List<FileInfoVo> records = fileInfoPage.getRecords().stream().map(fileInfo -> { | ||||
|             FileInfoVo vo = new FileInfoVo(); | ||||
|             BeanUtils.copyProperties(fileInfo, vo); | ||||
|             vo.setPreviewUrl("/fileInfo/preview/" + fileInfo.getId()); | ||||
|             vo.setDownloadUrl("/fileInfo/download/" + fileInfo.getId()); | ||||
|             return vo; | ||||
|         }).collect(Collectors.toList()); | ||||
|     /** | ||||
|      * 提取图片的EXIF元数据(包括定位信息) | ||||
|      */ | ||||
|     private Map<String, Object> extractImageMetadata(InputStream inputStream) { | ||||
|         try { | ||||
|             Map<String, Object> result = new HashMap<>(); | ||||
|             Metadata metadata = ImageMetadataReader.readMetadata(inputStream); | ||||
|  | ||||
|         // 构建分页结果 | ||||
|         Page<FileInfoVo> resultPage = new Page<>(); | ||||
|         resultPage.setRecords(records); | ||||
|         resultPage.setTotal(fileInfoPage.getTotal()); | ||||
|         resultPage.setSize(fileInfoPage.getSize()); | ||||
|         resultPage.setCurrent(fileInfoPage.getCurrent()); | ||||
|         resultPage.setPages(fileInfoPage.getPages()); | ||||
|         return ApiResponse.success(resultPage); | ||||
|             // 遍历所有元数据目录 | ||||
|             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(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 ZZX9599
					ZZX9599