1111import javax .imageio .ImageIO ;
1212import lombok .RequiredArgsConstructor ;
1313import net .coobird .thumbnailator .Thumbnails ;
14- import org .springframework .beans .factory .annotation .Value ;
1514import org .springframework .stereotype .Service ;
1615import org .springframework .web .multipart .MultipartFile ;
1716import software .amazon .awssdk .core .sync .RequestBody ;
1817import software .amazon .awssdk .services .s3 .S3Client ;
1918import software .amazon .awssdk .services .s3 .model .ObjectCannedACL ;
2019import software .amazon .awssdk .services .s3 .model .PutObjectRequest ;
20+ import team .wego .wegobackend .image .config .AwsS3Properties ;
21+ import team .wego .wegobackend .image .config .ImageProperties ;
2122import team .wego .wegobackend .image .domain .ImageFile ;
23+ import team .wego .wegobackend .image .domain .ImageSize ;
2224import team .wego .wegobackend .image .domain .exception .ImageException ;
2325import 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 )
0 commit comments