Skip to content

Commit

Permalink
[Weekly/11/Refactor/ExtractRestClient] RestClientUtil 이용, 로직 추출 (#108)
Browse files Browse the repository at this point in the history
  • Loading branch information
lja3723 committed Nov 15, 2024
1 parent d5b29f3 commit eec6154
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 91 deletions.
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public abstract class ImageService<T extends Image> {
protected ImageStorageService imageStorageService;

@Value("${image.api-url}")
private String domainName;
private String apiUrl;

protected abstract ImageRepository<T> getImageRepository();

Expand All @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -34,19 +35,17 @@ public ImageRequest saveToDirectory(MultipartFile image, String subPath) {
}

public ImageRequest saveToDirectory(String imageUrl, String subPath) {
ResponseEntity<byte[]> 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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,44 @@
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
public class RestClientUtil {

private final RestClient client;

public <T> ResponseEntity<T> get(String url, Class<T> classType) {
public <T> T get(Class<T> 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 <T, B> ResponseEntity<T> post(String url, HttpHeaders headers, B body, Class<T> classType) {
public <T> T post( Class<T> 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, B> T post(Class<T> 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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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")
Expand All @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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")
Expand All @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -30,6 +29,7 @@ public abstract class BaseMember {
@Id
@Setter(AccessLevel.NONE)
@GeneratedValue(strategy = GenerationType.IDENTITY)
// TODO: 네이밍 소문자로 바꾸기
private Long Id;

@Column(nullable = false)
Expand Down
Loading

0 comments on commit eec6154

Please sign in to comment.