Skip to content

Commit

Permalink
refactor: CompletableFuture 을 활용한 비동기처리
Browse files Browse the repository at this point in the history
  • Loading branch information
KimChanJin97 committed Jun 21, 2024
1 parent 906d639 commit 168e855
Show file tree
Hide file tree
Showing 11 changed files with 180 additions and 69 deletions.
11 changes: 11 additions & 0 deletions src/main/java/capstone/facefriend/bucket/BucketException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package capstone.facefriend.bucket;

import capstone.facefriend.common.exception.BaseException;
import capstone.facefriend.common.exception.ExceptionType;

public class BucketException extends BaseException {

public BucketException(ExceptionType exceptionType) {
super(exceptionType);
}
}
36 changes: 36 additions & 0 deletions src/main/java/capstone/facefriend/bucket/BucketExceptionType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package capstone.facefriend.bucket;

import capstone.facefriend.common.exception.ExceptionType;
import capstone.facefriend.common.exception.Status;

public enum BucketExceptionType implements ExceptionType {

FAIL_TO_UPLOAD(Status.SERVER_ERROR, 9001, "S3 업로드에 실패했습니다."),
FAIL_TO_GET_INPUT_STREAM(Status.SERVER_ERROR, 9002, "Input Stream 추출에 실패했습니다."),
;

private final Status status;
private final int exceptionCode;
private final String message;

BucketExceptionType(Status status, int exceptionCode, String message) {
this.status = status;
this.exceptionCode = exceptionCode;
this.message = message;
}

@Override
public Status status() {
return status;
}

@Override
public int exceptionCode() {
return exceptionCode;
}

@Override
public String message() {
return message;
}
}
59 changes: 40 additions & 19 deletions src/main/java/capstone/facefriend/bucket/BucketService.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import capstone.facefriend.chat.repository.ChatMessageRepository;
import capstone.facefriend.chat.repository.ChatRoomMemberRepository;
import capstone.facefriend.chat.repository.ChatRoomRepository;
import capstone.facefriend.common.aop.TimeTrace;
import capstone.facefriend.member.domain.member.Member;
import capstone.facefriend.member.repository.MemberRepository;
import capstone.facefriend.member.exception.member.MemberException;
Expand All @@ -26,10 +27,12 @@
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import static capstone.facefriend.bucket.BucketExceptionType.*;
import static capstone.facefriend.chat.exception.ChatExceptionType.*;

