-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
fix: Bus 엔티티 비관적 락 적용, refactor: Bus UseCase, Service 분리
- Loading branch information
Showing
12 changed files
with
342 additions
and
236 deletions.
There are no files selected for viewing
91 changes: 0 additions & 91 deletions
91
dodam-api/src/main/java/b1nd/dodamapi/bus/BusController.java
This file was deleted.
Oops, something went wrong.
77 changes: 77 additions & 0 deletions
77
dodam-api/src/main/java/b1nd/dodamapi/bus/handler/BusController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package b1nd.dodamapi.bus.handler; | ||
|
||
import b1nd.dodamapi.bus.usecase.BusApplicationUseCase; | ||
import b1nd.dodamapi.common.response.Response; | ||
import b1nd.dodamapi.common.response.ResponseData; | ||
import b1nd.dodamapi.bus.usecase.BusUseCase; | ||
import b1nd.dodamapi.bus.usecase.dto.req.BusReq; | ||
import b1nd.dodamapi.bus.usecase.dto.res.BusRes; | ||
import b1nd.dodamcore.bus.domain.entity.Bus; | ||
import jakarta.validation.Valid; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.web.bind.annotation.*; | ||
|
||
import java.util.List; | ||
|
||
@RestController | ||
@RequestMapping("/bus") | ||
@RequiredArgsConstructor | ||
public class BusController { | ||
|
||
private final BusUseCase busUseCase; | ||
private final BusApplicationUseCase busApplicationUseCase; | ||
|
||
@PostMapping | ||
public Response registerBus(@RequestBody @Valid BusReq req) { | ||
return busUseCase.register(req); | ||
} | ||
|
||
@PatchMapping("/{id}") | ||
public Response modifyBus(@PathVariable int id, @RequestBody BusReq req) { | ||
return busUseCase.modify(id, req); | ||
} | ||
|
||
@DeleteMapping("/{id}") | ||
public Response deleteBus(@PathVariable int id) { | ||
return busUseCase.delete(id); | ||
} | ||
|
||
@GetMapping | ||
public ResponseData<List<Bus>> getValidBuses() { | ||
return busUseCase.getValid(); | ||
} | ||
|
||
@GetMapping("/list") | ||
public ResponseData<List<BusRes>> getBuses(@RequestParam int page, @RequestParam int limit) { | ||
return busUseCase.getBuses(page, limit); | ||
} | ||
|
||
@GetMapping("/date") | ||
public ResponseData<List<BusRes>> getBusesByDate( | ||
@RequestParam int year, | ||
@RequestParam int month, | ||
@RequestParam int day | ||
) { | ||
return busUseCase.getBusesByDate(year, month, day); | ||
} | ||
|
||
@GetMapping("/apply") | ||
public ResponseData<Bus> getMy() { | ||
return busUseCase.getMy(); | ||
} | ||
|
||
@PostMapping("/apply/{id}") | ||
public Response applyBus(@PathVariable int id) { | ||
return busApplicationUseCase.apply(id); | ||
} | ||
|
||
@PatchMapping("/apply/{id}") | ||
public Response modifyApplication(@PathVariable int id) { | ||
return busApplicationUseCase.modify(id); | ||
} | ||
|
||
@DeleteMapping("/apply/{id}") | ||
public Response cancelApplication(@PathVariable int id) { | ||
return busApplicationUseCase.cancel(id); | ||
} | ||
} |
85 changes: 85 additions & 0 deletions
85
dodam-api/src/main/java/b1nd/dodamapi/bus/usecase/BusApplicationUseCase.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package b1nd.dodamapi.bus.usecase; | ||
|
||
import b1nd.dodamapi.common.response.Response; | ||
import b1nd.dodamcore.bus.application.BusApplicationService; | ||
import b1nd.dodamcore.bus.application.BusService; | ||
import b1nd.dodamcore.bus.domain.entity.Bus; | ||
import b1nd.dodamcore.bus.domain.entity.BusMember; | ||
import b1nd.dodamcore.bus.domain.exception.BusAlreadyApplyException; | ||
import b1nd.dodamcore.bus.domain.exception.BusMemberNotFoundException; | ||
import b1nd.dodamcore.common.util.ZonedDateTimeUtil; | ||
import b1nd.dodamcore.member.application.MemberService; | ||
import b1nd.dodamcore.member.domain.entity.Student; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Component; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
import java.time.LocalDateTime; | ||
import java.util.function.Consumer; | ||
|
||
|
||
@Component | ||
@Transactional(rollbackFor = Exception.class) | ||
@RequiredArgsConstructor | ||
public class BusApplicationUseCase { | ||
|
||
private final BusService busService; | ||
private final BusApplicationService busApplicationService; | ||
private final MemberService memberService; | ||
|
||
public Response apply(int busId) { | ||
Bus bus = busService.getByIdForUpdate(busId); | ||
Student student = memberService.getStudentFromSession(); | ||
if(busApplicationService.hasValidApplication(student, ZonedDateTimeUtil.nowToLocalDateTime())) { | ||
throw new BusAlreadyApplyException(); | ||
} | ||
busApplicationService.save( | ||
BusMember.builder() | ||
.bus(bus) | ||
.student(student) | ||
.build() | ||
); | ||
return Response.created("버스 신청 성공"); | ||
} | ||
|
||
public Response modify(int busId) { | ||
Bus newBus = busService.getByIdForUpdate(busId); | ||
Student student = memberService.getStudentFromSession(); | ||
findValidApplication( | ||
student, | ||
ZonedDateTimeUtil.nowToLocalDateTime(), | ||
(busMember) -> { | ||
Bus oldBus = busService.getByIdForUpdate(busMember.getBus().getId()); | ||
oldBus.decreaseApplyCount(); | ||
busMember.modifyBus(newBus); | ||
newBus.increaseApplyCount(); | ||
} | ||
); | ||
return Response.noContent("버스 신청 수정 성공"); | ||
} | ||
|
||
public Response cancel(int busId) { | ||
Student student = memberService.getStudentFromSession(); | ||
findValidApplication( | ||
student, | ||
ZonedDateTimeUtil.nowToLocalDateTime(), | ||
(busMember) -> { | ||
Bus bus = busService.getByIdForUpdate(busId); | ||
bus.decreaseApplyCount(); | ||
busApplicationService.delete(busMember); | ||
} | ||
); | ||
return Response.noContent("버스 신청 취소 성공"); | ||
} | ||
|
||
private void findValidApplication(Student student, LocalDateTime now, Consumer<? super BusMember> action) { | ||
busApplicationService.findValidApplication(student, now) | ||
.ifPresentOrElse( | ||
action, | ||
() -> { | ||
throw new BusMemberNotFoundException(); | ||
} | ||
); | ||
} | ||
|
||
} |
91 changes: 91 additions & 0 deletions
91
dodam-api/src/main/java/b1nd/dodamapi/bus/usecase/BusUseCase.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
package b1nd.dodamapi.bus.usecase; | ||
|
||
import b1nd.dodamapi.bus.usecase.dto.req.BusReq; | ||
import b1nd.dodamapi.bus.usecase.dto.res.BusMemberRes; | ||
import b1nd.dodamapi.bus.usecase.dto.res.BusRes; | ||
import b1nd.dodamapi.common.response.Response; | ||
import b1nd.dodamapi.common.response.ResponseData; | ||
import b1nd.dodamcore.bus.application.BusApplicationService; | ||
import b1nd.dodamcore.bus.application.BusService; | ||
import b1nd.dodamcore.bus.domain.entity.Bus; | ||
import b1nd.dodamcore.bus.domain.entity.BusMember; | ||
import b1nd.dodamcore.common.util.ModifyUtil; | ||
import b1nd.dodamcore.common.util.ZonedDateTimeUtil; | ||
import b1nd.dodamcore.member.application.MemberService; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
import java.time.LocalDate; | ||
import java.time.LocalDateTime; | ||
import java.util.List; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
@Transactional(readOnly = true) | ||
public class BusUseCase { | ||
|
||
private final BusService busService; | ||
private final BusApplicationService busApplicationService; | ||
private final MemberService memberService; | ||
|
||
@Transactional(rollbackFor = Exception.class) | ||
public Response register(BusReq req) { | ||
busService.save(req.mapToBus()); | ||
return Response.created("버스 등록 성공"); | ||
} | ||
|
||
@Transactional(rollbackFor = Exception.class) | ||
public Response modify(int id, BusReq modifyBusReq) { | ||
Bus bus = busService.getByIdForUpdate(id); | ||
bus.updateBus( | ||
ModifyUtil.modifyIfNotNull(modifyBusReq.busName(), bus.getBusName()), | ||
ModifyUtil.modifyIfNotNull(modifyBusReq.description(), bus.getDescription()), | ||
ModifyUtil.modifyIfNotNull(modifyBusReq.leaveTime(), bus.getLeaveTime()), | ||
ModifyUtil.modifyIfNotNull(modifyBusReq.timeRequired(), bus.getTimeRequired()), | ||
ModifyUtil.modifyIfNotZero(modifyBusReq.peopleLimit(), bus.getPeopleLimit()) | ||
); | ||
return Response.noContent("버스 수정 성공"); | ||
} | ||
|
||
@Transactional(rollbackFor = Exception.class) | ||
public Response delete(int id) { | ||
Bus bus = busService.getById(id); | ||
busService.delete(bus); | ||
return Response.noContent("버스 삭제 성공"); | ||
} | ||
|
||
public ResponseData<List<Bus>> getValid() { | ||
LocalDateTime now = ZonedDateTimeUtil.nowToLocalDateTime(); | ||
return ResponseData.ok("유효 버스 조회 성공", busService.getValid(now, now.plusDays(7))); | ||
} | ||
|
||
public ResponseData<List<BusRes>> getBuses(int page, int limit) { | ||
return ResponseData.ok("버스 조회 성공", parseToBusList(busService.getAll(page, limit))); | ||
} | ||
|
||
public ResponseData<List<BusRes>> getBusesByDate(int year, int month, int day) { | ||
return ResponseData.ok("해당 날짜의 버스 조회 성공", parseToBusList(busService.getAllByDate(LocalDate.of(year, month, day)))); | ||
} | ||
|
||
private List<BusRes> parseToBusList(List<Bus> buses) { | ||
return buses.stream() | ||
.map(bus -> BusRes.createFromBus( | ||
bus, | ||
getBusApplications(bus).stream() | ||
.map(BusMemberRes::createFromBusMember) | ||
.toList() | ||
) | ||
).toList(); | ||
} | ||
|
||
private List<BusMember> getBusApplications(Bus bus) { | ||
return busApplicationService.getByBus(bus); | ||
} | ||
|
||
public ResponseData<Bus> getMy() { | ||
int studentId = memberService.getStudentFromSession().getId(); | ||
return ResponseData.ok("신청한 버스 조회 성공", busService.getByStudent(ZonedDateTimeUtil.nowToLocalDateTime(), studentId)); | ||
} | ||
|
||
} |
2 changes: 1 addition & 1 deletion
2
...mcore/bus/application/dto/req/BusReq.java → .../dodamapi/bus/usecase/dto/req/BusReq.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
...bus/application/dto/res/BusMemberRes.java → ...api/bus/usecase/dto/res/BusMemberRes.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
...mcore/bus/application/dto/res/BusRes.java → .../dodamapi/bus/usecase/dto/res/BusRes.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.