21.01.27 JSPCommunity 프로젝트(게시물 페이징 추가, 토스트에디터,뷰어 추가)
2021. 1. 27. 19:51ㆍJAVA/JSP Community 사이트 프로젝트
<UsrArticleController.java>
// 리스트 가져오기
public String showList(HttpServletRequest request, HttpServletResponse response) {
int boardId = Integer.parseInt(request.getParameter("boardId"));
String searchKeywordType = request.getParameter("searchKeywordType");
String searchKeyword = request.getParameter("searchKeyword");
// 총 게시물 수 카운트
int totalCount = articleService.getArticlesCountByBoardId(boardId, searchKeywordType, searchKeyword);
// 페이징
int articlesInAPage = 10; // 한 페이지에 들어갈 article 수 설정
int page = Util.getAsInt(request.getParameter("page"), 1); // pageNum이 null이면 1로 변환, 정수형(int)이 아니면 정수형으로
// 변환
int pageLimitStartIndex = (page - 1) * articlesInAPage;
List<Article> articles = articleService.getArticlesForPrintByBoardId(boardId, pageLimitStartIndex,
articlesInAPage, searchKeywordType, searchKeyword);
int pageMenuBoxSize = 5; // 한 메인페이지 화면에 나올 하단 페이지 메뉴 버튼 수 ex) 1 2 3 4 5 6 7 8 9 10
int totalArticlesCount = totalCount; // 전체 article의 수 카운팅
int totalPages = (int) Math.ceil((double) totalArticlesCount / articlesInAPage); // 총 필요 페이지 수 카운팅
// 총 필요 페이지 수까지 버튼 만들기
// 하단 페이지 이동 버튼 메뉴 만들기
// 1. pageMenuBox내 시작 번호, 끝 번호 설정
int previousPageNumCount = (page - 1) / pageMenuBoxSize; // 현재 페이지가 2이면 previousPageNumCount = 1/5
int boxStartNum = pageMenuBoxSize * previousPageNumCount + 1; // 총 페이지 수 30이면 1~5 6~10 11~15
int boxEndNum = pageMenuBoxSize + boxStartNum - 1;
if (boxEndNum > totalPages) {
boxEndNum = totalPages;
}
// 2. '이전','다음' 버튼 페이지 계산
int boxStartNumBeforePage = boxStartNum - 1;
if (boxStartNumBeforePage < 1) {
boxStartNumBeforePage = 1;
}
int boxEndNumAfterPage = boxEndNum + 1;
if (boxEndNumAfterPage > totalPages) {
boxEndNumAfterPage = totalPages;
}
// 3. '이전','다음' 버튼 필요 유무 판별
boolean boxStartNumBeforePageBtnNeedToShow = boxStartNumBeforePage != boxStartNum;
boolean boxEndNumAfterPageBtnNeedToShow = boxEndNumAfterPage != boxEndNum;
// 만약, 해당 게시판 번호의 게시판이 없으면 알림 메시지와 뒤로 돌아가기 실시
if (articles.size() <= 0) {
request.setAttribute("alertMsg", "해당 키워드가 포함된 게시물이 존재하지 않습니다.");
request.setAttribute("historyBack", true); // historyBack: 뒤로 돌아가기
return "common/redirect";
}
request.setAttribute("totalCount", totalCount);
request.setAttribute("articles", articles);
request.setAttribute("totalCount", totalCount);
request.setAttribute("page", page);
request.setAttribute("boxStartNum", boxStartNum);
request.setAttribute("boxEndNum", boxEndNum);
request.setAttribute("boxStartNumBeforePage", boxStartNumBeforePage);
request.setAttribute("boxEndNumAfterPage", boxEndNumAfterPage);
request.setAttribute("boxStartNumBeforePageBtnNeedToShow", boxStartNumBeforePageBtnNeedToShow);
request.setAttribute("boxEndNumAfterPageBtnNeedToShow", boxEndNumAfterPageBtnNeedToShow);
return "usr/article/list";
}
<list.jsp>
<!-- 메인-리스트 하단 메뉴 시작 -->
<div class="article-page-menu-section">
<div class="article-page-menu">
<ul class="flex flex-jc-c">
<c:if test="${boxStartNumBeforePageBtnNeedToShow}">
<c:set var="aUrl" value="?boardId=${param.boardId}&page=${boxStartNumBeforePage}&searchKeywordType=${param.searchKeywordType}&searchKeyword=${param.searchKeyword}" />
<li class="before-btn"><a href="${aUrl}" class="flex flex-ai-c"> < 이전</a></li>
</c:if>
<c:forEach var="i" begin="${boxStartNum}" end="${boxEndNum}" step="1">
<c:set var="aClass" value="${page == i ? 'article-page-menu__link--selected' : '???' }" />
<c:set var="aUrl" value="?boardId=${param.boardId}&page=${i}&searchKeywordType=${param.searchKeywordType}&searchKeyword=${param.searchKeyword}" />
<li><a href="${aUrl}" class="page-btn flex flex-ai-c ${aClass}">${i}</a></li>
</c:forEach>
<c:if test="${boxEndNumAfterPageBtnNeedToShow}">
<c:set var="aUrl" value="?boardId=${param.boardId}&page=${boxEndNumAfterPage}&searchKeywordType=${param.searchKeywordType}&searchKeyword=${param.searchKeyword}" />
<li class="after-btn"><a href="${aUrl}" class="flex flex-ai-c">다음 ></a></li>
</c:if>
</ul>
</div>
</div>
<!-- 메인-리스트 하단 메뉴 끝 -->
<common.js>
function ArticleDetail__Body__init() {
if (toastui === undefined) {
return;
}
/* 유튜브 함수 시작 */
//유튜브 영상임을 감지하고 공간을 형성하는 함수
function youtubePlugin() {
toastui.Editor.codeBlockManager.setReplacer('youtube', youtubeId => {
// Indentify multiple code blocks
const wrapperId = `yt${Math.random()
.toString(36)
.substr(2, 10)}`;
// Avoid sanitizing iframe tag
setTimeout(renderYoutube.bind(null, wrapperId, youtubeId), 0);
return `<div id="${wrapperId}"></div>`;
});
}
//유튜브 영상 렌더링 함수
function renderYoutube(wrapperId, youtubeId) {
const el = document.querySelector(`#${wrapperId}`);
el.innerHTML = `<div class="toast-ui-youtube-plugin-wrap"><iframe src="https://www.youtube.com/embed/${youtubeId}" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></div>`;
}
/* 유튜브 함수 끝 */
/* codepen 함수 시작 */
function codepenPlugin() {
toastui.Editor.codeBlockManager.setReplacer('codepen', url => {
const wrapperId = `yt${Math.random().toString(36).substr(2, 10)}`;
// Avoid sanitizing iframe tag
setTimeout(renderCodepen.bind(null, wrapperId, url), 0);
return `<div id="${wrapperId}"></div>`;
});
}
function renderCodepen(wrapperId, url) {
const el = document.querySelector(`#${wrapperId}`);
var urlParams = new URLSearchParams(url.split('?')[1]);
var height = urlParams.get('height');
el.innerHTML = `<div class="toast-ui-codepen-plugin-wrap"><iframe height="${height}" scrolling="no" src="${url}" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true"></iframe></div>`;
}
/* codepen 함수 끝 */
/* toastui-editor 함수 시작 */
function Editor__init() {
$('.toast-ui-editor').each(function(index, node) {
var initialValue = $(node).prev().html().trim().replace(/t-script/gi, 'script');
var editor = new toastui.Editor({
el: node,
previewStyle: 'vertical',
initialValue: initialValue,
height:600,
plugins: [toastui.Editor.plugin.codeSyntaxHighlight, youtubePlugin, codepenPlugin]
});
$(node).data('data-toast-editor', editor);
});
}
/* toastui-editor 함수 끝 */
/* toastui-viewer 함수 시작 */
function EditorViewer__init() {
$('.toast-ui-viewer').each(function(index, node) {
var initialValue = $(node).prev().html().trim().replace(/t-script/gi, 'script');
// var body = document.querySelector('.article-detail-cell__body > div > span');
// var initValue = body.innerHTML.trim();
var viewer = new toastui.Editor.factory({
el: node,
initialValue: initialValue,
viewer: true,
plugins: [toastui.Editor.plugin.codeSyntaxHighlight, youtubePlugin, codepenPlugin]
});
});
}
EditorViewer__init();
Editor__init();
}
ArticleDetail__Body__init();
/* toastui-viewer 함수 끝 */
<doWriteForm.jsp>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<c:set var="pageTitle" value="신규 게시물 등록" />
<%@ include file="../../part/head.jspf"%>
<h1>${pageTitle}</h1>
<script>
let DoWriteForm_submited = false;
function check(form){
if(DoWriteForm_submited){
alert('처리중입니다.');
return;
}
if(form.title.value.trim().length == 0){
alert("제목을 입력하세요.")
form.title.focus();
return false;
}
const editor = $(form).find('.toast-ui-editor').data('data-toast-editor');
const body = editor.getMarkdown().trim();
if(body.length == 0){
alert("내용을 입력하세요.")
form.body.focus();
return false;
}
form.body.value = body;
form.submit();
DoWriteForm_submited = true;
}
</script>
<form name="form" onsubmit="check(this); return false;" action="doWrite" method="POST">
<input type="hidden" name="boardId" value="${param.boardId}">
<input type="hidden" name="body">
<span>TITLE</span>
<br />
<input type="text" name="title" maxlength="50" placeholder="제목 입력">
<hr />
<span>BODY</span>
<br />
<script type="text/x-template"></script>
<div class="toast-ui-editor"></div>
<hr />
<input type="submit" value="등록">
<button type="button" onclick="history.back();">뒤로가기</button>
</form>
<%@ include file="../../part/foot.jspf"%>