지난 시간에 정리했던 jsp와 Thymeleaf 동시에 사용하기를 토대로 기존 jsp게시판의 화면을 thymeleaf로 동일하게 보여줄 수 있도록 수정해보겠다.
우선 기존 board/main.jsp
안의 내용을 그대로 복사해서 resources/templates/thymeleaf
안에 board.html
파일 생성 후 붙여넣기를 해준다.
그 다음 타임리프를 사용하기 위해 다음 작업을 해준다.
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
컨트롤러에서 리턴될 페이지 위치를 변경해준다.
BoardConroller.java
@RequestMapping("/main")
public String main(Board board, Model model, @RequestParam(defaultValue = "1") int page){
// 게시글 총 개수
int total = boardService.cntBoard();
model.addAttribute("cntBoard", total);
// 페이징
PaginateDto paginate = new PaginateDto(5, 3);
paginate.setPageNo(page);
paginate.setTotalSize(total);
board.setPageNo(page);
board.setPageSize(paginate.getPageSize());
board.setPageOffset(paginate.getPageOffset());
model.addAttribute("paginate", paginate);
model.addAttribute("board", boardService.getBoardlist(board));
//return "board/main";
return "thymeleaf/main";
}
수정된 main.html 코드 전체이다.
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>게시판 메인 - 타임리프</title>
<style>
.button-container {
margin-top: 20px;
}
.button-container input {
margin-right: 10px;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
}
th {
background-color: #f2f2f2;
}
</style>
</head>
<body>
<h1>게시글 목록</h1>
게시판 총 <span th:text="${cntBoard}">0</span> 개
<table>
<thead>
<tr>
<th class="one wide">번호</th>
<th class="ten wide">글제목</th>
<th class="two wide">작성자</th>
<th class="three wide">작성일</th>
<th class="four wide">조회수</th>
</tr>
</thead>
<tbody>
<tr th:each="board : ${board}">
<td><span th:text="${board.bno}">1</span></td>
<td><a th:href="@{/board/{bno}(bno=${board.bno})}"><span th:text="${board.title}">제목</span></a></td>
<td><span th:text="${board.writer}">작성자</span></td>
<td><span th:text="${board.regdate}">작성일</span></td>
<td><span th:text="${board.hit}">조회수</span></td>
</tr>
</tbody>
</table>
<!-- 로그인 여부에 따라 버튼 표시 -->
<div class="button-container">
<div th:if="${#httpServletRequest.remoteUser != null}">
<!-- 사용자가 로그인한 경우 -->
<input type="button" value="user 목록" onclick="location.href='/user/main'"><br/><br/>
<input type="button" value="글 작성" onclick="location.href='/write'"><br/><br/>
<input type="button" value="로그아웃" onclick="location.href='/logout'"><br/><br/>
</div>
<div th:if="${#httpServletRequest.remoteUser == null}">
<!-- 사용자가 로그인하지 않은 경우 -->
<input type="button" value="로그인" onclick="location.href='/login'"><br/><br/>
<input type="button" value="회원가입" onclick="location.href='/join'"><br/><br/>
</div>
</div>
<!-- 페이징 처리 시작 -->
<div class="col-sm-12 col-md-7" style="margin: auto">
<div class="dataTables_paginate paging_simple_numbers" id="dataTable_paginate">
<div class="paging">
<div th:if="${paginate != null}">
<!-- 이전 페이지 링크 -->
<div th:if="${paginate.nationBegin > 1}">
<a th:href="@{${paginate.params}(${paginate.pageName}=${paginate.nationBegin - 1})}" page="${paginate.nationBegin - 1}" class="prev">이전</a>
</div>
<div th:if="${paginate.nationBegin <= 1}">
<a href="#" onclick="return false" class="prev">이전</a>
</div>
<!-- 페이지 번호 링크 -->
<span th:each="pageNum : ${#numbers.sequence(paginate.nationBegin, paginate.nationClose)}">
<span th:if="${pageNum == paginate.pageNo}">
<strong class="current" th:text="${pageNum}">1</strong>
</span>
<span th:if="${pageNum != paginate.pageNo}">
<a th:href="@{${paginate.params}(${paginate.pageName}=${pageNum})}" th:text="${pageNum}">1</a>
</span>
</span>
<!-- 다음 페이지 링크 -->
<div th:if="${paginate.nationClose < paginate.totalPage}">
<a th:href="@{${paginate.params}(${paginate.pageName}=${paginate.nationClose + 1})}" page="${paginate.nationClose + 1}" class="next">다음</a>
</div>
<div th:if="${paginate.nationClose >= paginate.totalPage}">
<a href="#" onclick="return false" class="next">다음</a>
</div>
</div>
</div>
</div>
</div>
<!-- 페이징 처리 끝 -->
</body>
</html>
이제 컨트롤러에서 글 상세, 작성 메서드의 리턴 페이지 위치 또한 변경해준다.
BoardController.java
@GetMapping("/board/{bno}")
public String boardDetail(@PathVariable Integer bno, Model model, Board board){
Board boardDetail = boardService.getBoard(bno);
List<FileDto> file = boardService.getFile(board);
board.setHit(boardService.hit(bno));
model.addAttribute("board", boardDetail);
model.addAttribute("getFile", file);
return "thymeleaf/write";
}
@RequestMapping("/write")
public String write(Model model, Board board){
// 모델에 사용자 정보 추가
aop.addUserToModel(model);
if(board.getBno()==null){
model.addAttribute("getBoard", board);
model.addAttribute("getFile", boardService.getFile(board));
}
return "thymeleaf/write";
}
board/write.jsp
안의 코드를 write.html
로 복사 붙여넣기 한 후 thymeleaf를 적용시켜준다.
완성코드는 다음과 같다.
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
<title>글 상세</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
</head>
<body>
<h1>글 상세보기</h1>
<form id="boardForm" method="post" action="/insertBoard">
<table width="90%">
<tr width="90%">
<td width="10%" align="center">작성자</td>
<td width="50%" th:if="${board.writer}" th:text="${board.writer}">작성자</td>
<!-- <td width="50%">${user.username}</td> -->
<td width="50%" th:text="${user}">사용자</td>
</tr>
<tr>
<td align="center">제목</td>
<td><input type="text" name="title" style="width: 95%;" th:value="${board.title}"></td>
</tr>
<tr>
<td align="center">내용</td>
<td><textarea name="content" style="width: 95%;height: 200px;" th:text="${board.content}"></textarea></td>
</tr>
<tr>
<td align="center">첨부파일 등록</td>
<td>
<input type="file" name="files" id="files" multiple="multiple" onchange="uploadFile(this)">
<div id="uploadDiv">
<div th:each="file, status : ${getFile}" class="uploadResult">
<span th:text="${status.index + 1} + '. '">1. </span>
<a th:href="@{/downloadFile(uuid=${file.uuid}, fileName=${file.filename})}" th:text="${file.filename}" download>파일명</a>
<input type="hidden" name="uuids" th:value="${file.uuid}">
<input type="hidden" name="filenames" th:value="${file.filename}">
<input type="hidden" name="contentTypes" th:value="${file.contentType}">
<label class="delBtn">◀ 삭제</label>
</div>
</div>
</td>
<br><br><br>
</tr>
<tr>
<td colspan="2" align="center">
<input type="hidden" name="bno" th:value="${board.bno}">
<button type="submit">등록</button>
<button type="button" onclick="history.back()">뒤로가기</button>
<button type="button" th:if="${board.bno}" onclick="deleteBoard()">삭제</button>
</td>
</tr>
</table>
</form>
<script>
// delBtn 개별 삭제 버튼
$(function () {
delBtnFile();
});
function delBtnFile() {
$(".delBtn").on("click", function () {
$(this).parent().remove();
stCnt();
});
}
// status.count ajax사용시 다시 그려주기
function stCnt() {
$('.uploadResult').each(function(index, item){
$(this).children('span').html(index + 1 + '. ');
});
}
// ajax 첨부파일 업로드
function uploadFile(obj) {
let files = obj.files;
let formData = new FormData();
for (let i = 0; i < files.length; i++){
formData.append("files", files[i]);
}
$.ajax({
type: 'post',
enctype: 'multipart/form-data',
url: '/ajaxFile',
data: formData,
processData: false,
contentType: false,
success: function(data) {
console.log(data);
let result = "";
let cnt = $('.uploadResult').length;
for (let i = 0; i < data.length; i++){
result += '<div class="uploadResult">';
result += '<span>' + (cnt + i + 1) + '. </span><a href="/downloadFile?uuid=' + data[i].uuid + '&filename=' + data[i].filename + '" download>' + data[i].filename + '</a>';
result += '<input type="hidden" name="uuids" value="' + data[i].uuid + '">';
result += '<input type="hidden" name="filenames" value="' + data[i].filename + '">';
result += '<input type="hidden" name="contentTypes" value="' + data[i].contentType + '">';
result += '<label type="button" class="delBtn"> ◀ 삭제</label>';
result += '</div>';
}
$('#uploadDiv').append(result);
delBtnFile();
}
});
}
// 글 삭제
function deleteBoard() {
const bno = document.getElementsByName("bno")[0].value;
if (confirm("정말 삭제하시겠습니까?")) {
fetch(`/delete/${bno}`, {
method: 'DELETE'
})
.then(response => {
if (response.ok) {
alert("삭제되었습니다.");
location.href = "/main";
} else {
alert("삭제에 실패하였습니다.");
}
})
.catch(error => {
console.error("Error:", error);
alert("삭제 중 오류가 발생하였습니다.");
});
}
}
</script>
</body>
</html>
이렇게까지 하면 기존 jsp에서 thymeleaf가 적용된 html파일로 변경된다.
기능 수행 및 화면은 기존과 동일하다.
잘보고갑니다!^^