본문 바로가기
개발 공부 Today I Learned

[국비 66일차 TIL] 공지사항, 글 삭제, 페이징

by 개발자신입 2024. 2. 27.
반응형

공지사항 만들기

공지사항 게시판 notice

  • NoticeController
  • NoticeService
  • NoticeServiceImpl
  • NoticeDAO
  • NoticeDTO
  • notice-mapper.xml


만드는 순서

DTO에 들어갈 내용

int nno, ndel, nread, nlike

String ntitle, ncontent, ndate

NoticeDTO.java

import lombok.Data;

@Data
public class NoticeDTO {
	private int nno, ndel, nread, nlike;
	private String ntitle, ncontent, ndate;
}

DB에 들어갈 내용

테이블명  notice
column nno(int, auto, PK),
ndel(int 1),
nread(int, 기본값 1),
nlike(int, 기본값 1),
 
ntitle(varchar, 50), 
ncontent(varchar, 500), 
ndate(datetype, current timestamp)

 

CREATE TABLE notice (
	nno INT AUTO_INCREMENT PRIMARY KEY,
	ndel INT,
	nread INT,
	nlike INT,
	ntitle VARCHAR(255),
	ncontent VARCHAR(500),
	ndate TIMESTAMP
);

NoticeService에 들어갈 추상 메소드 (인터페이스)

  • public List<NoticeDTO> noticeList();
  • public NoticeDTO detail(int no);
  • public int noticeWrite(NoticeDTO);
  • public int noticeDel(int no);
  • public int noticeUpdate(NoticeDTO);

NoticeService.java 

public interface NoticeService {

    public List<NoticeDTO> noticeList();
    public NoticeDTO detail(int no);
    public int noticeWrite(NoticeDTO noticeDTO);
    public int noticeDel(int no);
    public int noticeUpdate(NoticeDTO noticeDTO); 
}


NoticeServiceImpl.java 

  1. 클래스 생성 시, 인터페이스 추가하기
  2. + AbstractService  상속받기
  3. @Service("noticeService") 어노테이션 추가

NoticeServiceImpl 클래스 생성 시 인터페이스 추가

 

@Service("noticeService")
public class NoticeServiceImpl extends AbstractService implements NoticeService {

	@Override
	public List<NoticeDTO> noticeList() {
		return null;
	}

	@Override
	public NoticeDTO detail(int no) {
		return null;
	}

	@Override
	public int noticeWrite(NoticeDTO dto) {
		return 0;
	}

	@Override
	public int noticeDel(int no) {
		return 0;
	}

	@Override
	public int noticeUpdate(NoticeDTO dto) {
		return 0;
	}

}

NoticeDAO.java

superclass 선택 후 생성하기 : AbstractDAO

NoticeDAO 생성 시 superclass 추가

 

@Repository
public class NoticeDAO extends AbstractDAO {

}

 

-> DAO를 NoticeServiceImpl 서비스와 연결시키기 (@Autowired로)

NoticeServiceImpl.java

	@Autowired
	private NoticeDAO noticeDAO;

NoticeController.java

Resource 어노테이션의 name은 NoticeServiceImpl에 적었던 "noticeService"

@Controller
public class NoticeController {
	
	@Resource(name="noticeService") // 서비스와 name이 일치해야함.
	private NoticeService noticeService;
	
	// 2024-02-27 공지 리스트
	@GetMapping("/notice")
	public String notice() {
		return "notice"; // ......./views/notice.jsp
	}

 

notice.jsp

<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>

 

<body> 안에 입력할 내용

			<div class="text-center">
				<h2 class="section-heading text-uppercase">공지사항</h2>
			</div>
			<div class="row text-center">
			<%
			List list = new ArrayList();
			list.add(1);
			list.add(2);
			list.add(3);
			request.setAttribute("list", list);
			%>
				
				<c:choose>
					<c:when test="${fn:length(list) gt 0}">테이블 출력</c:when>
					<c:otherwise>출력할 값이 없습니다.</c:otherwise>
				</c:choose>

 

import 부분 삭제

<%@page import="java.util.List"%>
<%@page import="java.util.ArrayList"%>

NoticeController.java

list를 컨트롤러에서 model로 받아오기

