【Java】날짜 기간 중복 체크 샘플
14387 단어 SpringBootjava8자바spring-boot
개요
날짜로 기간을 가진 데이터를 등록할 때 이미 등록한 기간과 중복되지 않도록 하고 싶다.
LocalDate를 사용한 Java 샘플이별로 발견되지 않았기 때문에 공개합니다.
환경
기간이 중복되는 패턴
날짜의 기간이 중복되는 패턴은 모두 4개.
1. 전반부가 쓰는 패턴(①의 종료일과 초록의 시작일이 동일도 포함한다)
2. 후반이 쓰는 패턴(②의 시작일과 녹색의 종료일이 동일도 포함한다)
3. 전부 쓰는 패턴(개시일과 종료일이 정확히 동일도 포함한다)
4. 일부가 쓰는 패턴
모든 패턴을 망라할 수 있는 조건식은 아래와 같다.
조건식緑.開始日 <= 黒.終了日 && 緑.終了日 => 黒.開始日
샘플
화면으로부터 개시일과 종료일을 입력해, 그 입력 기간이 기존의 기간(복수)과 중복되어 있지 않은 경우만 등록할 수 있는 샘플.
등록할 날짜 기간이 있는 Model 클래스
등록하는 시작일과 종료일, 자동 번호 매기기의 ID를 가지는 화면에 건네주는 Model 클래스.
DurationModel.javapackage com.tamorieeeen.sample.model;
import java.time.LocalDate;
import org.springframework.format.annotation.DateTimeFormat;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
*
* @author tamorieeeen
*
*/
@Getter
@Setter
@NoArgsConstructor
public class DurationModel {
// 保存時にauto_incrementで採番
private int id;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate startDate;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate endDate;
}
기간 중복 판정 로직 Service 클래스
Controller에서 호출되는 Service 클래스입니다.
DurationService.javapackage com.tamorieeeen.sample.service;
import java.time.LocalDate;
import java.util.List;
import javax.transaction.Transactional;
import org.springframework.stereotype.Service;
import com.tamorieeeen.sample.model.DurationModel;
/**
*
* @author tamorieeeen
*
*/
@Service
public class DurationService {
/**
* すでに登録済の期間とかぶってないかチェック
*/
public boolean isInvalid(DurationModel model) {
return this.getDurationList()
.stream()
.filter(u -> model.getId() != u.getId()) // ※1
.anyMatch(u ->
(order.getStartDate().isBefore(u.getEndDate())
&& order.getEndDate().isAfter(u.getStartDate()))
|| order.getStartDate().isEqual(u.getEndDate())
|| order.getEndDate().isEqual(u.getStartDate()));
}
/**
* 一覧を取得
*/
private List<DurationModel> getDurationList() {
// TODO すでに登録済のデータを取得
}
/**
* 新規登録/更新
*/
@Transactional
public void saveDuration(DurationModel model) {
// TODO DBなどへのデータ保存処理
}
}
※1: 비교원(model)의 ID는 기간 체크를 제외한다
이렇게 하지 않으면 데이터 갱신시에 this.getDurationList()
에 비교원 데이터도 포함되어 있기 때문에 중복 취급으로 validation에 걸려 버리기 (위해)때문에.
신규 등록 밖에 생각하지 않는다면, 이 행은 불필요.
Controller 클래스
실제로는 밸리데이션 체크에 @Validated
와 BindingResult
를 사용하고 있지만 그 부분은 생략.
DurationController.java/**
*
* @author tamorieeeen
*
*/
@Controller
public class DurationController {
@Autowired
private DurationService durationService;
/**
* 新規登録
*/
@GetMapping("/duration/register")
public String register(Model model) {
model.addAttribute("duration", new DurationModel());
return "duration/register";
}
/**
* 新規登録処理
*/
@PostMapping("/duration/register")
public String registerComplete(Model model,
@ModelAttribute("duration") DurationModel duration,
RedirectAttributes redirect) {
// バリデーションチェック
if (durationService.isInvalid(duration)) {
model.addAttribute("invalid", true);
return "duration/register";
}
durationService.saveDuration(duration);
redirect.addFlashAttribute("complete", true);
return "redirect:/duration/register";
}
}
화면측 html(thymeleaf)
html 헤더는 공통화하고 있지만 이번에는 관계 없기 때문에 생략. 신경이 쓰이는 사람은 Thymeleaf에서 머리글 바닥글을 공통화하는 방법 를 참고해 주세요.
register.html<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="common :: meta_header('sample',~{::link},~{::script},~{::meta})">
</head>
<body>
<div th:if="${complete}">
<p>期間を登録しました。</p>
</div>
<div th:if="${invalid}">
<p>期間が重複しているため、登録できません。</p>
</div>
<form th:action="@{/duration/register}" method="post" th:object="${duration}">
<table>
<tr><td>開始日</td><td>
<input type="date" th:field="*{startDate}" th:value="*{startDate}" />
</td></tr>
<tr><td>終了日</td><td>
<input type="date" th:field="*{endDate}" th:value="*{endDate}" />
</td></tr>
</table>
<input type="button" th:value="登録する" onclick="submit();" />
</form>
</body>
</html>
참고
緑.開始日 <= 黒.終了日 && 緑.終了日 => 黒.開始日
화면으로부터 개시일과 종료일을 입력해, 그 입력 기간이 기존의 기간(복수)과 중복되어 있지 않은 경우만 등록할 수 있는 샘플.
등록할 날짜 기간이 있는 Model 클래스
등록하는 시작일과 종료일, 자동 번호 매기기의 ID를 가지는 화면에 건네주는 Model 클래스.
DurationModel.java
package com.tamorieeeen.sample.model;
import java.time.LocalDate;
import org.springframework.format.annotation.DateTimeFormat;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
*
* @author tamorieeeen
*
*/
@Getter
@Setter
@NoArgsConstructor
public class DurationModel {
// 保存時にauto_incrementで採番
private int id;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate startDate;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate endDate;
}
기간 중복 판정 로직 Service 클래스
Controller에서 호출되는 Service 클래스입니다.
DurationService.java
package com.tamorieeeen.sample.service;
import java.time.LocalDate;
import java.util.List;
import javax.transaction.Transactional;
import org.springframework.stereotype.Service;
import com.tamorieeeen.sample.model.DurationModel;
/**
*
* @author tamorieeeen
*
*/
@Service
public class DurationService {
/**
* すでに登録済の期間とかぶってないかチェック
*/
public boolean isInvalid(DurationModel model) {
return this.getDurationList()
.stream()
.filter(u -> model.getId() != u.getId()) // ※1
.anyMatch(u ->
(order.getStartDate().isBefore(u.getEndDate())
&& order.getEndDate().isAfter(u.getStartDate()))
|| order.getStartDate().isEqual(u.getEndDate())
|| order.getEndDate().isEqual(u.getStartDate()));
}
/**
* 一覧を取得
*/
private List<DurationModel> getDurationList() {
// TODO すでに登録済のデータを取得
}
/**
* 新規登録/更新
*/
@Transactional
public void saveDuration(DurationModel model) {
// TODO DBなどへのデータ保存処理
}
}
※1: 비교원(model)의 ID는 기간 체크를 제외한다
이렇게 하지 않으면 데이터 갱신시에
this.getDurationList()
에 비교원 데이터도 포함되어 있기 때문에 중복 취급으로 validation에 걸려 버리기 (위해)때문에.신규 등록 밖에 생각하지 않는다면, 이 행은 불필요.
Controller 클래스
실제로는 밸리데이션 체크에
@Validated
와 BindingResult
를 사용하고 있지만 그 부분은 생략.DurationController.java
/**
*
* @author tamorieeeen
*
*/
@Controller
public class DurationController {
@Autowired
private DurationService durationService;
/**
* 新規登録
*/
@GetMapping("/duration/register")
public String register(Model model) {
model.addAttribute("duration", new DurationModel());
return "duration/register";
}
/**
* 新規登録処理
*/
@PostMapping("/duration/register")
public String registerComplete(Model model,
@ModelAttribute("duration") DurationModel duration,
RedirectAttributes redirect) {
// バリデーションチェック
if (durationService.isInvalid(duration)) {
model.addAttribute("invalid", true);
return "duration/register";
}
durationService.saveDuration(duration);
redirect.addFlashAttribute("complete", true);
return "redirect:/duration/register";
}
}
화면측 html(thymeleaf)
html 헤더는 공통화하고 있지만 이번에는 관계 없기 때문에 생략. 신경이 쓰이는 사람은 Thymeleaf에서 머리글 바닥글을 공통화하는 방법 를 참고해 주세요.
register.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="common :: meta_header('sample',~{::link},~{::script},~{::meta})">
</head>
<body>
<div th:if="${complete}">
<p>期間を登録しました。</p>
</div>
<div th:if="${invalid}">
<p>期間が重複しているため、登録できません。</p>
</div>
<form th:action="@{/duration/register}" method="post" th:object="${duration}">
<table>
<tr><td>開始日</td><td>
<input type="date" th:field="*{startDate}" th:value="*{startDate}" />
</td></tr>
<tr><td>終了日</td><td>
<input type="date" th:field="*{endDate}" th:value="*{endDate}" />
</td></tr>
</table>
<input type="button" th:value="登録する" onclick="submit();" />
</form>
</body>
</html>
참고
Reference
이 문제에 관하여(【Java】날짜 기간 중복 체크 샘플), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/tamorieeeen/items/b44d75368e2e65a6283f텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)