Java 将新预订添加到预订列表中,每个预订有两个本地日期(签入、签出)
所以我正在做一个个人项目,试图学习Java8和SpringBoot。 我正在开发一个RESTAPI,您可以在其中查看和预订住宿 这是我的模型课,这是住宿课:Java 将新预订添加到预订列表中,每个预订有两个本地日期(签入、签出),java,spring-boot,localdate,Java,Spring Boot,Localdate,所以我正在做一个个人项目,试图学习Java8和SpringBoot。 我正在开发一个RESTAPI,您可以在其中查看和预订住宿 这是我的模型课,这是住宿课: @Data @Document(collection = "accommodations") public class Accommodation { @Id private String accommodationId; private Double pricePerNight; private Inte
@Data
@Document(collection = "accommodations")
public class Accommodation {
@Id
private String accommodationId;
private Double pricePerNight;
private Integer guests;
private Address address;
private Landlord landlord;
private List<Review> reviews;
private List<Booking> bookings;
private Accommodation() {
this.reviews = new ArrayList<>();
this.bookings = new ArrayList<>();
}
public Accommodation(Double pricePerNight, Integer guests, Address address, Landlord landlord) {
this();
this.pricePerNight = pricePerNight;
this.guests = guests;
this.address = address;
this.landlord = landlord;
}
public Boolean isAvailableBetween(LocalDate checkin, LocalDate checkout) {
// TODO: fix
boolean available = bookings
.stream()
.anyMatch(b ->
(checkin.isAfter(b.getCheckin()) || checkin.isEqual(b.getCheckin())) &&
(checkout.isBefore(b.getCheckout()) || checkout.isEqual(b.getCheckout()))
);
return !available;
}
}
现在,我一直坚持的是,我想完成的是确保您可以将预订添加到住宿预订列表中,前提是新预订的签入和签出本地日期不与同一列表中任何其他预订的本地日期重叠
TLDR;需要确保您只能在住宿可用的日子内预订住宿
以下是my Service类中的方法,控制器在HTTP POST预订请求后调用该方法:
public BookingDto bookAccommodation(String accommodationId, BookingDto bookingDto) {
// TODO: fix and improve
if (this.isCheckoutDateInvalid(bookingDto)) {
throw new InvalidRequestException("Invalid request.", Arrays.asList("Check Out must be after Check In."));
}
Optional<Accommodation> accommodation = this.accommodationRepository.findById(accommodationId);
accommodation.orElseThrow(() -> new AccommodationNotFoundException(String.format("Accommodation not found for ID: {}", accommodationId)));
return accommodation
.filter(a -> a.isAvailableBetween(bookingDto.getCheckin(), bookingDto.getCheckout()))
.map(a -> bookAccommodationInternal(bookingDto, a))
.orElseThrow(() -> new AccommodationNotAvailableException(String.format("Accommodation already booked for ID: {}", accommodationId)));
}
private Boolean isCheckoutDateInvalid(BookingDto bookingDto) {
return bookingDto.getCheckout().isBefore(bookingDto.getCheckin());
}
private BookingDto bookAccommodationInternal(BookingDto bookingDto, Accommodation accommodation) {
Booking booking = this.accommodationMapper.toBooking(bookingDto);
accommodation.getBookings().add(booking);
log.info(String.format("New booking created for ID: {}", booking.getBookingId()));
this.accommodationRepository.save(accommodation);
BookingDto newBookingDto = new BookingDto(booking);
return this.linkAssembler.addLinksToBooking(accommodation.getAccommodationId(), newBookingDto);
}
现在,正如您从代码中看到的,我尝试使用isAvailableBetween方法中的流,该方法由调节类拥有。我使用的谓词在某些情况下有效:
例如,如果住宿的预订列表(我们称之为Acc1)有两个具有以下LocalDate的预订:
预订1
登记日期:2019年10月10日
结帐日期:2019年10月31日
预订2
登记日期:2019年11月1日
结帐日期:2019年11月9日
添加带有以下内容的Booking3:
登记日期:2019年10月12日
结帐日期:2019年10月25日
这是不可能的
但可能会错误地添加带有以下内容的预订4:
登记日期:2019年10月12日
结帐日期:2019年11月2日
关于如何修复这个谓词并仍然使用Java流,有什么建议吗
或者有没有其他更好的方法来完成这种预订系统
我也愿意接受关于我分享的其余代码的任何提示。什么都可以。努力改进
提前感谢。您的错误在这里:
.anyMatch(b ->
(checkin.isAfter(b.getCheckin()) || checkin.isEqual(b.getCheckin())) &&
(checkout.isBefore(b.getCheckout()) || checkout.isEqual(b.getCheckout()))
);
首先,变量名应该被占用,不可用,这与您正在检查的相反。第二,我认为正确的条件没有得到测试:
.anyMatch(b -> b.getCheckin().isBefore(checkout)
&& b.getCheckout().isAfter(checkin)
);
我喜欢从另一个角度来考虑:如果预订完全在我们提议的预订之前或之后,那么住宿是可用的。因此,如果b.getCheckin在签出之前或之后,或者b.getCheckout在签入之前或之后。上述代码中的条件是否定的,因此检查预订b是否与建议的冲突。将此添加到您的预订类别:
@Data
public class Booking {
private String bookingId;
private LocalDate checkin;
private LocalDate checkout;
private LocalDate bookedAt;
private Booking(){
this.bookedAt = LocalDate.now();
this.bookingId = new ObjectId().toString();
}
public Booking(LocalDate checkin, LocalDate checkout) {
this();
this.checkin = checkin;
this.checkout = checkout;
}
}
public boolean isDateInsideCheckedIn(LocalDate date) {
return checkin.isBefore(date) && checkout.isAfter(date);
}
将iAvailableBetween替换为以下内容:
public boolean isAvailableBetween(LocalDate checkin, LocalDate checkout) {
return bookings.stream()
.noneMatch(b ->
(b.isDateInsideCheckedIn(checkin) || b.isDateInsideCheckedIn(checkout))
|| (b.getCheckin().equals(checkin) && b.getCheckout().equals(checkout)));
}
现在将检查现有预订中是否没有签入和签出,以及签入和签出在现有预订中是否不完全相同。您是否考虑过对数据库执行查询,检查新预订日期之间是否有住宿?您好!谢谢你的回复。虽然这不包括以下情况:如果已经有一个预订,签入日期为2019年10月10日,签出日期为2019年10月20日,我尝试添加一个新预订,签入日期为2019年10月11日,签出日期为2019年10月25日,那么这个新预订将被错误添加。嗯?然后b.getCheckin是10月10日,10月25日之前,b.getCheckout是20月20日,10月11日之后,所以我的代码应该检测到它们重叠。我相信您需要的是。编辑:这实际上允许您在同一天多次添加预订。尝试添加两次预订,签入时间为2019年10月29日签出时间为2019年10月29日,两次都有效。哦,我假设签入后也会严格执行签出,而不是在同一日期,因此预订时间至少为一晚。我可能还没有完全理解这些要求。我希望你能根据你的具体需要调整代码。这实际上看起来很干净。虽然前面建议的代码工作得很好,但我想尝试一下。我想知道在性能方面,这种选择是否比anyMatch更好。我认为这取决于一个房间内通常有多少预订。你可能只有在有很多条目的情况下才会觉得有什么不同。但从理论上讲,noneMatch会更有效,因为它在找到匹配项后会立即停止检查,而anyMatch会在停止之前浏览整个列表。如果现有的预订时间是10月12日至19日,而新的预订时间是10月5日至26日?签入和签出都不在现有预订的日期内,也不等于现有签入或签出的日期,因此是否会错误创建此新预订?
public boolean isAvailableBetween(LocalDate checkin, LocalDate checkout) {
return bookings.stream()
.noneMatch(b ->
(b.isDateInsideCheckedIn(checkin) || b.isDateInsideCheckedIn(checkout))
|| (b.getCheckin().equals(checkin) && b.getCheckout().equals(checkout)));
}