	// 2024-02-27 공지 리스트, 요구사항 확인
	@GetMapping("/notice")
	public String notice(Model model) {
		List<NoticeDTO> list = noticeService.noticeList();
		model.addAttribute("list", list);
		
		return "notice"; // ......./views/notice.jsp
	}

NoticeServiceImpl.java

서비스 안에 기존에 있던 리스트의 return 부분

	@Override
	public List<NoticeDTO> noticeList() {
		return noticeDAO.noticeList();
	}

 

-> noticeList 생성 (DAO)

NoticeDAO.java

@Repository
public class NoticeDAO extends AbstractDAO {

	public List<NoticeDTO> noticeList() {
		return sqlSession.selectList("notice.noticeList"); // 지금은 파라미터가 비어있어서 1개만 적은거임.
	}

notice-mapper.xml

<mapper namespace="notice">
	
	<select id="noticeList" resultType="org.green.dto.NoticeDTO">
		SELECT nno, ndel, nread, nlike, ntitle, ndate
		FROM notice
	</select>
	
</mapper>

notice.jsp

	<!-- 게시판 -->
	<br>
	<br>
	<section class="page-section" id="services">
		<div class="container">
			<div class="text-center">
				<h2 class="section-heading text-uppercase">공지사항</h2>
			</div>
			<div class="row text-center">
				<%-- 			<%
			List list = new ArrayList();
			list.add(1);
			list.add(2);
			list.add(3);
			request.setAttribute("list", list);
			%> --%>

				<c:choose>
					<c:when test="${fn:length(list) gt 0}">
						<table>
							<thead>
								<tr>
									<th>번호</th>
									<th>제목</th>
									<th>작성일</th>
									<th>조회수</th>
								</tr>
							</thead>
							<c:forEach items="${list }" var="row">
								<tr>
									<td onclick="detail(${row.nno })">${row.nno }</td>
									<td class="title"><a href="./detail?no=${row.nno }">
											${row.ntitle } </a></td>
									<td>${row.ndate }</td>
									<td>${row.nlike }</td>
								</tr>
							</c:forEach>
						</table>
					</c:when>
					<c:otherwise>
						<h1>공지사항이 없습니다.</h1>
					</c:otherwise>
				</c:choose>

				<!-- 글쓰기 버튼 -->
				<div class="d-flex justify-content-end">
					<button type="button" class="btn btn-primary btn-lg mt-3" data-bs-toggle="modal" data-bs-target="#write">글쓰기</button>
				</div>
			</div>
		</div>
	</section>

mybatis-config.xml

* alias : mapper의 resultType명 

<typeAlias type="org.green.dto.NoticeDTO" alias="notice"/>

NoticeController.java

	// 공지 글 작성하기 -> admin 관리자 화면에서
	@GetMapping("/admin/noticeWrite")
	public String noticeWrite() {
		return "admin/noticeWrite"; // ...../views/admin/noticeWrite.jsp => admin 폴더 만들어야함.
	}

 

-> admin 폴더 만들기 :     ...../views/admin/noticeWrite.jsp 경로
-> admin 폴더 안에 noticeWrite 생성

 

noticeWrite.jsp

<title>admin Write</title>
</head>
<body>
	<h1>공자사항 글쓰기</h1>
	<form action="./admin/noticeWrite" method="post">
		<input name="ntitle">
		<textarea name="ncontent"></textarea>
		<button type="submit">공지 작성</button>
	</form>
</body>
</html>

NoticeController.java

	@PostMapping("/admin/noticeWrite")
	public String noticeWrite(NoticeDTO dto) {
//		System.out.println(dto.getNtitle());
//		System.out.println(dto.getNcontent());
		
		int result = noticeService.noticeWrite(dto);
		return "redirect:/notice";
		
	}

 

-> noticeWrite (ServiceImpl, DAO에 생성)

NoticeServiceImpl.java

	@Override
	public int noticeWrite(NoticeDTO dto) {
		return noticeDAO.noticeWrite(dto);
	}

NoticeDAO.java

	public int noticeWrite(NoticeDTO dto) {
		return sqlSession.insert("notice.noticeWrite", dto);
	}

 

-> mapper에 sql문 <insert> 추가

