Skip to content

Commit 91abd6a

Browse files
committed
TEST COMMIT : 간단한 api 긴급 추가용 test commit 입니다.
1 parent 098f1c2 commit 91abd6a

File tree

1 file changed

+169
-82
lines changed

1 file changed

+169
-82
lines changed

build.gradle

Lines changed: 169 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,96 +1,183 @@
1-
plugins {
2-
id 'java'
3-
id 'org.springframework.boot' version '3.3.6'
4-
id 'io.spring.dependency-management' version '1.1.7'
1+
package inha.gdgoc;
2+
3+
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
import org.springframework.beans.factory.annotation.Value;
6+
import org.springframework.http.MediaType;
7+
import org.springframework.web.bind.annotation.PostMapping;
8+
import org.springframework.web.bind.annotation.RequestBody;
9+
import org.springframework.web.bind.annotation.RequestMapping;
10+
import org.springframework.web.bind.annotation.RequestParam;
11+
import org.springframework.web.bind.annotation.RequestPart;
12+
import org.springframework.web.bind.annotation.RestController;
13+
import org.springframework.web.multipart.MultipartFile;
14+
import io.awspring.cloud.s3.S3Template;
15+
import java.net.URLEncoder;
16+
import java.nio.charset.StandardCharsets;
17+
import java.time.Instant;
18+
import java.util.Map;
19+
import java.util.UUID;
20+
21+
import jakarta.persistence.*;
22+
import org.springframework.data.jpa.repository.JpaRepository;
23+
import org.springframework.stereotype.Service;
24+
import org.springframework.transaction.annotation.Transactional;
25+
import java.time.LocalDateTime;
26+
import java.util.List;
27+
import java.util.stream.Collectors;
28+
29+
@SpringBootApplication
30+
public class GdgocApplication {
31+
32+
public static void main(String[] args) {
33+
// Ensure schema auto-creation if not explicitly configured (dev convenience)
34+
if (System.getProperty("spring.jpa.hibernate.ddl-auto") == null
35+
&& (System.getenv("SPRING_JPA_HIBERNATE_DDL_AUTO") == null || System.getenv("SPRING_JPA_HIBERNATE_DDL_AUTO").isBlank())) {
36+
System.setProperty("spring.jpa.hibernate.ddl-auto", "update");
37+
}
38+
SpringApplication.run(GdgocApplication.class, args);
39+
}
40+
541
}
642

7-
group = 'inha'
8-
version = '0.0.1-SNAPSHOT'
43+
@RestController
44+
@RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE)
45+
class InlineRecruitController {
946

10-
/* ===== Java Toolchain ===== */
11-
java {
12-
toolchain {
13-
languageVersion = JavaLanguageVersion.of(17)
14-
}
15-
}
47+
private final S3Template s3Template;
48+
private final String bucket;
49+
private final CoreRecruitService coreRecruitService;
1650

17-
/* ===== Configurations ===== */
18-
configurations {
19-
compileOnly {
20-
extendsFrom annotationProcessor
51+
InlineRecruitController(S3Template s3Template,
52+
@Value("${spring.cloud.aws.s3.bucket:gdgoc-fileupload}") String bucket,
53+
CoreRecruitService coreRecruitService) {
54+
this.s3Template = s3Template;
55+
this.bucket = bucket;
56+
this.coreRecruitService = coreRecruitService;
2157
}
22-
}
23-
24-
/* ===== Repositories ===== */
25-
repositories {
26-
mavenCentral()
27-
}
2858

29-
/* ===== Dependencies ===== */
30-
dependencies {
31-
// --- Spring Boot Starters ---
32-
implementation 'org.springframework.boot:spring-boot-starter-web'
33-
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
34-
implementation 'org.springframework.boot:spring-boot-starter-validation'
35-
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
36-
implementation 'org.springframework.boot:spring-boot-starter-mail'
37-
38-
// --- DB & JPA Utils ---
39-
implementation 'com.vladmihalcea:hibernate-types-60:2.21.1'
40-
implementation 'org.postgresql:postgresql:42.7.3'
41-
runtimeOnly 'com.h2database:h2' // 테스트/로컬용 인메모리 DB
42-
43-
// --- QueryDSL ---
44-
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
45-
annotationProcessor 'com.querydsl:querydsl-apt:5.0.0:jakarta'
46-
annotationProcessor 'jakarta.annotation:jakarta.annotation-api'
47-
annotationProcessor 'jakarta.persistence:jakarta.persistence-api'
48-
49-
// --- JWT (JJWT 0.9.x, 레거시 패키지) ---
50-
implementation 'io.jsonwebtoken:jjwt:0.9.1'
51-
52-
// --- AWS (S3) ---
53-
implementation 'io.awspring.cloud:spring-cloud-aws-starter-s3'
54-
55-
// --- Flyway (DB Migration) ---
56-
implementation "org.flywaydb:flyway-core:10.21.0"
57-
implementation "org.flywaydb:flyway-database-postgresql:10.21.0"
58-
59-
// --- 환경변수(.env) ---
60-
implementation 'io.github.cdimascio:java-dotenv:5.2.2'
61-
62-
// --- Lombok ---
63-
compileOnly 'org.projectlombok:lombok'
64-
annotationProcessor 'org.projectlombok:lombok'
65-
66-
// --- Test ---
67-
testImplementation 'org.springframework.boot:spring-boot-starter-test'
68-
testImplementation 'org.mockito:mockito-core:5.6.0'
69-
testImplementation 'org.mockito:mockito-junit-jupiter:5.6.0'
70-
testImplementation 'org.assertj:assertj-core:3.24.2'
71-
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
72-
73-
// swagger
74-
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.6.0'
75-
}
59+
// 1) 지원서 접수: POST /core-recruit
60+
@PostMapping(path = "/core-recruit", consumes = MediaType.APPLICATION_JSON_VALUE)
61+
public Map<String, Object> submitCoreRecruit(@RequestBody CoreRecruitRequest body) {
62+
Long id = coreRecruitService.save(body);
63+
return Map.of("id", id, "status", "OK");
64+
}
7665

77-
dependencyManagement {
78-
imports {
79-
mavenBom "io.awspring.cloud:spring-cloud-aws-dependencies:3.1.1"
80-
// ↑ 3.x 대 사용 (프로젝트에 맞는 최신 3.x 가능)
66+
// 2) 파일 업로드: POST /fileupload (multipart/form-data; field name = "file")
67+
@PostMapping(path = "/fileupload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
68+
public Map<String, String> upload(@RequestPart("file") MultipartFile file,
69+
@RequestParam(value = "folder", required = false) String folder) {
70+
try {
71+
if (s3Template == null || bucket == null || bucket.isBlank()) {
72+
throw new IllegalStateException("S3Template 또는 버킷 설정이 없습니다. (spring.cloud.aws.s3.bucket)");
73+
}
74+
String safeName = file.getOriginalFilename() == null ? "file" : file.getOriginalFilename();
75+
String key = (folder == null || folder.isBlank() ? "uploads" : folder)
76+
+ "/" + Instant.now().toEpochMilli()
77+
+ "_" + UUID.randomUUID()
78+
+ "_" + URLEncoder.encode(safeName, StandardCharsets.UTF_8);
79+
80+
s3Template.upload(bucket, key, file.getInputStream());
81+
String url = s3Template.createUrl(bucket, key).toString();
82+
return Map.of("url", url);
83+
} catch (Exception e) {
84+
throw new RuntimeException("파일 업로드 실패: " + e.getMessage(), e);
85+
}
8186
}
8287
}
8388

84-
/* ===== Tasks ===== */
85-
86-
// 테스트: 프로필과 JUnit 플랫폼 한 곳에서 설정
87-
tasks.test {
88-
useJUnitPlatform()
89-
systemProperty "spring.profiles.active", "test"
89+
// 단순 DTO (public 필드로 최소 구현; Lombok 불필요)
90+
class CoreRecruitRequest {
91+
public String name;
92+
public String studentId;
93+
public String phone;
94+
public String major;
95+
public String email;
96+
public String team;
97+
public String motivation;
98+
public String wish;
99+
public String strengths;
100+
public String pledge;
101+
public java.util.List<String> fileUrls;
90102
}
91103

92-
// QueryDSL 생성물 경로 고정
93-
tasks.withType(JavaCompile).configureEach {
94-
options.annotationProcessorGeneratedSourcesDirectory = file("build/generated/sources/annotationProcessor/java/main")
104+
@Entity
105+
@Table(name = "core_recruits")
106+
class CoreRecruit {
107+
@Id
108+
@GeneratedValue(strategy = GenerationType.IDENTITY)
109+
private Long id;
110+
111+
@Column(nullable = false) private String name;
112+
@Column(nullable = false) private String studentId;
113+
@Column(nullable = false) private String phone;
114+
@Column(nullable = false) private String major;
115+
@Column(nullable = false) private String email;
116+
@Column(nullable = false) private String team;
117+
@Column(nullable = false, length = 2000) private String motivation;
118+
@Column(nullable = false, length = 2000) private String wish;
119+
@Column(nullable = false, length = 2000) private String strengths;
120+
@Column(nullable = false, length = 2000) private String pledge;
121+
122+
// fileUrls는 간단히 '\n'으로 join하여 TEXT로 저장 (최소 변경)
123+
@Column(columnDefinition = "TEXT") private String fileUrlsJoined;
124+
125+
@Column(nullable = false) private LocalDateTime createdAt;
126+
127+
// getters/setters
128+
public Long getId() { return id; }
129+
public String getName() { return name; }
130+
public void setName(String name) { this.name = name; }
131+
public String getStudentId() { return studentId; }
132+
public void setStudentId(String studentId) { this.studentId = studentId; }
133+
public String getPhone() { return phone; }
134+
public void setPhone(String phone) { this.phone = phone; }
135+
public String getMajor() { return major; }
136+
public void setMajor(String major) { this.major = major; }
137+
public String getEmail() { return email; }
138+
public void setEmail(String email) { this.email = email; }
139+
public String getTeam() { return team; }
140+
public void setTeam(String team) { this.team = team; }
141+
public String getMotivation() { return motivation; }
142+
public void setMotivation(String motivation) { this.motivation = motivation; }
143+
public String getWish() { return wish; }
144+
public void setWish(String wish) { this.wish = wish; }
145+
public String getStrengths() { return strengths; }
146+
public void setStrengths(String strengths) { this.strengths = strengths; }
147+
public String getPledge() { return pledge; }
148+
public void setPledge(String pledge) { this.pledge = pledge; }
149+
public String getFileUrlsJoined() { return fileUrlsJoined; }
150+
public void setFileUrlsJoined(String fileUrlsJoined) { this.fileUrlsJoined = fileUrlsJoined; }
151+
public LocalDateTime getCreatedAt() { return createdAt; }
152+
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
95153
}
96154

155+
interface CoreRecruitRepository extends JpaRepository<CoreRecruit, Long> { }
156+
157+
@Service
158+
class CoreRecruitService {
159+
private final CoreRecruitRepository repo;
160+
CoreRecruitService(CoreRecruitRepository repo) { this.repo = repo; }
161+
162+
@Transactional
163+
public Long save(CoreRecruitRequest req) {
164+
CoreRecruit e = new CoreRecruit();
165+
e.setName(req.name);
166+
e.setStudentId(req.studentId);
167+
e.setPhone(req.phone);
168+
e.setMajor(req.major);
169+
e.setEmail(req.email);
170+
e.setTeam(req.team);
171+
e.setMotivation(req.motivation);
172+
e.setWish(req.wish);
173+
e.setStrengths(req.strengths);
174+
e.setPledge(req.pledge);
175+
if (req.fileUrls != null && !req.fileUrls.isEmpty()) {
176+
e.setFileUrlsJoined(req.fileUrls.stream().collect(Collectors.joining("\n")));
177+
} else {
178+
e.setFileUrlsJoined(null);
179+
}
180+
e.setCreatedAt(LocalDateTime.now());
181+
return repo.save(e).getId();
182+
}
183+
}

0 commit comments

Comments
 (0)