아아아
CSS는 아에 하기 싫다...
그냥 Json으로 뿌릴까? ㅠㅠㅠ
최근 알고리즘쪽에 재미 들려서 그거 하다가 이거 소홀히 하게 됨 ㅋㅋ
대충 검색 페이지 만든거...
추가 된 기능이라 하면
get 요청을 할 때 아에 모델에 넣어서 보내기로 했다.
@GetMapping("/search")
public String searchLottoCountCondition(Model model) {
model.addAttribute(new WinNumberSearchDto());
model.addAttribute("leastCount", leastDrawNumberAndDateDto);
return "searchLotto";
}
실은 dto 클래스를 메서드를 통해 매번 생성해서 넘기는 방식이었는데, 에러 핸들을 하다 보니 그냥 메서드를 빈 등록해서 상수처럼 때리면 어떨까 싶었음.
@Bean
public LeastDrawNumberAndDateDto setLeastDrawNumberAndDateDto() {
Pageable pageable = PageRequest.of(0, 1, Sort.Direction.DESC, "drawNo");
Page<WinNumber> find = winNumberRepository.findLastIndex(pageable);
List<WinNumber> content = find.getContent();
WinNumber winNumber = content.get(0);
return new LeastDrawNumberAndDateDto(winNumber.getDrawNoDate(), winNumber.getDrawNo());
}
이제 보니까 그냥 메서드 처리 했어도 될 거 같은데, 이미 이렇게 한거 일단 냅둬보고 뭔 문제가 생기면 다시 돌리면 되겠지 싶음
<div class="menu-name">
<h2>로또 당첨 이력 횟수 조회</h2>
<div th:object="${leastCount}">
<h3>최신 당첨 이력 날짜</h3>
<p th:text="*{drawNoDate}">최신 당첨 날짜</p>
<h3>최신 당첨 회차</h3>
<p th:text="${leastCount.drawNo} + '회'">최신 당첨 회차</p>
</div>
</div>
꾸미는거 나중에 생각하고 일딴 때려 박아줬다.
<div>
<button class="refresh"> 당첨 이력 새로 고침 보턴 </button>
</div>
버튼 만들고...
<script>
const refresh = document.querySelector(".refresh");
refresh.addEventListener("click", () => {
alert("당첨 이력을 확인 하고 최신화 합니다.");
location.href='refresh';
})
</script>
그냥 새로고침 되면 잘 모르니까 얼럿창을 띄우기로함. 그리고 refresh 요청을 때린다.
@GetMapping("/refresh")
public String refreshWinNumberDB() {
winNumberService.refreshWinNumber();
return "redirect:search";
}
public void refreshWinNumber() {
setUp.saveWinNumberForStart();
}
굳이 이렇게 계층을 나눠야 하나 싶기도 함. 그냥 setup을 DI 받아서 쓸까...
몇 개의 당첨 회차를 분석할 것인가! 에서 숫자를 입력받는데
이게 0이면 에러를 넣어줘야 한다.
<form action="/search" th:object="${winNumberSearchDto}" method="post" >
<label>최근 회차 기준 몇 회 전까지 분석합니까? (ex : 100을 입력할 경우! 최신회차-100 ~ 최신회차)</label>
<br>
<input type="text" th:field="*{count}" th:errorclass="field-error">
<div class="field-error" th:errors="*{count}"> 잘못 된 데이터 </div>
<button type="submit"> 검색 </button>
</form>
html은 이런 식으로 해두자. 에러가 있으면 알아서 뻘개지게 해놨다.
@PostMapping("/search")
public String searchLottoCount(@Valid WinNumberSearchDto winNumberSearchDto,
BindingResult bindingResult,
Model model) {
if (bindingResult.hasErrors()) {
// 에러 처리
log.error("에러 발생! = {}", bindingResult);
model.addAttribute("leastCount", leastDrawNumberAndDateDto);
return "searchLotto";
}
HistoryNumber historyNumber = winNumberService.makeHistoryNumber(winNumberSearchDto.getCount());
model.addAttribute("result", historyNumber);
return "winCount";
}
bindingResult에 에러가 있다면 로그를 찍어주고 searchLotto로 넘어간다.
이 때, 최신 당첨 회차 값을 넘겨줘야 해서 모델에 Dto를 하나 넘겨줬다.
public HistoryNumber makeHistoryNumber(int count) {
int[] countNumbers = new int[45];
Map<Integer, Integer> mostNumbers = new TreeMap<>();
Map<Integer, Integer> minNumbers = new TreeMap<>();
List<WinNumber> content = setContent(count);
setCountNumbers(content, countNumbers);
setTreeMaps(countNumbers, mostNumbers, minNumbers);
return new HistoryNumber(mostNumbers, minNumbers, countNumbers);
}
private List<WinNumber> setContent(int count) {
Pageable pageable = PageRequest.of(0, count, Sort.Direction.DESC, "drawNo");
Page<WinNumber> find = winNumberRepository.findLastIndex(pageable);
List<WinNumber> content = find.getContent();
return content;
}
private void setTreeMaps(int[] countNumbers, Map<Integer, Integer> mostNumbers, Map<Integer, Integer> minNumbers) {
int max = Arrays.stream(countNumbers).max().getAsInt();
int min = Arrays.stream(countNumbers).min().getAsInt();
for (int i = 0; i < countNumbers.length; i++) {
int countNumber = countNumbers[i];
if (countNumber == max) {
mostNumbers.put(i + 1, countNumber);
} else if (countNumber == min) {
minNumbers.put(i + 1, countNumber);
}
}
}
private static void setCountNumbers(List<WinNumber> content, int[] countNumbers) {
content.stream()
.forEach(e -> {
int winNumber1 = e.getWinNumber1() - 1;
int winNumber2 = e.getWinNumber2() - 1;
int winNumber3 = e.getWinNumber3() - 1;
int winNumber4 = e.getWinNumber4() - 1;
int winNumber5 = e.getWinNumber5() - 1;
int winNumber6 = e.getWinNumber6() - 1;
countNumbers[winNumber1]++;
countNumbers[winNumber2]++;
countNumbers[winNumber3]++;
countNumbers[winNumber4]++;
countNumbers[winNumber5]++;
countNumbers[winNumber6]++;
});
}
이 전 방식은 int[] 인덱스가 당첨 번호를 뜻하는 거라 전체 번호를 넘기면 괜찮은데 아닐 경우 앞단에 보내기가 애매했음. 그래서 map을 활용했다.
setContent는 db에서 당첨 번호들을 불러오는 역할
setCountNumbers는 int[]를 채우는 역할이다.
setTreeMaps는 최다빈도, 최소빈도 번호들을 각각 넣어준다.
<h3>가장 당첨 빈도가 높은 숫자</h3>
<ul th:each="mostNumber : ${result.getMostNumbers()}">
<li> <span th:text="${mostNumber.getKey()} + ' : ' + ${mostNumber.getValue()} + '회'"> </span> </li>
</ul>
<h3>가장 당첨 빈도가 낮은 숫자</h3>
<ul th:each="minNumber : ${result.getMinNumbers()}">
<li> <span th:text="${minNumber.getKey()} + ' : ' + ${minNumber.getValue()} + '회'"> </span> </li>
</ul>
이런 식으로 html을 대충 후려갈겨 주자.
그럼 이런 화면이 된다.
RestApi만 만들다가 모델을 쓰려니까 에러 핸들이 좀 헷갈렸었다.
그래도 뭐 아직 어려운 부분은 하진 않고 있으니...