	<insert id="noticeWrite" parameterType="notice">
		INSERT INTO notice (ntitle, ncontent)
		VALUES (#{ntitle}, #{ncontent})
	</insert>

NoticeController.java

	@GetMapping("/noticeDetail")
	public String noticeDetail(@RequestParam(value="no", defaultValue = "0", required = true) int no, Model model) {
		
		if(no == 0) {
			return "redirect:/error";
		} else {
			NoticeDTO detail = noticeService.detail(no);
			if(detail.getNno() == 0) {
				return "reidrect:/error";
			} else {
				model.addAttribute("detail", detail);
				return "noticeDetail";
			}
		}
	}
}

공지글 상세보기

notice-mapper.xml

 

   <select id="noticeDetail" resultType="notice" parameterType="Integer">
		SELECT nno, ndel, nread, ntitle, ndate, ncontent
		FROM notice
		WHERE nno=#{nno} AND ndel=1
	</select>

NoticeServiceImpl.java

   @Override
   public NoticeDTO detail(int no) {
      return noticeDAO.detail(no);
   }

 

-> detail 생성 (DAO에)

NoticeDAO.java

	public NoticeDTO detail(int no) {
		return sqlSession.selectOne("notice.noticeDetail", no);
	}

notice.jsp

	<!-- 게시판 -->
	<br>
	<br>
	<section class="page-section" id="services">
		<div class="container">
			<div class="text-center">
				<h2 class="section-heading text-uppercase">공지사항</h2>
			</div>
			<div class="row text-center">

				<c:choose>
					<c:when test="${fn:length(list) gt 0}">
						<table>
							<thead>
								<tr>
									<th>번호</th>
									<th>제목</th>
									<th>작성일</th>
									<th>조회수</th>
								</tr>
							</thead>
							<c:forEach items="${list }" var="row">
								<tr>
									<td onclick="noticeDetail(${row.nno })">${row.nno }</td>
									<td class="title"><a href="./noticeDetail?no=${row.nno }">
											${row.ntitle } </a></td>
									<td>${row.ndate }</td>
									<td>${row.nlike }</td>
								</tr>
							</c:forEach>
						</table>
					</c:when>
					<c:otherwise>
						<h1>공지사항이 없습니다.</h1>
					</c:otherwise>
				</c:choose>

noticeDetail.jsp

	<!-- 게시판 -->
	<section class="page-section" id="detail">
		<div class="container">
			<div class="text-center">
				<h2 class="section-heading text-uppercase">공지사항 디테일</h2>
			</div>

			<c:if test="${not empty detail}">
				<div class="card mb-4" style="min-height: 500px;">
					<div class="card-body">
						<div class="h2">${detail.ntitle}</div>
						<div class="row p-2 bg-secondary">
							<div class="col align-middle text-start">
								관리자
								<a      class="btn btn-primary" href="./noticeDel${detail.nno }">[삭제]</a>
								<button class="btn btn-primary" onclick="location.href='./noticeUpdate?no=${detail.nno}'">수정</button>
							</div>
							<div class="col align-middle text-end">${detail.ndate}</div>
						</div>
						<div class="mt-4 h-auto">${detail.ncontent}</div>
					</div>
				</div>
				<button class="btn btn-warning" onclick="history.back()">공지사항</button>
				<hr>
			</c:if>

			<c:if test="${empty detail}">
				<!-- detail이 null인 경우 처리 -->
				<p>공지사항이 존재하지 않습니다.</p>
			</c:if>
		</div>
	</section>

 


공지 글 삭제하기

NoticeController.java

	    // noticeDel
	    @GetMapping("/noticeDel{no}")
	    public String noticeDel(@PathVariable("no") int no) {
	    	System.out.println("@PathVariable : " + no);

	    	noticeService.noticeDel(no);
	    	return "redirect:/notice";
	}

NoticeServiceImpl.java

	@Override
	public int noticeDel(int no) {
		return noticeDAO.noticeDel(no);
	}

NoticeDAO.java

	public int noticeDel(int no) {
		return sqlSession.update("notice.noticeDel",no);
	}

notice-mapper.xml

    <update id="noticeDel" parameterType="Integer">
    	UPDATE notice SET ndel='0'
    	WHERE nno=#{nno} AND ndel=1
    </update>

 

삭제된 글은 화면에 보이지 않도록 하려면 mapper의 noticeList를 수정해야 함. 

* ndel이 1인 글만 화면에 노출 WHERE ndel=1

