From fe99d2a8d7620d3051bc3000d965707e63e5c298 Mon Sep 17 00:00:00 2001 From: Jangan Lee Date: Mon, 11 Nov 2024 01:44:07 +0900 Subject: [PATCH] =?UTF-8?q?[Weekly/11/Refactor/ExtractRestClient]=20RestCl?= =?UTF-8?q?ientUtil=20=EC=9D=B4=EC=9A=A9,=20=EB=A1=9C=EC=A7=81=20=EC=B6=94?= =?UTF-8?q?=EC=B6=9C=20(#108)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Image/api/dto/ImageResponse.java | 4 +- .../Image/application/ImageService.java | 4 +- .../application/ImageStorageService.java | 23 +++--- .../_common/util/RestClientUtil.java | 24 ++++-- .../oauth/GoogleRequestService.java | 72 ++++++++++------- .../oauth/KakaoRequestService.java | 78 +++++++++++-------- .../wouldyouin/member/persist/BaseMember.java | 2 +- .../payment/application/PaymentService.java | 16 ++-- 8 files changed, 132 insertions(+), 91 deletions(-) diff --git a/src/main/java/org/ktc2/cokaen/wouldyouin/Image/api/dto/ImageResponse.java b/src/main/java/org/ktc2/cokaen/wouldyouin/Image/api/dto/ImageResponse.java index 70e789e8..3ecdd1dc 100644 --- a/src/main/java/org/ktc2/cokaen/wouldyouin/Image/api/dto/ImageResponse.java +++ b/src/main/java/org/ktc2/cokaen/wouldyouin/Image/api/dto/ImageResponse.java @@ -1,5 +1,6 @@ package org.ktc2.cokaen.wouldyouin.Image.api.dto; +import java.nio.file.Paths; import java.time.LocalDateTime; import lombok.Builder; import lombok.Getter; @@ -15,11 +16,10 @@ public class ImageResponse { private String extension; private LocalDateTime createdDate; - public static ImageResponse from(Image image, String apiUrlHeader) { return ImageResponse.builder() .id(image.getId()) - .url(apiUrlHeader + "/" + image.getUrl()) + .url(Paths.get(apiUrlHeader, image.getUrl()).toString()) .size(image.getSize()) .extension(image.getExtension()) .createdDate(image.getCreatedDate()) diff --git a/src/main/java/org/ktc2/cokaen/wouldyouin/Image/application/ImageService.java b/src/main/java/org/ktc2/cokaen/wouldyouin/Image/application/ImageService.java index b7afb8ff..435d156c 100644 --- a/src/main/java/org/ktc2/cokaen/wouldyouin/Image/application/ImageService.java +++ b/src/main/java/org/ktc2/cokaen/wouldyouin/Image/application/ImageService.java @@ -22,7 +22,7 @@ public abstract class ImageService { protected ImageStorageService imageStorageService; @Value("${image.api-url}") - private String domainName; + private String apiUrl; protected abstract ImageRepository getImageRepository(); @@ -38,7 +38,7 @@ public T getById(Long id) { } protected ImageResponse create(ImageRequest imageRequest) { - return ImageResponse.from(getImageRepository().save(toEntity(imageRequest)), domainName); + return ImageResponse.from(getImageRepository().save(toEntity(imageRequest)), apiUrl); } protected void delete(Long id) { diff --git a/src/main/java/org/ktc2/cokaen/wouldyouin/Image/application/ImageStorageService.java b/src/main/java/org/ktc2/cokaen/wouldyouin/Image/application/ImageStorageService.java index 8ec82554..80b59bbb 100644 --- a/src/main/java/org/ktc2/cokaen/wouldyouin/Image/application/ImageStorageService.java +++ b/src/main/java/org/ktc2/cokaen/wouldyouin/Image/application/ImageStorageService.java @@ -2,13 +2,14 @@ import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Optional; import lombok.RequiredArgsConstructor; import org.ktc2.cokaen.wouldyouin.Image.api.dto.ImageRequest; import org.ktc2.cokaen.wouldyouin._common.exception.FailedToUploadImageException; import org.ktc2.cokaen.wouldyouin._common.util.FileUtil; import org.ktc2.cokaen.wouldyouin._common.util.RestClientUtil; import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.ResponseEntity; +import org.springframework.http.HttpHeaders; import org.springframework.stereotype.Component; import org.springframework.web.multipart.MultipartFile; @@ -34,19 +35,17 @@ public ImageRequest saveToDirectory(MultipartFile image, String subPath) { } public ImageRequest saveToDirectory(String imageUrl, String subPath) { - ResponseEntity response = client.get(imageUrl, byte[].class); - if (response.getBody() == null) { - throw new FailedToUploadImageException("응답 본문이 비어있어 이미지를 가져올 수 없습니다."); - } - if (!response.getStatusCode().is2xxSuccessful()) { - throw new FailedToUploadImageException("이미지 URL에 대한 요청을 실패하였습니다."); - } + byte[] response = client.get(byte[].class, imageUrl, new HttpHeaders(), + (req, rsp) -> { throw new FailedToUploadImageException("이미지 URL에 대한 요청을 실패하였습니다."); } + ); + Optional.ofNullable(response).orElseThrow( + () -> new FailedToUploadImageException("응답 본문이 비어있어 이미지를 가져올 수 없습니다.")); String extension = FileUtil.getExtension(imageUrl); String fileName = FileUtil.generateUuidName() + "." + extension; - Path path = Paths.get(parentPath, subPath, fileName); - FileUtil.saveFile(response.getBody(), path); - long size = response.getBody().length; - return ImageRequest.of(path.toString(), size, extension); + String relativeFilePath = Paths.get(subPath, fileName).toString(); + Path absoluteFilePath = Paths.get(parentPath, relativeFilePath); + FileUtil.saveFile(response, absoluteFilePath); + return ImageRequest.of(relativeFilePath, (long) response.length, extension); } public void delete(String imagePath) { diff --git a/src/main/java/org/ktc2/cokaen/wouldyouin/_common/util/RestClientUtil.java b/src/main/java/org/ktc2/cokaen/wouldyouin/_common/util/RestClientUtil.java index 464d4200..a1a1e533 100644 --- a/src/main/java/org/ktc2/cokaen/wouldyouin/_common/util/RestClientUtil.java +++ b/src/main/java/org/ktc2/cokaen/wouldyouin/_common/util/RestClientUtil.java @@ -1,10 +1,12 @@ package org.ktc2.cokaen.wouldyouin._common.util; +import java.util.function.Predicate; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpHeaders; -import org.springframework.http.ResponseEntity; +import org.springframework.http.HttpStatusCode; import org.springframework.stereotype.Component; import org.springframework.web.client.RestClient; +import org.springframework.web.client.RestClient.ResponseSpec.ErrorHandler; @Component @RequiredArgsConstructor @@ -12,19 +14,31 @@ public class RestClientUtil { private final RestClient client; - public ResponseEntity get(String url, Class classType) { + public T get(Class classType, String url, HttpHeaders headers, ErrorHandler errorHandler) { return client.get() .uri(url) + .headers(httpHeaders -> httpHeaders.putAll(headers)) .retrieve() - .toEntity(classType); + .onStatus(Predicate.not(HttpStatusCode::is2xxSuccessful), errorHandler) + .body(classType); } - public ResponseEntity post(String url, HttpHeaders headers, B body, Class classType) { + public T post( Class classType, String url, HttpHeaders headers, ErrorHandler errorHandler) { + return client.post() + .uri(url) + .headers(httpHeaders -> httpHeaders.addAll(headers)) + .retrieve() + .onStatus(Predicate.not(HttpStatusCode::is2xxSuccessful), errorHandler) + .body(classType); + } + + public T post(Class classType, String url, HttpHeaders headers, B body, ErrorHandler errorHandler) { return client.post() .uri(url) .headers(httpHeaders -> httpHeaders.addAll(headers)) .body(body) .retrieve() - .toEntity(classType); + .onStatus(Predicate.not(HttpStatusCode::is2xxSuccessful), errorHandler) + .body(classType); } } \ No newline at end of file diff --git a/src/main/java/org/ktc2/cokaen/wouldyouin/auth/application/oauth/GoogleRequestService.java b/src/main/java/org/ktc2/cokaen/wouldyouin/auth/application/oauth/GoogleRequestService.java index c15e9e8b..f70095d2 100644 --- a/src/main/java/org/ktc2/cokaen/wouldyouin/auth/application/oauth/GoogleRequestService.java +++ b/src/main/java/org/ktc2/cokaen/wouldyouin/auth/application/oauth/GoogleRequestService.java @@ -3,16 +3,16 @@ import com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy; import com.fasterxml.jackson.databind.annotation.JsonNaming; import java.util.Objects; +import org.ktc2.cokaen.wouldyouin._common.util.RestClientUtil; import org.ktc2.cokaen.wouldyouin.auth.application.oauth.dto.AccessTokenResponse; import org.ktc2.cokaen.wouldyouin.auth.application.oauth.dto.OauthRequest; import org.ktc2.cokaen.wouldyouin.auth.application.oauth.dto.OauthResourcesResponse; import org.ktc2.cokaen.wouldyouin.member.persist.AccountType; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatusCode; import org.springframework.http.MediaType; import org.springframework.stereotype.Service; -import org.springframework.web.client.RestClient; +import org.springframework.web.util.UriComponentsBuilder; @Service public class GoogleRequestService extends OauthRequestService { @@ -38,11 +38,46 @@ public class GoogleRequestService extends OauthRequestService { @Value("${oauth.google.redirect_uri}") private String redirectUri; + private final RestClientUtil client; + private final String loginRequestUri; + private final String accessRequestUri; + private final HttpHeaders loginRequestHeaders; + + public GoogleRequestService(RestClientUtil restClientUtil) { + + this.client = restClientUtil; + + loginRequestUri = UriComponentsBuilder.newInstance() + .scheme("https") + .host(loginRequestHost) + .path(loginRequestPath) + .build(true) + .toString(); + + accessRequestUri = UriComponentsBuilder.newInstance() + .scheme("https") + .host(accessRequestHost) + .path(accessRequestPath) + .build(true) + .toString(); + + loginRequestHeaders = new HttpHeaders(); + loginRequestHeaders.add(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE); + } + + protected HttpHeaders getAccessRequestHeaders(AccessTokenResponse authenticationResponse) { + HttpHeaders accessRequestHeaders = new HttpHeaders(); + accessRequestHeaders.add(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE); + accessRequestHeaders.add(HttpHeaders.AUTHORIZATION, "Bearer " + authenticationResponse.getAccessToken()); + return accessRequestHeaders; + } + @Override protected AccountType getAccountType() { return AccountType.google; } + @Override protected OauthRequest getOauthRequestBase() { return OauthRequest.builder() .grantType("authorization_code") @@ -54,36 +89,17 @@ protected OauthRequest getOauthRequestBase() { @Override protected OauthResourcesResponse requestLoginAndAccessResources(OauthRequest request) { - AccessTokenResponse authenticationResponse = RestClient.create() - .post() - .uri(uriBuilder -> uriBuilder - .scheme("https") - .host(loginRequestHost) - .path(loginRequestPath) - .build(true)) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE) - .body(request) - .retrieve() + + AccessTokenResponse authenticationResponse = client.post( + AccessTokenResponse.class, loginRequestUri, loginRequestHeaders, request, // TODO: 커스텀 예외 추가 - .onStatus(HttpStatusCode::is4xxClientError, (httpRequest, clientHttpResponse) -> { throw new RuntimeException("에러"); }) - .onStatus(HttpStatusCode::is5xxServerError, (httpRequest, clientHttpResponse) -> { throw new RuntimeException("에러"); }) - .body(AccessTokenResponse.class); + (req, response) -> { throw new RuntimeException("에러"); }); Objects.requireNonNull(authenticationResponse); - GoogleAccessRequestResponse result = RestClient.create() - .get() - .uri(uriBuilder -> uriBuilder - .scheme("https") - .host(accessRequestHost) - .path(accessRequestPath) - .build(true)) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE) - .header(HttpHeaders.AUTHORIZATION, "Bearer " + authenticationResponse.getAccessToken()) - .retrieve() + GoogleAccessRequestResponse result = client.get( + GoogleAccessRequestResponse.class, accessRequestUri, getAccessRequestHeaders(authenticationResponse), // TODO: 커스텀 예외 추가 - .onStatus(HttpStatusCode::is4xxClientError, (httpRequest, clientHttpResponse) -> { throw new RuntimeException("에러"); }) - .onStatus(HttpStatusCode::is5xxServerError, (httpRequest, clientHttpResponse) -> { throw new RuntimeException("에러"); }) - .body(GoogleAccessRequestResponse.class); + (req, rsp) -> { throw new RuntimeException("에러"); }); Objects.requireNonNull(result); return OauthResourcesResponse.builder() diff --git a/src/main/java/org/ktc2/cokaen/wouldyouin/auth/application/oauth/KakaoRequestService.java b/src/main/java/org/ktc2/cokaen/wouldyouin/auth/application/oauth/KakaoRequestService.java index 1a8cb838..57ae9585 100644 --- a/src/main/java/org/ktc2/cokaen/wouldyouin/auth/application/oauth/KakaoRequestService.java +++ b/src/main/java/org/ktc2/cokaen/wouldyouin/auth/application/oauth/KakaoRequestService.java @@ -5,16 +5,16 @@ import java.util.Objects; import lombok.Getter; import lombok.RequiredArgsConstructor; +import org.ktc2.cokaen.wouldyouin._common.util.RestClientUtil; import org.ktc2.cokaen.wouldyouin.auth.application.oauth.dto.AccessTokenResponse; import org.ktc2.cokaen.wouldyouin.auth.application.oauth.dto.OauthRequest; import org.ktc2.cokaen.wouldyouin.auth.application.oauth.dto.OauthResourcesResponse; import org.ktc2.cokaen.wouldyouin.member.persist.AccountType; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatusCode; import org.springframework.http.MediaType; import org.springframework.stereotype.Service; -import org.springframework.web.client.RestClient; +import org.springframework.web.util.UriComponentsBuilder; @Service public class KakaoRequestService extends OauthRequestService { @@ -45,6 +45,45 @@ protected AccountType getAccountType() { return AccountType.kakao; } + private final RestClientUtil client; + private final String loginRequestUri; + private final String accessRequestUri; + private final HttpHeaders loginRequestHeaders; + + public KakaoRequestService(RestClientUtil restClientUtil) { + this.client = restClientUtil; + + OauthRequest request = getOauthRequestBase(); + loginRequestUri = UriComponentsBuilder.newInstance() + .scheme("https") + .host(loginRequestHost) + .path(loginRequestPath) + .queryParam("grant_type", request.getGrantType()) + .queryParam("client_id", request.getClientId()) + .queryParam("client_secret", request.getClientSecret()) + .queryParam("code", request.getCode()) + .build(true) + .toString(); + + accessRequestUri = UriComponentsBuilder.newInstance() + .scheme("https") + .host(accessRequestHost) + .path(accessRequestPath) + .build(true) + .toString(); + + loginRequestHeaders = new HttpHeaders(); + loginRequestHeaders.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE); + } + + protected HttpHeaders getAccessRequestHeaders(AccessTokenResponse authenticationResponse) { + HttpHeaders accessRequestHeaders = new HttpHeaders(); + accessRequestHeaders.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE); + accessRequestHeaders.add(HttpHeaders.AUTHORIZATION, "Bearer " + authenticationResponse.getAccessToken()); + return accessRequestHeaders; + } + + @Override protected OauthRequest getOauthRequestBase() { return OauthRequest.builder() .grantType("authorization_code") @@ -56,39 +95,16 @@ protected OauthRequest getOauthRequestBase() { @Override protected OauthResourcesResponse requestLoginAndAccessResources(OauthRequest request) { - AccessTokenResponse authenticationResponse = RestClient.create() - .post() - .uri(uriBuilder -> uriBuilder - .scheme("https") - .host(loginRequestHost) - .path(loginRequestPath) - .queryParam("grant_type", request.getGrantType()) - .queryParam("client_id", request.getClientId()) - .queryParam("client_secret", request.getClientSecret()) - .queryParam("code", request.getCode()) - .build(true)) - .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE) - .retrieve() + AccessTokenResponse authenticationResponse = client.post( + AccessTokenResponse.class, loginRequestUri, loginRequestHeaders, // TODO: 커스텀 예외 추가 - .onStatus(HttpStatusCode::is4xxClientError, (httpRequest, clientHttpResponse) -> { throw new RuntimeException("에러"); }) - .onStatus(HttpStatusCode::is5xxServerError, (httpRequest, clientHttpResponse) -> { throw new RuntimeException("에러"); }) - .body(AccessTokenResponse.class); + (req, rsp) -> { throw new RuntimeException("에러"); }); Objects.requireNonNull(authenticationResponse); - KakaoAccessRequestResponse result = RestClient.create() - .get() - .uri(uriBuilder -> uriBuilder - .scheme("https") - .host(accessRequestHost) - .path(accessRequestPath) - .build(true)) - .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE) - .header(HttpHeaders.AUTHORIZATION, "Bearer " + authenticationResponse.getAccessToken()) - .retrieve() + KakaoAccessRequestResponse result = client.get( + KakaoAccessRequestResponse.class, accessRequestUri, getAccessRequestHeaders(authenticationResponse), // TODO: 커스텀 예외 추가 - .onStatus(HttpStatusCode::is4xxClientError, (httpRequest, clientHttpResponse) -> { throw new RuntimeException("에러"); }) - .onStatus(HttpStatusCode::is5xxServerError, (httpRequest, clientHttpResponse) -> { throw new RuntimeException("에러"); }) - .body(KakaoAccessRequestResponse.class); + (req, rsp) -> { throw new RuntimeException("에러"); }); Objects.requireNonNull(result); return OauthResourcesResponse.builder() diff --git a/src/main/java/org/ktc2/cokaen/wouldyouin/member/persist/BaseMember.java b/src/main/java/org/ktc2/cokaen/wouldyouin/member/persist/BaseMember.java index 2d7afb34..e2a80e47 100644 --- a/src/main/java/org/ktc2/cokaen/wouldyouin/member/persist/BaseMember.java +++ b/src/main/java/org/ktc2/cokaen/wouldyouin/member/persist/BaseMember.java @@ -5,7 +5,6 @@ import jakarta.persistence.Entity; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; -import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; @@ -30,6 +29,7 @@ public abstract class BaseMember { @Id @Setter(AccessLevel.NONE) @GeneratedValue(strategy = GenerationType.IDENTITY) + // TODO: 네이밍 소문자로 바꾸기 private Long Id; @Column(nullable = false) diff --git a/src/main/java/org/ktc2/cokaen/wouldyouin/payment/application/PaymentService.java b/src/main/java/org/ktc2/cokaen/wouldyouin/payment/application/PaymentService.java index c8a48c45..3476c52e 100644 --- a/src/main/java/org/ktc2/cokaen/wouldyouin/payment/application/PaymentService.java +++ b/src/main/java/org/ktc2/cokaen/wouldyouin/payment/application/PaymentService.java @@ -1,5 +1,6 @@ package org.ktc2.cokaen.wouldyouin.payment.application; +import java.nio.file.Paths; import lombok.RequiredArgsConstructor; import org.ktc2.cokaen.wouldyouin._common.exception.FailedToPayException; import org.ktc2.cokaen.wouldyouin._common.util.KakaoPayUtil; @@ -7,7 +8,6 @@ import org.ktc2.cokaen.wouldyouin.payment.dto.KakaoPayRequest; import org.ktc2.cokaen.wouldyouin.payment.dto.KakaoPayResponse; import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; @Service @@ -30,17 +30,13 @@ public class PaymentService { private String secretKey; public KakaoPayResponse createPayment(KakaoPayRequest kakaoPayRequest) { - ResponseEntity response = client.post( - kakaoPayRequestHost + "/" + kakaoPaySinglePaymentUrl, + return client.post( + KakaoPayResponse.class, + Paths.get(kakaoPayRequestHost, kakaoPaySinglePaymentUrl).toString(), KakaoPayUtil.createKakaoPayRequestHeaders(kakaoPayRequestHost, secretKey), KakaoPayUtil.createKakaoPayRequestBody(kakaoPayRequest, approvalUrl, cancelUrl, failUrl), - KakaoPayResponse.class + (req, rsp) -> { throw new FailedToPayException("카카오페이 API 요청을 실패하였습니다."); } ); - if (!response.getStatusCode().is2xxSuccessful()) { - throw new FailedToPayException("카카오페이 API 요청을 실패하였습니다."); - } - return response.getBody(); } - // Todo: pay 취소 기능 추가 -} +} \ No newline at end of file