Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,5 @@ out/
**/src/main/resources/application-**
.env
app/gradle.properties
app/newrelic/newrelic.yml
app/newrelic/newrelic.yml
/heapdump
2 changes: 1 addition & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ tasks.named("jib") {

jib {
from {
image = "qasker/eclipse-temurin-21-libreoffice"
image = "amazoncorretto:21"
}
to {
image = "${project.property("DOCKER_ID")}/${project.property("DOCKER_IMAGE_NAME")}"
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ plugins {


group = "com.icc.qasker"
version = "1.5.1"
version = "1.6.0"

subprojects {
apply plugin: 'java'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package com.icc.qasker.aws;

import com.icc.qasker.aws.dto.S3UploadRequest;
import com.icc.qasker.aws.dto.S3UploadResponse;
import com.icc.qasker.aws.dto.FileExistStatusResponse;
import com.icc.qasker.aws.dto.PresignRequest;
import com.icc.qasker.aws.dto.PresignResponse;

public interface S3Service {

S3UploadResponse uploadFile(S3UploadRequest s3UploadRequest);
PresignResponse requestPresign(PresignRequest presignRequest);

FileExistStatusResponse checkFileExistence(String originalFileName);
}

Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
package com.icc.qasker.aws;

import org.springframework.web.multipart.MultipartFile;

public interface S3ValidateService {

void checkCloudFrontUrlWithThrowing(String url);

void validateFileWithThrowing(MultipartFile multipartFile);

void validateS3Bucket(String url);
void validateFileWithThrowing(String fileName, String contentType);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.icc.qasker.aws.dto;

public record FileExistStatusResponse(
Status status
) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.icc.qasker.aws.dto;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;

public record PresignRequest(

@NotBlank(message = "파일명은 필수입니다.")
String originalFileName,

@NotBlank(message = "파일 타입(MIME)은 필수입니다.")
String contentType,

@NotNull(message = "파일 크기는 필수입니다.")
@Positive(message = "파일 크기는 0보다 커야 합니다.")
long fileSize
) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.icc.qasker.aws.dto;

public record PresignResponse(
String uploadUrl,
String finalUrl,
boolean isPdf
) {

}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.icc.qasker.aws.dto;

public enum Status {
NOT_EXIST,
EXIST
}
4 changes: 0 additions & 4 deletions modules/aws/impl/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@ dependencies {
implementation project(":global")
implementation project(":aws:aws-api")
// ────────────────────────────────
// 문서 변환 (PDF 등)
// ────────────────────────────────
implementation "org.jodconverter:jodconverter-local-lo:4.4.9"
// ────────────────────────────────
// AWS SDK
// ────────────────────────────────
implementation platform("software.amazon.awssdk:bom:2.27.24")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.icc.qasker.aws.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Profile;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import software.amazon.awssdk.services.s3.model.PutObjectResponse;

@Configuration
@Profile("stress-test")
public class MockS3ClientConfig {

@Bean
@Primary
public S3Client mockS3Client() {
// 익명 클래스로 S3Client의 동작을 가로챔
return new S3Client() {
@Override
public String serviceName() {
return "s3";
}

@Override
public void close() {
// Do nothing
}

@Override
public PutObjectResponse putObject(PutObjectRequest putObjectRequest,
RequestBody requestBody) {
System.out.println("Mock S3 Upload: " + putObjectRequest.key());

try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}

return PutObjectResponse.builder().build();
}
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.presigner.S3Presigner;

@Configuration
@AllArgsConstructor
Expand All @@ -16,7 +17,7 @@ public class S3ClientConfig {
private final AwsS3Properties awsS3Properties;

@Bean
public S3Client createS3Client() {
public S3Client s3Client() {
String accessKey = awsS3Properties.accessKey();
String secretKey = awsS3Properties.secretKey();
String region = awsS3Properties.region();
Expand All @@ -26,4 +27,17 @@ public S3Client createS3Client() {
return S3Client.builder().region(Region.of(region))
.credentialsProvider(StaticCredentialsProvider.create(awsCredentials)).build();
}

@Bean
public S3Presigner s3Presigner() {
return S3Presigner.builder()
.region(Region.of(awsS3Properties.region()))
.credentialsProvider(StaticCredentialsProvider.create(
AwsBasicCredentials.create(
awsS3Properties.accessKey(),
awsS3Properties.secretKey()
)
))
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@

import com.icc.qasker.aws.S3Service;
import com.icc.qasker.aws.controller.doc.S3ApiDoc;
import com.icc.qasker.aws.dto.S3UploadRequest;
import com.icc.qasker.aws.dto.S3UploadResponse;
import com.icc.qasker.aws.dto.FileExistStatusResponse;
import com.icc.qasker.aws.dto.PresignRequest;
import com.icc.qasker.aws.dto.PresignResponse;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
Expand All @@ -18,11 +22,19 @@ public class S3Controller implements S3ApiDoc {

public final S3Service s3Service;

@PostMapping("/upload")
public ResponseEntity<S3UploadResponse> upload(
@ModelAttribute
S3UploadRequest s3UploadRequest
@GetMapping("/check-file-exist")
public ResponseEntity<FileExistStatusResponse> checkFileExist(
@RequestParam("url") String url
) {
return ResponseEntity.ok(s3Service.uploadFile(s3UploadRequest));
return ResponseEntity.ok(s3Service.checkFileExistence(url));
}

@PostMapping("/request-presign")
public ResponseEntity<PresignResponse> upload(
@Valid
@RequestBody
PresignRequest presignRequest
) {
return ResponseEntity.ok(s3Service.requestPresign(presignRequest));
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,31 @@
package com.icc.qasker.aws.controller.doc;

import com.icc.qasker.aws.dto.S3UploadRequest;
import com.icc.qasker.aws.dto.S3UploadResponse;
import com.icc.qasker.aws.dto.FileExistStatusResponse;
import com.icc.qasker.aws.dto.PresignRequest;
import com.icc.qasker.aws.dto.PresignResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

@Tag(name = "S3", description = "S3 관련 API")
public interface S3ApiDoc {

@Operation(summary = "S3에 파일을 업로드한다")
@PostMapping("/upload")
ResponseEntity<S3UploadResponse> upload(
@ModelAttribute
S3UploadRequest s3UploadRequest
@Operation(summary = "프리사인드 URL을 얻는다")
@PostMapping("/request-presign")
ResponseEntity<PresignResponse> upload(
@Valid
@RequestBody
PresignRequest presignRequest
);

@Operation(summary = "파일이 존재하는지 확인한다")
@GetMapping("/check-file-exist")
ResponseEntity<FileExistStatusResponse> checkFileExist(
@RequestParam("url") String url
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ public record AwsS3Properties(
String bucketName,
String accessKey,
String secretKey,
int signatureDuration,
int maxFileNameLength,
String allowedExtensions
) {
Expand Down
Loading