[AJAX + SPA게시판 클라이언트단 글 작성, 삭제 구현]
1. index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath }/CSS/common.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://kit.fontawesome.com/a076d05399.js"></script>
<script src="${pageContext.request.contextPath }/JS/board.js"></script>
<title>SPA 게시판</title>
</head>
<body>
<h2>게시판 - SPA</h2>
<%-- 글목록 --%>
<div id="list">
<div class="d01">
<div class="left" id="pageinfo"></div>
<div class="right" id="pageRows"></div>
</div>
<div class="clear"></div>
<form id="frmList" name="frmList">
<table>
<thead>
<th>#</th>
<th>UID</th>
<th>제목</th>
<th>작성자</th>
<th>조회수</th>
<th>작성일</th>
</thead>
<tbody>
</tbody>
</table>
</form>
<%--버튼 --%>
<div class="d01">
<div class="left">
<button type="button" id="btnDel" class="btn danger">글삭제</button>
</div>
<div class="right">
<button type="button" id="btnWrite" class="btn success">글작성</button>
</div>
</div>
</div>
<br>
<%-- 페이징 --%>
<div class="center">
<ul class="pagination" id="pagination">
</ul>
</div>
<%--글작성 --%>
<div id="dlg_write" class="modal">
<form class="modal-content animate" id="frmWrite" name="frmWrite" method="post">
<div class="container">
<h3>새글 작성</h3>
<span class="close" title="Close Modal">×</span>
<label for="subject"><b>글제목</b></label>
<input type="text" placeholder="글제목(필수)" name="subject" required>
<label for="name"><b>작성자</b></label>
<input type="text" placeholder="작성자(필수)" name="name" required>
<label for="content"><b>내용</b></label>
<textarea placeholder="글내용" name="content"></textarea>
<button type="submit" class="btn success">작성</button>
</div>
</form>
</div>
</body>
</html>
2. board.js
var page = 1 // 현재 페이지
var pageRows = 10 // 한 페이지에 보여지는 게시글 개수
$(document).ready(function(){
// 게시판 목록 1페이지 로딩
loadPage(page);
// 글작성 버튼 누르면 팝업
$("#btnWrite").click(function() {
$("#dlg_write").show();
});
// 모달 대화상자에서 close 버튼 누르면 닫기
$(".modal .close").click(function(){
$(this).parents(".modal").hide();
});
// 글 작성 submit 되면
$("#frmWrite").submit(function(){
$(this).parents(".modal").hide();
return chkWrite();
});
// 글 삭제 버튼 누르면
$("#btnDel").click(function(){
chkDelete();
});
});
// page 번째 페이지 로딩
function loadPage(page){
$.ajax({
url : "list.ajax?page=" + page + "&pageRows=" + pageRows
, type : "GET"
, cache : false
, success : function(data, status){
if(status == "success"){
//alert("AJAX 성공: 받아쮸~");
updateList(data);
}
}
});
} // end loadPage()
//
function updateList(jsonObj){
result = "";
if(jsonObj.status == "OK"){
var count = jsonObj.count;
// 전역변수 업데이트!
window.page = jsonObj.page;
window.pageRows = jsonObj.pagerows;
var i;
var items = jsonObj.data; // 배열
for(i = 0; i < count; i++){
result += "<tr>\n";
result += "<td><input type='checkbox' name='uid' value='" + items[i].uid + "'></td>\n";
result += "<td>" + items[i].uid + "</td>\n";
result += "<td>" + items[i].subject + "</td>\n";
result += "<td>" + items[i].name + "</td>\n";
result += "<td>" + items[i].viewcnt + "</td>\n";
result += "<td>" + items[i].regdate + "</td>\n";
result += "</tr>\n";
} // end for
$("#list tbody").html(result); // 테이블 업데이트!
// 페이지 정보 업데이트
$("#pageinfo").text(jsonObj.page + "/" + jsonObj.totalpage + "페이지, " + jsonObj.totalcnt + "개의 글");
// pageRows
var txt = "<select id='rows' onchange='changePageRows()'>\n";
txt += "<option " + ((window.pageRows == 10)?"selected":"") + " value='10'>10개씩</option>\n";
txt += "<option " + ((window.pageRows == 20)?"selected":"") + " value='20'>20개씩</option>\n";
txt += "<option " + ((window.pageRows == 50)?"selected":"") + " value='50'>50개씩</option>\n";
txt += "<option " + ((window.pageRows == 100)?"selected":"") + " value='100'>100개씩</option>\n";
txt += "</select>\n";
$("#pageRows").html(txt);
// 페이징 업데이트
var pagination = buildPagination(jsonObj.writepages, jsonObj.totalpage, jsonObj.page, jsonObj.pagerows);
$("#pagination").html(pagination);
return true;
} else {
alert(jsonObj.message);
return false;
}
return false;
} // end updateList()
function buildPagination(writePages, totalPage, curPage, pageRows){
var str = ""; // 최종적으로 페이징에 나타날 HTML 문자열 <li> 태그로 구성
// 페이징에 보여질 숫자들 (시작숫자 start_page ~ 끝숫자 end_page)
var start_page = ( (parseInt( (curPage - 1 ) / writePages ) ) * writePages ) + 1;
var end_page = start_page + writePages - 1;
if (end_page >= totalPage){
end_page = totalPage;
}
//■ << 표시 여부
if(curPage > 1){
str += "<li><a onclick='loadPage(1)' class='tooltip-top' title='처음'><i class='fas fa-angle-double-left'></i></a></li>\n";
}
//■ < 표시 여부
if (start_page > 1)
str += "<li><a onclick='loadPage(" + (start_page -1) + ")' class='tooltip-top' title='이전'><i class='fas fa-angle-left'></i></a></li>\n";
//■ 페이징 안의 '숫자' 표시
if (totalPage > 1) {
for (var k = start_page; k <= end_page; k++) {
if (curPage != k)
str += "<li><a onclick='loadPage(" + k + ")'>" + k + "</a></li>\n";
else
str += "<li><a class='active tooltip-top' title='현재페이지'>" + k + "</a></li>\n";
}
}
//■ > 표시
if (totalPage > end_page){
str += "<li><a onclick='loadPage("+ (end_page + 1 ) + ")' class='tooltip-top' title='다음'><i class='fas fa-angle-right'></i></a></li>\n";
}
//■ >> 표시
if (curPage < totalPage) {
str += "<li><a onclick='(" + totalPage + ")' class='tooltip-top' title='맨끝'><i class='fas fa-angle-double-right'></i></a></li>\n";
}
return str;
} // end buildPagination()
function changePageRows(){
window.pageRows = $("#rows").val();
loadPage(window.page);
}
// 새글 등록 처리
function chkWrite() {
var data = $("#frmWrite").serialize(); // 해당 폼 안의 name이 있는 것들을 끌어 들어옴
// 리턴값은 Object
//alert(data + "--" + typeof data);
//subject=aaa&name=bbb&content=ccc--string
// ajax request
$.ajax({
url : "writeOk.ajax",
type : "POST",
cache : false,
data : data, // POST 로 ajax request 하는 경우 parameter 담기
success : function(data, status){
if(status == "success"){
if(data.status = "OK") {
alert("INSERT 성공" + data.count + "개 : " + data.status);
loadPage(1); // 첫 페이지 리로딩
} else {
alert("INSERT 실패" + data.status + " : " + data.message);
}
}
}
});
// request 후, form 에 입력된것 reset()
$("#frmWrite")[0].reset();
// type이 submit일때 비록 action이 없더라도
// 자기 페이지로 리로딩된다...!!
// 페이지 리로딩을 원치 않는다면 리턴 값을 false 값을 주면 된다!
return false; // 페이지 리로딩은 안 할 것이다
} // end chkWrite();
// check된 uid의 게시글들만 삭제하기
function chkDelete() {
var uids = []; // 빈 배열 준비
// .each는 $("#list tbody input[name=uid") 각각에
// each function()을 실행시키라는 의미!
$("#list tbody input[name=uid]").each(function() {
//$(this)는 checkbox
if($(this).is(":checked")) { // jQuery에서 check 여부 확인 방법
uids.push($(this).val()); // 배열에 uid 값 추가
}
});
//alert(uids);
if(uids.length == 0) {
alert("삭제할 글을 체크해 주세요");
} else {
if(!confirm(uids.length + "개의 글을 삭제하시겠습니까?")) return false;
var data = $("#frmList").serialize();
// uid=1010&uid=1011&uid=1012
$.ajax({
url : "deleteOk.ajax",
type : "POST",
data : data,
cache : false,
success : function(data, status){
if(status == "success"){
if(data.status == "OK"){
alert("DELETE 성공 " + data.count + "개");
// 현재 페이지 리로딩
loadPage(window.page);
} else {
alert("DELETE 실패 " + data.message);
}
}
}
});
}
} // end chkDelete()
3. common.css
@charset "UTF-8";
/* 기본 버튼 */
.btn {
border: none;
color: white;
padding: 14px 28px;
font-size: 16px;
cursor: pointer;
}
.success {background-color: #4CAF50;} /* Green */
.success:hover {background-color: #46a049;}
.info {background-color: #2196F3;} /* Blue */
.info:hover {background: #0b7dda;}
.warning {background-color: #ff9800;} /* Orange */
.warning:hover {background: #e68a00;}
.danger {background-color: #f44336;} /* Red */
.danger:hover {background: #da190b;}
.default {background-color: #e7e7e7; color: black;} /* Gray */
.default:hover {background: #ddd;}
/* 글 목록 */
#list table {width: 100%;}
#list table, #list th, #list td {
border: 1px solid black;
border-collapse: collapse;
}
#list th, #list td {
padding: 10px;
}
.clear { clear: both; }
.left {
float: left;
}
.right {
float: right;
}
/* 페이징 */
.center {
text-align: center;
}
ul.pagination{
list-style-type:none
}
ul.pagination li{
display: inline-block;
}
ul.pagination a {
color: black;
float: left;
padding: 4px 8px;
text-decoration: none;
transition: background-color .3s;
/* border: 1px solid #ddd; */
/* margin: 0 4px; */
margin: 0px;
}
ul.pagination a.active {
background-color: #4CAF50;
color: white;
border: 1px solid #4CAF50;
}
ul.pagination a:hover:not(.active) {background-color: #ddd;}
/* 버튼 그룹 */
.d01 {
margin: 5px 0;
}
/* 모달 팝업 */
/* 모달 팝업 */
.modal { /* 모달 전체 적용 */
background-color: rgba(0, 0, 0, 0.4);
width: 100%;
height: 100%;
position : fixed;
top: 0;
left: 0;
z-index: 1;
padding-top: 40px; /* 내부여백 */
overflow: auto;
display : none; /* 기본적으로 안보이기 */
}
.modal .modal-content {
background-color: #fefefe; /* 배경은 흰색 */
width: 80%; /* 화면대비 80% */
margin: 5% auto 15% auto; /* 위에서 5%, 아래에서 15%, 좌우 중앙정렬 */
border: 1px solid #888; /* 테두리 */
}
.modal .container {
padding: 16px;
position: relative; /* 이래야 안에 있는 absolute 들이 동작 */
}
.modal .close { /* close 버튼 */
font-size: 35px;
font-weight: bold;
color: #000;
position: absolute;
right: 25px;
top: 0px;
}
.modal .close:hover,
.modal .cloas:focus {
color: red;
cursor: pointer;
}
.modal input[type=text] {
width: 100%;
border: 1px solid #ccc;
margin: 8px 0;
padding: 12px 20px;
display: inline-block;
border: 1px solid #ccc;
box-sizing: border-box;
}
.modal textarea {
width: 100%;
margin: 8px 0;
}
.modal button {
width: 100%;
cursor: pointer;
}
.modal .canbelbtn { /* 취소 버튼일 경우 추가적인 스타일 */
background-color: #f44336;
width: auto;
padding: 10px 18px;
}
'웹_프론트_백엔드 > JAVA프레임윅기반_풀스택' 카테고리의 다른 글
2020.06.16 (0) | 2020.06.16 |
---|---|
JSP Team Project(2020.05.25 ~ 2020.06.15) (0) | 2020.06.16 |
2020.06.09 (0) | 2020.06.09 |
2020.06.08 (0) | 2020.06.08 |
2020.06.05 (0) | 2020.06.05 |