	<select id="noticeList" resultType="notice"> 
		SELECT nno, ndel, nread, nlike, ntitle, ncontent, ndate
		FROM notice
		WHERE ndel=1
		ORDER BY nno DESC
	</select>

페이징 만들기

Board에서 페이징 만들었던 내용 참고

 

NoticeController.java

@Controller
public class NoticeController {
	
	@Resource(name="noticeService") // 서비스와 name이 일치해야함.
	private NoticeService noticeService;

	@Autowired
	private Util util;
	
	// 2024-02-27 공지 리스트, 요구사항 확인
	// 페이징
	@GetMapping("/notice")
	public String notice(@RequestParam(value = "pageNo", required = false) String no ,Model model) {
		
		int currentPageNo=1;
		if(util.str2Int(no) > 0 ) { // 정수=1, 정수가 아니면 currentPageNo
			currentPageNo = Integer.parseInt(no);
		}
			
		// 전체 글 수 totalRecordCount (0, 1인 것들만 가져오기)
		int totalRecordCount = noticeService.totalRecordCount();

		// pagination
		PaginationInfo paginationInfo = new PaginationInfo();
		paginationInfo.setCurrentPageNo(currentPageNo); // 현재 페이지 번호
		paginationInfo.setRecordCountPerPage(10); // 한 페이지에 게시되는 게시물 수 
		paginationInfo.setPageSize(10); // 페이징 리스트의 사이즈 (페이징 숫자 수)
		paginationInfo.setTotalRecordCount(totalRecordCount); // 전체 게시물 건 수
		
		List<NoticeDTO> list = noticeService.noticeList(paginationInfo.getFirstRecordIndex());
		model.addAttribute("list", list);
		
		//페이징 관련 정보가 있는 PaginationInfo 객체를 모델에 반드시 넣어준다.
		model.addAttribute("paginationInfo", paginationInfo); 
		model.addAttribute("pageNo", currentPageNo);		
		
		return "notice"; // ......./views/notice.jsp
	}

 

-> totalRecordCount를 NoticeService에 추가

NoticeService.java

추가 내용 : int totalRecordCount();

public interface NoticeService {

    public List<NoticeDTO> noticeList(int pageNo);
    public NoticeDTO detail(int no);
    public int noticeWrite(NoticeDTO dto);
    public int noticeDel(int no);
    public int noticeUpdate(NoticeDTO dto);
	public int totalRecordCount();
    
}

NoticeServiceImpl.java

* noticeList 매개변수에 int pageNo

* totalRecordCount() 생성

	@Override
	public List<NoticeDTO> noticeList(int pageNo) {
		return noticeDAO.noticeList(pageNo);
	}

	@Override
	public int totalRecordCount() {
		return noticeDAO.totalRecordCount();
	}

notice.jsp

<script type="text/javascript">

// 전자정부 페이징 이동 스크립트
function linkPage(pageNo){
	location.href="./notice?pageNo="+pageNo;
}

</script>

 

페이징 코드 : table이 끝나는 밑에 넣어주기 

<!-- 페이징 -->
<div class="m-2 bg-secondary">
	<ui:pagination paginationInfo="${paginationInfo}" type="text" jsFunction="linkPage" />
</div>

notice-mapper.xml

	<select id="totalRecordCount" resultType="Integer">
		SELECT COUNT(*) FROM notice WHERE ndel=1
	</select>

