코드의 디버그를 활용하여 오류나는 곳을 찾아볼 수있다. 그러나... 오늘 디버그로 찾지 못한 이슈가 발생했다... 로깅으로 에러부분을 확인하였지만 계속해서 null point가 발생하여 환경설정을 확인하고 설치된 버전을 확인하며 에러를 찾고 있었습니다. 그렇게 찾다가 관련된 코드를 구글링하며 코드를 비교하면서 발견한 에러는... () 중복으로 인한 에러였습니다.
이번 경험을 통해 디버그시 에러가 발생한 부분의 코드를 더 뜯어보고 확인하는 습관을 만들어야 겠다고 생각했습니다.
미니 프로젝트에서 이미지 파일을 업로드하여 저장하는 기능을 구현하게 되었습니다.
처음 계획은 로컬 디렉토리에 업로드된 파일을 저장하고 저장된 위치를 DB에 저장하는 방식으로 진행하였으나,
AWS S3 storage 를 발견하여 AWS S3를 사용하기로 하였습니다.
//s3 연결
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
spring:
# multipartFile 용량 늘려주는 설정
servlet:
multipart:
max-file-size: 10MB
max-request-size: 10MB
cloud:
aws:
# s3 bucket 이름 배포시 변경 필요
s3:
bucket: 버킷 이름
# user access-key, secret-key 배포시 작성 필요
credentials:
access-key: access-key
secret-key: secret-key
# s3 region
region:
static: ap-northeast-2 (설정한 지역)
auto: false
stack:
auto: false
@Configuration
public class AwsS3Config {
@Value("${cloud.aws.credentials.access-key}")
private String accessKey;
@Value(("${cloud.aws.credentials.secret-key}"))
private String secretKey;
@Value("${cloud.aws.region.static}")
private String region;
@Bean
@Primary
public BasicAWSCredentials awsCredentialsProvider(){
return new BasicAWSCredentials(accessKey, secretKey);
}
@Bean
public AmazonS3 amazonS3() {
return AmazonS3ClientBuilder.standard()
.withRegion(region)
.withCredentials(
new AWSStaticCredentialsProvider(awsCredentialsProvider())
)
.build();
}
//aws S3 접속
@Bean
public AmazonS3Client amazonS3Client() {
BasicAWSCredentials awsCredentials = new BasicAWSCredentials(accessKey, secretKey);
return (AmazonS3Client) AmazonS3ClientBuilder.standard()
.withRegion(region)
.withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
.build();
}
}
public class S3Uploader {
@Value("${cloud.aws.s3.bucket}")
private String bucket;
private final AmazonS3Client amazonS3Client;
@Value("${file.path}") // application.yml 에 설정된 외부경로, final 사용하면 안됨
private String uploadFolder;
public String S3Uploader(MultipartFile file) {
// TODO: 2022/06/13
// aws s3 적용
String imgFileName = createFileName(file);
// TODO: 2022/06/13
// aws s3 적용
ObjectMetadata objectMetadata = new ObjectMetadata();
objectMetadata.setContentLength(file.getSize());
objectMetadata.setContentType(file.getContentType());
try {
amazonS3Client.putObject(
new PutObjectRequest(bucket, imgFileName, file.getInputStream(), objectMetadata)
.withCannedAcl(CannedAccessControlList.PublicRead)); // S3 업로드
// log.info("content-type : {}, getInputStream : {}", imgFile.getFile().getContentType(), imgFile.getFile().getInputStream());
} catch (IOException e) {
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "File upload is failed.");
}
// 버킷에서 파일에 해당하는 url을 가져
return amazonS3Client.getUrl(bucket, imgFileName).toString();
}
private String createFileName(MultipartFile file) {
// 파일 이름이 1.jpg 라면 originFilename 은 1.jpg이다.
// 동일한 파일명이 업로드 된다면 덮어씌워지기 때문에 UUID_파일명으로 생성한다.
// // 파일명 생성이 어떻게 되는지 확인하기 위한 log
// log.info("imageFileName = {}", imageFileName);
return "images/" + UUID.randomUUID() + "_" + file.getOriginalFilename();
}
}
createFileName 메소드를 사용하여 파일이 저장될 경로와 파일 이름을 생성하였습니다.
ObjectMetadata 객체를 생성하여 AWS S3에 전달할 데이터를 저장하여 amazonS3Client.putObject
를 이용하여 AWS 에 전달하였습니다.