2022. 4. 26. 13:11ㆍ[Spring]_/[Spring]_포트폴리오 페이지 만들기
[환경]
개발툴 : IntelliJ
DB : oracle
프레임워크 : spring , mybatis
사용 언어 : ES6, Java , Html5 , CSS
완성 화면]
개발 목표 : 기존에 만든 게시판에서 SPA 구현을 위해 등록기능 menu1 로 병합
https://yn971106.tistory.com/78
해당 포스트에서 검색기능 추가 및 쿼리 개선, 코드 개선을 한 부분을 정리하였습니다.
[ 메뉴 1 의 전체 소스코드 ]
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<style>
.board {
width: 100%;
}
</style>
</head>
<body>
<div id="content">
<div id="contentwrap">
<h2>CRUD</h2>
<button class="regi">등록</button>
<select id="selectview">
<option value="10" selected="selected">10개씩 보기</option>
<option value="15">15개씩 보기</option>
<option value="20">20개씩 보기</option>
</select>
<select class="searchoption">
<option value="titlename">제목</option>
<option value="wirtername">작성자</option>
</select>
<input type="text" class="searchtext" value =""/>
<button class="detailsearch">조회</button>
<table border="1" class="board">
<thead>
<tr>
<th>번호</th>
<th>제목</th>
<th>글쓴이</th>
<th>작성일자</th>
<th>조회수</th>
</tr>
</thead>
<tbody id="table">
</tbody>
<!-- forEach 문은 리스트 객체 타입을 꺼낼때 많이 활용된다. -->
</table>
<span id="nav"></span>
</div>
</div>
</body>
</html>
<script>
$(document).ready(async function () {
let regibtn = document.querySelector('.regi');
let tbody = document.querySelector('#table');
let viewcnt = document.querySelector('#selectview');
let nav = document.querySelector('#nav');
let $common = $commons.history
let searchoption = document.querySelector('.searchoption');
let searchtext = document.querySelector('.searchtext');
let detailsearchbtn = document.querySelector('.detailsearch');
searchtext.onkeyup = function(e){
if(e.key === "Enter" || e.keyCode === 13 ){
detailsearchbtn.click();
}
}
viewcnt.onchange = function(){
detailsearchbtn.click();
}
regibtn.onclick = function () {
let url = "/regi/loader.do"
let parentContent = document.querySelector('#contentwrap');
let id = _commons().util.random();
$common.sethistory(url,parentContent,id);
let test = $common.gethistory(url);
console.log(test);
$('#content').load(url,function(){
});
}
detailsearchbtn.onclick = function(){
let wr;
let ti;
if(searchoption.value == "titlename" ){
ti = searchtext.value;
wr = "";
}else{
wr = searchtext.value;
ti = "";
}
createBoard(1,wr,ti);
createPagenation(wr,ti);
}
detailsearchbtn.click();
async function createPagenation(wr,ti) {
let cnt;
while(nav.firstChild){
nav.removeChild(nav.firstChild);
}
await fetch('/board/boardcount.do', {
method: "POST",
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
writer : wr,
title : ti
})
}).then(res => res.json())
.then(data => {
cnt = data;
})
//총 페이지 수
let totalpagecnt = Math.ceil(cnt / viewcnt.value);
//페이지 숫자 생성.
for (let i = 1; i <= totalpagecnt; i++) {
//html 생성하기.
let node = document.createElement('a');
const template = `
<a class="navclick" href="javascript:void(0)">\${i}</a>
`
node.innerHTML = template;
node.querySelector('a').onclick = function () {
createBoard(i,wr,ti);
}
nav.appendChild(node);
}
}
//테이블 생성
async function createBoard(nowpage,wr,ti) {
while(tbody.firstChild){
tbody.removeChild(tbody.firstChild);
}
await fetch('/board/search.do', {
method: "POST",
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
view: viewcnt.value, // ~만큼 보기
pagenum: nowpage, // 페이지 숫자클릭넘버.
writer : wr,
title : ti
})
}).then(res => res.json())
.then(data => {
for (let i = 0; i < data.length; i++) {
let node = document.createElement('tr');
const template = `
<th><a href="javascript:void(0)" class="boardlink">\${data[i].NUM}</a></th>
<th>\${data[i].title}</th>
<th>\${data[i].writer}</th>
<th>\${data[i].regdate}</th>
<th>\${data[i].viewcnt}</th>
`
node.innerHTML = template;
tbody.appendChild(node);
let boardlink = document.getElementsByClassName('boardlink');
boardlink[i].onclick =function(){
selectBoard(data[i].bno);
}
}
});
}
//테이블 목록 클릭시 함수
function selectBoard(bno){
fetch('/board/selectboard.do',{
method:"POST",
headers: {
'content-type': 'application/json'
},
body :JSON.stringify({
bno: bno
})
}).then(res => res.json())
.then(data => {
console.log(data);
console.log(data[0].content);
let url = "/board/selectboarddetail.do"
let parentContent = document.querySelector('#contentwrap');
let id = _commons().util.random();
$common.sethistory(url,parentContent,id);
let jsondata = {
"title" : data[0].title,
"content" : data[0].content,
"writer" : data[0].writer,
"regdate" : data[0].regdate,
"bno" : data[0].bno
}
$('#content').load(url,jsondata,function(){
});
})
}
});
</script>
1] 게시글 등록기능
regibtn.onclick = function () {
let url = "/regi/loader.do"
let parentContent = document.querySelector('#contentwrap');
let id = _commons().util.random();
$common.sethistory(url,parentContent,id);
let test = $common.gethistory(url);
console.log(test);
$('#content').load(url,function(){
});
}
등록 버튼 클릭시 전환할 화면 url 을 지정하고
등록 화면에서 뒤로가기 버튼 클릭시 이전의 화면을 다시 보여줘야 하기 때문에 이전에 만든 history 객체를 사용합니다.
히스토리 객체 생성은 다음 포스트 참고
https://yn971106.tistory.com/93
let $common = $commons.history
상단에 선언한 $common 변수로부터 원하는 함수를 찾아 사용 가능합니다.
저장할 element를 queryselector 를 이용해서 저장하고
이를 sethistory 를 이용해서 url을 key 값으로 element를 저장합니다.
그리고 나서 교체할 화면의 element를 선택하고 load 함수로 해당 url 요청으로 가져온 jsp 파일을
$ 선택자로 선택한 부분만 변경시킵니다.
1-2] Controller
@RequestMapping("/regi/loader.do")
public String regi() {
return "/menu/boardregister";
}
단순히 화면 전환을 위한 jsp 의 위치를 반환합니다.
2] 등록 화면 jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<div id="contentwrap2">
<input type="text" placeholder="제목" id="subject" name="subject">
<input type="text" placeholder="내용" id="writecontent" name="content">
<button type="button" class="reg">등록</button>
<button type="button" class="backbtn">취소</button>
</div>
</body>
</html>
<script src='/js/jquery-3.6.0.min.js?ver=1'></script>
<script>
$(document).ready(function(){
let title = document.querySelector('#subject');
let content = document.querySelector('#writecontent');
let $globalStorage = $commons.storage.g_variable;
let writer = $globalStorage.getValue("loginUser");
let date = $commons.util.date();
let $common = $commons.history
let backbtn = document.querySelector('.backbtn');
let regibtn = document.querySelector('.reg');
let changecontent =document.querySelector('#content');
backbtn.onclick = function(){
console.log('click back')
let test = $common.gethistory("/regi/loader.do");
console.log(test.content);
// $('#content').load("/menu/menu1.do",function (){
//
// });
let oldElement = document.querySelector('div#contentwrap2');
changecontent.replaceChild(test.content,oldElement);
};
regibtn.onclick = function(){
fetch("/board/register.do",{
method: 'POST',
headers: {
'content-type' : 'application/json'
},
body: JSON.stringify({
title: title.value,
content : content.value,
writer : writer,
regdate: date,
viewcnt : 0
})
}).then(res => res.json());
$common.deletehistory("/regi/loader.do");
let url = 'menu/menu1.do'
$('#main_content').load(url,function(){
});
}
});
</script>
해당 코드에서는 각각의 엘리먼트를 선언하고
이벤트를 달아줍니다.
2-1] 등록버튼 이벤트
regibtn.onclick = function(){
fetch("/board/register.do",{
method: 'POST',
headers: {
'content-type' : 'application/json'
},
body: JSON.stringify({
title: title.value,
content : content.value,
writer : writer,
regdate: date,
viewcnt : 0
})
}).then(res => res.json());
$common.deletehistory("/regi/loader.do");
let url = 'menu/menu1.do'
$('#main_content').load(url,function(){
});
}
해당 코드에서 사용하는 선언문은
let title = document.querySelector('#subject');
let content = document.querySelector('#writecontent');
let $globalStorage = $commons.storage.g_variable;
let writer = $globalStorage.getValue("loginUser");
let date = $commons.util.date();
let regibtn = document.querySelector('.reg');
다음과 같습니다.
코드에서는 fetch 함수를 이용해서 쿼리를 던지고 전달 데이터는 html 에 입력된 값을 전달하게 됩니다.
전달할 값 중 writer 의 경우 현제 로그인한 계정 이름이 들어가야 하기 때문에.
Localstorage 에 저장된 유저정보를 가져오고 이를 전달합니다.
Localstorage 사용은 다음 포스트 참고
https://yn971106.tistory.com/54
통신에 성공하면 화면이 전환 될 것입니다.
※Controller - Service - Mapper 구조는 이전 포스트와 동일
https://yn971106.tistory.com/78
화면 전환시 등록된 게시글이 보여야 하고, 이는 갱신을 뜻합니다.
따라서 이전의 history를 가지고 있을 필요가 없으니. 이전에 저장한 url = key 값을 가진 객체를 삭제합니다.
그리고 content element 부분에 menu1을 다시 불러옵니다.
2-2] 취소버튼 이벤트
backbtn.onclick = function(){
console.log('click back')
let test = $common.gethistory("/regi/loader.do");
console.log(test.content);
// $('#content').load("/menu/menu1.do",function (){
//
// });
let oldElement = document.querySelector('div#contentwrap2');
changecontent.replaceChild(test.content,oldElement);
};
뒤로가기란 이전에 조회한 정보, 목록이 그대로 나와야 합니다. 따라서 등록페이지 진입 전에 저장한 history 객체의 content 부분을 가져오면 됩니다.
common 에 지정한 gethistory 함수를 이용해서 url 키를 가진 객체의 content 를 가져옵니다.
그리고 현제 있는 노드 -> oldElement 를 queryselector 로 지정하고
replaceChild 함수를 이용해서 서로를 교체합니다.
URL의 이동 없이 정상적으로 화면이 바뀌는 모습을 확인 할 수 있습니다.
감사합니다.
'[Spring]_ > [Spring]_포트폴리오 페이지 만들기' 카테고리의 다른 글
[포트폴리오 페이지]_15단계_CRUD 게시판 구현_(목록 Read 기능) (0) | 2022.04.26 |
---|---|
[포트폴리오 페이지]_14단계_CRUD 게시판 구현_(검색 기능) (0) | 2022.04.26 |
[포트폴리오 페이지]_12단계_SPA 구현을 위한 History 객체 만들기 (0) | 2022.04.26 |
[포트폴리오 페이지]_11단계_CRUD 게시판 구현_(feat.페이징 처리) (0) | 2022.04.18 |
[포트폴리오 페이지]_8단계_로그인 기능구현_(feat.oracleDB) (0) | 2022.04.03 |