Skip to content

Commit 3b6baef

Browse files
authored
[FEAT] 이미지 기능 재수정
[FEAT] 이미지 기능 재수정
2 parents 5a113f5 + eb922b2 commit 3b6baef

File tree

7 files changed

+172
-164
lines changed

7 files changed

+172
-164
lines changed

src/main/java/team/wego/wegobackend/common/response/ApiResponse.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ public record ApiResponse<T>(
99
) {
1010

1111
public static <T> ApiResponse<T> success(T data) {
12-
return new ApiResponse<>(Boolean.TRUE, data);
12+
return new ApiResponse<>(true, data);
1313
}
1414

1515
public static <T> ApiResponse<T> success(boolean isSuccess, T data) {
1616
return new ApiResponse<>(isSuccess, data);
1717
}
1818

1919
public static <T> ApiResponse<T> success(String message) {
20-
return new ApiResponse<>(Boolean.TRUE, null);
20+
return new ApiResponse<>(true, null);
2121
}
2222

2323
public static <T> ApiResponse<T> error(String message) {

src/main/java/team/wego/wegobackend/image/application/service/ImageUploadService.java

Lines changed: 61 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,16 @@
1111
import javax.imageio.ImageIO;
1212
import lombok.RequiredArgsConstructor;
1313
import net.coobird.thumbnailator.Thumbnails;
14-
import org.springframework.beans.factory.annotation.Value;
1514
import org.springframework.stereotype.Service;
1615
import org.springframework.web.multipart.MultipartFile;
1716
import software.amazon.awssdk.core.sync.RequestBody;
1817
import software.amazon.awssdk.services.s3.S3Client;
1918
import software.amazon.awssdk.services.s3.model.ObjectCannedACL;
2019
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
20+
import team.wego.wegobackend.image.config.AwsS3Properties;
21+
import team.wego.wegobackend.image.config.ImageProperties;
2122
import team.wego.wegobackend.image.domain.ImageFile;
23+
import team.wego.wegobackend.image.domain.ImageSize;
2224
import team.wego.wegobackend.image.domain.exception.ImageException;
2325
import team.wego.wegobackend.image.domain.exception.ImageExceptionCode;
2426

@@ -40,27 +42,8 @@ public class ImageUploadService {
4042
);
4143

4244
private final S3Client s3Client;
43-
44-
@Value("${aws.s3.bucket}")
45-
private String bucket;
46-
47-
@Value("${aws.s3.public-endpoint}")
48-
private String publicEndpoint;
49-
50-
@Value("${image.max-size-bytes}")
51-
private long maxSizeBytes;
52-
53-
@Value("${image.max-width}")
54-
private int maxWidth;
55-
56-
@Value("${image.max-height}")
57-
private int maxHeight;
58-
59-
@Value("${image.thumb-max-width}")
60-
private int thumbMaxWidth;
61-
62-
@Value("${image.thumb-max-height}")
63-
private int thumbMaxHeight;
45+
private final AwsS3Properties awsS3Properties;
46+
private final ImageProperties imageProperties;
6447

6548
public ImageFile uploadOriginal(String dir, MultipartFile file, int index) {
6649
validateDir(dir);
@@ -74,7 +57,7 @@ public ImageFile uploadOriginal(String dir, MultipartFile file, int index) {
7457
byte[] bytes = resizeIfNeededKeepFormat(file);
7558

7659
putToS3(key, bytes, file.getContentType());
77-
String url = publicEndpoint + "/" + key;
60+
String url = awsS3Properties.getPublicEndpoint() + "/" + key;
7861

7962
return new ImageFile(key, url);
8063
}
@@ -88,51 +71,60 @@ public List<ImageFile> uploadAllOriginal(String dir, List<MultipartFile> files)
8871
return result;
8972
}
9073

91-
public ImageFile uploadAsWebp(String dir, MultipartFile file, int index) {
74+
public ImageFile uploadAsWebpWithSize(
75+
String dir,
76+
MultipartFile file,
77+
int index,
78+
ImageSize size
79+
) {
9280
validateDir(dir);
9381
validateImageSize(file);
9482
validateImageContentType(file);
9583
validateExtension(file.getOriginalFilename());
9684

9785
String baseName = buildBaseName(index);
98-
String key = dir + "/" + baseName + ".webp";
86+
String key = dir + "/" + baseName + "_" + size.width() + "x" + size.height() + ".webp";
9987

100-
byte[] bytes = convertToWebp(file);
88+
byte[] bytes = convertToWebpWithSize(file, size);
10189

10290
putToS3(key, bytes, "image/webp");
103-
String url = publicEndpoint + "/" + key;
91+
String url = awsS3Properties.getPublicEndpoint() + "/" + key;
10492

10593
return new ImageFile(key, url);
10694
}
10795

108-
public List<ImageFile> uploadAllAsWebp(String dir, List<MultipartFile> files) {
109-
List<ImageFile> result = new ArrayList<>();
110-
for (int i = 0; i < files.size(); i++) {
111-
MultipartFile file = files.get(i);
112-
result.add(uploadAsWebp(dir, file, i));
113-
}
114-
return result;
115-
}
116-
117-
public ImageFile uploadThumb(String dir, MultipartFile file, int index) {
96+
public List<ImageFile> uploadAsWebpWithSizes(
97+
String dir,
98+
MultipartFile file,
99+
int index,
100+
List<ImageSize> sizes
101+
) {
118102
validateDir(dir);
119103
validateImageSize(file);
120104
validateImageContentType(file);
121105
validateExtension(file.getOriginalFilename());
122106

123-
String originalFilename = file.getOriginalFilename();
124-
String key = buildKey(dir, originalFilename, index);
107+
String baseName = buildBaseName(index);
108+
List<ImageFile> result = new ArrayList<>();
125109

126-
byte[] bytes = resizeToThumb(file);
110+
for (ImageSize size : sizes) {
111+
String key = dir + "/" + baseName + "_" + size.width() + "x" + size.height() + ".webp";
112+
byte[] bytes = convertToWebpWithSize(file, size);
127113

128-
putToS3(key, bytes, file.getContentType());
129-
String url = publicEndpoint + "/" + key;
114+
putToS3(key, bytes, "image/webp");
115+
String url = awsS3Properties.getPublicEndpoint() + "/" + key;
130116

131-
return new ImageFile(key, url);
117+
result.add(new ImageFile(key, url));
118+
}
119+
120+
return result;
132121
}
133122

134123
public void delete(String key) {
135-
s3Client.deleteObject(builder -> builder.bucket(bucket).key(key));
124+
s3Client.deleteObject(builder -> builder
125+
.bucket(awsS3Properties.getBucket())
126+
.key(key)
127+
);
136128
}
137129

138130
public void deleteAll(List<String> keys) {
@@ -141,7 +133,25 @@ public void deleteAll(List<String> keys) {
141133
}
142134
}
143135

136+
private byte[] convertToWebpWithSize(MultipartFile file, ImageSize size) {
137+
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
138+
Thumbnails.of(file.getInputStream())
139+
.size(size.width(), size.height())
140+
.outputFormat("webp")
141+
.toOutputStream(byteArrayOutputStream);
142+
143+
if (byteArrayOutputStream.size() == 0) {
144+
throw new ImageException(ImageExceptionCode.WEBP_CONVERT_FAILED);
145+
}
146+
147+
return byteArrayOutputStream.toByteArray();
148+
} catch (IOException e) {
149+
throw new ImageException(ImageExceptionCode.IMAGE_IO_ERROR, e, "WebP 변환");
150+
}
151+
}
152+
144153
private void validateImageSize(MultipartFile file) {
154+
long maxSizeBytes = imageProperties.getMaxSizeBytes();
145155
if (file.getSize() > maxSizeBytes) {
146156
throw new ImageException(ImageExceptionCode.INVALID_IMAGE_SIZE, maxSizeBytes);
147157
}
@@ -212,29 +222,13 @@ private String buildBaseName(int index) {
212222
return timestamp + "_" + index + "_" + uuid;
213223
}
214224

215-
private byte[] convertToWebp(MultipartFile file) {
216-
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
217-
Thumbnails.of(file.getInputStream())
218-
.size(maxWidth, maxHeight)
219-
.outputFormat("webp")
220-
.toOutputStream(byteArrayOutputStream);
221-
222-
if (byteArrayOutputStream.size() == 0) {
223-
throw new ImageException(ImageExceptionCode.WEBP_CONVERT_FAILED);
224-
}
225-
226-
return byteArrayOutputStream.toByteArray();
227-
} catch (IOException e) {
228-
throw new ImageException(ImageExceptionCode.IMAGE_IO_ERROR, e, "WebP 변환");
229-
}
230-
}
231-
232225
private byte[] resizeIfNeededKeepFormat(MultipartFile file) {
233-
return resizeToBox(file, maxWidth, maxHeight, "이미지 리사이즈");
234-
}
235-
236-
private byte[] resizeToThumb(MultipartFile file) {
237-
return resizeToBox(file, thumbMaxWidth, thumbMaxHeight, "썸네일 생성");
226+
return resizeToBox(
227+
file,
228+
imageProperties.getMaxWidth(),
229+
imageProperties.getMaxHeight(),
230+
"이미지 리사이즈"
231+
);
238232
}
239233

240234
private byte[] resizeToBox(
@@ -297,7 +291,7 @@ private String getFormatName(String originalFilename) {
297291

298292
private void putToS3(String key, byte[] bytes, String contentType) {
299293
PutObjectRequest putObjectRequest = PutObjectRequest.builder()
300-
.bucket(bucket)
294+
.bucket(awsS3Properties.getBucket())
301295
.key(key)
302296
.contentType(contentType)
303297
.acl(ObjectCannedACL.PUBLIC_READ)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package team.wego.wegobackend.image.config;
2+
3+
import lombok.Data;
4+
import org.springframework.boot.context.properties.ConfigurationProperties;
5+
import org.springframework.stereotype.Component;
6+
7+
@Data
8+
@Component
9+
@ConfigurationProperties(prefix = "aws.s3")
10+
public class AwsS3Properties {
11+
12+
private String bucket;
13+
14+
private String publicEndpoint;
15+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package team.wego.wegobackend.image.config;
2+
3+
import lombok.Data;
4+
import org.springframework.boot.context.properties.ConfigurationProperties;
5+
import org.springframework.stereotype.Component;
6+
7+
@Data
8+
@Component
9+
@ConfigurationProperties(prefix = "image")
10+
public class ImageProperties {
11+
12+
private long maxSizeBytes;
13+
private int maxWidth;
14+
private int maxHeight;
15+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package team.wego.wegobackend.image.domain;
2+
3+
public record ImageSize(int width, int height) {
4+
}

0 commit comments

Comments
 (0)