list() GET 메서드 주석 처리
// @GetMapping("/list")
public String list(Model model, @RequestParam(value="page", defaultValue = "0") int page,
@RequestParam(value = "kw", defaultValue = "") String keyword) {
Page<Board> paging = this.boardService.getList(page, keyword); // 검색 추가
model.addAttribute("paging", paging);
model.addAttribute("kw", keyword);
return "board/list";
}
/entity/Board.java 조회수 필드 추가
private Integer hit; // 24.06.26 조회수 추가
/service/BoardService.java hitBoard() 메서드 추가
// 조회수 증가 메서드
@Transactional // 조회하면서 업데이트하므로!
public Board hitBoard(Long bno) {
// Optional 기능 => Null 체크!
Optional<Board> oboard = this.boardRepository.findByBno(bno);
if(oboard.isPresent()) {
Board board = oboard.get();
// board.setHit(board.getHit() + 1); // !!!!! 예외발생
board.setHit(Optional.ofNullable(board.getHit()).orElse(0) + 1); // getHit() 값이 null일때 0으로 바꿔라
return board;
} else {
throw new NotFoundException("board NOT FOUND!!");
}
}
💥 null point 에러 발생
board.setHit(board.getHit() + 1); // !!!!!
- null값에 +1을 하게 되면 null값을 가지고 오게 되면 null point error 발생!!
board.setHit(Optional.ofNullable(board.getHit()).orElse(0) + 1); // getHit() 값이 null일때 0으로 바꿔라
- getHit() 값이 null일때 0으로 바꿔서 예외처리
/controller/BoardController.java detail() 메서드 수정
@GetMapping("/detail/{bno}")
public String detail(Model model,
@PathVariable("bno") Long bno, ReplyForm replyForm, HttpServletRequest request) {
String prevUrl = request.getHeader("referer");//이전 페이지 변수 담기
log.info(String.format("현재 이전 페이지: %s", prevUrl));
// Board board = this.boardService.getBoard(bno);
Board board = this.boardService.hitBoard(bno); // 조회수 증가하고 리턴
model.addAttribute("board", board);
model.addAttribute("prevUrl", prevUrl); //이전 페이지 URL 뷰에 전달
return "board/detail";
}
- 기존의 Board board = this.boardService.getBoard(bno); 주석처리한 것을
- Board board = this.boardService.hitBoard(bno);로 변경
/templates/board/list.html에 new뱃지와 조회수 추가
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org" layout:decorate="~{layout}">
<div layout:fragment="main-content" class="container my-3">
<!-- 검색창 영역 -->
<div class="row my-3 align-items-center">
<div class="col-8">
<a th:href="@{|/board/create/${category}|}" class="btn btn-sm btn-primary my-2">게시글 등록</a>
</div>
<div class="col-4">
<div class="input-group">
<input type="text" id="search_kw" class="form-control" th:value="${kw}">
<button id="btn_search" type="button" class="btn btn-sm btn-outline-secondary">검색</button>
</div>
</div>
</div>
<!-- 게시글 리스트 -->
<table class="table table-light table-striped">
<thead class="table-dark">
<tr class="text-center">
<th>번호</th>
<th style="width: 50%;">제목</th>
<th>작성자</th>
<th>조회수</th>
<th>작성일</th>
</tr>
</thead>
<tbody>
<tr th:each="board, loop : ${paging}" class="text-center">
<td th:text="${paging.getTotalElements - (paging.number * paging.size) - loop.index}" class="text-end"></td>
<td class="text-start">
<a th:href="@{|/board/detail/${board.bno}|}" th:text="${board.title}"></a>
<!-- 댓글 개수 띄워주는 함수 -->
<span th:if="${#lists.size(board.replyList) > 0}" th:text="${#lists.size(board.replyList)}"
class="badge text-bg-success"></span>
<span th:if="${#temporals.format(board.createDate, 'yyyy-MM-dd') == #temporals.format(#temporals.createNow(), 'yyyy-MM-dd')}"
class="badge text-bg-primary">New</span>
</td>
<!-- 작성자 추가 -->
<td>
<span th:if="${board.writer != null}" th:text="${board.writer.username}"></span>
</td>
<!-- 조회수 추가 24.06.26 -->
<td><span th:text="${board.hit}"></span></td>
<td th:text="${#temporals.format(board.createDate, 'yyyy-MM-dd')}"></td>
<!-- <td th:text="${#temporals.format(board.createDate, 'yyyy-MM-dd HH:mm')}"></td> -->
</tr>
</tbody>
</table>
<!-- 페이징 시작 -->
<div th:if="${!paging.isEmpty()}">
<ul class="pagination justify-content-center">
<!-- 이전 버튼 -->
<li th:classappend="${!paging.hasPrevious} ? disabled" class="page-item">
<!-- classappend: 만약에 페이징에 hasPrevious값이 없으면 ? 뒤의 결과를 도출 -->
<!-- <a th:href="@{|?page=0|}" class="page-link"><<</a> 이전 방식 -->
<a th:data-page="${0}" href="javascript:void(0)" class="page-link"><<</a>
<!-- href="javascript:void(0)" : 아무일도 일어나지 않는 형태 -->
</li>
<li th:classappend="${!paging.hasPrevious} ? disabled" class="page-item">
<!-- <a th:href="@{|?page=${paging.number-1}|}" class="page-link"><</a> -->
<a th:data-page="${paging.number-1}" href="javascript:void(0)" class="page-link"><</a>
</li>
<!-- 페이지 번호 버튼 -->
<li th:each="page : ${#numbers.sequence(0, paging.totalPages-1)}"
th:if="${page >= paging.number-4 and page <= paging.number+4}"
th:classappend="${page == paging.number} ? 'active'"
class="page-item">
<!-- <a th:href="@{|?page=${page}|}" th:text="${page+1}" class="page-link"></a> -->
<a th:data-page="${page}" th:text="${page+1}" href="javascript:void(0)" class="page-link"></a>
</li>
<!-- 다음 버튼 -->
<li th:classappend="${!paging.hasNext} ? disabled" class="page-item">
<!-- <a th:href="@{|?page=${paging.number+1}|}" class="page-link">></a> -->
<a th:data-page="${paging.number+1}" href="javascript:void(0)" class="page-link">></a>
</li>
<li th:classappend="${!paging.hasNext} ? disabled" class="page-item">
<!-- <a th:href="@{|?page=${paging.totalPages-1}|}" class="page-link">>></a> -->
<a th:data-page="${paging.totalPages-1}" href="javascript:void(0)" class="page-link">>></a>
</li>
</ul>
</div>
<!-- 검색부분 영역 / 이 두 값이 GET URL ?kw=&page=1 계속 가지고 감 -->
<form th:action="@{|/board/list/${category}|}" method="get" id="searchForm">
<input type="hidden" id="kw" name="kw" th:value="${kw}"> <!-- id, name 둘다 필요 -->
<input type="hidden" id="page" name="page" th:value="${paging.number}">
</form>
</div>
<script layout:fragment="sub-script" type="text/javascript">
const page_elements =document.getElementsByClassName("page-link");
Array.from(page_elements).forEach(function(element) {
element.addEventListener("click",function(e) {
document.getElementById('page').value = this.dataset.page;
document.getElementById('searchForm').submit();
});
});
const btn_search = document.getElementById("btn_search");
btn_search.addEventListener("click", function(e) {
document.getElementById('kw').value = document.getElementById('search_kw').value;
document.getElementById('page').value = 0; // 검색할 경우 0페이지부터
document.getElementById('searchForm').submit();
});
// 검색창 엔터 검색
const search_kw = document.getElementById("search_kw");
search_kw.addEventListener("keypress", function(e) {
if(event.key == 'Enter') {
event.preventDefault(); // HTML은 부모자식관계로 구성되므로 자식에서는 이 이벤트가 발생하면 안됨.
document.getElementById('btn_search').click();
}
});
</script>
</html>
- 조회수 추가된 것 확인할 수 있음!
'Spring Boot > STUDY' 카테고리의 다른 글
[Spring Boot] JPA 프로젝트 - 에러페이지 작업 (0) | 2024.06.27 |
---|---|
[Spring Boot] JPA 프로젝트 - AWS로 서버 연결 (1) | 2024.06.26 |
[Spring Boot] JPA 프로젝트 - 카테고리 추가 (0) | 2024.06.25 |
[Spring Boot] JPA 프로젝트 - 마크다운 적용 (1) | 2024.06.25 |
[Spring Boot] JPA 프로젝트 - @Query를 사용한 검색 기능 구현(2) (0) | 2024.06.25 |