위로 아래

글목록 HTML

자바스크립트를 이용해 각 제목의 <a> 태그를 클릭하면 <table> 태그 밑의 hidden input value에 a 태그의 input value 값을 넣고 submit해서,

제목을 클릭하면 각 줄마다의 bno 값을 다음 페이지로 전송한다.

 

조회수가 10이 넘어가면 hot.gif 이미지가 붙도록 설정한다.

답글일 경우엔 앞에 re.gif 이미지를 붙인다.

blevel로 몇 번째의 답글인지 표시하여 해당 답글만큼 level.gif 이미지의 크기를 늘려 더 크게 들여쓰기 한다.

 

jstl 태그 라이브러리 중 function을 이용해 게시글의 개수를 파악해 게시글이 없으면 없음을 띄운다.

jstl 태그 라이브러리 중 core를 이용하여 게시글을 forEach 반복문을 통해 나열한다.

 

또한, 페이지를 관리하는 박스를 제작하기 위해 jstl 라이브러리 중 core를 사용하여 전달 받은 페이지 개수만큼 forEach 반복문으로 페이지를 만들고, 

클릭 시 해당 페이지에 속하는 게시글만 뜨도록 현재 페이지인 p를 전달해 해당 페이지의 start와 end 변수를 구하도록 하여 쿼리문을 다루는 DAO에 전달한다.

페이지 이동 시에는 주소 뒤에 쿼리를 붙여 정보를 전달해준다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>게시글 목록</title>

<link rel="stylesheet" href="css/list.css" type="text/css">
<script src="jquery/jquery-3.7.0.min.js"></script>
<script src="js/list.js"></script>

</head>
<body>
<div class="btn">
	<a href="writeForm?curPage=${pdto.curPage}">글쓰기</a>
</div>
<table>
	<thead>
		<tr><th colspan="6">게시글 목록 (전체 게시글 수 : ${totalCnt})</th></tr>
		<tr>
			<th>번호</th>
			<th>제목</th>
			<th>작성자</th>
			<th>최종수정일</th>
			<th>조회수</th>
			<th>아이피</th>
		</tr>
	</thead>
	<tbody>
		<c:choose>
			<c:when test = "${fn:length(articles)==0}">
				<tr>
					<td colspan="6">게시글이 없습니다.</td>
				</tr>
			</c:when>
			<c:when test = "${fn:length(articles)>0}">
				<c:forEach var = "article" items = "${articles}" varStatus="i">
					<tr>
						<td class="col1">${article.rn}</td>
						<td class="col2">
							<c:choose>
								<c:when test="${article.blevel==0}">
									<img src="images/level.gif" width="5px;">
								</c:when>
								<c:when test="${article.blevel>0 }">
									<img src="images/level.gif" width="${article.blevel*10}px;" style="height:15px;">
									<img src="images/re.gif">
								</c:when>								
							</c:choose>
							<a class="content">
								${article.subject}
								<input type = "hidden" name="no" value="${article.bno}">
							</a>
						</td>
						<td class="col3">${article.writer}</td>
						<td class="col4">${article.regdate}</td>
						<td class="col5">
							${article.readcount}
							<c:if test="${article.readcount>10}">
								<img src="images/hot.gif" style="width:30px; height:15px;">
							</c:if>
						</td>
						<td class="col6">${article.ip}</td>
					</tr>
				</c:forEach>
			</c:when>
		</c:choose>
	</tbody>
	<tfoot>
		<tr>
			<td colspan="6" style="text-align:center;">
				<c:if test = "${pdto.startPg > pBlock}">
					<a href="list?curPage=${pdto.startPg-1}&curBlock=${pdto.curBlock-1}">[이전]</a>
				</c:if>
				<c:forEach begin="${pdto.startPg}" end="${pdto.endPg}" var="p" step="1">
					<c:choose>
						<c:when test="${p==pdto.curPage}">
							<a href="list?curPage=${p}&curBlock=${pdto.curBlock}"><span style="font-weight:bold;"><c:out value="${p}"/></span></a>&nbsp;
						</c:when>
						<c:when test="${p!=pdto.curPage}">
							<a href="list?curPage=${p}&curBlock=${pdto.curBlock}"><span><c:out value="${p}"/></span></a>&nbsp;
						</c:when>
					</c:choose>
				</c:forEach>
				<c:if test = "${pdto.endPg<pdto.pgCnt}">
					<a href="list?curPage=${pdto.startPg+pBlock}&curBlock=${pdto.curBlock+1}">[다음]</a>
				</c:if>
			</td>
		</tr>
	</tfoot>
