-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[feat] 사용자 프로필 관련 API 생성 (S3 Multipart 관련) (#26)
* [chore] #23 add required dependency in build.gradle * [feat] #23 s3 related setting * [feat] #23 create exception and add exception in globalExceptionHandler * [feat] #23 create user logic * [chore] #23 delete unnecessary file (UserInfoService)
- Loading branch information
Showing
17 changed files
with
398 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package org.kkumulkkum.server.config; | ||
|
||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import software.amazon.awssdk.auth.credentials.SystemPropertyCredentialsProvider; | ||
import software.amazon.awssdk.regions.Region; | ||
import software.amazon.awssdk.services.s3.S3Client; | ||
|
||
@Configuration | ||
public class AwsConfig { | ||
|
||
private static final String AWS_ACCESS_KEY_ID = "aws.accessKeyId"; | ||
private static final String AWS_SECRET_ACCESS_KEY = "aws.secretAccessKey"; | ||
|
||
private final String accessKey; | ||
private final String secretKey; | ||
private final String regionString; | ||
|
||
public AwsConfig(@Value("${aws-property.access-key}") final String accessKey, | ||
@Value("${aws-property.secret-key}") final String secretKey, | ||
@Value("${aws-property.aws-region}") final String regionString) { | ||
this.accessKey = accessKey; | ||
this.secretKey = secretKey; | ||
this.regionString = regionString; | ||
} | ||
|
||
@Bean | ||
public SystemPropertyCredentialsProvider systemPropertyCredentialsProvider() { | ||
System.setProperty(AWS_ACCESS_KEY_ID, accessKey); | ||
System.setProperty(AWS_SECRET_ACCESS_KEY, secretKey); | ||
return SystemPropertyCredentialsProvider.create(); | ||
} | ||
|
||
@Bean | ||
public Region getRegion() { | ||
return Region.of(regionString); | ||
} | ||
|
||
@Bean | ||
public S3Client getS3Client() { | ||
return S3Client.builder() | ||
.region(getRegion()) | ||
.credentialsProvider(systemPropertyCredentialsProvider()) | ||
.build(); | ||
} | ||
} |
51 changes: 51 additions & 0 deletions
51
src/main/java/org/kkumulkkum/server/controller/UserController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package org.kkumulkkum.server.controller; | ||
|
||
import jakarta.validation.Valid; | ||
import lombok.RequiredArgsConstructor; | ||
import org.kkumulkkum.server.annotation.UserId; | ||
import org.kkumulkkum.server.dto.user.request.ImageUpdateDto; | ||
import org.kkumulkkum.server.dto.user.response.UserDto; | ||
import org.kkumulkkum.server.dto.user.response.UserNameDto; | ||
import org.kkumulkkum.server.service.user.UserService; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.*; | ||
|
||
@RestController | ||
@RequiredArgsConstructor | ||
@RequestMapping("/api/v1") | ||
public class UserController { | ||
|
||
private final UserService userService; | ||
|
||
@PatchMapping("/users/me/image") | ||
public ResponseEntity<Void> updateImage( | ||
@UserId final Long userId, | ||
@Valid @ModelAttribute final ImageUpdateDto imageUpdateDto | ||
) { | ||
userService.updateImage(userId, imageUpdateDto); | ||
return ResponseEntity.ok().build(); | ||
} | ||
|
||
@DeleteMapping("/users/me/image") | ||
public ResponseEntity<Void> deleteImage( | ||
@UserId final Long userId | ||
) { | ||
userService.deleteImage(userId); | ||
return ResponseEntity.ok().build(); | ||
} | ||
|
||
@PatchMapping("/users/me/name") | ||
public ResponseEntity<UserNameDto> updateName( | ||
@UserId final Long userId, | ||
@Valid @RequestBody final UserNameDto userNameDto | ||
) { | ||
return ResponseEntity.ok().body(userService.updateName(userId, userNameDto)); | ||
} | ||
|
||
@GetMapping("/users/me") | ||
public ResponseEntity<UserDto> getUserInfo( | ||
@UserId final Long userId | ||
) { | ||
return ResponseEntity.ok().body(userService.getUserInfo(userId)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 10 additions & 0 deletions
10
src/main/java/org/kkumulkkum/server/dto/user/request/ImageUpdateDto.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package org.kkumulkkum.server.dto.user.request; | ||
|
||
import jakarta.validation.constraints.NotNull; | ||
import org.springframework.web.multipart.MultipartFile; | ||
|
||
public record ImageUpdateDto( | ||
@NotNull | ||
MultipartFile image | ||
) { | ||
} |
10 changes: 10 additions & 0 deletions
10
src/main/java/org/kkumulkkum/server/dto/user/request/NameUpdateDto.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package org.kkumulkkum.server.dto.user.request; | ||
|
||
import jakarta.validation.constraints.NotBlank; | ||
import jakarta.validation.constraints.Size; | ||
|
||
public record NameUpdateDto( | ||
@NotBlank @Size(max = 5) | ||
String name | ||
) { | ||
} |
23 changes: 23 additions & 0 deletions
23
src/main/java/org/kkumulkkum/server/dto/user/response/UserDto.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package org.kkumulkkum.server.dto.user.response; | ||
|
||
import org.kkumulkkum.server.domain.UserInfo; | ||
|
||
public record UserDto( | ||
String name, | ||
int level, | ||
int promiseCount, | ||
int tardyCount, | ||
Long tardySum, | ||
String profileImg | ||
) { | ||
public static UserDto from(UserInfo userInfo) { | ||
return new UserDto( | ||
userInfo.getName(), | ||
userInfo.getLevel(), | ||
userInfo.getPromiseCount(), | ||
userInfo.getTardyCount(), | ||
userInfo.getTardySum(), | ||
userInfo.getProfileImg() | ||
); | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
src/main/java/org/kkumulkkum/server/dto/user/response/UserNameDto.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package org.kkumulkkum.server.dto.user.response; | ||
|
||
import org.kkumulkkum.server.domain.UserInfo; | ||
|
||
public record UserNameDto( | ||
String name | ||
) { | ||
public static UserNameDto from(UserInfo userInfo) { | ||
return new UserNameDto(userInfo.getName()); | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
src/main/java/org/kkumulkkum/server/exception/AwsException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package org.kkumulkkum.server.exception; | ||
|
||
import lombok.Getter; | ||
import lombok.RequiredArgsConstructor; | ||
import org.kkumulkkum.server.exception.code.AwsErrorCode; | ||
|
||
@Getter | ||
@RequiredArgsConstructor | ||
public class AwsException extends RuntimeException { | ||
private final AwsErrorCode errorCode; | ||
} |
21 changes: 21 additions & 0 deletions
21
src/main/java/org/kkumulkkum/server/exception/code/AwsErrorCode.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package org.kkumulkkum.server.exception.code; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
import org.springframework.http.HttpStatus; | ||
|
||
@Getter | ||
@AllArgsConstructor | ||
public enum AwsErrorCode implements DefaultErrorCode { | ||
// 400 Bad Request | ||
INVALID_IMAGE_EXTENSION(HttpStatus.BAD_REQUEST, 40080, "이미지 확장자는 jpg, png, webp만 가능합니다."), | ||
IMAGE_SIZE_EXCEEDED(HttpStatus.BAD_REQUEST,40081, "이미지 사이즈는 5MB를 넘을 수 없습니다."), | ||
|
||
// 404 Not Found | ||
NOT_FOUND_IMAGE(HttpStatus.NOT_FOUND, 40480, "삭제할 이미지를 찾을 수 없습니다."), | ||
; | ||
|
||
private HttpStatus httpStatus; | ||
private int code; | ||
private String message; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
83 changes: 83 additions & 0 deletions
83
src/main/java/org/kkumulkkum/server/external/S3Service.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package org.kkumulkkum.server.external; | ||
|
||
import org.kkumulkkum.server.config.AwsConfig; | ||
import org.kkumulkkum.server.exception.AwsException; | ||
import org.kkumulkkum.server.exception.code.AwsErrorCode; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.stereotype.Component; | ||
import org.springframework.web.multipart.MultipartFile; | ||
import software.amazon.awssdk.core.sync.RequestBody; | ||
import software.amazon.awssdk.services.s3.S3Client; | ||
import software.amazon.awssdk.services.s3.model.DeleteObjectRequest; | ||
import software.amazon.awssdk.services.s3.model.PutObjectRequest; | ||
|
||
import java.io.IOException; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
import java.util.UUID; | ||
|
||
@Component | ||
public class S3Service { | ||
|
||
private final String bucketName; | ||
private final AwsConfig awsConfig; | ||
private static final List<String> IMAGE_EXTENSIONS = Arrays.asList("image/jpeg", "image/png", "image/jpg", "image/webp"); | ||
|
||
public S3Service(@Value("${aws-property.s3-bucket-name}") final String bucketName, AwsConfig awsConfig) { | ||
this.bucketName = bucketName; | ||
this.awsConfig = awsConfig; | ||
} | ||
|
||
public String uploadImage(String directoryPath, MultipartFile image) throws IOException { | ||
final String extension = getFileExtension(image.getOriginalFilename()); | ||
final String key = directoryPath + generateImageFileName(extension); | ||
final S3Client s3Client = awsConfig.getS3Client(); | ||
|
||
validateExtension(image); | ||
validateFileSize(image); | ||
|
||
PutObjectRequest request = PutObjectRequest.builder() | ||
.bucket(bucketName) | ||
.key(key) | ||
.contentType(image.getContentType()) | ||
.contentDisposition("inline") | ||
.build(); | ||
|
||
RequestBody requestBody = RequestBody.fromBytes(image.getBytes()); | ||
s3Client.putObject(request, requestBody); | ||
return key; | ||
} | ||
|
||
public void deleteImage(String key) throws IOException { | ||
final S3Client s3Client = awsConfig.getS3Client(); | ||
|
||
s3Client.deleteObject((DeleteObjectRequest.Builder builder) -> | ||
builder.bucket(bucketName) | ||
.key(key) | ||
.build() | ||
); | ||
} | ||
|
||
private String getFileExtension(String fileName) { | ||
return fileName.substring(fileName.lastIndexOf(".") + 1); | ||
} | ||
|
||
private String generateImageFileName(String extension) { | ||
return UUID.randomUUID() + "." + extension; | ||
} | ||
|
||
private void validateExtension(MultipartFile image) { | ||
String contentType = image.getContentType(); | ||
if (!IMAGE_EXTENSIONS.contains(contentType)) { | ||
throw new AwsException(AwsErrorCode.INVALID_IMAGE_EXTENSION); | ||
} | ||
} | ||
|
||
private static final Long MAX_FILE_SIZE = 5 * 1024 * 1024L; | ||
|
||
private void validateFileSize(MultipartFile image) { | ||
if (image.getSize() > MAX_FILE_SIZE) { | ||
throw new AwsException(AwsErrorCode.IMAGE_SIZE_EXCEEDED); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.