diff --git a/recruitment-service/build.gradle b/recruitment-service/build.gradle index fc713c2..176a78b 100644 --- a/recruitment-service/build.gradle +++ b/recruitment-service/build.gradle @@ -1,7 +1,7 @@ plugins { id 'java' - id 'org.springframework.boot' version '3.4.5' - id 'io.spring.dependency-management' version '1.1.7' + id 'org.springframework.boot' version '3.1.5' + id 'io.spring.dependency-management' version '1.1.3' } group = 'com.example' @@ -28,6 +28,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-validation' + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0' compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' runtimeOnly 'com.mysql:mysql-connector-j' diff --git a/recruitment-service/src/main/java/com/example/recruitment/controller/RecruitmentController.java b/recruitment-service/src/main/java/com/example/recruitment/controller/RecruitmentController.java index f595bc3..9e15016 100644 --- a/recruitment-service/src/main/java/com/example/recruitment/controller/RecruitmentController.java +++ b/recruitment-service/src/main/java/com/example/recruitment/controller/RecruitmentController.java @@ -2,15 +2,13 @@ import com.example.recruitment.dto.RecruitmentDetailDto; import com.example.recruitment.dto.RecruitmentRequestDto; +import com.example.recruitment.dto.order.OrderRequestDto; import com.example.recruitment.entity.Recruitment; import com.example.recruitment.entity.RecruitmentParticipant; -import com.example.recruitment.entity.Store; import com.example.recruitment.entity.User; import com.example.recruitment.repository.RecruitmentParticipantRepository; import com.example.recruitment.repository.RecruitmentRepository; -import com.example.recruitment.repository.StoreRepository; -import com.example.recruitment.repository.UserRepository; - +import com.example.recruitment.service.RecruitmentService; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; @@ -21,29 +19,27 @@ @RestController @RequiredArgsConstructor -@RequestMapping("/api/recruitments") +@RequestMapping("/api/v1/recruitments") public class RecruitmentController { + private final RecruitmentService recruitmentService; private final RecruitmentRepository recruitmentRepository; - private final UserRepository userRepository; - private final StoreRepository storeRepository; private final RecruitmentParticipantRepository participantRepository; - // 모집글 생성 + //모집글 생성 (Order 서버에 주문 생성 포함) @PostMapping - public Recruitment createRecruitment(@Valid @RequestBody RecruitmentRequestDto dto) { - User user = userRepository.findById(dto.getUserId()).orElseThrow(); - Store store = storeRepository.findById(dto.getStoreId()).orElseThrow(); - - Recruitment recruitment = new Recruitment(); - recruitment.setUser(user); - recruitment.setStore(store); - recruitment.setTitle(dto.getTitle()); - recruitment.setDescription(dto.getDescription()); - recruitment.setDeadlineTime(dto.getDeadlineTime()); - recruitment.setStatus("RECRUITING"); + public ResponseEntity createRecruitment(@Valid @RequestBody RecruitmentRequestDto dto) { + recruitmentService.createRecruitment(dto); + return ResponseEntity.ok("모집글 생성 완료"); + } - return recruitmentRepository.save(recruitment); + //모집글 참여 (Order 서버에 주문 생성 포함) + @PostMapping("/{recruitmentId}/join") + public ResponseEntity joinRecruitment(@PathVariable Long recruitmentId, + @RequestParam Long userId, + @RequestBody OrderRequestDto orderRequestDto) { + recruitmentService.joinRecruitment(recruitmentId, userId, orderRequestDto); + return ResponseEntity.ok("모집글 참여 완료"); } // 모집글 전체 조회 @@ -52,84 +48,56 @@ public List getAll() { return recruitmentRepository.findAll(); } - // 상태별 조회 (ex. /api/recruitments?status=RECRUITING) + // 상태별 조회 @GetMapping(params = "status") public List getByStatus(@RequestParam String status) { return recruitmentRepository.findByStatus(status); } + // 모집글 상세 조회 @GetMapping("/{recruitmentId}") -public ResponseEntity getRecruitmentDetail(@PathVariable Long recruitmentId) { - Recruitment recruitment = recruitmentRepository.findById(recruitmentId).orElseThrow(); - - // 참여자 목록 조회 - List participantEntities = - participantRepository.findByRecruitmentId(recruitmentId); - - List participants = participantEntities.stream() - .map(RecruitmentParticipant::getUser) - .toList(); - - // DTO 구성 - RecruitmentDetailDto dto = new RecruitmentDetailDto(); - dto.setId(recruitment.getId()); - dto.setTitle(recruitment.getTitle()); - dto.setDescription(recruitment.getDescription()); - dto.setStatus(recruitment.getStatus()); - dto.setDeadlineTime(recruitment.getDeadlineTime()); - dto.setUser(recruitment.getUser()); - dto.setStore(recruitment.getStore()); - dto.setParticipants(participants); - - return ResponseEntity.ok(dto); -} - - @GetMapping("/user/{userId}/created-recruitments") -public List getRecruitmentsCreatedByUser(@PathVariable Long userId) { - return recruitmentRepository.findByUserId(userId); -} - -// 특정 유저가 참여한 모집글 조회 - @GetMapping("/user/{userId}/joined-recruitments") -public List getRecruitmentsJoinedByUser(@PathVariable Long userId) { - List participantList = participantRepository.findByUserId(userId); - return participantList.stream() - .map(RecruitmentParticipant::getRecruitment) - .toList(); -} - - - - - // 모집글 참여 - @PostMapping("/{recruitmentId}/join") - public ResponseEntity joinRecruitment(@PathVariable Long recruitmentId, @RequestParam Long userId) { - User user = userRepository.findById(userId).orElseThrow(); + public ResponseEntity getRecruitmentDetail(@PathVariable Long recruitmentId) { Recruitment recruitment = recruitmentRepository.findById(recruitmentId).orElseThrow(); - boolean alreadyJoined = participantRepository - .findByUserIdAndRecruitmentId(userId, recruitmentId) - .isPresent(); - - if (alreadyJoined) { - return ResponseEntity.badRequest().body("이미 참여한 모집입니다."); - } + List participants = + participantRepository.findByRecruitmentId(recruitmentId); + List participantUsers = participants.stream() + .map(RecruitmentParticipant::getUser) + .toList(); + + RecruitmentDetailDto dto = new RecruitmentDetailDto(); + dto.setId(recruitment.getId()); + dto.setTitle(recruitment.getTitle()); + dto.setDescription(recruitment.getDescription()); + dto.setStatus(recruitment.getStatus()); + dto.setDeadlineTime(recruitment.getDeadlineTime()); + dto.setUser(recruitment.getUser()); + dto.setStore(recruitment.getStore()); + dto.setParticipants(participantUsers); + + return ResponseEntity.ok(dto); + } - RecruitmentParticipant participant = new RecruitmentParticipant(); - participant.setUser(user); - participant.setRecruitment(recruitment); - participant.setJoinedAt(LocalDateTime.now()); + // 유저가 만든 모집글 + @GetMapping("/user/{userId}/created-recruitments") + public List getRecruitmentsCreatedByUser(@PathVariable Long userId) { + return recruitmentRepository.findByUserId(userId); + } - participantRepository.save(participant); - return ResponseEntity.ok("모집글 참여 완료"); + // 유저가 참여한 모집글 + @GetMapping("/user/{userId}/joined-recruitments") + public List getRecruitmentsJoinedByUser(@PathVariable Long userId) { + List participantList = participantRepository.findByUserId(userId); + return participantList.stream() + .map(RecruitmentParticipant::getRecruitment) + .toList(); } - // 모집 상태 업데이트 (CONFIRMED 또는 FAILED) + // 모집 상태 업데이트 @PatchMapping("/{recruitmentId}/status") public ResponseEntity updateRecruitmentStatus(@PathVariable Long recruitmentId) { Recruitment recruitment = recruitmentRepository.findById(recruitmentId).orElseThrow(); LocalDateTime now = LocalDateTime.now(); - long participantCount = participantRepository.countByRecruitmentId(recruitmentId); if (now.isAfter(recruitment.getDeadlineTime())) { @@ -145,68 +113,56 @@ public ResponseEntity updateRecruitmentStatus(@PathVariable Long recruitmentI } } - // 주문 수락 상태로 변경 (ACCEPTED) + // 주문 수락 상태 변경 @PatchMapping("/{recruitmentId}/accept") public ResponseEntity acceptRecruitment(@PathVariable Long recruitmentId) { Recruitment recruitment = recruitmentRepository.findById(recruitmentId).orElseThrow(); - if (!"CONFIRMED".equals(recruitment.getStatus())) { return ResponseEntity.badRequest().body("주문 수락은 CONFIRMED 상태에서만 가능합니다."); } - recruitment.setStatus("ACCEPTED"); recruitmentRepository.save(recruitment); - return ResponseEntity.ok("상태가 ACCEPTED로 변경되었습니다."); } - // 배달 완료 상태로 변경 (DELIVERED) + // 배달 완료 상태 변경 @PatchMapping("/{recruitmentId}/deliver") public ResponseEntity completeDelivery(@PathVariable Long recruitmentId) { Recruitment recruitment = recruitmentRepository.findById(recruitmentId).orElseThrow(); - if (!"ACCEPTED".equals(recruitment.getStatus())) { return ResponseEntity.badRequest().body("배달 완료는 ACCEPTED 상태에서만 가능합니다."); } - recruitment.setStatus("DELIVERED"); recruitmentRepository.save(recruitment); - return ResponseEntity.ok("상태가 DELIVERED로 변경되었습니다."); } -// 모집글 삭제 - @DeleteMapping("/{recruitmentId}") -public ResponseEntity deleteRecruitment(@PathVariable Long recruitmentId) { - Recruitment recruitment = recruitmentRepository.findById(recruitmentId).orElseThrow(); - - recruitmentRepository.delete(recruitment); - return ResponseEntity.ok("모집글이 삭제되었습니다."); -} - -// 모집글 수정 -@PutMapping("/{recruitmentId}") -public ResponseEntity updateRecruitment(@PathVariable Long recruitmentId, - @Valid @RequestBody RecruitmentRequestDto dto) { - Recruitment recruitment = recruitmentRepository.findById(recruitmentId).orElseThrow(); - // (선택) 본인 작성한 글인지 확인 - if (!recruitment.getUser().getId().equals(dto.getUserId())) { - return ResponseEntity.status(403).body("작성자만 수정할 수 있습니다."); + // 모집글 삭제 + @DeleteMapping("/{recruitmentId}") + public ResponseEntity deleteRecruitment(@PathVariable Long recruitmentId) { + Recruitment recruitment = recruitmentRepository.findById(recruitmentId).orElseThrow(); + recruitmentRepository.delete(recruitment); + return ResponseEntity.ok("모집글이 삭제되었습니다."); } - // 수정할 항목들 업데이트 - recruitment.setTitle(dto.getTitle()); - recruitment.setDescription(dto.getDescription()); - recruitment.setDeadlineTime(dto.getDeadlineTime()); + // 모집글 수정 + @PutMapping("/{recruitmentId}") + public ResponseEntity updateRecruitment(@PathVariable Long recruitmentId, + @Valid @RequestBody RecruitmentRequestDto dto) { + Recruitment recruitment = recruitmentRepository.findById(recruitmentId).orElseThrow(); + if (!recruitment.getUser().getId().equals(dto.getUserId())) { + return ResponseEntity.status(403).body("작성자만 수정할 수 있습니다."); + } - // (선택) 가게 변경도 허용 - if (dto.getStoreId() != null) { - Store store = storeRepository.findById(dto.getStoreId()).orElseThrow(); - recruitment.setStore(store); - } + recruitment.setTitle(dto.getTitle()); + recruitment.setDescription(dto.getDescription()); + recruitment.setDeadlineTime(dto.getDeadlineTime()); - recruitmentRepository.save(recruitment); - return ResponseEntity.ok("모집글이 수정되었습니다."); -} + if (dto.getStoreId() != null) { + recruitment.setStore(recruitment.getStore()); + } + recruitmentRepository.save(recruitment); + return ResponseEntity.ok("모집글이 수정되었습니다."); + } } diff --git a/recruitment-service/src/main/java/com/example/recruitment/controller/SwaggerTestController.java b/recruitment-service/src/main/java/com/example/recruitment/controller/SwaggerTestController.java new file mode 100644 index 0000000..ec9233a --- /dev/null +++ b/recruitment-service/src/main/java/com/example/recruitment/controller/SwaggerTestController.java @@ -0,0 +1,14 @@ +package com.example.recruitment.controller; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/swagger-test") +public class SwaggerTestController { + @GetMapping + public String test() { + return "Swagger works!"; + } +} diff --git a/recruitment-service/src/main/java/com/example/recruitment/dto/RecruitmentRequestDto.java b/recruitment-service/src/main/java/com/example/recruitment/dto/RecruitmentRequestDto.java index d2e5f2e..a97aa2c 100644 --- a/recruitment-service/src/main/java/com/example/recruitment/dto/RecruitmentRequestDto.java +++ b/recruitment-service/src/main/java/com/example/recruitment/dto/RecruitmentRequestDto.java @@ -1,13 +1,14 @@ package com.example.recruitment.dto; +import com.example.recruitment.dto.order.OrderRequestDto; +import lombok.Getter; +import lombok.Setter; + import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; - import java.time.LocalDateTime; - -import lombok.Getter; -import lombok.Setter; +import java.util.List; @Getter @Setter @@ -27,25 +28,19 @@ public class RecruitmentRequestDto { @NotNull(message = "마감 시간은 필수입니다.") private LocalDateTime deadlineTime; -} - - -//원래 dto 코드 -/* - * package com.example.recruitment.dto; + @NotBlank(message = "카테고리는 비어 있을 수 없습니다.") + private String category; -import java.time.LocalDateTime; + // 주문용 메뉴 정보 + private List menus; -import lombok.Getter; -import lombok.Setter; - -@Getter @Setter -public class RecruitmentRequestDto { - private Long userId; - private Long storeId; - private String title; - private String description; - private LocalDateTime deadlineTime; + //OrderRequestDto 변환 메서드 + public OrderRequestDto toOrderRequestDto() { + OrderRequestDto dto = new OrderRequestDto(); + dto.setUserId(this.userId); + dto.setStoreId(this.storeId); + dto.setMenus(this.menus); + return dto; + } } - */ diff --git a/recruitment-service/src/main/java/com/example/recruitment/dto/order/OrderRequestDto.java b/recruitment-service/src/main/java/com/example/recruitment/dto/order/OrderRequestDto.java new file mode 100644 index 0000000..c948a2f --- /dev/null +++ b/recruitment-service/src/main/java/com/example/recruitment/dto/order/OrderRequestDto.java @@ -0,0 +1,32 @@ +package com.example.recruitment.dto.order; + +import java.util.List; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter + +public class OrderRequestDto { + private Long groupId; + private Long userId; + private Long storeId; + private List menus; + + @Getter @Setter + public static class MenuDto { + private Long menuId; + private String menuName; + private int basePrice; + private int count; + private List options; + } + + @Getter @Setter + public static class OptionDto { + private Long optionId; + private String optionName; + private int price; + } +} diff --git a/recruitment-service/src/main/java/com/example/recruitment/dto/order/OrderResponseDto.java b/recruitment-service/src/main/java/com/example/recruitment/dto/order/OrderResponseDto.java new file mode 100644 index 0000000..c5e64b9 --- /dev/null +++ b/recruitment-service/src/main/java/com/example/recruitment/dto/order/OrderResponseDto.java @@ -0,0 +1,10 @@ +package com.example.recruitment.dto.order; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class OrderResponseDto { + private Long orderId; +} diff --git a/recruitment-service/src/main/java/com/example/recruitment/entity/Recruitment.java b/recruitment-service/src/main/java/com/example/recruitment/entity/Recruitment.java index 3bf93ef..6c1b1ff 100644 --- a/recruitment-service/src/main/java/com/example/recruitment/entity/Recruitment.java +++ b/recruitment-service/src/main/java/com/example/recruitment/entity/Recruitment.java @@ -4,6 +4,7 @@ import lombok.*; import java.time.LocalDateTime; +import java.util.ArrayList; import java.util.List; @Entity @@ -24,9 +25,25 @@ public class Recruitment { @OneToMany(mappedBy = "recruitment", cascade = CascadeType.ALL, orphanRemoval = true) private List participants; - private String title; private String description; + private String status; // RECRUITING, CONFIRMED 등 + private LocalDateTime deadlineTime; + + //카테고리 추가가 + @Column(nullable = false) + private String category; + + @Column(name = "order_id") + private Long orderId; + + @ElementCollection + private List orderIds = new ArrayList<>(); + + public void addOrderId(Long orderId) { + this.orderIds.add(orderId); +} + } diff --git a/recruitment-service/src/main/java/com/example/recruitment/entity/RecruitmentParticipant.java b/recruitment-service/src/main/java/com/example/recruitment/entity/RecruitmentParticipant.java index 36be138..23b03cd 100644 --- a/recruitment-service/src/main/java/com/example/recruitment/entity/RecruitmentParticipant.java +++ b/recruitment-service/src/main/java/com/example/recruitment/entity/RecruitmentParticipant.java @@ -26,5 +26,8 @@ public class RecruitmentParticipant { @Column(name = "joined_at", nullable = false) private LocalDateTime joinedAt; + + @Column(name = "order_id") + private Long orderId; } diff --git a/recruitment-service/src/main/java/com/example/recruitment/exception/GlobalExceptionHandler.java b/recruitment-service/src/main/java/com/example/recruitment/exception/GlobalExceptionHandler.java index 2b29798..dd5a88a 100644 --- a/recruitment-service/src/main/java/com/example/recruitment/exception/GlobalExceptionHandler.java +++ b/recruitment-service/src/main/java/com/example/recruitment/exception/GlobalExceptionHandler.java @@ -1,13 +1,13 @@ package com.example.recruitment.exception; +import com.example.recruitment.common.ApiResponse; +import com.example.recruitment.common.FieldErrorDetail; +import jakarta.servlet.http.HttpServletRequest; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; -import com.example.recruitment.common.ApiResponse; -import com.example.recruitment.common.FieldErrorDetail; - import java.util.List; @RestControllerAdvice @@ -21,7 +21,7 @@ public ResponseEntity> handleCustomException(CustomException .body(ApiResponse.fail(ec.getCode(), ec.getMessage(), ec.getStatus())); } - //유효성 검사 실패 + // 유효성 검사 실패 @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity> handleValidationException(MethodArgumentNotValidException e) { List errorList = e.getBindingResult().getFieldErrors() @@ -34,8 +34,15 @@ public ResponseEntity> handleValidationException(MethodArgum .body(ApiResponse.validationFail(errorList)); } + // 그 외 모든 예외 처리 @ExceptionHandler(Exception.class) - public ResponseEntity> handleGeneralException(Exception e) { + public ResponseEntity> handleGeneralException(Exception e, HttpServletRequest request) throws Exception { + String path = request.getRequestURI(); + + if (path != null && (path.contains("/v3/api-docs") || path.contains("/swagger"))) { + throw e; // Swagger 요청은 예외 처리하지 않고 Spring에게 맡김 +} + return ResponseEntity .status(ErrorCode.INTERNAL_ERROR.getStatus()) .body(ApiResponse.fail( @@ -45,5 +52,3 @@ public ResponseEntity> handleGeneralException(Exception e) { )); } } - - diff --git a/recruitment-service/src/main/java/com/example/recruitment/repository/RecruitmentParticipantRepository.java b/recruitment-service/src/main/java/com/example/recruitment/repository/RecruitmentParticipantRepository.java index f468437..0e371bf 100644 --- a/recruitment-service/src/main/java/com/example/recruitment/repository/RecruitmentParticipantRepository.java +++ b/recruitment-service/src/main/java/com/example/recruitment/repository/RecruitmentParticipantRepository.java @@ -1,21 +1,26 @@ package com.example.recruitment.repository; +import com.example.recruitment.entity.Recruitment; import com.example.recruitment.entity.RecruitmentParticipant; +import com.example.recruitment.entity.User; + import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; import java.util.Optional; public interface RecruitmentParticipantRepository extends JpaRepository { - // 특정 유저가 특정 모집글에 이미 참여했는지 확인 + + // 특정 유저가 특정 모집글에 이미 참여했는지 확인 Optional findByUserIdAndRecruitmentId(Long userId, Long recruitmentId); - // 특정 모집글에 참여한 인원 수 카운트 + // 특정 모집글에 참여한 인원 수 카운트 long countByRecruitmentId(Long recruitmentId); List findByRecruitmentId(Long recruitmentId); - List findByUserId(Long userId); - + List findByUserId(Long userId); + //참여 여부 확인 메서드 + boolean existsByRecruitmentAndUser(Recruitment recruitment, User user); } diff --git a/recruitment-service/src/main/java/com/example/recruitment/service/OrderClient.java b/recruitment-service/src/main/java/com/example/recruitment/service/OrderClient.java new file mode 100644 index 0000000..0921560 --- /dev/null +++ b/recruitment-service/src/main/java/com/example/recruitment/service/OrderClient.java @@ -0,0 +1,40 @@ +package com.example.recruitment.service; + +import com.example.recruitment.dto.order.OrderRequestDto; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import java.util.Map; + +@Service +public class OrderClient { + + private final RestTemplate restTemplate = new RestTemplate(); + + //직접 값 선언 + private final String serverUrl = "http://54.66.149.225:8100"; + private final String path = "/api/v1/orders"; + + public Long createOrder(OrderRequestDto requestDto) { + String fullUrl = serverUrl + path; + + ResponseEntity response = restTemplate.postForEntity(fullUrl, requestDto, Map.class); + + if (response.getStatusCode().is2xxSuccessful()) { + Map responseBody = response.getBody(); + + if (responseBody != null && responseBody.containsKey("data")) { + Map data = (Map) responseBody.get("data"); + + if (data != null && data.containsKey("orderId")) { + return Long.valueOf(data.get("orderId").toString()); + } + } + + throw new RuntimeException("응답에 orderId 없음"); + } + + throw new RuntimeException("주문 생성 실패: " + response.getStatusCode()); + } +} diff --git a/recruitment-service/src/main/java/com/example/recruitment/service/RecruitmentService.java b/recruitment-service/src/main/java/com/example/recruitment/service/RecruitmentService.java new file mode 100644 index 0000000..7b96fc9 --- /dev/null +++ b/recruitment-service/src/main/java/com/example/recruitment/service/RecruitmentService.java @@ -0,0 +1,92 @@ +package com.example.recruitment.service; + +import com.example.recruitment.dto.RecruitmentRequestDto; +import com.example.recruitment.dto.order.OrderRequestDto; +import com.example.recruitment.entity.Recruitment; +import com.example.recruitment.entity.RecruitmentParticipant; +import com.example.recruitment.entity.Store; +import com.example.recruitment.entity.User; +import com.example.recruitment.repository.RecruitmentParticipantRepository; +import com.example.recruitment.repository.RecruitmentRepository; +import com.example.recruitment.repository.StoreRepository; +import com.example.recruitment.repository.UserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +public class RecruitmentService { + + private final RecruitmentRepository recruitmentRepository; + private final UserRepository userRepository; + private final StoreRepository storeRepository; + private final RecruitmentParticipantRepository participantRepository; + private final OrderClient orderClient; // 주문 서버와 통신할 client + + /** + * 모집글 생성 시: + * - 사용자 및 가게 조회 + * - 모집글 저장 + * - 주문 서버에 주문 생성 요청 + * - 생성된 orderId를 모집글에 저장 + */ + @Transactional + public void createRecruitment(RecruitmentRequestDto dto) { + User user = userRepository.findById(dto.getUserId()) + .orElseThrow(() -> new RuntimeException("사용자 없음")); + Store store = storeRepository.findById(dto.getStoreId()) + .orElseThrow(() -> new RuntimeException("가게 없음")); + + Recruitment recruitment = new Recruitment(); + recruitment.setUser(user); + recruitment.setStore(store); + recruitment.setTitle(dto.getTitle()); + recruitment.setDescription(dto.getDescription()); + recruitment.setDeadlineTime(dto.getDeadlineTime()); + recruitment.setStatus("RECRUITING"); + recruitment.setCategory(dto.getCategory()); + recruitmentRepository.save(recruitment); + + // 주문 서버에 주문 생성 요청 + OrderRequestDto orderDto = dto.toOrderRequestDto(); + orderDto.setGroupId(recruitment.getId()); + Long orderId = orderClient.createOrder(orderDto); + + // orderId를 모집글에 저장 + recruitment.setOrderId(orderId); + recruitmentRepository.save(recruitment); + } + + /** + * 모집글 참여 시: + * - 사용자 및 모집글 조회 + * - 중복 참여 여부 확인 + * - 주문 서버에 주문 생성 요청 + * - 생성된 orderId를 RecruitmentParticipant에 저장 + */ + @Transactional + public void joinRecruitment(Long recruitmentId, Long userId, OrderRequestDto orderDto) { + Recruitment recruitment = recruitmentRepository.findById(recruitmentId) + .orElseThrow(() -> new RuntimeException("모집 없음")); + User user = userRepository.findById(userId) + .orElseThrow(() -> new RuntimeException("사용자 없음")); + + boolean alreadyJoined = participantRepository.existsByRecruitmentAndUser(recruitment, user); + if (alreadyJoined) { + throw new RuntimeException("이미 참여한 모집입니다."); + } + + // 주문 서버에 주문 생성 요청 + orderDto.setGroupId(recruitmentId); + orderDto.setUserId(userId); + Long orderId = orderClient.createOrder(orderDto); + + // 참여자 등록 + 주문 ID 저장 + RecruitmentParticipant participant = new RecruitmentParticipant(); + participant.setRecruitment(recruitment); + participant.setUser(user); + participant.setOrderId(orderId); + participantRepository.save(participant); + } +} diff --git a/recruitment-service/src/main/resources/application.properties b/recruitment-service/src/main/resources/application.properties index 68e1557..dad7e22 100644 --- a/recruitment-service/src/main/resources/application.properties +++ b/recruitment-service/src/main/resources/application.properties @@ -7,3 +7,4 @@ spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true spring.jpa.properties.hibernate.format_sql=true +