Skip to content

Commit bc41c34

Browse files
authored
Merge pull request #13 from dochmai382/dev
포트폴리오 등록 로직 수정 및 미사용 코드 삭제
2 parents 13becd9 + ec14c95 commit bc41c34

7 files changed

Lines changed: 242 additions & 189 deletions

File tree

src/main/java/org/sunday/projectpop/controller/portfolio/PortfolioController.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import org.springframework.http.HttpStatus;
99
import org.springframework.http.MediaType;
1010
import org.springframework.http.ResponseEntity;
11+
import org.springframework.security.core.Authentication;
1112
import org.springframework.stereotype.Controller;
1213
import org.springframework.ui.Model;
1314
import org.springframework.validation.BindingResult;
@@ -33,7 +34,10 @@ public class PortfolioController {
3334

3435
// 포트폴리오 목록 조회
3536
@GetMapping
36-
public String getMyPortfolios(Model model) {
37+
public String getMyPortfolios(Model model
38+
// @RequestParam String userId
39+
) {
40+
3741
String userId = "dummy1"; // TODO: Authentication에서 userId 받기
3842
List<PortfolioSimple> portfolios = portfolioService.getMyPortfolios(userId);
3943
model.addAttribute("portfolios", portfolios);

src/main/java/org/sunday/projectpop/controller/portfolio/PortfolioRestController.java

Lines changed: 0 additions & 163 deletions
This file was deleted.

src/main/java/org/sunday/projectpop/model/dto/PortfolioRequest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import jakarta.validation.constraints.Size;
66
import org.springframework.web.multipart.MultipartFile;
77
import org.sunday.projectpop.model.enums.PortfolioType;
8+
import org.sunday.projectpop.validator.FileValidation;
89

910
import java.util.List;
1011

@@ -22,6 +23,8 @@ public record PortfolioRequest(
2223
String description,
2324

2425
List<String> urls,
26+
27+
// @FileValidation(message = "첨부된 파일에 문제가 있습니다.")
2528
List<MultipartFile> files,
2629

2730
// 수정용 필요

src/main/java/org/sunday/projectpop/model/enums/PortfolioType.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
// FIXME: 수정. 직업이 아닌 종목으로
44
public enum PortfolioType {
55
DEVELOP,
6-
ART,
6+
// ART,
77
}

src/main/java/org/sunday/projectpop/service/llm/LLMClient.java

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
import org.springframework.web.reactive.function.client.WebClient;
99
import reactor.core.publisher.Mono;
1010

11+
import java.util.HashMap;
1112
import java.util.List;
13+
import java.util.Map;
1214

1315
@Component
1416
public class LLMClient {
@@ -26,11 +28,31 @@ private WebClient createWebClient() {
2628
.build();
2729
}
2830

31+
// 토큰 수 확인
32+
public Mono<Integer> countTokens(String text) {
33+
Map<String, Object> requestBody = new HashMap<>();
34+
Map<String, Object> content = new HashMap<>();
35+
content.put("parts", new Object[]{Map.of("text", text)});
36+
requestBody.put("contents", new Object[]{content});
37+
38+
return createWebClient()
39+
.post()
40+
.uri(":countTokens?key=%s", apiKey)
41+
.bodyValue(requestBody)
42+
.retrieve()
43+
.bodyToMono(Map.class)
44+
.map(response -> (Integer) ((Map<?, ?>) response.get("usage")).get("totalTokens"))
45+
.onErrorResume(e -> {
46+
System.err.println("토큰 수 계산 중 오류 발생: " + e.getMessage());
47+
return Mono.error(e);
48+
});
49+
}
50+
2951
// LLM 피드백 요청
3052
public Mono<String> feedback(String content, String type) {
3153
return createWebClient()
3254
.post()
33-
.uri("?key=%s".formatted(apiKey))
55+
.uri(":generateContent?key=%s".formatted(apiKey))
3456
.bodyValue(buildFeedbackPrompt(content, type))
3557
.retrieve()
3658
.bodyToMono(GeminiResponse.class)
@@ -114,7 +136,7 @@ private GeminiRequest buildFeedbackPrompt(String content, String type) {
114136
public Mono<String> summarize(String content, String type) {
115137
return createWebClient()
116138
.post()
117-
.uri("?key=%s".formatted(apiKey))
139+
.uri(":generateContent?key=%s".formatted(apiKey))
118140
.bodyValue(buildSummaryPrompt(content, type))
119141
.retrieve()
120142
.bodyToMono(GeminiResponse.class)
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package org.sunday.projectpop.validator;
2+
3+
import jakarta.validation.Constraint;
4+
import jakarta.validation.ConstraintValidator;
5+
import jakarta.validation.ConstraintValidatorContext;
6+
import jakarta.validation.Payload;
7+
import org.springframework.web.multipart.MultipartFile;
8+
9+
import java.lang.annotation.ElementType;
10+
import java.lang.annotation.Retention;
11+
import java.lang.annotation.RetentionPolicy;
12+
import java.lang.annotation.Target;
13+
import java.util.List;
14+
15+
// 커스텀 어노테이션
16+
@Constraint(validatedBy = FileValidation.FileValidator.class)
17+
@Target({ElementType.FIELD})
18+
@Retention(RetentionPolicy.RUNTIME)
19+
public @interface FileValidation {
20+
21+
String message() default "유효하지 않은 파일 형식 또는 크기입니다.";
22+
23+
Class<?>[] groups() default {};
24+
25+
Class<? extends Payload>[] payload() default {};
26+
27+
// Inner validator class
28+
class FileValidator implements ConstraintValidator<FileValidation, List<MultipartFile>> {
29+
// 허용 파일 Type (MIME types)
30+
private static final List<String> ALLOWED_MIME_TYPES = List.of(
31+
"application/pdf",
32+
"text/markdown",
33+
"text/csv",
34+
"text/plain",
35+
"application/msword", // .doc
36+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document", // .docx
37+
"application/vnd.ms-excel", // .xls
38+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", // .xlsx
39+
"application/vnd.ms-powerpoint", // .ppt
40+
"application/vnd.openxmlformats-officedocument.presentationml.presentation" // .pptx
41+
);
42+
// MAX 파일 사이즈 (50MB)
43+
private static final long MAX_FILE_SIZE = 50 * 1024 * 1024; // 50MB
44+
45+
@Override
46+
public boolean isValid(List<MultipartFile> files, ConstraintValidatorContext context) {
47+
// 빈 파일 체크
48+
if (files == null || files.isEmpty()) {
49+
return true;
50+
}
51+
52+
for (MultipartFile file : files) {
53+
if (file.isEmpty()) continue;
54+
55+
// 파일 크기 체크
56+
if (file.getSize() > MAX_FILE_SIZE) {
57+
context.disableDefaultConstraintViolation();
58+
context.buildConstraintViolationWithTemplate("파일 크기는 50MB를 초과할 수 없습니다: " + file.getOriginalFilename())
59+
.addConstraintViolation();
60+
return false;
61+
}
62+
63+
// 파일 형식 체크
64+
String contentType = file.getContentType();
65+
if (contentType == null || !ALLOWED_MIME_TYPES.contains(contentType)) {
66+
context.disableDefaultConstraintViolation();
67+
context.buildConstraintViolationWithTemplate("지원되지 않는 파일 형식입니다: " + file.getOriginalFilename())
68+
.addConstraintViolation();
69+
return false;
70+
}
71+
}
72+
return true;
73+
}
74+
}
75+
}

0 commit comments

Comments
 (0)