왕초보일지

240208 TIL |

다시은 2024. 2. 8. 22:34

 

aws s3 이미지 업로드

 

MultipartFile 업로드 방식

 

 

참조 : ( https://techblog.woowahan.com/11392/ , https://varjm.tistory.com/79 , https://growth-coder.tistory.com/114, https://chb2005.tistory.com/200 )

https://chb2005.tistory.com/200

https://techblog.woowahan.com/11392/

클라이언트에서 첨부파일로 이미지를 업로드하면

스프링부트에서 이미지 파일을 MultipartFile 객체로 변환, S3 에 파일업로드, 

클라이언트에 이미지 url 을 반환

 

aws s3 버킷 생성

IAM, 정책 설정

 

 

S3Service

더보기
package org.example.todolist.infra.aws

import com.amazonaws.services.s3.AmazonS3Client
import com.amazonaws.services.s3.model.ObjectMetadata
import com.amazonaws.services.s3.model.PutObjectRequest
import com.amazonaws.util.IOUtils
import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.PropertySource
import org.springframework.stereotype.Service
import org.springframework.web.multipart.MultipartFile
import java.io.ByteArrayInputStream
import java.io.IOException
import java.util.*

@PropertySource("classpath:aws.yml")
@Service
class S3Service(
    private val s3Client: AmazonS3Client
) {

    @Value("\${bucket}")
    lateinit var bucket: String
    @Value("\${dir}")
    lateinit var dir: String

    @Throws(IOException::class)
    fun imageUpload(file: MultipartFile): String { // 파일 업로드시 톰캣이 임시 디렉터리에 저장, MultipartFile 로 매핑
        val fileName = UUID.randomUUID().toString() + "-" + file.originalFilename
        val objMeta = ObjectMetadata() // MultipartFile 매핑 -> 메타데이터에 접근 가능

        val bytes = IOUtils.toByteArray(file.inputStream) // multipartFile 내용 바이트 변환
        objMeta.contentLength = bytes.size.toLong() // 업로드될 파일의 크기 설정
        val byteArrayIs = ByteArrayInputStream(bytes) //

        s3Client.putObject(
            PutObjectRequest(bucket, dir + fileName, byteArrayIs, objMeta)
        )
        return s3Client.getUrl(bucket, dir + fileName).toString() // url 반환



    }

}

 

AweConfig

더보기
package org.example.todolist.infra.aws

import com.amazonaws.auth.AWSCredentials
import com.amazonaws.auth.AWSStaticCredentialsProvider
import com.amazonaws.auth.BasicAWSCredentials
import com.amazonaws.services.s3.AmazonS3Client
import com.amazonaws.services.s3.AmazonS3ClientBuilder
import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.PropertySource

@PropertySource("classpath:aws.yml")
@Configuration
class AwsConfig {
    @Value("\${accessKey}")
    private val accessKey: String? = null
    @Value("\${secretKey}")
    private val secretKey: String? = null
    @Value("\${region}")
    private val region: String? = null


    @Bean
    fun amazonS3Client(): AmazonS3Client{
        val awsCredentials: AWSCredentials = BasicAWSCredentials(accessKey, secretKey)
        return AmazonS3ClientBuilder.standard()
            .withRegion(region)
            .withCredentials(AWSStaticCredentialsProvider(awsCredentials))
            .build() as AmazonS3Client
    }
}

 

 

 

post 생성할 때 userprincipal 을 받아오는게 문제가 되는건지 접근을 다 열어놔도 아래와 같이 뜬다.

 

 

 

해결방법을 못찾아서 일단 이미지 업로드 메소드만 따로 빼서 userprincipal 안 받고 실행하면 정상적으로 s3 에 업로드가 된다.

.authorizeHttpRequests {
                it.requestMatchers(
                    "/swagger-ui/**", "/v3/api-docs/**", "/posts","/auth/**", "/images/**"
                ).permitAll()
                    .anyRequest().authenticated()
            }

 

게시글 업로드 할 때 이미지가 같이 업로드가 돼야 정상적인 업로드인데 어떻게 해결할 수 있을까...

 

 

 

postman 업로드 성공

@Operation(summary = "할 일 생성")
    @PostMapping(
        consumes = [MediaType.MULTIPART_FORM_DATA_VALUE]
        )
    fun createPost(@AuthenticationPrincipal userPrincipal: UserPrincipal,
                   @RequestPart(required = false) multipartFile: MultipartFile?,
                   @Valid@RequestPart postRequest: PostRequest,
    ): ResponseEntity<Any> {
        if (multipartFile == null || multipartFile.isEmpty) {
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("이미지를 넣어주세요")
        }
        val image = s3Service.imageUpload(multipartFile)
        return ResponseEntity.status(HttpStatus.CREATED).body(postService.createdPost(userPrincipal, postRequest))
    }

 

RequestPart("" => postman key

@RequestPart(required = false)

https://velog.io/@hellozin/RequestParamrequired-false-%EC%A3%BC%EC%9D%98%ED%95%A0-%EC%A0%90