package cn.van.business.controller; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.io.File; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; /** * 图片访问控制器 * 用于访问转换后的jpg图片 * * @author System */ @Slf4j @RestController @RequestMapping("/images") public class ImageController { /** * 图片存储根目录 */ @Value("${image.convert.storage-path:${java.io.tmpdir}/comment-images}") private String storagePath; /** * 获取转换后的图片 * * @param filename 文件名(通常是MD5值.jpg) * @return 图片文件 */ @GetMapping("/{filename:.+}") public ResponseEntity getImage(@PathVariable String filename) { try { // 安全检查:防止路径遍历攻击 if (filename.contains("..") || filename.contains("/") || filename.contains("\\")) { log.warn("非法的文件名请求: {}", filename); return ResponseEntity.badRequest().build(); } Path filePath = Paths.get(storagePath, filename); File file = filePath.toFile(); if (!file.exists() || !file.isFile()) { log.warn("图片文件不存在: {}", filePath); return ResponseEntity.notFound().build(); } // 检查文件是否在存储目录内(防止路径遍历) Path storageDir = Paths.get(storagePath).toAbsolutePath().normalize(); Path resolvedPath = filePath.toAbsolutePath().normalize(); if (!resolvedPath.startsWith(storageDir)) { log.warn("非法的文件路径访问: {}", resolvedPath); return ResponseEntity.badRequest().build(); } Resource resource = new FileSystemResource(file); // 判断文件类型 String contentType = Files.probeContentType(filePath); if (contentType == null) { // 如果无法探测,默认使用image/jpeg contentType = MediaType.IMAGE_JPEG_VALUE; } return ResponseEntity.ok() .contentType(MediaType.parseMediaType(contentType)) .header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=\"" + filename + "\"") .body(resource); } catch (Exception e) { log.error("获取图片失败: {}", filename, e); return ResponseEntity.internalServerError().build(); } } }