	<select id="noticeList" parameterType="Integer" resultType="notice">
		SELECT nno, ntitle, ndate
		FROM notice
		WHERE ndel=1
		ORDER BY nno DESC
		LIMIT #{pageNo}, 10
	</select>

notice.jsp 전체코드

<%@ 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://egovframework.gov/ctl/ui" prefix="ui"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="utf-8" />
<meta name="viewport"
	content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="description" content="" />
<meta name="author" content="" />

<title>공지사항</title>

<!-- Font Awesome icons (free version)-->
<script src="https://use.fontawesome.com/releases/v6.3.0/js/all.js"
	crossorigin="anonymous"></script>
<!-- Google fonts-->
<link href="https://fonts.googleapis.com/css?family=Montserrat:400,700"
	rel="stylesheet" type="text/css" />
<link
	href="https://fonts.googleapis.com/css?family=Roboto+Slab:400,100,300,700"
	rel="stylesheet" type="text/css" />
<!-- Core theme CSS (includes Bootstrap)-->
<link href="css/styles.css" rel="stylesheet" />
<link href="css/board.css" rel="stylesheet" />
<script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>
<script
	src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"
	integrity="sha512-v2CJ7UaYy4JwqLDIrZUI/4hqeoQieOmAZNXBeQyjo21dadnwR+8ZaIJVT8EE2iyI61OV8e6M8PP2/4hpQINQ/g=="
	crossorigin="anonymous" referrerpolicy="no-referrer"></script>

<!-- summer note -->
<script src="/js/summernote-lite.js"></script>
<script src="/js/summernote/summernote-ko-KR.js"></script>
<link rel="stylesheet" href="/css/summernote/summernote-lite.css">
<link
	href="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote-bs4.min.css"
	rel="stylesheet">
<script
	src="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote-bs4.min.js"></script>
<!-- summer note -->

<script type="text/javascript">
// 전자정부 페이징 이동 스크립트
function linkPage(pageNo){
	location.href="./notice?pageNo="+pageNo;
}
</script>
<style>
thead {
	background-color: #007bff; /* 원하는 배경색으로 수정 가능 */
	color: #fff; /* 텍스트 색상 설정 */
}
</style>
</head>

<body id="page-top">
	<!-- Navigation 코드 이동 : menu.jsp -->
	<%@ include file="menu.jsp"%>

	<!-- 게시판 -->
	<br>
	<br>
	<section class="page-section" id="services">
		<div class="container">
			<div class="text-center">
				<h2 class="section-heading text-uppercase">공지사항</h2>
			</div>
			<div class="row text-center">
				<c:choose>
					<c:when test="${fn:length(list) gt 0}">
						<table>
							<thead>
								<tr>
									<th>번호</th>
									<th>제목</th>
									<th>작성일</th>
									<th>조회수</th>
								</tr>
							</thead>
							<c:forEach items="${list}" var="row">
								<tr>
									<td onclick="noticeDetail(${row.nno})">${row.nno}</td>
									<td class="title"><a href="./noticeDetail?no=${row.nno}">
									${row.ntitle}
									</a></td>
									<td>${row.ndate}</td>
									<td>${row.nlike}</td>
								</tr>
							</c:forEach>
						</table>
						<!-- 페이징 -->
						<div class="m-2 bg-secondary">
							<ui:pagination paginationInfo="${paginationInfo}" type="text"
								jsFunction="linkPage" />
						</div>
					</c:when>
					<c:otherwise>
						<p>공지사항이 없습니다.</p>
					</c:otherwise>
				</c:choose>


				<!-- 글쓰기 버튼 -->
				<div class="d-flex justify-content-end">
					<button type="button" class="btn btn-primary btn-lg mt-3"
						data-bs-toggle="modal" data-bs-target="#write">글쓰기</button>
				</div>
			</div>
		</div>
	</section>

	<!-- Bootstrap core JS-->
	<script
		src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>
	<!-- Core theme JS-->
	<script src="js/scripts.js"></script>
	<script src="https://cdn.startbootstrap.com/sb-forms-latest.js"></script>

	<script>
$(document).ready(function() {
	//여기 아래 부분
	$('#summernote').summernote({
		lang: "ko-KR", // default: 'en-US'
		height: 400,
		fontNames : ['D2Coding', 'Arial Black', 'Comic Sans MS', 'Courier New'],
		placeholder: '간단하게 작성해주세요🥰',
		toolbar: [
		    // [groupName, [list of button]]
		    ['style', ['bold', 'italic', 'underline', 'clear']],
		    /* ['font', ['strikethrough', 'superscript', 'subscript']], */
		    ['fontname', ['fontname','fontsize', 'color']],
		    ['para', ['ul', 'ol', 'paragraph']],
		    /* ['height', ['height']] */
		    ['table', ['table','link', 'picture', 'video', 'fullscreen', 'codeview', 'help']]
		  ]
	});
});
</script>

</body>
</html>
반응형

댓글