Event의 Enrollment 목록 순서를 정하려면
@OneToMany(mappedBy = "event")
@OrderBy("enrolledAt")
private List<Enrollment> enrollments = new ArrayList<>();
스프링 데이너 JPA가 제공하는 도메인 컨버터 사용하기
@GetMapping("/events/{eventId}/enrollments/{enrollmentId}/reject")
public String rejectEnrollment(@PathVariable Long eventId, @PathVariable Long enrollmentId) {
Event event = eventRepository.findById(eventId).orElseThrow();
Enrollment enrollment = enrollmentRepository.findById(enrollmentId).orElseThrow();
}
@GetMapping("/events/{eventId}/enrollments/{enrollmentId}/reject")
public String rejectEnrollment(@PathVariable("eventId") Event event,
@PathVariable("enrollmentId") Enrollment enrollment) {
}
이전 코드 리팩토링
package me.weekbelt.studyolle.event;
@Service
@Transactional
@RequiredArgsConstructor
public class EventService {
// .......
public void cancelEnrollment(Event event, Account account) {
Enrollment enrollment = enrollmentRepository.findByEventAndAccount(event, account);
if(!enrollment.isAttended()) { // 조건문 추가
event.removeEnrollment(enrollment);
enrollmentRepository.delete(enrollment);
event.acceptNextWaitingEnrollment();
}
}
}
package me.weekbelt.studyolle.domain;
@NamedEntityGraph(
name = "Event.withEnrollments",
attributeNodes = @NamedAttributeNode("enrollments")
)
@NoArgsConstructor
@Getter
@Setter
@EqualsAndHashCode(of = "id")
@Entity
public class Event {
// ......
public boolean isEnrollableFor(UserAccount userAccount) {
return isNotClosed() && !this.isAttended(userAccount) && !isAlreadyEnrolled(userAccount);
}
public boolean isDisenrollableFor(UserAccount userAccount) {
return isNotClosed() && !this.isAttended(userAccount) && isAlreadyEnrolled(userAccount);
}
// .......
}
참가 신청 수락 요청, 출석체크 요청을 처리하는 핸들러 작성
package me.weekbelt.studyolle.event;
@Controller
@RequestMapping("/study/{path}")
@RequiredArgsConstructor
public class EventController {
// .........
private final EnrollmentService enrollmentService;
// .........
// 화면 칸 간격을 맞추기위해 Get요청을보냄 원래 POST요청을 해야함
// 모임 참가 신청 수락
@GetMapping("/events/{eventId}/enrollments/{enrollmentId}/accept")
public String acceptEnrollment(@CurrentAccount Account account, @PathVariable String path,
@PathVariable Long eventId, @PathVariable Long enrollmentId) {
Study study = studyService.getStudyToUpdate(account, path);
Event event = eventService.findEventById(eventId);
Enrollment enrollment = enrollmentService.findEnrollmentById(enrollmentId);
eventService.acceptEnrollment(event, enrollment);
return "redirect:/study/" + study.getEncodedPath() + "/events/" + eventId;
}
// 모임 참가 신청 거절
@GetMapping("/events/{eventId}/enrollments/{enrollmentId}/reject")
public String rejectEnrollment(@CurrentAccount Account account, @PathVariable String path,
@PathVariable Long eventId, @PathVariable Long enrollmentId) {
Study study = studyService.getStudyToUpdate(account, path);
Event event = eventService.findEventById(eventId);
Enrollment enrollment = enrollmentService.findEnrollmentById(enrollmentId);
eventService.rejectEnrollment(event, enrollment);
return "redirect:/study/" + study.getEncodedPath() + "/events/" + eventId;
}
// 출석 체크인
@GetMapping("/events/{eventId}/enrollments/{enrollmentId}/checkin")
public String checkInEnrollment(@CurrentAccount Account account, @PathVariable String path,
@PathVariable Long eventId, @PathVariable Long enrollmentId) {
Study study = studyService.getStudyToUpdate(account, path);
Event event = eventService.findEventById(eventId);
Enrollment enrollment = enrollmentService.findEnrollmentById(enrollmentId);
eventService.checkInEnrollment(enrollment);
return "redirect:/study/" + study.getEncodedPath() + "/events/" + eventId;
}
// 체크인 취소
@GetMapping("/events/{eventId}/enrollments/{enrollmentId}/cancel-checkin")
public String cancelCheckInEnrollment(@CurrentAccount Account account, @PathVariable String path,
@PathVariable Long eventId, @PathVariable Long enrollmentId) {
Study study = studyService.getStudyToUpdate(account, path);
Event event = eventService.findEventById(eventId);
Enrollment enrollment = enrollmentService.findEnrollmentById(enrollmentId);
eventService.cancelCheckInEnrollment(enrollment);
return "redirect:/study/" + study.getEncodedPath() + "/events/" + eventId;
}
}
EnrollmentService에서 enrollmentId의 Enrollment를 불러오기 위한 findEventById메소드 작성
package me.weekbelt.studyolle.event;
@RequiredArgsConstructor
@Transactional
@Service
public class EnrollmentService {
private final EnrollmentRepository enrollmentRepository;
public Enrollment findEnrollmentById(Long enrollmentId) {
return enrollmentRepository.findById(enrollmentId)
.orElseThrow(() -> new IllegalArgumentException("찾는 참가자가 없습니다."));
}
}
참가신청 수락/거절/체크인/체크인 취소를 처리하는 메소드 작성
package me.weekbelt.studyolle.event;
@Service
@Transactional
@RequiredArgsConstructor
public class EventService {
// .......
public void acceptEnrollment(Event event, Enrollment enrollment) {
event.accept(enrollment);
}
public void rejectEnrollment(Event event, Enrollment enrollment) {
event.reject(enrollment);
}
public void checkInEnrollment(Enrollment enrollment) {
enrollment.setAttended(true);
}
public void cancelCheckInEnrollment(Enrollment enrollment) {
enrollment.setAttended(false);
}
}
참가신청 수락을 Event엔티티에 위임시키때문에 accept, reject메소드를 Event엔티티에 작성한다.
package me.weekbelt.studyolle.domain;
@NamedEntityGraph(
name = "Event.withEnrollments",
attributeNodes = @NamedAttributeNode("enrollments")
)
@NoArgsConstructor
@Getter
@Setter
@EqualsAndHashCode(of = "id")
@Entity
public class Event {
// .........
public void accept(Enrollment enrollment) {
if(this.eventType == EventType.CONFIRMATIVE && this.limitOfEnrollments > this.getNumberOfAcceptedEnrollments()) {
enrollment.setAccepted(true);
}
}
public void reject(Enrollment enrollment) {
if(this.eventType == EventType.CONFIRMATIVE) {
enrollment.setAccepted(false);
}
}
}
앞서 작성한 핸들러를 좀더 간단히 만들 수 있다.
package me.weekbelt.studyolle.event;
@Controller
@RequestMapping("/study/{path}")
@RequiredArgsConstructor
public class EventController {
// .......
@GetMapping("/events/{id}")
public String getEvent(@CurrentAccount Account account, @PathVariable String path,
@PathVariable("id") Event event, Model model) {
model.addAttribute(account);
model.addAttribute(event);
model.addAttribute(studyService.getStudy(path));
return "event/view";
}
// .......
@GetMapping("/events/{id}/edit")
public String updateEventForm(@CurrentAccount Account account, @PathVariable String path,
@PathVariable("id") Event event, Model model) {
Study study = studyService.getStudyToUpdate(account, path);
model.addAttribute("account", account);
model.addAttribute("study", study);
model.addAttribute("event", event);
model.addAttribute(modelMapper.map(event, EventForm.class));
return "event/update-form";
}
@PostMapping("/events/{id}/edit")
public String updateEventSubmit(@CurrentAccount Account account, @PathVariable String path,
@PathVariable("id") Event event, @Valid EventForm eventForm,
Errors errors, Model model) {
Study study = studyService.getStudyToUpdate(account, path);
// 화면에 EventType 창이 없어도 서버에 요청이 가능하기 때문에 이것을 방지하기 위해
eventForm.setEventType(event.getEventType());
eventValidator.validateUpdateForm(eventForm, event, errors);
if (errors.hasErrors()) {
model.addAttribute("account", account);
model.addAttribute("study", study);
model.addAttribute("event", event);
return "event/update-form";
}
eventService.updateEvent(event, eventForm);
return "redirect:/study/" + study.getEncodedPath() + "/events/" + event.getId();
}
@DeleteMapping("/events/{id}")
public String cancelEvent(@CurrentAccount Account account, @PathVariable String path,
@PathVariable("id") Event event) {
Study study = studyService.getStudyToUpdateStatus(account, path);
eventService.deleteEvent(event);
return "redirect:/study/" + study.getEncodedPath() + "/events";
}
@PostMapping("/events/{id}/enroll")
public String newEnrollment(@CurrentAccount Account account, @PathVariable String path,
@PathVariable("id") Event event) {
Study study = studyService.getStudyToEnroll(path);
eventService.newEnrollment(event, account);
return "redirect:/study/" + study.getEncodedPath() + "/events/" + event.getId();
}
@PostMapping("/events/{id}/disenroll")
public String cancelEnrollment(@CurrentAccount Account account, @PathVariable String path,
@PathVariable("id") Event event) {
Study study = studyService.getStudyToEnroll(path);
eventService.cancelEnrollment(event, account);
return "redirect:/study/" + study.getEncodedPath() + "/events/" + event.getId();
}
// 화면 칸 간격을 맞추기위해 Get요청을보냄 원래 POST요청을 해야함
@GetMapping("/events/{eventId}/enrollments/{enrollmentId}/accept")
public String acceptEnrollment(@CurrentAccount Account account, @PathVariable String path,
@PathVariable("eventId") Event event, @PathVariable("enrollmentId") Enrollment enrollment) {
Study study = studyService.getStudyToUpdate(account, path);
eventService.acceptEnrollment(event, enrollment);
return "redirect:/study/" + study.getEncodedPath() + "/events/" + event.getId();
}
@GetMapping("/events/{eventId}/enrollments/{enrollmentId}/reject")
public String rejectEnrollment(@CurrentAccount Account account, @PathVariable String path,
@PathVariable("eventId") Event event, @PathVariable("enrollmentId") Enrollment enrollment) {
Study study = studyService.getStudyToUpdate(account, path);
eventService.rejectEnrollment(event, enrollment);
return "redirect:/study/" + study.getEncodedPath() + "/events/" + event.getId();
}
@GetMapping("/events/{eventId}/enrollments/{enrollmentId}/checkin")
public String checkInEnrollment(@CurrentAccount Account account, @PathVariable String path,
@PathVariable("eventId") Event event, @PathVariable("enrollmentId") Enrollment enrollment) {
Study study = studyService.getStudyToUpdate(account, path);
eventService.checkInEnrollment(enrollment);
return "redirect:/study/" + study.getEncodedPath() + "/events/" + event.getId();
}
@GetMapping("/events/{eventId}/enrollments/{enrollmentId}/cancel-checkin")
public String cancelCheckInEnrollment(@CurrentAccount Account account, @PathVariable String path,
@PathVariable("eventId") Event event, @PathVariable("enrollmentId") Enrollment enrollment) {
Study study = studyService.getStudyToUpdate(account, path);
eventService.cancelCheckInEnrollment(enrollment);
return "redirect:/study/" + study.getEncodedPath() + "/events/" + event.getId();
}
}
참고: https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-JPA-%EC%9B%B9%EC%95%B1#
'스프링과 JPA 기반 웹 어플리케이션 개발 > 5부 모임' 카테고리의 다른 글
67. 모임 참가 신청 및 취소 (0) | 2020.05.06 |
---|---|
66. 모임 취소 (0) | 2020.05.04 |
65. 모임 수정 (0) | 2020.05.04 |
64. 모임 목록 조회 (0) | 2020.05.04 |
63. 모임 조회 (0) | 2020.05.04 |