Spring Boot项目文件操作接口仅POST可用,GET/DELETE报500错误
问题分析与修复方案
核心问题1:Optional 直接调用 get() 引发空指针异常
StorageService 的 outputFile 方法中,当 repository.findByName(fileName) 查询不到目标文件时,dbFileData 是空的 Optional 对象,直接调用 dbFileData.get() 会抛出 NoSuchElementException,这是 GET 接口返回500错误的直接原因。
修复代码:
修改 StorageService 的 outputFile 方法,先判断文件是否存在:
public byte[] outputFile(String fileName){ Optional<FileData> dbFileData = repository.findByName(fileName); if(!dbFileData.isPresent()){ throw new RuntimeException("文件不存在:" + fileName); } return decompressFile(dbFileData.get().getFileData()); }
同时在 Controller 层捕获异常,返回友好响应:
@GetMapping("/{fileName}") public ResponseEntity<?> outputFile(@PathVariable String fileName){ try { byte[] fileData = service.outputFile(fileName); String contentType = service.getType(fileName); return ResponseEntity.status(HttpStatus.OK) .contentType(MediaType.parseMediaType(contentType)) .body(fileData); } catch (RuntimeException e) { return ResponseEntity.status(HttpStatus.NOT_FOUND) .body(e.getMessage()); } }
核心问题2:GET 接口 Content-Type 设置错误
当前 GET 接口使用 MediaType.MULTIPART_FORM_DATA,这是上传文件的请求格式,返回文件内容时应该使用文件对应的实际媒体类型(如图片用 image/png、文档用 application/pdf),否则客户端无法正确解析文件。
修复代码:
从数据库中读取文件的原始类型,设置正确的 Content-Type:
@GetMapping("/{fileName}") public ResponseEntity<?> outputFile(@PathVariable String fileName){ try { Optional<FileData> dbFileData = repository.findByName(fileName); if(!dbFileData.isPresent()){ return ResponseEntity.status(HttpStatus.NOT_FOUND) .body("文件不存在:" + fileName); } FileData fileData = dbFileData.get(); byte[] content = service.decompressFile(fileData.getFileData()); return ResponseEntity.status(HttpStatus.OK) .contentType(MediaType.parseMediaType(fileData.getType())) .body(content); } catch (Exception e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body("获取文件失败:" + e.getMessage()); } }
潜在问题:JPA 实体类缺少无参构造函数
FileData 实体类仅提供带参数的构造函数,而 JPA 在实例化实体时必须依赖无参构造函数。虽然当前 POST 接口正常,但会导致后续查询或持久化操作出现隐性异常。
修复代码:
给 FileData 添加无参构造函数:
@Entity @Table(name="FileData") @Data public class FileData { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private String type; @Lob @Column(name="filedata") private byte[] fileData; // 添加JPA必需的无参构造函数 public FileData() {} public FileData(String name, String type, byte[] fileData) { this.name = name; this.type = type; this.fileData = fileData; } }
额外优化:添加日志与异常细化
在 StorageService 中添加日志记录,方便排查问题:
import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Service public class StorageService { private static final Logger logger = LoggerFactory.getLogger(StorageService.class); @Autowired private StorageRepository repository; public byte[] outputFile(String fileName){ Optional<FileData> dbFileData = repository.findByName(fileName); if(!dbFileData.isPresent()){ logger.error("未找到文件:{}", fileName); throw new RuntimeException("文件不存在:" + fileName); } try { return decompressFile(dbFileData.get().getFileData()); } catch (Exception e) { logger.error("解压文件失败:{}", fileName, e); throw new RuntimeException("解压文件失败:" + e.getMessage()); } } }
内容的提问来源于stack exchange,提问作者Micu Bogdan
相关产品推荐
相关产品推荐

