Skip to content

Commit

Permalink
Merge pull request #28 from ShwimPing/refactor/ldy/deploy
Browse files Browse the repository at this point in the history
[REFACTOR] CDN+ 적용
  • Loading branch information
leedy3838 authored Sep 21, 2024
2 parents 3743b0e + 8740f52 commit 6fee920
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ public class NCPStorageService {
@Value("${cloud.aws.s3.bucket}")
private String bucket;

@Value("${cloud.aws.cdn.domain}")
private String cdnDomain;

public String uploadFile(MultipartFile multipartFile, String path) {
// UUID를 사용하여 파일 이름 생성
String fileName = UUID.randomUUID() + "_" + Objects.requireNonNull(multipartFile.getOriginalFilename());
Expand All @@ -40,20 +43,22 @@ public String uploadFile(MultipartFile multipartFile, String path) {
amazonS3.putObject(new PutObjectRequest(bucket, fileLocation, multipartFile.getInputStream(), metadata)
.withCannedAcl(CannedAccessControlList.PublicRead));

return amazonS3.getUrl(bucket, fileLocation).toString();
return cdnDomain + "/" + fileLocation;
} catch (IOException e) {
throw new FileConvertFailException(GlobalErrorCode.FILE_CONVERT_FAIL);
}
}

public void deleteFile(String fileUrl) {
// URL에서 파일 이름 추출
String fileName = fileUrl.substring(fileUrl.indexOf(bucket) + bucket.length() + 1);
String fileName = fileUrl.substring(cdnDomain.length() + 1);

log.info("fileName: {}", fileName);

try {
amazonS3.deleteObject(new DeleteObjectRequest(bucket, fileName));
} catch (Exception e) {
log.error("파일 삭제 실패: {}", e.getMessage());
// 필요 시 적절한 예외 처리 추가
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,34 +9,57 @@
import com.shwimping.be.global.exception.response.ErrorResponse.ValidationError;
import com.shwimping.be.global.exception.response.ErrorResponse.ValidationErrors;
import com.shwimping.be.place.exception.PlaceNotFoundException;
import com.shwimping.be.review.exception.CanNotDeleteReviewException;
import com.shwimping.be.review.exception.ReviewNotFoundException;
import jakarta.servlet.http.HttpServletRequest;
import java.util.List;

import com.shwimping.be.user.exception.InvalidEmailException;
import com.shwimping.be.user.exception.InvalidPasswordException;
import com.shwimping.be.user.exception.UserNotFoundException;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.ResponseEntity;
import org.springframework.lang.NonNull;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

private static final Logger log = LoggerFactory.getLogger("ErrorLogger");
private static final String LOG_FORMAT_INFO = "\n[🔵INFO] - ({} {})\n(id: {}, role: {})\n{}\n {}: {}";
private static final String LOG_FORMAT_ERROR = "\n[🔴ERROR] - ({} {})\n(id: {}, role: {})";

@ExceptionHandler(PlaceNotFoundException.class)
public ResponseEntity<Object> handlePlaceNotFound(PlaceNotFoundException e) {
public ResponseEntity<Object> handlePlaceNotFound(PlaceNotFoundException e, HttpServletRequest request) {
logInfo(e.getErrorCode(), e, request);
return handleExceptionInternal(e.getErrorCode());
}

@ExceptionHandler(CanNotDeleteReviewException.class)
public ResponseEntity<Object> handleCanNotDeleteReview(CanNotDeleteReviewException e, HttpServletRequest request) {
logInfo(e.getErrorCode(), e, request);
return handleExceptionInternal(e.getErrorCode());
}

@ExceptionHandler(ReviewNotFoundException.class)
public ResponseEntity<Object> handleReviewNotFound(ReviewNotFoundException e, HttpServletRequest request) {
logInfo(e.getErrorCode(), e, request);
return handleExceptionInternal(e.getErrorCode());
}

@ExceptionHandler(FileConvertFailException.class)
public ResponseEntity<Object> handleFileConvertFail(FileConvertFailException e) {
public ResponseEntity<Object> handleFileConvertFail(FileConvertFailException e, HttpServletRequest request) {
logInfo(e.getErrorCode(), e, request);
return handleExceptionInternal(e.getErrorCode());
}

Expand All @@ -53,12 +76,14 @@ public ResponseEntity<Object> handleMethodArgumentNotValid(
}

@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<Object> handleIllegalArgument() {
public ResponseEntity<Object> handleIllegalArgument(IllegalArgumentException e, HttpServletRequest request) {
logInfo(GlobalErrorCode.INVALID_PARAMETER, e, request);
return handleExceptionInternal(GlobalErrorCode.INVALID_PARAMETER);
}

@ExceptionHandler(Exception.class)
public ResponseEntity<Object> handleAllException() {
public ResponseEntity<Object> handleAllException(Exception e, HttpServletRequest request) {
logError(e, request);
return handleExceptionInternal(GlobalErrorCode.INTERNAL_SERVER_ERROR);
}

Expand Down Expand Up @@ -121,4 +146,33 @@ private ErrorResponse makeErrorResponse(BindException e) {
.results(new ValidationErrors(validationErrorList))
.build();
}

private void logInfo(ErrorCode ec, Exception e, HttpServletRequest request) {
log.info(LOG_FORMAT_INFO, request.getMethod(), request.getRequestURI(), getUserId(),
getRole(), ec.getHttpStatus(), e.getClass().getName(), e.getMessage());
}

private void logError(Exception e, HttpServletRequest request) {
log.error(LOG_FORMAT_ERROR, request.getMethod(), request.getRequestURI(), getUserId(), getRole(), e);
}

private String getUserId() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

if (authentication != null && authentication.isAuthenticated()) {
return authentication.getName(); // 사용자의 id
} else {
return "anonymous";
}
}

private String getRole() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

if (authentication != null && authentication.isAuthenticated()) {
return authentication.getAuthorities().toString(); // 사용자의 role
} else {
return "anonymous";
}
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package com.shwimping.be.review.application;

import com.amazonaws.util.StringUtils;
import com.shwimping.be.global.application.NCPStorageService;
import com.shwimping.be.place.application.PlaceService;
import com.shwimping.be.place.domain.Place;
import com.shwimping.be.review.dto.request.ReviewUploadRequest;
import com.shwimping.be.review.dto.response.ReviewSimpleResponse;
import com.shwimping.be.review.dto.response.ReviewSimpleResponseList;
import com.shwimping.be.review.exception.CanNotDeleteReviewException;
import com.shwimping.be.review.exception.ReviewNotFoundException;
import com.shwimping.be.review.exception.errorcode.ReviewErrorCode;
import com.shwimping.be.review.repository.ReviewRepository;
import com.shwimping.be.user.application.UserService;
import com.shwimping.be.user.domain.User;
Expand Down Expand Up @@ -50,4 +54,24 @@ public void uploadReview(Long userId, ReviewUploadRequest reviewUploadRequest, M

reviewRepository.save(reviewUploadRequest.toEntity(place, user, imageUrl));
}

@Transactional
public void deleteReview(Long userId, Long reviewId) {
reviewRepository.findById(reviewId)
.ifPresentOrElse(
review -> {
if (review.getUser().getId().equals(userId)) {
if (StringUtils.hasValue(review.getReviewImageUrl())) {
ncpStorageService.deleteFile(review.getReviewImageUrl());
}
reviewRepository.delete(review);
} else {
throw new CanNotDeleteReviewException(ReviewErrorCode.CANNOT_DELETE_REVIEW);
}
},
() -> {
throw new ReviewNotFoundException(ReviewErrorCode.REVIEW_NOT_FOUND);
}
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.shwimping.be.review.exception;

import com.shwimping.be.global.exception.errorcode.ErrorCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public class CanNotDeleteReviewException extends RuntimeException {
private final ErrorCode errorCode;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.shwimping.be.review.exception;

import com.shwimping.be.global.exception.errorcode.ErrorCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public class ReviewNotFoundException extends RuntimeException {
private final ErrorCode errorCode;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.shwimping.be.review.exception.errorcode;

import com.shwimping.be.global.exception.errorcode.ErrorCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;

@Getter
@RequiredArgsConstructor
public enum ReviewErrorCode implements ErrorCode {

REVIEW_NOT_FOUND(HttpStatus.NOT_FOUND, "Review not found"),
CANNOT_DELETE_REVIEW(HttpStatus.FORBIDDEN, "Author of the review can only delete the review"),
;

private final HttpStatus httpStatus;
private final String message;
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
Expand Down Expand Up @@ -62,4 +63,18 @@ public ResponseEntity<ResponseTemplate<?>> uploadReview(
.status(HttpStatus.OK)
.body(ResponseTemplate.EMPTY_RESPONSE);
}

// 리뷰 삭제
@Operation(summary = "리뷰 삭제", description = "리뷰 삭제, 본인의 리뷰만 삭제 가능")
@DeleteMapping("/{reviewId}")
public ResponseEntity<ResponseTemplate<?>> deleteReview(
@AuthenticationPrincipal Long userId,
@PathVariable Long reviewId) {

reviewService.deleteReview(userId, reviewId);

return ResponseEntity
.status(HttpStatus.OK)
.body(ResponseTemplate.EMPTY_RESPONSE);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,30 @@


import com.shwimping.be.global.util.DummyDataInit;
import com.shwimping.be.global.util.NCPProperties;
import com.shwimping.be.user.domain.User;
import com.shwimping.be.user.domain.type.Provider;
import com.shwimping.be.user.repository.UserRepository;
import java.util.ArrayList;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.security.crypto.password.PasswordEncoder;

import java.util.ArrayList;
import java.util.List;

@Slf4j
@RequiredArgsConstructor
@Order(1)
@DummyDataInit
public class UserInitializer implements ApplicationRunner {

@Value("${cloud.aws.cdn.domain}")
private String defaultProfileImageUrl;

private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
private final NCPProperties ncpProperties;

private static final String DUMMY_PROFILE_IMAGE_URL = "/profile/ic_profile.svg";

Expand All @@ -39,7 +40,7 @@ public void run(ApplicationArguments args) {
.nickname("관리자")
.fcmToken("fcmToken")
.isAlarmAllowed(true)
.profileImageUrl(ncpProperties.s3().endpoint() + ncpProperties.s3().bucket() + DUMMY_PROFILE_IMAGE_URL)
.profileImageUrl(defaultProfileImageUrl + DUMMY_PROFILE_IMAGE_URL)
.email("[email protected]")
.password(passwordEncoder.encode("adminPassword"))
.provider(Provider.SELF)
Expand All @@ -50,7 +51,7 @@ public void run(ApplicationArguments args) {
.nickname("user1")
.fcmToken("fcmToken")
.isAlarmAllowed(true)
.profileImageUrl(ncpProperties.s3().endpoint() + ncpProperties.s3().bucket() + DUMMY_PROFILE_IMAGE_URL)
.profileImageUrl(defaultProfileImageUrl + DUMMY_PROFILE_IMAGE_URL)
.email("[email protected]")
.password(passwordEncoder.encode("user1Password"))
.provider(Provider.SELF)
Expand All @@ -61,7 +62,7 @@ public void run(ApplicationArguments args) {
.nickname("user2")
.fcmToken("fcmToken")
.isAlarmAllowed(true)
.profileImageUrl(ncpProperties.s3().endpoint() + ncpProperties.s3().bucket() + DUMMY_PROFILE_IMAGE_URL)
.profileImageUrl(defaultProfileImageUrl + DUMMY_PROFILE_IMAGE_URL)
.email("[email protected]")
.password(passwordEncoder.encode("user2Password"))
.provider(Provider.SELF)
Expand Down

0 comments on commit 6fee920

Please sign in to comment.