게시판 상세조회 (3)
게시판 등록기능 (2)
지난 포스팅은 html 및 js를 다뤘다. 이어서 백엔드를 진행해보려한다. xhr.open('POST', '/auth/admin/manage/board_list', true);js에서 getBoardList라는 함수를 실행하고해당 URL에 POST방식으로 요청을 보낸다. 1.C
ekeprl.tistory.com
지난 포스팅에서 게시판에 글을작성하고 등록하는 기능을 완성했다.
이번 포스팅은 해당 게시물을 클릭해 모달을 띄워 작성한 내용을 보여주는 기능을 작성하려한다.
작성한 글들을 보여주는 게시판이다.
1.JS
/*게시판 상세 모달*/
clickList: function (idx) {
var item = document.getElementsByClassName('Boardlist');
for (var i = 0; i < item.length; i++) {
item[i].classList.remove('clickon');
}
if (item[idx]) {
item[idx].classList.add('clickon');
} else {
console.warn('item[' + idx + '] is undefined');
}
// 단순히 데이터만 요청 (모달은 응답 받은 뒤 열기)
BoardJS.getBoarddetailList(BoardData[idx].board_id);
},
게시판에서 게시글을 선택하면,
클릭한 게시물의 색상을 바꿔 표시를 해주고,
BoardJS.getBoarddetailList(board_id)를 실행시킨다.
클릭 시 해당 게시물의 idx를 따라 board_id를 변수로 넘기는 형식으로 구성했다.
getBoarddetailList : function (board_id) {
var formdata = new FormData();
formdata.append('board_id',board_id);
// CSRF 토큰 추가 (input hidden에서 가져오는 경우)
var csrfToken = document.getElementById('_csrf')?.value;
var csrfHeader = '_csrf'; // 서버에서 기대하는 파라미터 이름 (Spring Security 기본값)
if (csrfToken) {
formdata.append(csrfHeader, csrfToken);
}
var xhr = new XMLHttpRequest();
xhr.timeout = 1000 * 90;
xhr.open('POST', '/auth/admin/manage/board_list_detail', true);
xhr.responseType = 'text';
xhr.setRequestHeader('Pragma', 'no-cache');
xhr.setRequestHeader('Cache-Control', 'no-cache, must-revalidate');
xhr.onreadystatechange = function () { };
xhr.ontimeout = function() { alert('요청 응답 시간 초과\n' + xhr.responseURL); };
xhr.onload = function () {
var res = JSON.parse(xhr.response);
if (res.RESULT === 'OK') {
if (res.LIST.length < 1) {
alert('조회 결과가 없습니다.');
} else {
var data = res.LIST[0];
BoardData[0] = data;
document.getElementById('board_detail_title').innerText = data.title;
document.getElementById('board_detail_regdate').innerText = data.regdt;
// BLOB -> 텍스트 출력
try {
document.getElementById('board_detail_contents').innerText = data.contents;
} catch (e) {
document.getElementById('board_detail_contents').innerText = '[내용이 없습니다]';
}
// 포커스 충돌 방지: 열기 전에 포커스 제거
document.activeElement?.blur();
var BoardDetailModal = new bootstrap.Modal(document.getElementById('BoardDetailModal'));
BoardDetailModal.show();
}
} else {
alert(res.MESSAGE);
}
};
xhr.onerror = function() { alert('ERROR : ' + xhr.status); };
xhr.send(formdata);
},
실행하는 함수를 설명하자면,
formdata에 저장되어있는 변수를 넘기는 형식을 사용했는데
Board.html에 작성되어있는 formdata에는 필요한 변수인 board_id가 들어있지않아.
따라서 함수를 실행할때 받아오는 변수 board_id를 formdata.append()를 통해 인입해주었다.
Spring Security (1) ~ (6)에 작성한 스프링시큐리티에서 CSRF토큰을 받아서 검증을 하기때문에
var csrfToken = document.getElementById('_csrf')?.value;
var csrfHeader = '_csrf';
HTML에 작성해두었던 input type="hidden"값을 받아와 인입했다.
var BoardDetailModal = new bootstrap.Modal(document.getElementById('BoardDetailModal'));
BoardDetailModal.show();
게시물을 상세보기할때 모달창을 열어서 보여주기위해 모달창을 띄우는 코드를 작성했다.
2. HTML
<!-- 게시판 상세보기 모달 -->
<div id="BoardDetailModal" class="modal fade" tabindex="-1" aria-labelledby="BoardDetailModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header px-4">
<h1 class="modal-title fs-4 fw-bold" id="BoardDetailModalLabel">게시글 상세보기</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body px-4">
<div class="mb-3">
<label for="board_detail_title" class="form-label fw-bold">제목</label>
<div id="board_detail_title" class="form-control bg-light" readonly></div>
</div>
<div class="mb-3">
<label for="board_detail_regdate" class="form-label fw-bold">작성일</label>
<div id="board_detail_regdate" class="form-control bg-light" readonly></div>
</div>
<div class="mb-3">
<label for="board_detail_contents" class="form-label fw-bold">내용</label>
<div id="board_detail_contents" class="form-control bg-light" style="min-height: 200px; white-space: pre-wrap;" readonly></div>
</div>
</div>
</div>
</div>
</div>
html에 작성한 모달창이다.
기초 구성은 제목, 작성일, 내용 세가지만 간단하게 출력하도록 작성했다.
3.Controller
/*게시판 상세조회*/
@ResponseBody
@RequestMapping(value = [("/auth/admin/manage/board_list_detail")], method = [(RequestMethod.POST)])
@Throws(Exception::class)
fun adminBoardDetailSelectList(board_id : String) : JSONObject {
return service.adminBoardDetailSelectList(board_id)
}
getBoarddetailList => js에서 이 함수가 실행되면
xhr.open('POST', '/auth/admin/manage/board_list_detail', true);
이 코드를 통해 controller에있는 상세조회를 실행시킨다.
4.Service
/*
* 게시판 상세 조회
* */
fun adminBoardDetailSelectList(board_id : String) : JSONObject{
val jobj = JSONObject()
try{
jobj["RESULT"] = "OK"
jobj["LIST"] = mapper.adminBoardDetailSelectList(board_id)
}catch (ex : Exception) {
logger.error("ERROR : ", ex)
jobj["RESULT"] = "ERROR"
jobj["MESSAGE"] = ex.toString()
}
return jobj
}
서비스단에서 json을 통해 값을 받아 사용한다.
5.mapper
/*
* 게시판 상세 조회
* */
fun adminBoardDetailSelectList(board_id : String) : List<HashMap<String, String>>
6.mapper.xml
<select id="adminBoardDetailSelectList" parameterType="String"
resultType="com.steamchk.ekeprl.www.common.model.BoardModel">
SELECT
title
, regdt
, contents
FROM user_board
WHERE board_id = #{board_id}
</select>
결과적으로 받아온 board_id(유니크값)을 변수로 넣어
해당 쿼리를 실행하고, 지난 게시판 글에 작성했던 model형식으로 반환을 해준다.
7.결과
작성한 게시물의 제목, 작성일, 내용이 출력되는것을 확인할 수 있다.
오늘은 여기서 마무리..!