@Transactional
Expand Down Expand Up @@ -62,51 +65,69 @@ public class BucketService {
public List<String> uploadOriginAndGenerated(
MultipartFile origin,
ByteArrayMultipartFile generated
) throws IOException {
/** upload origin to s3 */
// set metadata
ObjectMetadata originMetadata = new ObjectMetadata();
originMetadata.setContentLength(origin.getInputStream().available());
originMetadata.setContentType(origin.getContentType());
) {
String originS3url = getOriginS3Url(origin);
String generatedS3url = getGeneratedS3url(generated);

return List.of(originS3url, generatedS3url);
}

private String getOriginS3Url(MultipartFile origin) {
ObjectMetadata originMetadata = null;
InputStream originInputStream = null;

try {
originMetadata = new ObjectMetadata();
originInputStream = origin.getInputStream();
originMetadata.setContentLength(originInputStream.available());
originMetadata.setContentType(origin.getContentType());
} catch (IOException e) {
throw new BucketException(FAIL_TO_GET_INPUT_STREAM);
}

String originObjectName = UUID.randomUUID() + ORIGIN_POSTFIX;
amazonS3.putObject(
new PutObjectRequest(
BUCKET_NAME,
originObjectName,
origin.getInputStream(), // origin
originInputStream,
originMetadata
).withCannedAcl(CannedAccessControlList.PublicRead)
);
String originS3url = amazonS3.getUrl(BUCKET_NAME, originObjectName).toString();
return amazonS3.getUrl(BUCKET_NAME, originObjectName).toString();
}

/** upload generated to s3 */
// set metadata
ObjectMetadata generatedMetadata = new ObjectMetadata();
generatedMetadata.setContentLength(generated.getInputStream().available());
generatedMetadata.setContentType(generatedMetadata.getContentType());
private String getGeneratedS3url(MultipartFile generated) {
ObjectMetadata generatedMetadata = null;
InputStream generatedInputStream = null;
try {
generatedMetadata = new ObjectMetadata();
generatedInputStream = generated.getInputStream();
generatedMetadata.setContentLength(generatedInputStream.available());
generatedMetadata.setContentType(generatedMetadata.getContentType());
} catch (IOException e) {
throw new BucketException(FAIL_TO_GET_INPUT_STREAM);
}

String generatedObjectName = UUID.randomUUID() + GENERATED_POSTFIX;
amazonS3.putObject(
new PutObjectRequest(
BUCKET_NAME,
generatedObjectName,
generated.getInputStream(), // generated
generatedInputStream,
generatedMetadata
).withCannedAcl(CannedAccessControlList.PublicRead)
);
String generatedS3url = amazonS3.getUrl(BUCKET_NAME, generatedObjectName).toString();

return List.of(originS3url, generatedS3url);
return amazonS3.getUrl(BUCKET_NAME, generatedObjectName).toString();
}


// FaceInfo : origin 수정 -> generated 수정
@TimeTrace
public List<String> updateOriginAndGenerated(
MultipartFile origin,
ByteArrayMultipartFile generated,
Long memberId
) throws IOException {
) {
Member member = findMemberById(memberId);

String originS3url = member.getFaceInfo().getOriginS3url();
Expand Down
23 changes: 0 additions & 23 deletions src/main/java/capstone/facefriend/chat/config/ChatAsyncConfig.java

This file was deleted.

11 changes: 11 additions & 0 deletions src/main/java/capstone/facefriend/common/aop/TimeTrace.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package capstone.facefriend.common.aop;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TimeTrace {
}
32 changes: 32 additions & 0 deletions src/main/java/capstone/facefriend/common/aop/TimeTraceAspect.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package capstone.facefriend.common.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

@Slf4j
@Component
@Aspect
public class TimeTraceAspect {

@Pointcut("@annotation(capstone.facefriend.common.aop.TimeTrace)")
private void timeTracePointcut() {
}

@Around("timeTracePointcut()")
public Object traceTime(ProceedingJoinPoint joinPoint) throws Throwable {
StopWatch stopWatch = new StopWatch();

try {
stopWatch.start();
return joinPoint.proceed();
} finally {
stopWatch.stop();
log.info("{} 소요 시간 = {}s", joinPoint.getSignature().toShortString(), stopWatch.getTotalTimeSeconds());
}
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
package capstone.facefriend.member.controller;

import capstone.facefriend.auth.controller.support.AuthMember;
import capstone.facefriend.common.aop.TimeTrace;
import capstone.facefriend.member.service.FaceInfoService;
import capstone.facefriend.member.dto.faceInfo.FaceInfoResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

@Slf4j
@RestController
Expand All @@ -26,16 +30,23 @@ public ResponseEntity<FaceInfoResponse> get(
}

@PutMapping("/face-info")
public ResponseEntity<FaceInfoResponse> update(
@TimeTrace
public DeferredResult<ResponseEntity<FaceInfoResponse>> updateOriginAndGenerated(
@RequestPart("origin")MultipartFile origin,
@RequestParam("styleId") Integer styleId,
@AuthMember Long memberId
) throws IOException {
return ResponseEntity.ok(faceInfoService.updateOrigin(origin, styleId, memberId));
) {
DeferredResult<ResponseEntity<FaceInfoResponse>> deferredResult = new DeferredResult<>();

CompletableFuture
.supplyAsync(() -> faceInfoService.updateOriginAndGenerated(origin, styleId, memberId))
.thenAccept(result -> deferredResult.setResult(ResponseEntity.ok(result)));

return deferredResult;
}

@DeleteMapping("/face-info")
public ResponseEntity<FaceInfoResponse> delete(
public ResponseEntity<FaceInfoResponse> deleteOriginAndGenerated(
@AuthMember Long memberId
) {
return ResponseEntity.ok(faceInfoService.deleteOriginAndGenerated(memberId));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
import capstone.facefriend.common.exception.BaseException;
import capstone.facefriend.common.exception.ExceptionType;

public class FaceException extends BaseException {
public class FaceInfoException extends BaseException {

public FaceException(ExceptionType exceptionType) {
public FaceInfoException(ExceptionType exceptionType) {
super(exceptionType);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,16 @@
import capstone.facefriend.common.exception.ExceptionType;
import capstone.facefriend.common.exception.Status;

public enum FaceExceptionType implements ExceptionType {
public enum FaceInfoExceptionType implements ExceptionType {

CANNOT_GET_BYTE(Status.SERVER_ERROR, 8001, "바이트를 추출할 수 없습니다."),
CANNOT_GET_INPUT_STREAM(Status.SERVER_ERROR, 8002, "인풋 스트림을 추출할 수 없습니다.");
FAIL_TO_GENERATE(Status.SERVER_ERROR, 8001, "바이트를 추출할 수 없습니다."),
;

private final Status status;
private final int exceptionCode;
private final String message;

FaceExceptionType(Status status, int exceptionCode, String message) {
FaceInfoExceptionType(Status status, int exceptionCode, String message) {
this.status = status;
this.exceptionCode = exceptionCode;
this.message = message;
Expand Down
Loading

0 comments on commit 168e855

Please sign in to comment.