Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- 컬렉션 타입
- abstract
- NestedFor
- oracle
- 생성자오버로드
- 집합_SET
- 자동차수리시스템
- 한국건설관리시스템
- 컬렉션프레임워크
- 제네릭
- exception
- 오라클
- 메소드오버로딩
- 사용자예외클래스생성
- cursor문
- 객체 비교
- 다형성
- EnhancedFor
- 환경설정
- 자바
- 추상메서드
- 인터페이스
- 대덕인재개발원
- 예외미루기
- 어윈 사용법
- 참조형변수
- Java
- GRANT VIEW
- 정수형타입
- 예외처리
Archives
- Today
- Total
거니의 velog
(19) 게시판 > 공지사항 페이지 > 코드 리뷰 본문
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles" %>
<c:set value="${pageContext.request.contextPath }" var="contextPath" />
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="author" content="부루마불" />
<meta name="description" content="대덕인재개발원 7월반 4조 부루마불의 여기갈래 프로젝트입니다." />
<meta name="keywords" content="부루마불, 여기갈래, 여행, 통합, 플랫폼" />
<meta name="copyright" content="대덕인재개발원" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>여기갈래 > 게시판</title>
<!-- 사용자 페이지 > 헤더세팅 영역 -->
<tiles:insertAttribute name="headerSettings" />
<!--
내부 CSS
- 내부 CSS는 외부 CSS의 스타일링을 건드리지 않기 위해서
개별적인 페이지에다 스타일을 적용할 때 종종 쓴다.
- 보통 프로토타이핑 테스트용이나, FE Leader의 판단에 따라 여기에
추가적인 스타일을 작성한다.
-->
<style>
.msub a {
color: #333;
}
</style>
<c:if test="${not empty message }">
<script type="text/javascript">
//alert("${message}");
$(function(){
// 성공시
<c:if test="${msgflag eq 'su'}">
Swal.fire({
title: "성공",
text: "${message}",
icon: "success"
});
</c:if>
// 실패시
<c:if test="${msgflag eq 'fa'}">
Swal.fire({
title: "실패",
text: "${message}",
icon: "error"
});
</c:if>
// 정보성 메시지
<c:if test="${msgflag eq 'in'}">
Swal.fire({
title: "안내",
text: "${message}",
icon: "info"
});
</c:if>
});
<c:remove var="message" scope="request" />
<c:remove var="message" scope="session" />
</script>
</c:if>
</head>
<body>
<!-- 사용자 페이지 > 헤더 영역 -->
<tiles:insertAttribute name="header" />
<!-- 사용자 페이지 > 게시판 구현 영역 -->
<tiles:insertAttribute name="userBoardContainer" />
<!-- 사용자 페이지 > 푸터 영역 -->
<tiles:insertAttribute name="footer" />
<!-- 사용자 페이지 > 자바스크립트 세팅 영역 -->
<tiles:insertAttribute name="settings" />
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<!-- 공지사항 css -->
<link href="${contextPath }/resources/css/userNoticeBoard.css" rel="stylesheet" />
<!-- 공지사항 게시판 리스트 영역 -->
<section class="noticeListContainer emptySpace">
<article class="communityHeadStyle">
<div class="comImgBox">
<img src="${contextPath }/resources/images/communityBgImg.jpg" alt="커뮤니티 배경 이미지" />
</div>
<div>
<h3>커뮤니티</h3>
<span>COMMUNITY</span>
</div>
</article>
<article class="noticeListContents cen">
<div>
<h4>공지사항</h4>
</div>
<div class="searchBoardCont">
<form action="" id="searchForm" name="searchForm">
<input type="hidden" id="page" name="page" />
<div class="btn-group">
<button type="button" class="btn btn-primary btn-sm">총 ${pagingVO.totalRecord } 개 게시물</button>
<button type="button" class="btn btn-secondary btn-sm">${pagingVO.currentPage } / ${pagingVO.totalPage } 페이지</button>
</div>
<div>
<div>
<select class="form-control" id="searchType" name="searchType">
<option value="title" <c:if test="${searchType eq 'title' }">selected</c:if>>제목</option>
<option value="writer" <c:if test="${searchType eq 'writer' }">selected</c:if>>작성자</option>
<option value="both" <c:if test="${searchType eq 'both' }">selected</c:if>>제목+작성자</option>
</select>
<i class="fas fa-chevron-down"></i>
</div>
<div>
<input class="form-control" type="text" id="searchWord" name="searchWord" placeholder="검색어 입력" value="${searchWord }" />
<button type="submit" id="searchBtn">
<i class="fas fa-search"></i>
</button>
</div>
</div>
</form>
</div>
<div class="imporNoticeListCont">
<c:set value="${importantNoticeList }" var="impList" />
<ul>
<c:choose>
<c:when test="${empty impList }">
<li class="impNoticeList">
<div style="text-align: center;">
등록된 중요공지 게시글이 존재하지 않습니다.
</div>
</li>
</c:when>
<c:otherwise>
<c:forEach items="${impList }" var="imp" varStatus="vs">
<li class="impNoticeList">
<div class="textDropVerticalAlign">
<span>중요공지</span>
<span class="textDrop">${imp.boTitle }</span>
<fmt:parseDate var="impParseData" value="${imp.boDate }" pattern="yyyy-MM-dd HH:mm:ss" />
<span><fmt:formatDate value="${impParseData }" pattern="yyyy-MM-dd"/></span>
<span class="plusMinus">
<i class="fas fa-plus"></i>
</span>
</div>
<div class="visibleDiv">
<p style="white-space: pre-wrap;">${imp.boContent }</p>
<!-- 반복 구간 -->
<%-- <c:out value="${imp.noticeFileList}"/>
<c:forEach items="${imp.noticeFileList}" var="noticeFile">
<p>fileNos == ${noticeFile.fileNos }</p>
<p>fileNames == ${noticeFile.fileNames }</p>
<p>fileSizes == ${noticeFile.fileSizes }</p>
<p>fileMimes == ${noticeFile.fileMimes }</p>
</c:forEach> --%>
<c:if test="${not empty imp.noticeFileList }">
<c:forEach items="${imp.noticeFileList}" var="noticeFile">
<c:set value="${fn:split(noticeFile.fileNames, ',') }" var="fnamearr" />
<c:set value="${fn:split(noticeFile.fileNos, ',') }" var="filenoarr" />
<c:forEach items="${fnamearr }" var="fname" varStatus="status">
<div class="imporNoticeFileDown">
<span class="badge bg-primary">파일 다운로드</span>
<a class="fileDownload" dataFileNo="${filenoarr[status.index] }" href="#">${fname }</a>
<i class="fas fa-file-download"></i>
</div>
</c:forEach>
</c:forEach>
</c:if>
</div>
</li>
</c:forEach>
</c:otherwise>
</c:choose>
</ul>
</div>
<div class="noticeListCont">
<ul>
<li class="noticeListHead">
<span>번호</span>
<span>제목</span>
<span>등록일</span>
<span>작성자</span>
<span>조회수</span>
</li>
<c:set value="${pagingVO.dataList }" var="noticeList" />
<c:choose>
<c:when test="${empty noticeList }">
<li class="noticeList textDropVerticalAlign">
<div style="text-align: center;">
등록된 공지사항 게시글이 존재하지 않습니다.
</div>
</li>
</c:when>
<c:otherwise>
<c:forEach items="${noticeList }" var="notice">
<li class="noticeList textDropVerticalAlign">
<span>${notice.boNo }</span>
<span class="textDrop">
<c:if test="${not empty fileExistNoticeList }">
<c:forEach items="${fileExistNoticeList }" var="fileExistList">
<c:if test="${fileExistList.boNo eq notice.boNo }">
<i class="fas fa-paperclip"></i>
</c:if>
</c:forEach>
</c:if>
<a href="/notice/user/detail.do?boNo=${notice.boNo }">
${notice.boTitle }
</a>
<c:if test="${notice.boImpor eq 'y' }">
<u style="text-decoration: none;" class="badge bg-danger">중요공지</u>
</c:if>
</span>
<fmt:parseDate var="parseData" value="${notice.boDate }" pattern="yyyy-MM-dd HH:mm:ss" />
<span><fmt:formatDate value="${parseData }" pattern="yyyy-MM-dd"/></span>
<span>${notice.boWriter }</span>
<span>${notice.boHit }</span>
</li>
</c:forEach>
</c:otherwise>
</c:choose>
</ul>
</div>
<div id="pagingArea">
${pagingVO.pagingHTML }
</div>
<c:if test="${sessionInfo.memCategory eq '03' }">
<div class="noticeBtnGroup">
<button type="button" class="btn btn-primary" id="noticeAddBtn">등록</button>
</div>
</c:if>
</article>
</section>
<%-- <c:out value="${fileExistNoticeList }" /> --%>
<!-- 공지사항 js -->
<script src="${contextPath }/resources/js/userNoticeBoard.js"></script>
<script>
$(function(){
// 공통 함수
$.importantNoticeBoardShowFn();
$.noticeBoardPagingFn();
var noticeAddBtn = $("#noticeAddBtn");
noticeAddBtn.click(function(){
location.href = "/notice/${sessionInfo.memId }/register.do";
});
var fileDownload = $(".fileDownload");
fileDownload.on("click", function(event){
event.preventDefault();
var fileNo = $(this).attr("dataFileNo");
location.href = "/notice/user/download.do?fileNo=" + fileNo;
});
// 종횡비 함수
var comImgBox = $(".comImgBox");
var comImg = $(".comImgBox img");
$.ratioBoxH(comImgBox, comImg);
});
</script>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<!-- 공지사항 css -->
<link href="${contextPath }/resources/css/userNoticeBoard.css" rel="stylesheet" />
<c:set value="등록" var="name" />
<c:if test="${status eq 'u' }">
<c:set value="수정" var="name" />
</c:if>
<!-- 공지사항 게시판 등록 영역 -->
<section class="noticeRegisterContainer emptySpace">
<article class="communityHeadStyle">
<div class="comImgBox">
<img src="${contextPath }/resources/images/communityBgImg.jpg" alt="커뮤니티 배경 이미지" />
</div>
<div>
<h3>커뮤니티</h3>
<span>COMMUNITY</span>
</div>
</article>
<article class="noticeRegisterContents cen">
<div>
<h4>공지사항 ${name }</h4>
</div>
<div class="card card-dark">
<form action="/notice/${sessionInfo.memId }/register.do" method="post" enctype="multipart/form-data" id="noticeForm" name="noticeForm">
<c:if test="${status eq 'u' }">
<input type="hidden" name="boNo" value="${notice.boNo }" />
</c:if>
<div class="card-body">
<div class="form-group">
<label for="boTitle">제목을 입력해주세요</label>
<%-- <input type="text" id="boTitle" name="boTitle" class="form-control" placeholder="제목 입력" value="<c:out value="${notice.boTitle }" escapeXml="true" />" /> --%>
<input type="text" id="boTitle" name="boTitle" class="form-control" placeholder="제목 입력" value="${notice.boTitle }" />
</div>
<div class="form-group">
<label for="boContent">내용을 입력해주세요</label>
<%-- <textarea id="boContent" name="boContent" class="form-control" rows="14"><c:out value="${notice.boContent }" escapeXml="true" /></textarea> --%>
<textarea id="boContent" name="boContent" class="form-control" rows="14">${notice.boContent }</textarea>
</div>
<div class="form-group">
<label for="boContent">파일 업로드</label>
<input type="file" class="form-control" id="boFile" name="boFile" multiple="multiple">
</div>
<div class="form-group">
<div>
<input class="form-check-input" type="checkbox" id="boImpor" name="boImpor" value="y" <c:if test="${notice.boImpor eq 'y' }">checked</c:if> />
<label class="form-check-label" for="boImpor">중요 공지 등록</label>
</div>
<div>
<button id="noticeRegBtn" type="button" class="btn btn-outline-primary">공지사항 ${name }</button>
<c:if test="${status ne 'u' }">
<button id="noticeListBtn" type="button" class="btn btn-outline-info" onclick="javascript:location.href='/notice/list.do'">목록으로 돌아가기</button>
</c:if>
<c:if test="${status eq 'u' }">
<button id="noticeListBtn" type="button" class="btn btn-outline-danger" onclick="javascript:location.href='/notice/user/detail.do?boNo=${notice.boNo }'">취소</button>
</c:if>
</div>
</div>
</div>
<c:if test="${not empty notice.noticeFileList }">
<div class="card-footer bg-white">
<div>
<span class="badge bg-danger">파일 삭제</span>
</div>
<div class="row">
<c:forEach items="${notice.noticeFileList }" var="noticeFile">
<div class="col-md-2 fileDownCont">
<div style="height: 140px;">
<c:choose>
<c:when test="${fn:split(noticeFile.fileMime, '/')[0] eq 'image' }">
<div class="previewImgBox">
<img src="/resources/notice/${notice.boNo }/${fn:split(noticeFile.fileSavepath, '/')[1] }" alt="파일 다운로드 이미지" />
</div>
</c:when>
<c:otherwise>
<i class="fas fa-file-download"></i>
</c:otherwise>
</c:choose>
</div>
<div class="plexHeight">
<h6>${noticeFile.fileName } (${noticeFile.fileFancysize })</h6>
</div>
<div>
<button type="button" class="btn btn-danger btn-sm noticeFileDownBtn" dataFileNo="${noticeFile.fileNo }">DELETE</button>
</div>
</div>
</c:forEach>
</div>
</div>
</c:if>
</form>
</div>
</article>
</section>
<!-- 공지사항 js -->
<script src="${contextPath }/resources/js/userNoticeBoard.js"></script>
<script src="${contextPath }/resources/ckeditor/ckeditor.js"></script>
<script>
$(function(){
// 공통 함수
$.noticeFormCKED();
$.noticeRegisterValidationChkFn();
$.fileDownBoxHeightFn();
$.removeFileFn();
// 종횡비 함수
var comImgBox = $(".comImgBox");
var comImg = $(".comImgBox img");
$.ratioBoxH(comImgBox, comImg);
$.eachPreviewImgBoxResizeFn();
});
</script>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<!-- 공지사항 css -->
<link href="${contextPath }/resources/css/userNoticeBoard.css" rel="stylesheet" />
<!-- 공지사항 게시판 상세 영역 -->
<section class="noticeDetailContainer emptySpace">
<article class="communityHeadStyle">
<div class="comImgBox">
<img src="${contextPath }/resources/images/communityBgImg.jpg" alt="커뮤니티 배경 이미지" />
</div>
<div>
<h3>커뮤니티</h3>
<span>COMMUNITY</span>
</div>
</article>
<article class="noticeDetailContents cen">
<div>
<h4>공지사항</h4>
</div>
<div class="card card-dark">
<div class="card-body">
<div class="form-group">
<ul class="noticeDetailTbl">
<li>
<div class="textDropVerticalAlign">
<span class="textDrop">
<%-- <c:out value="${noticeDetail.boTitle }" /> --%>
${noticeDetail.boTitle }
</span>
<span>${noticeDetail.boWriter }</span>
<fmt:parseDate var="detailParseData" value="${noticeDetail.boDate }" pattern="yyyy-MM-dd HH:mm:ss" />
<span><fmt:formatDate value="${detailParseData }" pattern="yyyy-MM-dd"/></span>
<span>조회 ${noticeDetail.boHit }</span>
<span>
<a href="javascript:window.print()">
<i class="fas fa-print"></i>
</a>
</span>
</div>
</li>
<li>
<%-- <div class="form-control" style="overflow: auto; position: relative; min-height: 380px;"><c:out value="${noticeDetail.boContent }" /></div> --%>
<div class="form-control" style="overflow: auto; position: relative; min-height: 380px;">${noticeDetail.boContent }</div>
</li>
<c:if test="${not empty prevNextInfo }">
<li class="prevNextBtnGroup">
<c:forEach items="${prevNextInfo }" var="btnInfo" varStatus="stat">
<c:if test="${btnInfo.prevnextFlag eq 'prev' }">
<div>
<a href="/notice/user/detail.do?boNo=${btnInfo.boNo }" class="textDropVerticalAlign">
<span>
<i class="fas fa-long-arrow-alt-left"></i>
</span>
<span>
<i class="badge bg-secondary">
이전글
</i>
</span>
<span class="textDrop">
${btnInfo.boTitle }
</span>
</a>
</div>
<c:if test="${fn:length(prevNextInfo) eq 1 }">
<div style="text-align: right; line-height: 100px; padding: 0px 20px;">
다음 글이 없습니다.
</div>
</c:if>
</c:if>
<c:if test="${btnInfo.prevnextFlag eq 'next' }">
<c:if test="${fn:length(prevNextInfo) eq 1 }">
<div style="text-align: left; line-height: 100px; padding: 0px 20px;">
이전 글이 없습니다.
</div>
</c:if>
<div>
<a href="/notice/user/detail.do?boNo=${btnInfo.boNo }" class="textDropVerticalAlign">
<span>
<i class="fas fa-long-arrow-alt-right"></i>
</span>
<span>
<i class="badge bg-secondary">
다음글
</i>
</span>
<span class="textDrop">
${btnInfo.boTitle }
</span>
</a>
</div>
</c:if>
</c:forEach>
</li>
</c:if>
</ul>
</div>
<form action="/notice/${sessionInfo.memId }/delete.do" method="post" id="deleteForm">
<input type="hidden" name="boNo" value="${noticeDetail.boNo }" />
</form>
<div class="form-group">
<c:if test="${sessionInfo.memCategory eq '03' }">
<button id="noticeDeleteBtn" type="button" class="btn btn-outline-danger">삭제</button>
<button id="noticeModifyBtn" type="button" class="btn btn-outline-warning">수정</button>
</c:if>
<button id="userListGoBtn" type="button" class="btn btn-outline-success">목록</button>
</div>
</div>
<c:if test="${not empty noticeDetail.noticeFileList }">
<div class="card-footer bg-white">
<div>
<span class="badge bg-dark">파일 다운로드</span>
</div>
<div class="row">
<!-- 반복 구간 -->
<c:forEach items="${noticeDetail.noticeFileList }" var="noticeFile">
<div class="col-md-2 fileDownCont">
<div style="height: 140px;">
<c:choose>
<c:when test="${fn:split(noticeFile.fileMime, '/')[0] eq 'image' }">
<div class="previewImgBox">
<img src="/resources/notice/${noticeDetail.boNo }/${fn:split(noticeFile.fileSavepath, '/')[1] }" alt="파일 다운로드 이미지" />
</div>
</c:when>
<c:otherwise>
<i class="fas fa-file-download"></i>
</c:otherwise>
</c:choose>
</div>
<div class="plexHeight">
<h6>${noticeFile.fileName } (${noticeFile.fileFancysize })</h6>
</div>
<div>
<button type="button" class="btn btn-secondary btn-sm noticeFileDownBtn" dataFileNo="${noticeFile.fileNo }">DOWNLOAD</button>
</div>
</div>
</c:forEach>
</div>
</div>
</c:if>
</div>
</article>
</section>
<!-- 공지사항 js -->
<script src="${contextPath }/resources/js/userNoticeBoard.js"></script>
<script src="${contextPath }/resources/ckeditor/ckeditor.js"></script>
<script>
$(function(){
// 공통 함수
$.fileDownBoxHeightFn();
// 파일 다운로드 함수
var noticeFileDownBtn = $(".noticeFileDownBtn");
noticeFileDownBtn.on("click", function(){
var fileNo = $(this).attr("dataFileNo");
location.href = "/notice/user/download.do?fileNo=" + fileNo;
});
// 목록으로 이동
var userListGoBtn = $("#userListGoBtn");
userListGoBtn.click(function(){
location.href = "/notice/list.do";
});
// 수정 이동
var noticeModifyBtn = $("#noticeModifyBtn");
noticeModifyBtn.click(function(){
location.href = "/notice/${sessionInfo.memId }/modify.do?boNo=${noticeDetail.boNo }";
});
// 삭제 이동
var noticeDeleteBtn = $("#noticeDeleteBtn");
var deleteForm = $("#deleteForm");
noticeDeleteBtn.click(function(){
//var agreeFlag = confirm("정말로 삭제하시겠습니까?");
//if(agreeFlag) {
// deleteForm.submit();
//}
Swal.fire({
title: "정말로 삭제하시겠습니까?",
showDenyButton: true,
confirmButtonText: "예",
denyButtonText: "아니오"
}).then((result) => {
if (result.isConfirmed) {
Swal.fire({
title: "공지사항 삭제",
text: "공지사항을 삭제합니다.",
icon: "info"
}).then((result) => {
// 모달이 닫힌 후에 실행될 코드
if (result.isConfirmed) {
// 확인 버튼이 클릭되었을 때
deleteForm.submit();
}
});
} else if (result.isDenied) {
Swal.fire({
title: "공지사항 삭제",
text: "공지사항 삭제를 취소합니다.",
icon: "error"
});
}
});
});
// 종횡비 함수
var comImgBox = $(".comImgBox");
var comImg = $(".comImgBox img");
$.ratioBoxH(comImgBox, comImg);
$.eachPreviewImgBoxResizeFn();
});
</script>
/* 공지사항 게시판 스타일 */
.noticeListContainer {
position: relative;
}
.communityHeadStyle {
height: 310px;
position: relative;
overflow: hidden;
}
.comImgBox {
position: relative;
height: inherit;
}
.comImgBox img {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(1.17);
}
.communityHeadStyle>div:last-of-type {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
text-align: center;
}
.communityHeadStyle>div:last-of-type h3 {
font-weight: 700;
font-size: 2.3rem;
margin-bottom: 15px;
}
.communityHeadStyle>div:last-of-type span {
color: white;
opacity: 0.6;
}
.noticeListContents,
.noticeRegisterContents,
.noticeDetailContents {
padding: 70px 0px;
}
.noticeListContents>div:first-of-type,
.noticeRegisterContents>div:first-of-type,
.noticeDetailContents>div:first-of-type {
padding: 0px 0px 40px;
text-align: center;
}
.noticeListContents>div:first-of-type>h4,
.noticeRegisterContents>div:first-of-type>h4,
.noticeDetailContents>div:first-of-type>h4 {
font-weight: 700;
font-size: 2rem;
margin-bottom: 0px;
}
.searchBoardCont {
margin-bottom: 40px;
}
#searchForm {
overflow: auto;
}
#searchForm>div:first-of-type {
float: left;
line-height: 38px;
}
#searchForm>div:last-of-type {
float: right;
width: 400px;
}
#searchForm>div:last-of-type>div:first-of-type,
#searchForm>div:last-of-type>div:last-of-type {
position: relative;
float: left;
}
#searchForm>div:last-of-type>div:first-of-type i {
position: absolute;
top: 12px;
right: 10px;
}
#searchForm>div:last-of-type>div:last-of-type {
float: right;
}
#searchType {
padding-right: 30px;
}
#searchBtn {
position: absolute;
top: 6px;
right: 10px;
border: none;
background-color: transparent;
display: block;
width: 25px;
outline: none;
border-radius: 4px;
border-radius: 4px;
color: #333;
transition: all 0.4s;
}
#searchBtn:hover {
background-color: #333;
color: white;
}
.imporNoticeListCont {
margin-bottom: 40px;
}
.imporNoticeListCont ul {
list-style: none;
margin-bottom: 0px;
padding-left: 0px;
}
.impNoticeList {
border-top: 1px solid #DC1C2C;
transition: all 0.4s;
}
.textDropVerticalAlign {
cursor: pointer;
}
.impNoticeList p {
margin-bottom: 0px;
}
.impNoticeList:last-of-type {
border-bottom: 1px solid #DC1C2C;
}
.impNoticeList>div:first-of-type {
padding: 20px 0px;
transition: all 0.4s;
}
.impNoticeList>div:first-of-type:hover {
background-color: #eee;
}
.impNoticeList>div:first-of-type span:first-of-type {
width: 100px;
color: #75819B;
}
.impNoticeList>div:first-of-type span:nth-of-type(2) {
width: calc(100% - 262px);
}
.impNoticeList>div:first-of-type span:nth-of-type(3) {
width: 100px;
}
.impNoticeList>div:first-of-type span:last-of-type {
width: 50px;
text-align: right;
color: #75819B;
}
.visibleDiv {
display: none;
/* min-height: 380px; */
}
.visibleDiv p {
padding: 10px 0px;
overflow: auto;
position: relative;
}
.imporNoticeFileDown {
padding-bottom : 20px;
}
.imporNoticeFileDown span,
.imporNoticeFileDown a {
margin-right: 5px;
}
.noticeListCont {
margin-bottom: 40px;
}
.noticeListCont ul {
list-style: none;
margin-bottom: 0px;
padding-left: 0px;
}
.noticeListCont li {
padding: 10px 0px;
}
.noticeListCont span {
display: inline-block;
text-align: center;
}
.noticeListCont span:first-of-type {
width: 50px;
}
.noticeListCont span:nth-of-type(2) {
width: calc(100% - 335px);
padding-right: 30px;
position: relative;
text-align: left;
}
/* .noticeListCont span:nth-of-type(2) i {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
} */
.noticeListCont span:nth-of-type(3){
width: 100px;
}
.noticeListCont span:nth-of-type(4){
width: 100px;
}
.noticeListCont span:last-of-type {
width: 70px;
}
.noticeListHead {
border-top: 2px solid #333;
padding: 15px 0px!important;
background-color: #eee;
}
.noticeListHead span {
font-weight: 700;
text-align: center!important;
}
.noticeList {
border-top: 1px solid #ddd;
}
.noticeList:last-of-type {
border-bottom: 1px solid #ddd;
}
#pagingArea {
margin-bottom: 40px;
}
#pagingArea ul {
margin: auto;
display: flex;
justify-content: center;
}
#pagingArea .page-link {
cursor: pointer;
}
.noticeBtnGroup {
text-align: right;
}
.noticeRegisterContents .form-group {
margin-bottom: 10px;
}
.noticeRegisterContents .form-group label {
margin-bottom: 10px;
}
.fileDownCont {
padding: 10px;
}
.fileDownCont h6 {
margin-bottom: 0px;
padding: 0px 10px;
}
.fileDownCont>div:first-of-type {
text-align: center;
font-size: 5rem;
background-color: #eee;
padding: 10px 0px;
border-radius: 4px 4px 0px 0px;
}
.fileDownCont>div:nth-of-type(2) {
background-color: #ddd;
text-align: center;
padding: 10px 0px;
}
.fileDownCont>div:last-of-type button {
width: 100%;
border-radius: 0px 0px 4px 4px;
}
#noticeForm .form-group:last-of-type {
padding-top: 10px;
overflow: auto;
}
#noticeForm .form-group:last-of-type>div:first-of-type {
float: left;
}
#noticeForm .form-group:last-of-type>div:first-of-type label {
margin-left: 10px;
}
#noticeForm .form-group:last-of-type>div:last-of-type {
float: right;
}
#noticeForm .form-group:last-of-type>div:last-of-type button:last-of-type {
margin-left: 10px;
}
.noticeDetailContents p {
margin-bottom: 0px;
}
.noticeDetailContents a {
color: #333;
}
.noticeDetailTbl {
list-style: none;
padding-left: 0px;
margin-bottom: 0px;
}
.noticeDetailTbl li:first-of-type div {
padding: 10px 0px 20px;
cursor: auto;
}
.noticeDetailTbl li:first-of-type span {
display: inline-block;
width: 110px;
text-align: center;
position: relative;
color: #555;
}
.noticeDetailTbl li:first-of-type span:first-of-type {
color: black;
font-size: 1.3rem;
padding: 0px;
width: calc(100% - 390px);
text-align: left;
}
.noticeDetailTbl li:first-of-type span:last-of-type {
width: 25px;
height: 25px;
background-color: #ddd;
border-radius: 50%;
margin-left: 20px;
transition: all 0.4s;
}
.noticeDetailTbl li:first-of-type span:last-of-type i {
font-size: 0.9rem;
}
.noticeDetailTbl li:first-of-type span:last-of-type:hover {
background-color: black;
}
.noticeDetailTbl li:first-of-type span:last-of-type:hover i {
color: white;
}
.noticeDetailTbl li:first-of-type span::after {
content: "";
position: absolute;
width: 1px;
height: 14px;
background-color: #555;
right: 0px;
top: 6px;
}
.noticeDetailTbl li:first-of-type span:last-of-type::after,
.noticeDetailTbl li:first-of-type span:first-of-type::after {
content: none;
}
.noticeDetailTbl li:nth-of-type(2) {
margin-bottom: 20px;
}
.prevNextBtnGroup {
overflow: auto;
margin-bottom: 20px;
}
.prevNextBtnGroup>div {
width: 300px;
height: 100px;
border-radius: 4px;
position: relative;
background-color: #eee;
}
.prevNextBtnGroup span {
display: inline-block;
width: 50px;
}
.prevNextBtnGroup span i {
font-style: normal;
padding: 10px 15px;
}
.prevNextBtnGroup>div:first-of-type {
float: left;
}
.prevNextBtnGroup>div:last-of-type {
float: right;
}
.prevNextBtnGroup span:first-of-type {
position: absolute;
top: 50%;
transform: translateY(-50%);
text-align: center;
width: 50px;
height: 50px;
line-height: 50px;
background-color: #ddd;
border-radius: 50%;
font-size: 1.3rem;
}
.prevNextBtnGroup>div:first-of-type span:first-of-type {
left: 10px;
}
.prevNextBtnGroup>div:first-of-type span:first-of-type,
.prevNextBtnGroup>div:last-of-type span:first-of-type {
transition: all 0.4s;
}
.prevNextBtnGroup>div:last-of-type span:first-of-type {
right: 10px;
}
.prevNextBtnGroup>div:first-of-type:hover span:first-of-type,
.prevNextBtnGroup>div:last-of-type:hover span:first-of-type {
background-color: black;
}
.prevNextBtnGroup>div:first-of-type:hover span:first-of-type i,
.prevNextBtnGroup>div:last-of-type:hover span:first-of-type i {
color: white;
}
.prevNextBtnGroup span:not(:first-of-type) {
display: block;
margin: 0px 70px;
width: calc(100% - 80px);
height: calc(100% / 2);
line-height: 50px;
}
.prevNextBtnGroup>div:first-of-type span:not(:first-of-type) {
margin-right: 10px;
}
.prevNextBtnGroup>div:last-of-type span:not(:first-of-type) {
margin-left: 10px;
text-align: right;
}
.noticeDetailContents .form-group:last-of-type {
text-align: right;
}
.noticeDetailContents .form-group:last-of-type button {
margin-left: 10px;
}
.noticeDetailContents .form-group:last-of-type button:first-of-type {
margin-left: 0px;
}
.previewImgBox {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
}
.previewImgBox img {
display: block;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
@media all and (max-width: 880px) {
.prevNextBtnGroup>div {
width: auto;
}
.prevNextBtnGroup>div>a>span:not(:first-of-type) {
display: none;
}
}
// 공지사항 > 중요공지 > 아코디언 게시판 기능
$.importantNoticeBoardShowFn = function(){
var textDropVerticalAlign = $(".textDropVerticalAlign");
textDropVerticalAlign.click(function(){
var thisIs = $(this);
var impNoticeTblCenter = thisIs.find(".plusMinus");
var visibleDiv = thisIs.parent().find(".visibleDiv").is(":visible");
console.log("visibleDiv : ", visibleDiv);
if(visibleDiv) { // 게시글이 눈에 보임
thisIs.parent().find(".visibleDiv").stop().slideUp(300);
impNoticeTblCenter.html("<i class='fas fa-plus'></i>");
}else { // 게시글이 눈에 보이지 않음
thisIs.parent().find(".visibleDiv").stop().slideDown(300);
impNoticeTblCenter.html("<i class='fas fa-minus'></i>");
}
// 방금 누른 것을 제외한 나머지 div는 싹 닫는다.
thisIs.parent().siblings(".impNoticeList").children(".visibleDiv").slideUp(300);
thisIs.parent().siblings(".impNoticeList").find(".plusMinus").html("<i class='fas fa-plus'></i>");
});
};
$.noticeBoardPagingFn = function(event){
var pagingArea = $("#pagingArea");
var searchForm = $("#searchForm");
pagingArea.on("click", "a", function(event){
event.preventDefault(); // a태그의 이벤트를 block
var pageNo = $(this).attr("data-page");
console.log("pageNo : ", pageNo);
searchForm.find("#page").val(pageNo);
searchForm.submit();
});
};
$.noticeFormCKED = function(){
CKEDITOR.replace("boContent", {
filebrowserUploadUrl: '/imageUpload.do'
});
CKEDITOR.config.height = "500px"; // CKEDITOR 높이 설정
};
$.noticeRegisterValidationChkFn = function(){
var noticeRegBtn = $("#noticeRegBtn");
var noticeForm = $("#noticeForm");
var boTitle = $("#boTitle");
noticeRegBtn.on("click", function(){
var titleFlag = $.falsyCheckFn(boTitle, "제목");
var boContent = CKEDITOR.instances.boContent.getData();
if(!titleFlag) return;
if(!boContent) {
//alert("내용을 입력해 주세요.");
Swal.fire({
title: "안내",
text: "내용을 입력해 주세요.",
icon: "info"
});
return false;
}
if($(this).text() == "공지사항 수정"){
noticeForm.attr("action", "/notice/admin/modify.do");
}
noticeForm.submit();
});
};
// 다운로드 박스 높이를 같게 조절하는 함수
$.fileDownBoxHeightFn = function(){
var fileDownCont = $(".fileDownCont");
var topBoxH = 0;
fileDownCont.each(function(i, v){
var thisIs = $(this);
var boxH = thisIs.find(".plexHeight").height();
//console.log("boxH : " + boxH);
if(topBoxH < boxH) {
topBoxH = boxH;
}
//console.log("topBoxH : " + topBoxH);
});
fileDownCont.siblings().find(".plexHeight").height(topBoxH);
};
// 다운로드 미리보기 이미지 각각의 종횡비 변경 함수
$.eachPreviewImgBoxResizeFn = function(){
$(".fileDownCont").each(function(i, v){
var thisIs = $(this);
var previewImgBox = thisIs.find(".previewImgBox");
var previewImg = thisIs.find("img");
$.ratioBoxH(previewImgBox, previewImg);
});
};
// 이미지 파일 삭제 처리 함수
$.removeFileFn = function(){
var noticeFileDelBtn = $(".noticeFileDownBtn");
noticeFileDelBtn.click(function(){
var thisIs = $(this);
var fileDelCont = $(".fileDownCont");
var delFileNo = thisIs.attr("dataFileNo");
//console.log("delFileNo : " + delFileNo);
$("#noticeForm").append("<input type='hidden' name='delNoticeNo' value='"+ delFileNo +"' />");
thisIs.parents(".fileDownCont").hide();
console.log("파일이 누네 보이니? : " + fileDelCont.is(":visible"));
var delFileVisible = fileDelCont.is(":visible");
if(!delFileVisible) {
thisIs.parents(".card-footer").hide();
}
});
};
package kr.or.ddit.users.board.vo;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import lombok.Data;
@Data
public class NoticeVO {
private int boNo;
private String boTitle;
private String boContent;
private String boWriter;
private String boDate;
private int boHit;
private String boImpor;
private String prevnextFlag;
private Integer[] delNoticeNo;
private MultipartFile[] boFile;
private List<NoticeFileVO> noticeFileList;
private NoticeFileVO noticeFileVO;
public void setBoFile(MultipartFile[] boFile) {
this.boFile = boFile;
if(boFile != null) {
List<NoticeFileVO> noticeFileList = new ArrayList<NoticeFileVO>();
for(MultipartFile item : boFile) {
if(StringUtils.isBlank(item.getOriginalFilename())) {
continue;
}
NoticeFileVO boardFileVO = new NoticeFileVO(item);
noticeFileList.add(boardFileVO);
}
this.noticeFileList = noticeFileList;
}
}
}
package kr.or.ddit.users.board.vo;
import org.apache.commons.io.FileUtils;
import org.springframework.web.multipart.MultipartFile;
import lombok.Data;
@Data
public class NoticeFileVO {
private MultipartFile item;
private Integer boNo;
private Integer fileNo;
private String fileName;
private Long fileSize;
private String fileFancysize;
private String fileMime;
private String fileSavepath;
private Integer fileDowncount;
public NoticeFileVO() {}
public NoticeFileVO(MultipartFile item) {
this.item = item;
this.fileName = item.getOriginalFilename();
this.fileSize = item.getSize();
this.fileMime = item.getContentType();
this.fileFancysize = FileUtils.byteCountToDisplaySize(fileSize);
}
private String fileNos;
private String fileNames;
private String fileSizes;
private String fileFancysizes;
private String fileMimes;
private String fileSavepaths;
private String fileDowncounts;
}
package kr.or.ddit.users.board.controller;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import kr.or.ddit.users.board.service.NoticeService;
import kr.or.ddit.users.board.vo.NoticeFileVO;
import kr.or.ddit.users.board.vo.NoticeVO;
import kr.or.ddit.users.login.vo.MemberVO;
import kr.or.ddit.utils.MediaUtils;
import kr.or.ddit.utils.ServiceResult;
import kr.or.ddit.vo.PaginationInfoVO;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Controller
@RequestMapping("/notice")
public class NoticeBoardController {
@Inject
private NoticeService noticeService;
// 공지사항 리스트 출력
@CrossOrigin(origins = "http://localhost")
@RequestMapping(value = "/list.do", method = RequestMethod.GET)
public String noticeList(
@RequestParam(name = "page", required = false, defaultValue = "1") int currentPage,
@RequestParam(required = false, defaultValue = "title") String searchType,
@RequestParam(required = false) String searchWord,
Model model
) {
/** 자료 수집 및 정의 */
Map<String,Object> param = new HashMap<>();
param.put("currentPage", currentPage);
param.put("searchType", searchType);
param.put("searchWord", searchWord);
/** 서비스 호출 */
// 공지사항 게시판 리스트 가져오기
noticeService.noticeList(param);
/** 반환 자료 */
PaginationInfoVO<NoticeVO> pagingVO = (PaginationInfoVO<NoticeVO>) param.get("pagingVO");
List<NoticeVO> importantNoticeList = (List<NoticeVO>) param.get("importantNoticeList");
List<NoticeVO> fileExistNoticeList = (List<NoticeVO>) param.get("fileExistNoticeList");
/** 자료 검증 */
log.info("pagingVO : " + pagingVO.toString());
log.info("importantNoticeList : " + importantNoticeList.toString());
log.info("importantNoticeList : " + importantNoticeList.toString());
log.info("fileExistNoticeList : " + fileExistNoticeList.toString());
/** 자료 반환 */
model.addAttribute("searchType", searchType);
model.addAttribute("searchWord", searchWord);
model.addAttribute("pagingVO", pagingVO);
model.addAttribute("importantNoticeList", importantNoticeList);
model.addAttribute("fileExistNoticeList", fileExistNoticeList);
return "board/noticeBoardList";
}
// 공지사항 파일 다운로드
@RequestMapping(value = "/user/download.do", method = RequestMethod.GET)
public ResponseEntity<byte[]> fileDownload(int fileNo) throws Exception {
InputStream in = null;
ResponseEntity<byte[]> entity = null;
String fileName = null;
NoticeFileVO fileVO = noticeService.selectFileInfo(fileNo);
if(fileVO != null) {
try {
fileName = fileVO.getFileName();
String formatName = fileName.substring(fileName.lastIndexOf(".") + 1);
MediaType mType = MediaUtils.getMediaType(formatName);
HttpHeaders headers = new HttpHeaders();
in = new FileInputStream(fileVO.getFileSavepath());
fileName = fileName.substring(fileName.indexOf("_") + 1);
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headers.add("Content-Disposition", "attachment; filename=\""+ new String(fileName.getBytes("UTF-8"), "ISO-8859-1") +"\"");
entity = new ResponseEntity<byte[]>(IOUtils.toByteArray(in), headers, HttpStatus.CREATED);
} catch (Exception e) {
e.printStackTrace();
} finally {
in.close();
}
}else {
entity = new ResponseEntity<byte[]>(HttpStatus.BAD_REQUEST);
}
return entity;
}
// 공지사항 상세보기
@CrossOrigin(origins = "http://localhost")
@RequestMapping(value = "/user/detail.do")
public String noticeDetail(int boNo, Model model) {
/** 자료수집 및 정의 */
Map<String,Object> param = new HashMap<>();
param.put("boNo", boNo);
/** 서비스 호출 */
noticeService.noticeDetail(param);
/** 반환 자료 */
NoticeVO noticeVO = (NoticeVO) param.get("noticeVO");
List<NoticeVO> prevNextList = (List<NoticeVO>) param.get("prevNextList");
/** 자료검증 */
log.info("noticeVO : " + noticeVO);
log.info("prevNextList : " + prevNextList);
/** 자료반환 */
model.addAttribute("noticeDetail", noticeVO);
model.addAttribute("prevNextInfo", prevNextList);
return "board/noticeBoardDetail";
}
///////////////////////////////////////////////////////////////////////////
// 공지사항 등록
@CrossOrigin(origins = "http://localhost")
@RequestMapping(value = "/admin/register.do", method = RequestMethod.GET)
public String noticeRegisterForm() {
return "board/noticeBoardForm";
}
@RequestMapping(value = "/admin/register.do", method = RequestMethod.POST)
public String noticeRegister(
HttpServletRequest req,
NoticeVO noticeVO,
RedirectAttributes ra,
Model model
) throws Exception {
String goPage = "";
Map<String, String> errors = new HashMap<String, String>();
if(StringUtils.isBlank(noticeVO.getBoTitle())) {
errors.put("boTitle", "제목을 입력해 주세요");
}
if(StringUtils.isBlank(noticeVO.getBoContent())) {
errors.put("boContent", "내용을 입력해 주세요");
}
if(errors.size() > 0) {
model.addAttribute("errors", errors);
model.addAttribute("msgflag", "fa");
model.addAttribute("noticeVO", noticeVO);
goPage = "board/noticeBoardForm";
}else {
HttpSession session = req.getSession();
MemberVO memberVO = (MemberVO) session.getAttribute("sessionInfo");
noticeVO.setBoWriter(memberVO.getMemName()); // 로그인 한 사용자의 이름으로 작성자 넣기
ServiceResult result = noticeService.insertNotice(req, noticeVO);
if(result.equals(ServiceResult.OK)) {
ra.addFlashAttribute("message", "공지사항 게시글이 성공적으로 등록되었습니다!");
ra.addFlashAttribute("msgflag", "su");
goPage = "redirect:/notice/list.do";
}else {
// 성공, 실패, 정보
// 성공 : su
// 실패 : fa
// 정보 : in
model.addAttribute("message", "서버 에러, 다시 시도해주세요!");
model.addAttribute("msgflag", "fa");
model.addAttribute("noticeVO", noticeVO);
goPage = "board/noticeBoardForm";
}
}
return goPage;
}
// 공지사항 삭제
@RequestMapping(value = "/admin/delete.do", method = RequestMethod.POST)
public String noticeDelete(
RedirectAttributes ra,
int boNo,
Model model
) {
String goPage = "";
ServiceResult result = noticeService.deleteNotice(boNo);
if(result.equals(ServiceResult.OK)) {
ra.addFlashAttribute("message", "공지사항 삭제가 완료되었습니다");
ra.addFlashAttribute("msgflag", "su");
goPage = "redirect:/notice/list.do";
}else {
ra.addFlashAttribute("message", "공지사항 삭제에 실패했습니다");
ra.addFlashAttribute("msgflag", "fa");
goPage = "redirect:/notice/user/detail.do?boNo=" + boNo;
}
return goPage;
}
// 공지사항 수정
@CrossOrigin(origins = "http://localhost")
@RequestMapping(value = "/admin/modify.do", method = RequestMethod.GET)
public String noticeModifyForm(int boNo, Model model) {
NoticeVO noticeVO = noticeService.selectNotice(boNo);
model.addAttribute("notice", noticeVO);
model.addAttribute("status", "u");
return "board/noticeBoardForm";
}
@RequestMapping(value = "/admin/modify.do", method = RequestMethod.POST)
public String noticeModify(
HttpServletRequest req,
NoticeVO noticeVO,
Model model,
RedirectAttributes ra
) {
String goPage = "";
HttpSession session = req.getSession();
MemberVO memberVO = (MemberVO) session.getAttribute("sessionInfo");
noticeVO.setBoWriter(memberVO.getMemName()); // 로그인 한 사용자의 이름으로 작성자 넣기
ServiceResult result = noticeService.modifyNotice(req, noticeVO);
if(result.equals(ServiceResult.OK)) {
ra.addFlashAttribute("message", "공지사항 수정이 완료되었습니다.");
ra.addFlashAttribute("msgflag", "su");
goPage = "redirect:/notice/user/detail.do?boNo=" + noticeVO.getBoNo();
}else {
model.addAttribute("notice", noticeVO);
model.addAttribute("message", "공지사항 수정이 실패했습니다!");
ra.addFlashAttribute("msgflag", "fa");
model.addAttribute("status", "u");
goPage = "board/noticeBoardForm";
}
return goPage;
}
}
package kr.or.ddit.users.board.service;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import kr.or.ddit.users.board.vo.NoticeFileVO;
import kr.or.ddit.users.board.vo.NoticeVO;
import kr.or.ddit.utils.ServiceResult;
public interface NoticeService {
public void noticeList(Map<String, Object> param);
public void noticeDetail(Map<String, Object> param);
public ServiceResult insertNotice(HttpServletRequest req, NoticeVO noticeVO) throws Exception;
public NoticeFileVO selectFileInfo(int fileNo);
public NoticeVO selectNotice(int boNo);
public ServiceResult deleteNotice(int boNo);
public ServiceResult modifyNotice(HttpServletRequest req, NoticeVO noticeVO);
}
package kr.or.ddit.users.board.service.impl;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import kr.or.ddit.mapper.NoticeBoardMapper;
import kr.or.ddit.users.board.service.NoticeService;
import kr.or.ddit.users.board.vo.NoticeFileVO;
import kr.or.ddit.users.board.vo.NoticeVO;
import kr.or.ddit.users.login.vo.MemberVO;
import kr.or.ddit.utils.FileUploadUtils;
import kr.or.ddit.utils.ServiceResult;
import kr.or.ddit.vo.PaginationInfoVO;
@Service
@Transactional(rollbackFor = Exception.class)
public class NoticeServiceImpl implements NoticeService {
@Inject
private NoticeBoardMapper noticeMapper;
@Override
public void noticeList(Map<String, Object> param) {
/** 파라미터 조회 */
int currentPage = (int) param.get("currentPage");
String searchType = (String) param.get("searchType");
String searchWord = (String) param.get("searchWord");
/** 파라미터 정의 */
PaginationInfoVO<NoticeVO> pagingVO = new PaginationInfoVO<NoticeVO>();
List<NoticeVO> importantNoticeList = new ArrayList<NoticeVO>();
List<NoticeVO> fileExistNoticeList = new ArrayList<NoticeVO>();
/** 메인로직 처리 */
// 검색 기능
if(StringUtils.isNotBlank(searchWord)) {
pagingVO.setSearchType(searchType);
pagingVO.setSearchWord(searchWord);
}
pagingVO.setCurrentPage(currentPage);
// 총 게시글 수 가져오기
int totalRecord = noticeMapper.selectNoticeCount(pagingVO);
pagingVO.setTotalRecord(totalRecord);
// 총 게시글을 리스트로 받아오기
List<NoticeVO> dataList = noticeMapper.selectNoticeList(pagingVO);
pagingVO.setDataList(dataList);
// 중요공지 리스트 가져오기
importantNoticeList = noticeMapper.importantNoticeList();
// 파일이 들어있는 게시글 리스트 가져오기
fileExistNoticeList = noticeMapper.fileExistNoticeList();
/** 반환자료 저장 */
param.put("pagingVO", pagingVO);
param.put("importantNoticeList", importantNoticeList);
param.put("fileExistNoticeList", fileExistNoticeList);
}
@Override
public void noticeDetail(Map<String, Object> param) {
/** 파라미터 조회 */
int boNo = (int) param.get("boNo");
/** 파라미터 정의 */
NoticeVO noticeVO = new NoticeVO();
List<NoticeVO> prevNextList = new ArrayList<NoticeVO>();
/** 메인로직 처리 */
// 조회수 증가
noticeMapper.incrementHit(boNo);
// 게시판 상세 정보 가져오기
noticeVO = noticeMapper.selectNotice(boNo);
// 이전글/이후글 정보 가져오기
prevNextList = noticeMapper.prevNextInfo(boNo);
/** 반환자료 저장 */
param.put("noticeVO", noticeVO);
param.put("prevNextList", prevNextList);
}
@Override
public ServiceResult insertNotice(HttpServletRequest req, NoticeVO noticeVO) throws Exception {
ServiceResult result = null;
int status = noticeMapper.insertNotice(noticeVO);
if(status > 0) {
List<NoticeFileVO> noticeFileList = noticeVO.getNoticeFileList();
FileUploadUtils.noticeBoardFileUpload(noticeFileList, noticeVO.getBoNo(), req, noticeMapper);
result = ServiceResult.OK;
}else {
result = ServiceResult.FAILED;
}
return result;
}
@Override
public NoticeFileVO selectFileInfo(int fileNo) {
return noticeMapper.selectFileInfo(fileNo);
}
@Override
public NoticeVO selectNotice(int boNo) {
noticeMapper.incrementHit(boNo); // 조회수 증가
return noticeMapper.selectNotice(boNo);
}
@Override
public ServiceResult deleteNotice(int boNo) {
ServiceResult result = null;
// 먼저 파일부터 삭제한다.
noticeMapper.deleteNoticeFile(boNo);
// 그 다음에 게시글을 삭제한다.
int status = noticeMapper.deleteNotice(boNo);
if(status > 0) {
result = ServiceResult.OK;
}else {
result = ServiceResult.FAILED;
}
return result;
}
@Override
public ServiceResult modifyNotice(HttpServletRequest req, NoticeVO noticeVO) {
ServiceResult result = null;
int status = noticeMapper.modifyNotice(noticeVO); // 공지사항 수정
if(status > 0) { // 공지사항 수정 완료
// 게시글 정보에서 파일 목록을 가져오기
List<NoticeFileVO> noticeFileList = noticeVO.getNoticeFileList();
try {
// 공지사항 업로드 진행
FileUploadUtils.noticeBoardFileUpload(noticeFileList, noticeVO.getBoNo(), req, noticeMapper);
// 기존에 등록되어 있는 파일 목록들 중, 수정하기 위해 delete 버튼을 눌러 삭제 처리로 넘겨준 파일 번호들
Integer[] delNoticeNo = noticeVO.getDelNoticeNo();
if(delNoticeNo != null) {
for(int i = 0; i > delNoticeNo.length; i++) {
// 삭제할 파일 번호 중, 파일 번호에 해당하는 게시판 파일 정보를 가져와 물리적인 삭제를 진행
NoticeFileVO noticeFileVO = noticeMapper.selectNoticeFile(delNoticeNo[i]);
File file = new File(noticeFileVO.getFileSavepath());
file.delete(); // 기존 파일이 업로드된 경로에 파일 삭제
}
noticeMapper.deleteNoticeFileList(delNoticeNo); // 파일번호에 해당하는 파일 데이터를 DB에서 삭제
}
} catch (Exception e) {
e.printStackTrace();
}
result = ServiceResult.OK;
}else {
result = ServiceResult.FAILED;
}
return result;
}
}
package kr.or.ddit.mapper;
import java.util.List;
import kr.or.ddit.users.board.vo.NoticeFileVO;
import kr.or.ddit.users.board.vo.NoticeVO;
import kr.or.ddit.vo.PaginationInfoVO;
public interface NoticeBoardMapper {
public int selectNoticeCount(PaginationInfoVO<NoticeVO> pagingVO);
public List<NoticeVO> selectNoticeList(PaginationInfoVO<NoticeVO> pagingVO);
public List<NoticeVO> importantNoticeList();
public List<NoticeVO> fileExistNoticeList();
public int insertNotice(NoticeVO noticeVO);
public void insertNoticeBoardFile(NoticeFileVO noticeFileVO);
public NoticeFileVO selectFileInfo(int fileNo);
public void incrementHit(int boNo);
public NoticeVO selectNotice(int boNo);
public List<NoticeVO> prevNextInfo(int boNo);
public void deleteNoticeFile(int boNo);
public int deleteNotice(int boNo);
public int modifyNotice(NoticeVO noticeVO);
public NoticeFileVO selectNoticeFile(Integer integer);
public void deleteNoticeFileList(Integer[] delNoticeNo);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="kr.or.ddit.mapper.NoticeBoardMapper">
<resultMap type="noticeVO" id="noticeMap">
<id property="boNo" column="bo_no" />
<result property="boNo" column="bo_no" />
<result property="boTitle" column="bo_title" />
<result property="boContent" column="bo_content" />
<result property="boWriter" column="bo_writer" />
<result property="boDate" column="bo_date" />
<result property="boHit" column="bo_hit" />
<result property="boImpor" column="bo_impor" />
<collection property="noticeFileList" resultMap="noticeFileMap" />
</resultMap>
<resultMap type="noticefileVO" id="noticeFileMap">
<id property="fileNo" column="file_no" />
<result property="fileNo" column="file_no" />
<result property="fileName" column="file_name" />
<result property="fileSize" column="file_size" />
<result property="fileFancysize" column="file_fancysize" />
<result property="fileMime" column="file_mime" />
<result property="fileSavepath" column="file_savepath" />
<result property="fileDowncount" column="file_downcount" />
<result property="fileNos" column="file_nos" />
<result property="fileNames" column="file_names" />
<result property="fileSizes" column="file_sizes" />
<result property="fileFancysizes" column="file_fancysizes" />
<result property="fileMimes" column="file_mimes" />
<result property="fileSavepaths" column="file_savepaths" />
<result property="fileDowncounts" column="file_downcounts" />
</resultMap>
<select id="selectNoticeCount" parameterType="pagingVO" resultType="int">
select count(bo_no) from notice
where 1=1
<!-- <include refid="noticeSearch" /> -->
<if test="searchType != null and searchType == 'title'">
and (bo_title like '%' || #{searchWord} || '%')
</if>
<if test="searchType != null and searchType == 'writer'">
and (bo_writer like '%' || #{searchWord} || '%')
</if>
<if test="searchType != null and searchType == 'both'">
and (bo_title like '%' || #{searchWord} || '%')
or (bo_writer like '%' || #{searchWord} || '%')
</if>
</select>
<select id="selectNoticeList" parameterType="pagingVO" resultType="noticeVO">
<include refid="commonMapper.pagingHeader" />
select
bo_no
, bo_title
, bo_content
, bo_writer
, bo_date
, bo_hit
, bo_impor
from notice n
where 1=1
<!-- <include refid="noticeSearch" /> -->
<if test="searchType != null and searchType == 'title'">
and (bo_title like '%' || #{searchWord} || '%')
</if>
<if test="searchType != null and searchType == 'writer'">
and (bo_writer like '%' || #{searchWord} || '%')
</if>
<if test="searchType != null and searchType == 'both'">
and (bo_title like '%' || #{searchWord} || '%')
or (bo_writer like '%' || #{searchWord} || '%')
</if>
<include refid="commonMapper.pagingFooter" />
</select>
<select id="importantNoticeList" resultMap="noticeMap">
<include refid="commonMapper.pagingHeader" />
SELECT
n.bo_no,
n.bo_title,
n.bo_content,
n.bo_writer,
n.bo_date,
n.bo_hit,
n.bo_impor,
LISTAGG(nf.file_no, ',') WITHIN GROUP (ORDER BY nf.file_no) AS file_nos,
LISTAGG(nf.file_name, ',') WITHIN GROUP (ORDER BY nf.file_no) AS file_names,
LISTAGG(nf.file_size, ',') WITHIN GROUP (ORDER BY nf.file_no) AS file_sizes,
LISTAGG(nf.file_fancysize, ',') WITHIN GROUP (ORDER BY nf.file_no) AS file_fancysizes,
LISTAGG(nf.file_mime, ',') WITHIN GROUP (ORDER BY nf.file_no) AS file_mimes,
LISTAGG(nf.file_savepath, ',') WITHIN GROUP (ORDER BY nf.file_no) AS file_savepaths,
LISTAGG(nf.file_downcount, ',') WITHIN GROUP (ORDER BY nf.file_no) AS file_downcounts
FROM
notice n
LEFT OUTER JOIN
noticefile nf
ON
n.bo_no = nf.bo_no
WHERE
1=1
AND
n.bo_impor = 'y'
GROUP BY
n.bo_no, n.bo_title, n.bo_content, n.bo_writer, n.bo_date, n.bo_hit, n.bo_impor
ORDER BY
n.bo_no DESC
<include refid="commonMapper.pagingFooters" />
</select>
<select id="fileExistNoticeList" resultType="noticeVO">
select
DISTINCT a.bo_no
from
notice a
, noticefile b
where 1=1
and a.bo_no = b.bo_no
</select>
<insert id="insertNotice" parameterType="noticeVO" useGeneratedKeys="true">
<selectKey keyProperty="boNo" order="BEFORE" resultType="int">
select seq_notice.nextval from dual
</selectKey>
INSERT INTO notice (
bo_no,
bo_title,
bo_content,
bo_writer,
bo_date,
bo_hit,
bo_impor
) VALUES (
#{boNo},
#{boTitle},
#{boContent},
#{boWriter},
sysdate,
0,
#{boImpor}
)
</insert>
<insert id="insertNoticeBoardFile" parameterType="noticefileVO">
INSERT INTO noticefile (
file_no,
bo_no,
file_name,
file_size,
file_fancysize,
file_mime,
file_savepath,
file_downcount
) VALUES (
seq_noticefile.nextval,
#{boNo},
#{fileName},
#{fileSize},
#{fileFancysize},
#{fileMime},
#{fileSavepath},
0
)
</insert>
<select id="selectFileInfo" parameterType="int" resultType="noticefileVO">
SELECT
file_no,
bo_no,
file_name,
file_size,
file_fancysize,
file_mime,
file_savepath,
file_downcount
FROM
noticefile
WHERE file_no = #{fileNo}
</select>
<update id="incrementHit" parameterType="int">
update notice
set
bo_hit = bo_hit + 1
where bo_no = ${boNo}
</update>
<select id="selectNotice" parameterType="int" resultMap="noticeMap">
select
n.bo_no
, n.bo_title
, n.bo_content
, n.bo_writer
, n.bo_date
, n.bo_hit
, n.bo_impor
, nf.file_no
, nf.file_name
, nf.file_size
, nf.file_fancysize
, nf.file_mime
, nf.file_savepath
, nf.file_downcount
from
notice n
left outer join
noticefile nf on(n.bo_no = nf.bo_no)
where
1=1
and
n.bo_no = ${boNo}
</select>
<select id="prevNextInfo" parameterType="int" resultType="noticeVO">
select a.*
from(
select bo_no, bo_title, bo_writer, bo_date, bo_hit, 'prev' as "prevnext_flag", row_number() over (order by bo_no desc) rnum from notice
<![CDATA[
where bo_no < ${boNo}
]]>
) a
where a.rnum = 1
union all
select a.*
from(
select bo_no, bo_title, bo_writer, bo_date, bo_hit, 'next' as "prevnext_flag", row_number() over (order by bo_no asc) rnum from notice
<![CDATA[
where bo_no > ${boNo}
]]>
) a
where a.rnum = 1
</select>
<delete id="deleteNoticeFile" parameterType="int">
DELETE FROM noticefile
WHERE bo_no = #{boNo}
</delete>
<delete id="deleteNotice" parameterType="int">
DELETE FROM notice
WHERE bo_no = #{boNo}
</delete>
<update id="modifyNotice" parameterType="noticeVO">
UPDATE notice
SET
bo_title = #{boTitle},
bo_content = #{boContent},
bo_writer = #{boWriter},
bo_date = sysdate,
bo_impor = #{boImpor}
WHERE bo_no = #{boNo}
</update>
<select id="selectNoticeFile" parameterType="int" resultType="noticefileVO">
SELECT
file_no,
file_name,
file_size,
file_fancysize,
file_mime,
file_savepath,
file_downcount
FROM
noticefile
WHERE file_no = #{fileNo}
</select>
<delete id="deleteNoticeFileList">
delete from noticefile
<where>
file_no in
<foreach collection="array" item="fileNo" open="(" close=")" separator=",">
${fileNo }
</foreach>
</where>
</delete>
</mapper>
'대덕인재개발원 > 대덕인재개발원_최종 포트폴리오' 카테고리의 다른 글
(21) 마이페이지 > 회원정보수정, 회원탈퇴 페이지 > 코드 리뷰 (1) | 2024.02.16 |
---|---|
(20) 게시판 > 공지사항 페이지 > 화면 설명 (0) | 2024.02.16 |
(18) 마이 트립 > 만남의 광장 페이지 > 화면 설명 (0) | 2024.02.16 |
(17) 마이 트립 > 만남의 광장 페이지 > 코드 리뷰 (0) | 2024.02.16 |
(16) 마이 트립 > 플래너 리스트 페이지 > 화면 설명 (0) | 2024.02.16 |