</table>
<form action="" method="post" name="content">
	<input type="hidden" name="bno" value="${article.bno}">
	<input type="hidden" name="curPage" value="${pdto.curPage}">
	<input type="hidden" name="curBlock" value="${pdto.curPage}">
</form>
</body>
</html>

 

 

글목록 CSS

@charset "UTF-8";

*{margin:0; padding: 0;}
table {border:1px solid black; border-collapse: collapse; width:90%; margin:0 auto;}
th, td {border:1px solid black; border-collapse: collapse; padding:10px; margin:5px;}
th {background-color: #cfcfff;}
td {background-color: #ffffff; font-weight: 200;}
.btn {height:30px; width:850px; text-align:right;}
a {color:black; text-decoration: none; }
a:hover {font-weight: bold;}
.col1 {width:8%;}
.col2 {width:35%;}
.col3 {width:20%;}
.col4 {width:15%;}
.col5 {width:10%;}
.col6 {width:12%;}

 

 

글목록 JavaScript

/**
 * 
 */
 $().ready(function(){
		let $item = $('a.content').on("click",function(){
			let idx = $item.index(this);
			//alert($("a.content input[type=hidden]").eq(idx).val());
			
			var f = $('form[name=content]')
			$('form input[name=bno]').attr('value', $("a.content input[name=no]").eq(idx).val());
			f.attr('action','content');
			f.submit();
		});
	})

 

 

 

 

 

글목록 컨트롤러

package com.ecom4.hi.board.control;

import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import com.ecom4.hi.HomeController;
import com.ecom4.hi.board.model.BoardDTO;
import com.ecom4.hi.board.model.PageDTO;
import com.ecom4.hi.board.model.RowInterPage;
import com.ecom4.hi.board.service.BoardService;

@Controller
public class BoardController {
	
	private static final Logger logger = LoggerFactory.getLogger(BoardController.class);

	//JavaBoard에서 작업했던 Action 역할을 하는 객체 - 비즈니스 로직 BIZ를 갖고 있다
	
	@Autowired
	private BoardService boardService;
	
	@RequestMapping(value = "/list")
	public String getArticles(HttpServletRequest request, HttpServletResponse response,
										BoardDTO dto, Model model, PageDTO pdto){
		

		logger.info("리스트 컨트롤러");
		
		Map<String, Object> resultSet = boardService.getArticles(dto, pdto);
		//List<BoardDTO> articles = boardService.getArticles(dto);
		
		model.addAttribute("articles",resultSet.get("articles"));
		model.addAttribute("totalCnt",resultSet.get("totalCnt"));
		model.addAttribute("pdto",resultSet.get("pdto"));
		model.addAttribute("pBlock",RowInterPage.PAGE_OF_BLOCK);
		
		return "board/BoardList";
	}
}

 

 

 

글목록 Service

RowInterPage 인터페이스

Service에서 사용할, 한 페이지당 게시글 개수와 한 블럭당 페이지 개수를 지정하는 인터페이스 설정

언제든지 다른 코드 수정 없이 쉽게 바꿀 수 있도록 따로 빼주어서 사용한다.

인터페이스를 작성하여 final과 대문자 변수명을 사용해 상수를 선언한다.

package com.ecom4.hi.board.model;

public interface RowInterPage {
	public static final int ROW_OF_PAGE = 6;
	public static final int PAGE_OF_BLOCK = 3;
}

 

 

boardService 인터페이스

package com.ecom4.hi.board.service;

import java.util.Map;

import com.ecom4.hi.board.model.BoardDTO;
import com.ecom4.hi.board.model.PageDTO;

public interface BoardService {

	Map<String, Object> getArticles(BoardDTO dto, PageDTO pdto);

}

 

boardServiceImpl 구현 클래스

package com.ecom4.hi.board.service;

import java.sql.ResultSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.ecom4.hi.board.dao.BoardDAO;
import com.ecom4.hi.board.model.BoardDTO;
import com.ecom4.hi.board.model.PageDTO;
import com.ecom4.hi.board.model.RowInterPage;

@Service(value = "boardService")
public class BoardServiceImpl implements BoardService {

	// DAO DI(Dependency Injection)
	@Autowired
	private BoardDAO boardDao;
	
	@Override
	public Map<String, Object> getArticles(BoardDTO dto, PageDTO pdto) {
		Map<String, Object> resultSet = new HashMap<String, Object>();
		
		if(pdto.getCurBlock()<0) pdto.setCurBlock(1);
		if(pdto.getCurPage()<0) pdto.setCurPage(1);
		
		int totalCnt = boardDao.getTotalCnt();
		resultSet.put("totalCnt",totalCnt);
		
		//현재 페이지 계산
		int start = (pdto.getCurPage()-1)*RowInterPage.ROW_OF_PAGE + 1;
		int end = (pdto.getCurPage()*RowInterPage.ROW_OF_PAGE)>totalCnt?
				totalCnt:pdto.getCurPage()*RowInterPage.ROW_OF_PAGE;
		
		dto.setStart(start);
		dto.setEnd(end);
		
		int pgCnt = (totalCnt%RowInterPage.ROW_OF_PAGE==0)?
				totalCnt/RowInterPage.ROW_OF_PAGE : totalCnt/RowInterPage.ROW_OF_PAGE+1;
		
		//페이지 블럭
		int pgBlock = (pgCnt%RowInterPage.PAGE_OF_BLOCK==0)?
				pgCnt/RowInterPage.PAGE_OF_BLOCK : pgCnt/RowInterPage.PAGE_OF_BLOCK+1;
		
		int startPg = (pdto.getCurBlock()-1)*RowInterPage.PAGE_OF_BLOCK+1;
		int endPg = (pdto.getCurBlock()*RowInterPage.PAGE_OF_BLOCK > pgCnt)?
				pgCnt : pdto.getCurBlock()*RowInterPage.PAGE_OF_BLOCK;
		
		pdto.setPgCnt(pgCnt);
		pdto.setPgBlock(pgBlock);
		pdto.setStartPg(startPg);
		pdto.setEndPg(endPg);
		
		resultSet.put("pdto",pdto);
		resultSet.put("articles", boardDao.getArticles(dto));
		
		return resultSet;
	}
}

현재 페이지 변수를 선정하고 처음엔 1로 초기화해준다. 

전체 게시글 수와, 

전체 페이지 수,

그리고 페이지마다 시작하는 게시글의 번호와 마지막 게시글의 번호를 작성한다.

시작하는 게시글 번호 변수인 start는, '이전 페이지 수 * 페이지당 게시글 수'로 구하고,

마지막 게시글 번호 변수인 End는, 

'최종 게시글 수 >= 현재 페이지 수 * 페이지당 게시글 수'일 경우엔 '현재 페이지수 * 페이지당 게시글 수'가 되도록 하고,

'최종 게시글 수 <= 현재 페이지 수 * 페이지당 게시글 수'일 경우엔 '최종 게시글 수'가 되도록 한다. 

 

 

 

글목록 DAO

package com.ecom4.hi.board.dao;

import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.ecom4.hi.board.model.BoardDTO;

@Repository(value = "boardDao")
public class BoardDAO {

	// 자원을 DI (의존성 주입)
	@Autowired
	private SqlSession sqlSession;

	private String namespace = "board.BoardDAO.";
	
	public List<BoardDTO> getArticles(BoardDTO dto) {		
		return sqlSession.selectList(namespace + "getArticles",dto);
	}
}

 

 

 

 

글목록 Mapper

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace = "board.BoardDAO">
<select id="getArticles" resultType="bvo">
SELECT * 
FROM(SELECT ROWNUM AS rn, A.* 
FROM(SELECT bno, bref, bstep, blevel, readcount, 
subject, content, writer, regdate, ip, passwd 
FROM board 
ORDER BY bref DESC, bno, bstep) A) 
WHERE rn BETWEEN #{start} AND #{end}
</select>

<select id="getTotalCnt" resultType="int">
	SELECT COUNT(bno) FROM BOARD
</select>

<insert id="writeAction" parameterType="bvo">
	<selectKey keyProperty="nbno" resultType="int" order="BEFORE">
		SELECT NVL(MAX(bno),0)+1 AS nbno FROM board
	</selectKey>
	INSERT INTO board
		(bno, bref, bstep, blevel, readcount, 
		subject, content, writer, regdate, ip, passwd) 
	VALUES (
		#{nbno},
		<choose>
			<when test="bno>0">
				#{bno},
				#{bstep}+1,
				#{blevel}+1,
			</when>
			<when test="bno==0 and bref==0">
				#{nbno},
				0,
				0,
			</when>
		</choose>
		#{readcount}, #{subject}, #{content}, #{writer}, SYSDATE, #{ip}, #{passwd}
	)
</insert>
</mapper>

 

 

 

 

 

완성 모습

페이지 박스도, 이미지 적용과 답글이 잘 적용되는 것도 확인할 수 있다.