주뇽's 저장소

[Troubleshooting] Spring Boot와 S3, Flutter를 사용하여 이미지 업로드 시 발생한 문제 해결하기 본문

웹개발/SpringBoot

[Troubleshooting] Spring Boot와 S3, Flutter를 사용하여 이미지 업로드 시 발생한 문제 해결하기

뎁쭌 2024. 5. 20. 23:51
728x90
반응형

내용:

최근에 Spring Boot와 S3, Flutter를 사용하여 게시판 프로젝트를 진행하던 중, 게시글에 이미지를 함께 올리는 기능을 구현하면서 여러 가지 문제에 직면했다. 이 글에서는 해당 문제의 원인과 해결 방법에 대해 자세히 설명한다.

문제 상황:

  • Spring Boot와 JPA를 사용하여 게시판 프로젝트를 진행 중이었다.
  • 게시글에 이미지를 함께 업로드하는 기능을 구현하려고 했다.
  • Postman을 사용하여 API를 테스트하던 중 Content-Type 'multipart/form-data'와 관련된 여러 오류가 발생했다.
  • 특히, Content-Type 'application/octet-stream' is not supported라는 오류가 반복적으로 발생했다.

문제 원인:

  • Spring Boot에서 multipart/form-data로 전송된 데이터를 올바르게 처리하지 못하고 있었다.
  • Postman에서 요청을 보내는 과정에서 Content-Type이 올바르게 설정되지 않아 발생한 문제였다.
  • 또한, S3에 이미지를 업로드할 때 메타데이터 설정이 누락되어 있었고, 이로 인해 발생한 경고 메시지들도 있었다.

해결 방법 1: Controller에서 @RequestPart 어노테이션 사용

먼저, 컨트롤러에서 @RequestPart 어노테이션을 사용하여 JSON 데이터를 처리하고, 이를 객체로 변환한다.

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.web.bind.annotation.RequestPart;

@PostMapping("/{categoryId}/post")
public ResponseEntity<String> createPost(@PathVariable(name = "categoryId") Long categoryId,
                                         @RequestPart(value = "images", required = false) List<MultipartFile> files,
                                         @RequestPart("postRequest") String postRequestJson,
                                         @AuthenticationPrincipal CustomUserDetails userDetails) {
    if (categoryId != 1) {
        ObjectMapper objectMapper = new ObjectMapper();
        PostRequest postRequest;
        try {
            postRequest = objectMapper.readValue(postRequestJson, PostRequest.class);
        } catch (JsonProcessingException e) {
            return ResponseEntity.badRequest().body("Invalid JSON format");
        }

        UserAccount userAccount = userDetails.getUserAccount();
        return postService.save(postRequest, userAccount, categoryId, files);
    }
    return ResponseEntity.badRequest().body("인기 게시판에는 게시글 작성이 불가능합니다.");
}

해결 방법 2: S3Service에서 ObjectMetadata 설정

이미지를 S3에 업로드할 때 ObjectMetadata에 Content-Length와 Content-Type을 설정한다.

import com.amazonaws.services.s3.model.ObjectMetadata;

private String uploadImage(MultipartFile file, String s3Key) {
    try {
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentLength(file.getSize());  // Content-Length 설정
        metadata.setContentType(file.getContentType());  // Content-Type 설정

        amazonS3.putObject(new PutObjectRequest(bucket, s3Key, file.getInputStream(), metadata));
    } catch (IOException e) {
        throw new RuntimeException("Failed to upload image to S3", e);
    }
    return amazonS3.getUrl(bucket, s3Key).toString();
}

추가 고려사항:

캐시로 인한 데이터 불일치 문제를 해결할 때와 마찬가지로, 다음 사항들을 고려할 수 있다.

캐시 설정 조정:

  • spring.jpa.properties.hibernate.cache.use_second_level_cache 속성을 false로 설정하여 2차 캐시를 비활성화할 수 있다.
  • spring.jpa.properties.hibernate.cache.use_query_cache 속성을 false로 설정하여 쿼리 캐시를 비활성화할 수 있다.

캐시 무효화:

  • 데이터 변경 작업이 발생한 경우, 해당 데이터와 관련된 캐시를 명시적으로 무효화할 수 있다.
  • @CacheEvict 어노테이션을 사용하여 특정 캐시 엔트리를 제거할 수 있다.

캐시 범위 제한:

  • @Cacheable 어노테이션의 condition 속성을 사용하여 캐시 적용 조건을 지정할 수 있다.
  • 특정 조건에 해당하는 경우에만 캐시를 사용하도록 제한할 수 있다.

마무리:

Spring Boot와 S3, Flutter를 사용하여 이미지 업로드 시 발생한 문제를 해결하는 방법에 대해 알아보았다. @RequestPart 어노테이션을 사용하여 JSON 데이터를 처리하거나, S3에 이미지를 업로드할 때 메타데이터를 설정하는 것이 효과적인 해결책이 될 수 있다. 추가로 캐시 설정 조정, 캐시 무효화, 캐시 범위 제한 등의 방법을 고려하여 캐시 관련 문제를 해결할 수 있다.