Skip to content

Commit

Permalink
[Weekly/11/Refactor/MemberControllers] 소셜로그인 깨짐 해결, 멤버 이미지 url respon…
Browse files Browse the repository at this point in the history
…se 수정 (#128)
  • Loading branch information
lja3723 authored Nov 13, 2024
1 parent 5eab29b commit a993101
Show file tree
Hide file tree
Showing 14 changed files with 106 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,21 +49,13 @@ public static String createRandomFileName(String extension) {
return UUID.randomUUID().toString().replace("-", "") + "." + extension;
}

public static String getExtension(MultipartFile file) {
if (file == null || file.getContentType() == null) {
throw new ExtensionParsingException("파일이 존재하지 않거나 콘텐츠 타입이 없습니다.");
}
public static String getExtension(String contentType) {
try {
return file.getContentType().split("/")[1];
return contentType.split("/")[1];
} catch (NullPointerException e) {
throw new ExtensionParsingException("파일이 존재하지 않거나 콘텐츠 타입이 없습니다.");
} catch (ArrayIndexOutOfBoundsException e) {
throw new ExtensionParsingException("파일의 확장자를 찾을 수 없습니다.");
}
}

public static String getExtension(String url) {
if (url == null || !url.contains(".")) {
throw new ExtensionParsingException("URL이 존재하지 않거나 확장자가 없습니다.");
}
return url.substring(url.lastIndexOf('.') + 1);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClient;
import org.springframework.web.client.RestClient.ResponseSpec.ErrorHandler;
Expand All @@ -23,6 +24,15 @@ public <T> T get(Class<T> classType, String url, HttpHeaders headers, ErrorHandl
.body(classType);
}

public <T> ResponseEntity<T> getResponseEntity(Class<T> classType, String url, HttpHeaders headers, ErrorHandler errorHandler) {
return client.get()
.uri(url)
.headers(httpHeaders -> httpHeaders.putAll(headers))
.retrieve()
.onStatus(Predicate.not(HttpStatusCode::is2xxSuccessful), errorHandler)
.toEntity(classType);
}

public <T> T post( Class<T> classType, String url, HttpHeaders headers, ErrorHandler errorHandler) {
return client.post()
.uri(url)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

import com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import jakarta.annotation.PostConstruct;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.ktc2.cokaen.wouldyouin._common.util.RestClientUtil;
import org.ktc2.cokaen.wouldyouin._common.util.UriUtil;
import org.ktc2.cokaen.wouldyouin.auth.application.oauth.dto.AccessTokenResponse;
Expand All @@ -14,7 +17,9 @@
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;

@Slf4j
@Service
@RequiredArgsConstructor
public class GoogleRequestService extends OauthRequestService {

@Value("${oauth.google.uri.login.host}")
Expand All @@ -39,13 +44,12 @@ public class GoogleRequestService extends OauthRequestService {
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;
private String loginRequestUri;
private String accessRequestUri;
private HttpHeaders loginRequestHeaders;

@PostConstruct
private void init() {
loginRequestUri = UriUtil.buildUrl("https", loginRequestHost, loginRequestPath);
accessRequestUri = UriUtil.buildUrl("https", accessRequestHost, accessRequestPath);

Expand Down Expand Up @@ -89,6 +93,8 @@ GoogleAccessRequestResponse.class, accessRequestUri, getAccessRequestHeaders(aut
// TODO: 커스텀 예외 추가
(req, rsp) -> { throw new RuntimeException("에러"); });

log.debug("#### GoogleAccessRequestResponse result = {}", result);

Objects.requireNonNull(result);
return OauthResourcesResponse.builder()
.socialId(result.id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@

import com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import jakarta.annotation.PostConstruct;
import java.util.Objects;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.ktc2.cokaen.wouldyouin._common.util.RestClientUtil;
import org.ktc2.cokaen.wouldyouin._common.util.UriUtil;
import org.ktc2.cokaen.wouldyouin.auth.application.oauth.dto.AccessTokenResponse;
Expand All @@ -16,9 +19,10 @@
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

@Slf4j
@Service
@RequiredArgsConstructor
public class KakaoRequestService extends OauthRequestService {

@Value("${oauth.kakao.uri.login.host}")
Expand Down Expand Up @@ -48,28 +52,23 @@ protected AccountType getAccountType() {
}

private final RestClientUtil client;
private final String loginRequestUri;
private final String accessRequestUri;
private final HttpHeaders loginRequestHeaders;
private String accessRequestUri;
private HttpHeaders loginRequestHeaders;

public KakaoRequestService(RestClientUtil restClientUtil) {
this.client = restClientUtil;

loginRequestUri = UriUtil.buildUrl("https", loginRequestHost, loginRequestPath, getLoginRequestQueryParams());
@PostConstruct
private void init() {
accessRequestUri = UriUtil.buildUrl("https", accessRequestHost, accessRequestPath);

loginRequestHeaders = new HttpHeaders();
loginRequestHeaders.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE);
}

protected MultiValueMap<String, String> getLoginRequestQueryParams() {
OauthRequest request = getOauthRequestBase();
protected String getLoginRequestUri(OauthRequest request) {
var queries = new LinkedMultiValueMap<String, String>();
queries.add("grant_type", request.getGrantType());
queries.add("client_id", request.getClientId());
queries.add("client_secret", request.getClientSecret());
queries.add("code", request.getCode());
return queries;
return UriUtil.buildUrl("https", loginRequestHost, loginRequestPath, queries);
}

protected HttpHeaders getAccessRequestHeaders(AccessTokenResponse authenticationResponse) {
Expand All @@ -92,16 +91,20 @@ protected OauthRequest getOauthRequestBase() {
@Override
protected OauthResourcesResponse requestLoginAndAccessResources(OauthRequest request) {
AccessTokenResponse authenticationResponse = client.post(
AccessTokenResponse.class, loginRequestUri, loginRequestHeaders,
AccessTokenResponse.class, getLoginRequestUri(request), loginRequestHeaders,
// TODO: 커스텀 예외 추가
(req, rsp) -> { throw new RuntimeException("에러"); });
(req, rsp) -> {
throw new RuntimeException("에러");
});

Objects.requireNonNull(authenticationResponse);
KakaoAccessRequestResponse result = client.get(
KakaoAccessRequestResponse.class, accessRequestUri, getAccessRequestHeaders(authenticationResponse),
// TODO: 커스텀 예외 추가
(req, rsp) -> { throw new RuntimeException("에러"); });

log.debug("#### KakaoAccessRequestResponse result = {}", result);

Objects.requireNonNull(result);
return OauthResourcesResponse.builder()
.socialId(result.getId().toString())
Expand All @@ -114,6 +117,7 @@ KakaoAccessRequestResponse.class, accessRequestUri, getAccessRequestHeaders(auth
@JsonNaming(SnakeCaseStrategy.class)
@RequiredArgsConstructor
@Getter
@ToString
static class KakaoAccessRequestResponse {

private final Long id;
Expand All @@ -123,6 +127,7 @@ static class KakaoAccessRequestResponse {
@JsonNaming(SnakeCaseStrategy.class)
@RequiredArgsConstructor
@Getter
@ToString
static class KakaoAccount {

private final Profile profile;
Expand All @@ -132,6 +137,7 @@ static class KakaoAccount {
@JsonNaming(SnakeCaseStrategy.class)
@RequiredArgsConstructor
@Getter
@ToString
static class Profile {

private final String nickname;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ public ResponseEntity<byte[]> getImage(@PathVariable String directory, @PathVari
return ResponseEntity.status(HttpStatus.OK).body(imageStorageService.readFromDirectory(Paths.get(directory, file)));
}

@GetMapping(value = "/{directory}/{thumbnail}/{file}", produces = {MediaType.IMAGE_PNG_VALUE, MediaType.IMAGE_JPEG_VALUE})
public ResponseEntity<byte[]> getThumnailImage(@PathVariable String directory, @PathVariable String thumbnail, @PathVariable String file) {
return ResponseEntity.status(HttpStatus.OK).body(imageStorageService.readFromDirectory(Paths.get(directory, thumbnail, file)));
}

@PostMapping
public ResponseEntity<ApiResponseBody<List<ImageResponse>>> uploadImages(
@RequestParam List<MultipartFile> images,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public void deleteImage(MemberIdentifier identifier, Long imageId) {
}

public String createThumbnail(String fileName) {
return imageStorageService.createThumbnailImage(getChildPath(), fileName);
return imageStorageService.createThumbnailImage(parentPath, getChildPath(), fileName);
}

public T getById(Long id) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@
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.ktc2.cokaen.wouldyouin._common.util.UriUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

Expand Down Expand Up @@ -42,31 +44,36 @@ public byte[] readFromDirectory(Path childPath) {
}

public ImageRequest saveToDirectory(MultipartFile image, String childPath) {
String extension = FileUtil.getExtension(image);
String extension = FileUtil.getExtension(image.getContentType());
String fileName = FileUtil.createRandomFileName(extension);
FileUtil.saveFile(image, Path.of(parentPath, childPath, fileName));
return ImageRequest.of(fileName, image.getSize(), extension);
}

public ImageRequest saveToDirectory(String imageUrl, String childPath) {
byte[] response = client.get(byte[].class, imageUrl, new HttpHeaders(),
ResponseEntity<byte[]> response = client.getResponseEntity(byte[].class, imageUrl, new HttpHeaders(),
(req, rsp) -> {
throw new FailedToUploadImageException("이미지 URL에 대한 요청을 실패하였습니다.");
}
);
Optional.ofNullable(response).orElseThrow(

String contentType = Optional.ofNullable(response.getHeaders().getContentType()).orElseThrow(
() -> new FailedToUploadImageException("응답 헤더에 콘텐츠 타입이 없어 이미지를 가져올 수 없습니다.")
).toString();
byte[] body = Optional.ofNullable(response.getBody()).orElseThrow(
() -> new FailedToUploadImageException("응답 본문이 비어있어 이미지를 가져올 수 없습니다.")
);
String extension = FileUtil.getExtension(imageUrl);

String extension = FileUtil.getExtension(contentType);
String fileName = FileUtil.createRandomFileName(extension);
Path path = Path.of(parentPath, childPath, fileName);
FileUtil.saveFile(response, path);
return ImageRequest.of(fileName, (long) response.length, extension);
FileUtil.saveFile(response.getBody(), path);
return ImageRequest.of(fileName, (long)body.length, extension);
}

// TODO : 썸네일 생성 코드 리팩토링, 파일 유틸로 이동
public String createThumbnailImage(String childPath, String originFileName) {
String fileName = FileUtil.createRandomFileName(thumbnailExtension);
public String createThumbnailImage(String apiHeader, String childPath, String originFileName) {
String fileName = originFileName;
String originImagePath = Path.of(parentPath, childPath, originFileName).toString();
String thumbnailImagePath = Path.of(parentPath, childPath, thumbnailChildPath).toString();
try {
Expand All @@ -77,7 +84,7 @@ public String createThumbnailImage(String childPath, String originFileName) {
} catch (Exception e) {
throw new RuntimeException(e);
}
return fileName;
return UriUtil.assembleFullUrl(apiHeader,childPath, thumbnailChildPath, fileName);
}

public void delete(String childPath, String fileName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public class MemberResponse {
private String nickname;
private String phoneNumber;
private String profileUrl;
private String profileThumbnailUrl;
private MemberType memberType;

private Area area;
Expand All @@ -29,34 +30,36 @@ public class MemberResponse {

private List<String> hashtag;

private static MemberResponseBuilder responseBase(BaseMember baseMember) {
private static MemberResponseBuilder responseBase(BaseMember baseMember, String profileUrl) {
return MemberResponse.builder()
.memberId(baseMember.getId())
.nickname(baseMember.getNickname())
.phoneNumber(baseMember.getPhone())
.profileUrl(baseMember.getProfileImage().getName());
.profileUrl(profileUrl)
.profileThumbnailUrl(baseMember.getProfileImageThumbnailUrl());

}

// TODO: normal member임에도 불구, curator 형식이 호출되는 현상 수정필요
public static MemberResponse from(final Member member) {
return responseBase(member)
public static MemberResponse from(final Member member, String profileUrl) {
return responseBase(member, profileUrl)
.memberType(member.getMemberType())
.area(member.getArea())
.gender(member.getGender())
.build();
}

public static MemberResponse from(final Host host) {
return responseBase(host)
public static MemberResponse from(final Host host, String profileUrl) {
return responseBase(host, profileUrl)
.memberType(host.getMemberType())
.intro(host.getIntro())
.likes(host.getLikes())
.hashtag(host.getHashtags())
.build();
}

public static MemberResponse from(final Curator curator) {
return responseBase(curator)
public static MemberResponse from(final Curator curator, String profileUrl) {
return responseBase(curator, profileUrl)
.memberType(curator.getMemberType())
.area(curator.getArea())
.gender(curator.getGender())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
@RequiredArgsConstructor
public class MemberAdditionalInfoRequest {

private final String phone;
private final Area area;
private final String gender;
private String phone;
private Area area;
private String gender;
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ public LikeableMemberService<Curator> getLikeableMemberService() {
@Override
@Transactional(readOnly = true)
public MemberResponse getMemberResponseById(Long id) {
return MemberResponse.from(getByIdOrThrow(id));
Curator curator = getByIdOrThrow(id);
return MemberResponse.from(curator, memberImageService.getImageUrl(curator.getProfileImage()));
}

@Override
Expand Down Expand Up @@ -73,18 +74,17 @@ public MemberResponse createCurator(Long normalMemberId) {
baseMemberRepository.flush();

curatorRepository.save(curator);
return MemberResponse.from(curator);
return MemberResponse.from(curator, memberImageService.getImageUrl(curator.getProfileImage()));
}

// TODO : 반대방향 연관관계 설정 setter?
@Transactional
public MemberResponse updateCurator(Long curatorId, CuratorEditRequest request) {
Curator curator = getByIdOrThrow(curatorId);
MemberImage image = memberImageService.getById(request.getProfileImageId());
String thumbnailImageUrl = memberImageService.createThumbnail(image.getName());
curator.updateFrom(request, image, thumbnailImageUrl);
image.setBaseMember(curator);
return MemberResponse.from(curator);
memberImageService.setBaseMember(image, curator);
return MemberResponse.from(curator, memberImageService.getImageUrl(curator.getProfileImage()));
}

@Override
Expand Down
Loading

0 comments on commit a993101

Please sign in to comment.