Skip to content

Commit e82390b

Browse files
committed
feat: 솜커톤 참가자 모집 API 생성
1 parent 47e2cc7 commit e82390b

File tree

10 files changed

+322
-4
lines changed

10 files changed

+322
-4
lines changed

src/main/java/dmu/dasom/api/domain/common/exception/ErrorCode.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public enum ErrorCode {
3636
SLOT_NOT_ACTIVE(400, "C027", "해당 슬롯이 비활성화 되었습니다."),
3737
FILE_ENCODE_FAIL(400, "C028", "파일 인코딩에 실패하였습니다."),
3838
RECRUITMENT_NOT_ACTIVE(400, "C029", "모집 기간이 아닙니다."),
39+
NOT_FOUND_PARTICIPANT(400, "C030", "참가자를 찾을 수 없습니다.")
3940
;
4041

4142
private final int status;
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package dmu.dasom.api.domain.interview.repositoty;
1+
package dmu.dasom.api.domain.interview.repository;
22

33
import dmu.dasom.api.domain.interview.entity.InterviewReservation;
44
import org.springframework.data.jpa.repository.JpaRepository;

src/main/java/dmu/dasom/api/domain/interview/repositoty/InterviewSlotRepository.java renamed to src/main/java/dmu/dasom/api/domain/interview/repository/InterviewSlotRepository.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package dmu.dasom.api.domain.interview.repositoty;
1+
package dmu.dasom.api.domain.interview.repository;
22

33
import dmu.dasom.api.domain.interview.entity.InterviewSlot;
44
import dmu.dasom.api.domain.interview.enums.InterviewStatus;

src/main/java/dmu/dasom/api/domain/interview/service/InterviewServiceImpl.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
import dmu.dasom.api.domain.interview.entity.InterviewReservation;
1111
import dmu.dasom.api.domain.interview.entity.InterviewSlot;
1212
import dmu.dasom.api.domain.interview.enums.InterviewStatus;
13-
import dmu.dasom.api.domain.interview.repositoty.InterviewReservationRepository;
14-
import dmu.dasom.api.domain.interview.repositoty.InterviewSlotRepository;
13+
import dmu.dasom.api.domain.interview.repository.InterviewReservationRepository;
14+
import dmu.dasom.api.domain.interview.repository.InterviewSlotRepository;
1515
import dmu.dasom.api.domain.recruit.service.RecruitServiceImpl;
1616
import jakarta.persistence.EntityListeners;
1717
import lombok.RequiredArgsConstructor;
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
package dmu.dasom.api.domain.somkathon.controller;
2+
3+
import dmu.dasom.api.domain.somkathon.dto.SomParticipantRequestDto;
4+
import dmu.dasom.api.domain.somkathon.dto.SomParticipantResponseDto;
5+
import dmu.dasom.api.domain.somkathon.service.SomParticipantService;
6+
import io.swagger.v3.oas.annotations.Operation;
7+
import io.swagger.v3.oas.annotations.media.Content;
8+
import io.swagger.v3.oas.annotations.media.ExampleObject;
9+
import io.swagger.v3.oas.annotations.media.Schema;
10+
import io.swagger.v3.oas.annotations.responses.ApiResponse;
11+
import io.swagger.v3.oas.annotations.responses.ApiResponses;
12+
import jakarta.validation.Valid;
13+
import lombok.RequiredArgsConstructor;
14+
import org.springframework.http.ResponseEntity;
15+
import org.springframework.web.ErrorResponse;
16+
import org.springframework.web.bind.annotation.*;
17+
18+
import java.util.List;
19+
20+
@RestController
21+
@RequestMapping("/api/participant")
22+
@RequiredArgsConstructor
23+
public class SomParticipantController {
24+
25+
private final SomParticipantService somParticipantService;
26+
27+
/**
28+
* 참가자 등록
29+
*/
30+
@Operation(summary = "솜커톤 참가자 등록", description = "솜커톤 참가자를 등록합니다.")
31+
@ApiResponses(value = {
32+
@ApiResponse(responseCode = "200", description = "참가자 등록 성공"),
33+
@ApiResponse(responseCode = "400", description = "중복 학번 또는 필수 값 누락",
34+
content = @Content(
35+
mediaType = "application/json",
36+
schema = @Schema(implementation = ErrorResponse.class),
37+
examples = {
38+
@ExampleObject(
39+
name = "중복된 학번",
40+
value = "{ \"code\": \"C002\", \"message\": \"이미 등록된 학번입니다.\" }"
41+
),
42+
@ExampleObject(
43+
name = "필수 값 누락",
44+
value = "{ \"code\": \"C001\", \"message\": \"요청한 값이 올바르지 않습니다.\" }"
45+
)}))})
46+
@PostMapping("/create")
47+
public ResponseEntity<SomParticipantResponseDto> create(@Valid @RequestBody final SomParticipantRequestDto request) {
48+
final SomParticipantResponseDto responseDto = somParticipantService.createParticipant(request);
49+
return ResponseEntity.ok(responseDto);
50+
}
51+
52+
/**
53+
* 모든 참가자 조회
54+
*/
55+
@Operation(summary = "솜커톤 참가자 목록 조회", description = "모든 솜커톤 참가자를 조회합니다.")
56+
@ApiResponses(value = {
57+
@ApiResponse(responseCode = "200", description = "참가자 목록 조회 성공")})
58+
@GetMapping
59+
public ResponseEntity<List<SomParticipantResponseDto>> findAll() {
60+
final List<SomParticipantResponseDto> participants = somParticipantService.getAllParticipants();
61+
return ResponseEntity.ok(participants);
62+
}
63+
64+
/**
65+
* 특정 참가자 조회
66+
*/
67+
@Operation(summary = "솜커톤 참가자 상세 조회", description = "특정 솜커톤 참가자의 상세 정보를 조회합니다.")
68+
@ApiResponses(value = {
69+
@ApiResponse(responseCode = "200", description = "참가자 상세 조회 성공"),
70+
@ApiResponse(responseCode = "400", description = "존재하지 않는 ID",
71+
content = @Content(
72+
mediaType = "application/json",
73+
schema = @Schema(implementation=ErrorResponse.class),
74+
examples={
75+
@ExampleObject(
76+
name="존재하지 않는 ID",
77+
value="{\"code\":\"C004\",\"message\":\"참가자를 찾을 수 없습니다.\"}")}))})
78+
@GetMapping("/{id}")
79+
public ResponseEntity<SomParticipantResponseDto> getById(@PathVariable final Long id) {
80+
final SomParticipantResponseDto responseDto = somParticipantService.getParticipant(id);
81+
return ResponseEntity.ok(responseDto);
82+
}
83+
84+
/**
85+
* 참가자 정보 수정
86+
*/
87+
@Operation(summary = "솜커톤 참가자 정보 수정", description = "특정 솜커톤 참가자의 정보를 수정합니다.")
88+
@ApiResponses(value = {
89+
@ApiResponse(responseCode = "200", description = "참가자 정보 수정 성공"),
90+
@ApiResponse(responseCode = "400", description = "중복 학번 또는 존재하지 않는 ID",
91+
content = @Content(
92+
mediaType = "application/json",
93+
schema=@Schema(implementation=ErrorResponse.class),
94+
examples={
95+
@ExampleObject(
96+
name="중복된 학번",
97+
value="{\"code\":\"C002\",\"message\":\"이미 등록된 학번입니다.\"}"),
98+
@ExampleObject(
99+
name="존재하지 않는 ID",
100+
value="{\"code\":\"C004\",\"message\":\"참가자를 찾을 수 없습니다.\"}")}))})
101+
@PutMapping("/{id}")
102+
public ResponseEntity<SomParticipantResponseDto> update(@PathVariable final Long id,
103+
@Valid @RequestBody final SomParticipantRequestDto request) {
104+
final SomParticipantResponseDto responseDto = somParticipantService.updateParticipant(id, request);
105+
return ResponseEntity.ok(responseDto);
106+
}
107+
108+
/**
109+
* 참가자 삭제 (Delete)
110+
*/
111+
@Operation(summary = "솜커톤 참가자 삭제", description = "특정 솜커톤 참가자를 삭제합니다.")
112+
@ApiResponses(value={
113+
@ApiResponse(responseCode="204",description="참가자 삭제 성공"),
114+
@ApiResponse(responseCode="400",description="존재하지 않는 ID",
115+
content=@Content(
116+
mediaType="application/json",
117+
schema=@Schema(implementation=ErrorResponse.class),
118+
examples={
119+
@ExampleObject(
120+
name="존재하지 않는 ID",
121+
value="{\"code\":\"C004\",\"message\":\"참가자를 찾을 수 없습니다.\"}")}))})
122+
@DeleteMapping("/{id}")
123+
public ResponseEntity<Void> delete(@PathVariable final Long id) {
124+
somParticipantService.deleteParticipant(id);
125+
return ResponseEntity.noContent().build();
126+
}
127+
128+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package dmu.dasom.api.domain.somkathon.dto;
2+
3+
import lombok.Getter;
4+
import lombok.Setter;
5+
6+
@Getter
7+
@Setter
8+
public class SomParticipantRequestDto {
9+
private String participantName; // 참가자 이름
10+
private String studentId;
11+
private String department; // 학과
12+
private String grade; // 학년
13+
private String contact; // 연락처
14+
private String email; // 이메일
15+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package dmu.dasom.api.domain.somkathon.dto;
2+
3+
import dmu.dasom.api.domain.somkathon.entity.SomParticipant;
4+
import lombok.Builder;
5+
import lombok.Getter;
6+
import lombok.Setter;
7+
8+
@Getter
9+
@Setter
10+
@Builder
11+
public class SomParticipantResponseDto {
12+
private Long id; // 참가자 ID
13+
private String participantName; // 참가자 이름
14+
private String studentId; // 학번
15+
private String department; // 학과
16+
private String grade; // 학년
17+
private String contact; // 연락처
18+
private String email; // 이메일
19+
20+
21+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package dmu.dasom.api.domain.somkathon.entity;
2+
3+
import dmu.dasom.api.domain.common.BaseEntity;
4+
import jakarta.persistence.*;
5+
import lombok.AllArgsConstructor;
6+
import lombok.Builder;
7+
import lombok.Getter;
8+
import lombok.NoArgsConstructor;
9+
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
10+
11+
@AllArgsConstructor
12+
@Builder
13+
@Entity
14+
@EntityListeners(AuditingEntityListener.class)
15+
@Getter
16+
@NoArgsConstructor
17+
public class SomParticipant extends BaseEntity {
18+
19+
@Id
20+
@GeneratedValue(strategy = GenerationType.IDENTITY)
21+
private Long id;
22+
23+
@Column(nullable = false)
24+
private String participantName; // 참가자 이름
25+
26+
@Column(nullable = false, unique = true)
27+
private String studentId; // 학번
28+
29+
@Column(nullable = false)
30+
private String department; // 학과
31+
32+
@Column(nullable = false)
33+
private String grade; // 학년
34+
35+
@Column(nullable = false)
36+
private String contact; // 연락처
37+
38+
@Column(nullable = false)
39+
private String email; // 이메일
40+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package dmu.dasom.api.domain.somkathon.repository;
2+
3+
import dmu.dasom.api.domain.somkathon.entity.SomParticipant;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
import org.springframework.stereotype.Repository;
6+
7+
import java.util.Optional;
8+
9+
@Repository
10+
public interface SomParticipantRepository extends JpaRepository<SomParticipant, Long> {
11+
Optional<SomParticipant> findByStudentId(String studentId); // 학번으로 참가자 조회
12+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package dmu.dasom.api.domain.somkathon.service;
2+
3+
import dmu.dasom.api.domain.common.exception.CustomException;
4+
import dmu.dasom.api.domain.common.exception.ErrorCode;
5+
import dmu.dasom.api.domain.somkathon.dto.SomParticipantRequestDto;
6+
import dmu.dasom.api.domain.somkathon.dto.SomParticipantResponseDto;
7+
import dmu.dasom.api.domain.somkathon.entity.SomParticipant;
8+
import dmu.dasom.api.domain.somkathon.repository.SomParticipantRepository;
9+
import lombok.RequiredArgsConstructor;
10+
import org.springframework.stereotype.Service;
11+
12+
import java.util.List;
13+
import java.util.stream.Collectors;
14+
15+
@Service
16+
@RequiredArgsConstructor
17+
public class SomParticipantService {
18+
private final SomParticipantRepository somParticipantRepository;
19+
20+
// 참가자 등록
21+
public SomParticipantResponseDto createParticipant(SomParticipantRequestDto requestDto) {
22+
if(somParticipantRepository.findByStudentId(requestDto.getStudentId()).isPresent()) {
23+
throw new CustomException(ErrorCode.DUPLICATED_STUDENT_NO);
24+
}
25+
26+
SomParticipant participant = SomParticipant.builder()
27+
.participantName(requestDto.getParticipantName())
28+
.studentId(requestDto.getStudentId())
29+
.department(requestDto.getDepartment())
30+
.grade(requestDto.getGrade())
31+
.contact(requestDto.getContact())
32+
.email(requestDto.getEmail())
33+
.build();
34+
35+
SomParticipant saved = somParticipantRepository.save(participant);
36+
37+
return toResponseDto(saved);
38+
}
39+
40+
/**
41+
* 모든 참가자 조회 (Read)
42+
*/
43+
public List<SomParticipantResponseDto> getAllParticipants() {
44+
return somParticipantRepository.findAll().stream()
45+
.map(this::toResponseDto)
46+
.collect(Collectors.toList());
47+
}
48+
49+
/**
50+
* 특정 참가자 조회 (Read)
51+
*/
52+
public SomParticipantResponseDto getParticipant(Long id){
53+
SomParticipant participant = somParticipantRepository.findById(id).orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_PARTICIPANT));
54+
55+
return toResponseDto(participant);
56+
}
57+
58+
public SomParticipantResponseDto updateParticipant(Long id, SomParticipantRequestDto requestDto){
59+
SomParticipant participant = somParticipantRepository.findById(id).orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_PARTICIPANT));
60+
61+
participant = SomParticipant.builder()
62+
.id(participant.getId())
63+
.participantName(requestDto.getParticipantName())
64+
.studentId(requestDto.getStudentId())
65+
.department(requestDto.getDepartment())
66+
.grade(requestDto.getGrade())
67+
.contact(requestDto.getContact())
68+
.email(requestDto.getEmail())
69+
.build();
70+
71+
SomParticipant updated = somParticipantRepository.save(participant);
72+
73+
return toResponseDto(updated);
74+
}
75+
76+
/**
77+
* 참가자 삭제 (Delete)
78+
*/
79+
public void deleteParticipant(Long id) {
80+
if (!somParticipantRepository.existsById(id)) {
81+
throw new RuntimeException("참가자를 찾을 수 없습니다.");
82+
}
83+
somParticipantRepository.deleteById(id);
84+
}
85+
86+
87+
/**
88+
* Entity → Response DTO 변환 메서드
89+
*/
90+
private SomParticipantResponseDto toResponseDto(SomParticipant participant) {
91+
return SomParticipantResponseDto.builder()
92+
.id(participant.getId())
93+
.participantName(participant.getParticipantName())
94+
.studentId(participant.getStudentId())
95+
.department(participant.getDepartment())
96+
.grade(participant.getGrade())
97+
.contact(participant.getContact())
98+
.email(participant.getEmail())
99+
.build();
100+
}
101+
}

0 commit comments

Comments
 (0)