2020년 01월 05일

업데이트:

필터


필터 생성 필터 생성


필터란?

요청이나 응답을 해줄 때 클라이언트와 서버(서블릿) 사이에서 데이터를 가공해 응답을 받을 때 가공된 데이터를 받게해주는 역할을 한다.

@WebFilter 어노테이션 : 어떤 요청이 왔을 때 필터를 동작하게 할건지?
여러 주소를 적고싶다면 주소창안에 urlPatterns = {} 를 작성해 주소를 ,로 구분해서 작성해준다.


로그인 필터

로그인에 성공해야 마이페이지의 기능을 사용할 수 있다.
필터처리를 안 해주면 로그아웃 상태에서도 주소창을 이용해 마이페이지에 접근할 수 있다.

–> 로그인 필터 생성 요청이 들어왔을 때 로그인이 되어있는지 검사해주는 역할



LoginFilter.java

package com.kh.wsp.filter;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.kh.wsp.member.model.vo.Member;

// 이 요청들은 로그인을 해야지만 수행할 수 있는 주소들이다.
@WebFilter(urlPatterns = 
				{"/member/myPage.do", "/member/changePwd.do", "/member/secession.do", 
				 "/member/updateMember.do", "/member/updatePwd.do","/member/updateStatus.do"})
public class LoginFilter implements Filter {

    public LoginFilter() {} // 기본 생성자
    public void init(FilterConfig fConfig) throws ServletException {}
	public void destroy() {}

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		// 필터링 동작을 작성하는 부분
		// ServletRequest, ServletResponse -> HttpRequest,HttpResponse의 부모
		// ServletRequest 매개변수를 HttpServletRequest로 다운캐스팅 진행
		HttpServletRequest req = (HttpServletRequest)request;
		HttpServletResponse res = (HttpServletResponse)response;
		
		// Session 얻어오기
		HttpSession session = req.getSession();
		// Session을 얻어오는 이유? 로그인한 회원정보가 저장되어 있음.
		// 로그인이 되었는지 알기 위해서 sesion에 있는 로그인된 회원 정보를 얻어와야 된다.
		Member loginMember = (Member)session.getAttribute("loginMember");
		
		if(loginMember == null) { // 로그인이 되어있지 않음
			// 메인페이지로 강제 이동
			res.sendRedirect(req.getContextPath());
		}else {
			chain.doFilter(request, response);
			// 다음 필터를 호출하는 역할
			// 다음 필터가 없다면 Servlet 또는 JSP로 이동
		}
	}
}


관리자 필터

관리자로 로그인 됐을 때만 수행할 수 있는 기능들

AdminFilter.java

package com.kh.wsp.filter;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.kh.wsp.member.model.vo.Member;


@WebFilter(urlPatterns= {"/notice/insertForm.do", "/notice/insert.do", "/notice/updateForm.do", 
						 "/notice/update.do", "/notice/delete.do"})
public class AdminFilter implements Filter {

  
    public AdminFilter() {}

	public void destroy() {}
	public void init(FilterConfig fConfig) throws ServletException {}

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		
		HttpServletRequest req = (HttpServletRequest)request;
		HttpServletResponse res = (HttpServletResponse)response;
		
		HttpSession session = req.getSession();
		
		Member loginMember = (Member)session.getAttribute("loginMember");
		
		if(loginMember == null || !loginMember.getMemberGrade().equals("A") ) { 
			// 로그인이 안 되어 있거나 회원 등급이 'A'가 아닌 경우
			
			// 메인페이지로 강제 이동
			res.sendRedirect(req.getContextPath());
		}else {
			chain.doFilter(request, response);
		}
	}
}




게시판


게시판 목록 조회


header.jsp

<li class="nav-item"><a class="nav-link" href="${contextPath }/board/list.do">Board</a></li>


게시판 목록 페이징 처리

PageInfo.java
페이징 처리에 필요한 vo

package com.kh.wsp.board.model.vo;

public class PageInfo { // 페이징 처리를 위한 값을 저장할  객체
	
	// 얻어 올 값
	private int currentPage; // 현재 페이지 번호를 저장할 변수
	private int listCount; // 전체 게시글 수를 저장할 변수
	
	// 설정할 값
	private int limit = 10; // 한 페이지에 보여질 게시글 목록 수 
	private int pageSize = 10; // 페이징바에 표시될 페이지 수
	
	
	// 계산할 값
	private int maxPage;    // 전체 목록 페이지의 수 == 마지막 페이지
	private int startPage;  // 페이징바 시작 페이지 번호
	private int endPage;    // 페이징바 끝 페이지 번호
	
	// 기본 생성자 사용 X
	
	
	public PageInfo(int currentPage, int listCount) {
		super();
		this.currentPage = currentPage;
		this.listCount = listCount;
		
		// 전달받은 값과 명시적으로 선언된 값을 이용하여 
		// makePageInfo()수행
		// vo가 생성되면 계산이 완료 된다.
		makePageInfo();
	}

	public PageInfo(int currentPage, int listCount, int limit, int pageSize) {
		super();
		this.currentPage = currentPage;
		this.listCount = listCount;
		this.limit = limit;
		this.pageSize = pageSize;
		
		makePageInfo();
	}
	
	

	public int getCurrentPage() {
		return currentPage;
	}

	public void setCurrentPage(int currentPage) {
		this.currentPage = currentPage;
	}

	public int getListCount() {
		return listCount;
	}

	public void setListCount(int listCount) {
		this.listCount = listCount;
		makePageInfo();
	}

	public int getLimit() {
		return limit;
	}

	public void setLimit(int limit) {
		this.limit = limit;
		makePageInfo();
	}

	public int getPageSize() {
		return pageSize;
	}

	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
		makePageInfo();
	}

	public int getMaxPage() {
		return maxPage;
	}

	public void setMaxPage(int maxPage) {
		this.maxPage = maxPage;
	}

	public int getStartPage() {
		return startPage;
	}

	public void setStartPage(int startPage) {
		this.startPage = startPage;
	}

	public int getEndPage() {
		return endPage;
	}

	public void setEndPage(int endPage) {
		this.endPage = endPage;
	}

	@Override
	public String toString() {
		return "PageInfo [currentPage=" + currentPage + ", listCount=" + listCount + ", limit=" + limit + ", pageSize="
				+ pageSize + ", maxPage=" + maxPage + ", startPage=" + startPage + ", endPage=" + endPage + "]";
	}
	
	
	// 페이징 처리에 필요한 값을 계산하는 메소드
	// private: 내부적으로만 사용 가능
	private void makePageInfo() {
		// maxPage : 총 페이지 수 == 마지막 페이지
		// 총 게시글 수가 100개, 한 페이지에 보여지는 게시글 수 10개 ==>  총 페이지 수 = 10, 마지막 페이지 = 10
		// 총 게 시글 수 101개, 한 페이지에 보여지는 게시글 수 10개 ==> 총 페이지 수 == (10.1 올림처리)11, 마지막 페이지 = 11
		maxPage = (int)Math.ceil((double)listCount / limit);
		
		
		// startPage: 페이징바 시작 번호
		// 페이징바에 페이지를 10개씩 보여줄 경우  1,11,21,31...
		startPage = (currentPage-1) / pageSize * pageSize + 1;
					// (11-1) / 10 * 10 + 1;
		
		// endPage : 페이징바의 끝 번호
		// 페이징바에 페이지를 10개씩 보여줄 경우 10,20,30,40 ...
		endPage = startPage + pageSize - 1;
		
		// 총 페이지의 수가 end페이지보다 작을 경우
		if(maxPage<=endPage) {
			endPage = maxPage;
		}
		
	}
}


BoardController.java

package com.kh.wsp.board.controller;

import java.io.IOException;
import java.util.List;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.kh.wsp.board.model.service.BoardService;
import com.kh.wsp.board.model.vo.Board;
import com.kh.wsp.board.model.vo.PageInfo;

@WebServlet("/board/*")
public class BoardController extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		
		// 요청이 들어오는 주소  --> /wsp/board/list.do
		String uri = request.getRequestURI();
		// /wsp
		String contextPath = request.getContextPath();
		String command = uri.substring((contextPath + "/board").length());
		//  /wsp/board/list.do 에서  /wsp/board 를 잘라낸다 --> /list.do 만 남음
		
		String path = null;
		RequestDispatcher view = null;
		
		String swalIcon = null;
		String swalTitle = null;
		String swalText = null;
		
		String errorMsg = null;
		
		try {
			BoardService service = new BoardService();
			
			// 현재 페이지를 얻어옴
			String cp = request.getParameter("cp");
			
			// 게시글 목록 조회 Controller **********************************************************
			if(command.equals("/list.do")) {
				errorMsg = "게시판 목록 조회 과정에서 오류 발생";
				
				// 1) 페이징 처리를 위한 값 계산 Service 호출
				PageInfo pInfo = service.getPageInfo(cp);


BoardService.java

/** 페이징 처리를 위한 값 계산 service
* @param cp
* @return PageInfo
* @throws Exception
*/
public PageInfo getPageInfo(String cp) throws Exception {
Connection conn = getConnection();

// cp가 null일 경우
int currentPage = cp == null ? 1 : Integer.parseInt(cp);

// DB에서 전체 게시글 수를 조회하여 반환받기
int listCount = dao.getListCount(conn);

close(conn);

return new PageInfo(currentPage, listCount);
}


BoardDao.java

/** 전체 게시글 수 반환 DAO
* @param conn
* @return listCount
* @throws Exception
*/
public int getListCount(Connection conn) throws Exception {
int listCount =0;
String query = prop.getProperty("getListCount");

try {
stmt = conn.createStatement();

rset = stmt.executeQuery(query);

if(rset.next()) {
    listCount = rset.getInt(1);
}

}finally {
close(rset);
close(stmt);
}
return listCount;
}


SQL

<!-- 전체 게시글 수 조회  -->
<entry key="getListCount">
SELECT COUNT(*) FROM V_BOARD
WHERE BOARD_STATUS = 'Y'	
</entry>





게시글 목록 조회

BoardController.java

// 2) 게시글 목록 조회 비즈니스 로직 수행
List<Board> bList = service.selectBoardList(pInfo);
// pInfo에 있는 currentPage, limit를 사용해야지만
// 현재 페이지에 맞는 게시글 목록만  조회할 수 있음.

/*for(Board b : bList) {
    System.out.println(b);
}*/

// 썸네일 추가 부분
path = "/WEB-INF/views/board/boardList.jsp";

request.setAttribute("bList", bList);
request.setAttribute("pInfo", pInfo);

view = request.getRequestDispatcher(path);
view.forward(request, response);
}


Board.java


package com.kh.wsp.board.model.vo;

import java.sql.Timestamp;

public class Board {
	private int boardNo;
	private String boardTitle;
	private String boardContent;
	private String memberId;
	private int readCount;
	private String categoryName;
	private Timestamp boardCreateDate;
	private Timestamp boardModifyDate;
	private String boardStatus;
	
	public Board() {}

	public Board(int boardNo, String boardTitle, String memberId, int readCount, String categoryName,
			Timestamp boardCreateDate) {
		super();
		this.boardNo = boardNo;
		this.boardTitle = boardTitle;
		this.memberId = memberId;
		this.readCount = readCount;
		this.categoryName = categoryName;
		this.boardCreateDate = boardCreateDate;
	}


	public Board(int boardNo, String boardTitle, String boardContent, String memberId, int readCount,
			String categoryName, Timestamp boardCreateDate, Timestamp boardModifyDate, String boardStatus) {
		super();
		this.boardNo = boardNo;
		this.boardTitle = boardTitle;
		this.boardContent = boardContent;
		this.memberId = memberId;
		this.readCount = readCount;
		this.categoryName = categoryName;
		this.boardCreateDate = boardCreateDate;
		this.boardModifyDate = boardModifyDate;
		this.boardStatus = boardStatus;
	}

	public int getBoardNo() {
		return boardNo;
	}

	public void setBoardNo(int boardNo) {
		this.boardNo = boardNo;
	}

	public String getBoardTitle() {
		return boardTitle;
	}

	public void setBoardTitle(String boardTitle) {
		this.boardTitle = boardTitle;
	}

	public String getBoardContent() {
		return boardContent;
	}

	public void setBoardContent(String boardContent) {
		this.boardContent = boardContent;
	}

	public String getMemberId() {
		return memberId;
	}

	public void setMemberId(String memberId) {
		this.memberId = memberId;
	}

	public int getReadCount() {
		return readCount;
	}

	public void setReadCount(int readCount) {
		this.readCount = readCount;
	}

	public String getCategoryName() {
		return categoryName;
	}

	public void setCategoryName(String categoryName) {
		this.categoryName = categoryName;
	}

	public Timestamp getBoardCreateDate() {
		return boardCreateDate;
	}

	public void setBoardCreateDate(Timestamp boardCreateDate) {
		this.boardCreateDate = boardCreateDate;
	}

	public Timestamp getBoardModifyDate() {
		return boardModifyDate;
	}

	public void setBoardModifyDate(Timestamp boardModifyDate) {
		this.boardModifyDate = boardModifyDate;
	}

	public String getBoardStatus() {
		return boardStatus;
	}

	public void setBoardStatus(String boardStatus) {
		this.boardStatus = boardStatus;
	}

	@Override
	public String toString() {
		return "Board [boardNo=" + boardNo + ", boardTitle=" + boardTitle + ", boardContent=" + boardContent
				+ ", memberId=" + memberId + ", readCount=" + readCount + ", categoryName=" + categoryName
				+ ", boardCreateDate=" + boardCreateDate + ", boardModifyDate=" + boardModifyDate + ", boardStatus="
				+ boardStatus + "]";
	}
}


BoardService.java

/** 게시글 목록 조회
* @param pInfo
* @return bList
* @throws Exception
*/
public List<Board> selectBoardList(PageInfo pInfo) throws Exception{
Connection conn = getConnection();

List<Board> bList = dao.selectBoardList(conn, pInfo);

close(conn);
return bList;
}


BoardDao.java

/** 게시글 목록 조회 DAO
* @param conn
* @param pInfo
* @return 
* @throws Exception
*/
public List<Board> selectBoardList(Connection conn, PageInfo pInfo) throws Exception {
List<Board> bList = null;

String query = prop.getProperty("selectBoardList");

try {
    // SQL 구문 조건절에 대입할 변수 생성
    int startRow = (pInfo.getCurrentPage()-1) * pInfo.getLimit() +1;
    int endRow = startRow + pInfo.getLimit()-1;
    
    pstmt = conn.prepareStatement(query);
    pstmt.setInt(1, startRow);
    pstmt.setInt(2, endRow);
    
    rset = pstmt.executeQuery();
    
    bList = new ArrayList<Board>();
    
    while(rset.next()) {
        Board board = new Board(rset.getInt("BOARD_NO"), 
                rset.getString("BOARD_TITLE"), rset.getString("MEMBER_ID"), 
                rset.getInt("READ_COUNT"), 
                rset.getString("CATEGORY_NM"), rset.getTimestamp("BOARD_CREATE_DT"));
        bList.add(board);
    }
    
}finally {
    close(rset);
    close(pstmt);
}

return bList;
}


SQL

<!-- 지정된 페이지 게시글 목록 조회  -->
<entry key="selectBoardList">
SELECT * FROM
    (SELECT ROWNUM RNUM, V.*
    FROM
        (SELECT * FROM V_BOARD WHERE BOARD_STATUS ='Y' ORDER BY BOARD_NO DESC)V)
WHERE RNUM BETWEEN ? AND ?
</entry>




목록 조회 후 boardList.jsp로 포워드

게시판 초기 화면

게시판 초기 화면



화면 구성 완료 후 화면

화면



boardList.jsp

<%-- 게시글 목록 출력 --%>
<tbody>
    <c:choose>
        <c:when test="${empty bList }">
        <!-- bList가 비어있을 때 : 게시글 목록 조회에서 조회되지 않았을 때  -->
                <tr>
                        <td colspan="6">존재하는 게시글이 없습니다.</td>
                </tr> 
        </c:when>
        
        <c:otherwise> <!-- 조회된 게시글 목록이 있을 때  -->
                <c:forEach var="board" items="${bList }">
                <!-- for문으로 반복접근해서 모든 데이터를 출력 해준다. 
                    한 바퀴마다 bList에서 하나씩 꺼내와 board에 담는다 -->
                        <tr>
                                <td>${board.boardNo }</td> <!--글번호 -->
                                <td>${board.categoryName }</td> <!--카테고리명 -->
                                <td class="boardTitle">
                                        ${board.boardTitle }
                                </td> <!--제목 -->
                                <td>${board.memberId }</td> <!--작성자 -->
                                <td>${board.readCount }</td> <!-- 조회수 -->
                                
                                <td>
                                        <%-- 날짜 출력 모양 지정 --%>
                <fmt:formatDate var="createDate" value="${board.boardCreateDate}" pattern="yyyy-MM-dd"/>
                <fmt:formatDate var="today" value="<%= new java.util.Date() %>" pattern="yyyy-MM-dd"/>
                
                <c:choose>
                <%--  작성일이 오늘이 아닐 경우 --%>
                <c:when test="${createDate != today}">
                    ${createDate }
                </c:when>
                
                <%--  작성일이 오늘일 경우 --%>
                <c:otherwise>
                    <fmt:formatDate value="${board.boardCreateDate}" pattern="HH:mm"/>
                                                </c:otherwise>
                                            </c:choose>
                                </td> <!-- 날짜 출력 -->
                        
                        </tr>	 
                </c:forEach>
        </c:otherwise>
    </c:choose>
</tbody>
</table>
</div>



게시판 페이징 처리


페이징처리



boardList.jsp

<%---------------------- Pagination ----------------------%>
<%-- 페이징 처리 주소를 쉽게 사용할  있도록 미리 변수에 저장 --%>
<c:url var="pageUrl" value="/board/list.do"/>

<!-- 화살표에 들어갈 주소를 변수로 생성 -->
<c:set var="firstPage" value="${pageUrl}?cp=1"/>
<c:set var="lastPage" value="${pageUrl}?cp=${pInfo.maxPage}"/>

<%-- EL을 이용한 숫자 연산의 단점 : 연산이 자료형에 영향을 받지 않는다. --%>
<%-- <fmt:parseNumber> : 숫자 형태를 지정하여 변수 선언 
integerOnly="true" : 정수로만 숫자 표현 (소수점 버림)
--%>

    
    <fmt:parseNumber var="c1" value="${(pInfo.currentPage - 1)/10}" integerOnly="true"/>
<fmt:parseNumber var="prev" value="${c1 * 10}" integerOnly="true"/>
<c:set var="prevPage" value="${pageUrl}?cp=${prev}"/> <!-- /board/list/do?cp=10  -->

<fmt:parseNumber var="c2" value="${(pInfo.currentPage + 9)/10}" integerOnly="true"/>
<fmt:parseNumber var="next" value="${c2 * 10 + 1}" integerOnly="true"/>
<c:set var="nextPage" value="${pageUrl}?cp=${next}"/>

            
    <div class="my-5">
<ul class="pagination">

    <%-- 현재 페이지가 10페이지 초과인 경우 --%>
    <c:if test="${pInfo.currentPage>10}">
        <li><!-- 첫 페이지로 이동(<<) -->
            <a class="page-link" href="${firstPage}">&lt;&lt;</a>
        </li>
        
        <li> <!-- 이전 페이지로 이동(<) -->
            <a class="page-link" href="${prevPage}">&lt;</a>
        </li>
    </c:if>

            
            <!-- 페이지 목록 -->
    <c:forEach var="page" begin="${pInfo.startPage}" end="${pInfo.endPage}">
        <c:choose>
            <c:when test="${pInfo.currentPage == page}">
            <li>
                <a class="page-link">${page}</a>
            </li>
            </c:when>
            
            <c:otherwise>
            <li>
                <a class="page-link" href="${pageUrl}?cp=${page}">${page}</a>
            </li>
            </c:otherwise>
        </c:choose>
    </c:forEach>
            
            
            <%-- 현재 페이지가 마지막 페이지 미만인 경우 --%>
    <c:if test="${next < pInfo.maxPage}">
        <li> <!-- 다음 페이지로 이동(>) -->
            <a class="page-link" href="${nextPage}">&gt;</a>
        </li>
        <li><!-- 마지막 페이지로 이동(>>) -->
            <a class="page-link" href="${lastPage}">&gt;&gt;</a>
        </li>
        
    </c:if>

</ul>
</div>




전체 BoardController

package com.kh.wsp.board.controller;

import java.io.IOException;
import java.util.List;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.kh.wsp.board.model.service.BoardService;
import com.kh.wsp.board.model.vo.Board;
import com.kh.wsp.board.model.vo.PageInfo;

@WebServlet("/board/*")
public class BoardController extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		
		// 요청이 들어오는 주소  --> /wsp/board/list.do
		String uri = request.getRequestURI();
		// /wsp
		String contextPath = request.getContextPath();
		String command = uri.substring((contextPath + "/board").length());
		//  /wsp/board/list.do 에서  /wsp/board 를 잘라낸다 --> /list.do 만 남음
		
		String path = null;
		RequestDispatcher view = null;
		
		String swalIcon = null;
		String swalTitle = null;
		String swalText = null;
		
		String errorMsg = null;
		
		try {
			BoardService service = new BoardService();
			
			// 현재 페이지를 얻어옴
			String cp = request.getParameter("cp");
			
			
			
    // 게시글 목록 조회 Controller **********************************************************
        if(command.equals("/list.do")) {
            errorMsg = "게시판 목록 조회 과정에서 오류 발생";
            
            // 1) 페이징 처리를 위한 값 계산 Service 호출
            PageInfo pInfo = service.getPageInfo(cp);
            
//				System.out.println(pInfo);
            
            // 2) 게시글 목록 조회 비즈니스 로직 수행
            List<Board> bList = service.selectBoardList(pInfo);
            // pInfo에 있는 currentPage, limit를 사용해야지만
            // 현재 페이지에 맞는 게시글 목록만  조회할 수 있음.
            
            /*for(Board b : bList) {
                System.out.println(b);
            }*/
            
            // 썸네일 추가 부분
            path = "/WEB-INF/views/board/boardList.jsp";
            
            request.setAttribute("bList", bList);
            request.setAttribute("pInfo", pInfo);
            
            view = request.getRequestDispatcher(path);
            view.forward(request, response);
			}
		}catch(Exception e) {
			e.printStackTrace();
			path = "/WEB-INF/views/common/errorPage.jsp";
			
			// 에러 메세지를 request객체에 담는다
			request.setAttribute("errorMsg", errorMsg);
			view = request.getRequestDispatcher(path);
			view.forward(request, response);
		}
	}
	protected void doPost(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		
		doGet(request, response);
	}
}


전체 boardList

<%@ 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="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>게시판</title>
<style>
.pagination {
	justify-content: center;
}

#searchForm {
	position: relative;
}

#searchForm>* {
	top: 0;
}

.boardTitle>img {
	width: 50px;
	height: 50px;
}

#list-table th {
	text-align: center;
}

#list-table td:not(:nth-of-type(3)) {
	text-align: center;
}

.list-wrapper{
	height: 540px;
}

</style>

</head>
<body>
<jsp:include page="../common/header.jsp"></jsp:include>
<div class="container my-5">

<h1>게시판</h1>

<div class="list-wrapper">
    <table class="table table-hover table-striped my-5" id="list-table">
        <thead>
            <tr>
                <th>글번호</th>
                <th>카테고리</th>
                <th>제목</th>
                <th>작성자</th>
                <th>조회수</th>
                <th>작성일</th>
            </tr>
        </thead>
        
        <%-- 게시글 목록 출력 --%>
<tbody>
<c:choose>
    <c:when test="${empty bList }">
    <!-- bList가 비어있을 때 : 게시글 목록 조회에서 조회되지 않았을 때  -->
            <tr>
                    <td colspan="6">존재하는 게시글이 없습니다.</td>
            </tr> 
    </c:when>
    
    <c:otherwise> <!-- 조회된 게시글 목록이 있을 때  -->
            <c:forEach var="board" items="${bList }">
            <!-- for문으로 반복접근해서 모든 데이터를 출력 해준다. 
                한 바퀴마다 bList에서 하나씩 꺼내와 board에 담는다 -->
                    <tr>
                            <td>${board.boardNo }</td> <!--글번호 -->
                            <td>${board.categoryName }</td> <!--카테고리명 -->
                            <td class="boardTitle">
                                    ${board.boardTitle }
                            </td> <!--제목 -->
                            <td>${board.memberId }</td> <!--작성자 -->
                            <td>${board.readCount }</td> <!-- 조회수 -->
                            
                            <td>
                                    <%-- 날짜 출력 모양 지정 --%>
            <fmt:formatDate var="createDate" value="${board.boardCreateDate}" pattern="yyyy-MM-dd"/>
            <fmt:formatDate var="today" value="<%= new java.util.Date() %>" pattern="yyyy-MM-dd"/>
            
            <c:choose>
            <%--  작성일이 오늘이 아닐 경우 --%>
            <c:when test="${createDate != today}">
                ${createDate }
            </c:when>
            
            <%--  작성일이 오늘일 경우 --%>
            <c:otherwise>
                <fmt:formatDate value="${board.boardCreateDate}" pattern="HH:mm"/>
                                            </c:otherwise>
                                        </c:choose>
                            </td> <!-- 날짜 출력 -->
                    
                    </tr>	 
            </c:forEach>
    </c:otherwise>
</c:choose>
</tbody>
</table>
</div>


<%-- 로그인이 되어있는 경우 --%>
<button type="button" class="btn btn-primary float-right" id="insertBtn" 
                onclick="location.href = 'insertForm.do'">글쓰기</button>


    <%---------------------- Pagination ----------------------%>
<%-- 페이징 처리 주소를 쉽게 사용할  있도록 미리 변수에 저장 --%>
<c:url var="pageUrl" value="/board/list.do"/>

<!-- 화살표에 들어갈 주소를 변수로 생성 -->
<c:set var="firstPage" value="${pageUrl}?cp=1"/>
<c:set var="lastPage" value="${pageUrl}?cp=${pInfo.maxPage}"/>

<%-- EL을 이용한 숫자 연산의 단점 : 연산이 자료형에 영향을 받지 않는다. --%>
<%-- <fmt:parseNumber> : 숫자 형태를 지정하여 변수 선언 
integerOnly="true" : 정수로만 숫자 표현 (소수점 버림)
--%>

    
    <fmt:parseNumber var="c1" value="${(pInfo.currentPage - 1)/10}" integerOnly="true"/>
<fmt:parseNumber var="prev" value="${c1 * 10}" integerOnly="true"/>
<c:set var="prevPage" value="${pageUrl}?cp=${prev}"/> <!-- /board/list/do?cp=10  -->

<fmt:parseNumber var="c2" value="${(pInfo.currentPage + 9)/10}" integerOnly="true"/>
<fmt:parseNumber var="next" value="${c2 * 10 + 1}" integerOnly="true"/>
<c:set var="nextPage" value="${pageUrl}?cp=${next}"/>

            
    <div class="my-5">
<ul class="pagination">

    <%-- 현재 페이지가 10페이지 초과인 경우 --%>
    <c:if test="${pInfo.currentPage>10}">
        <li><!-- 첫 페이지로 이동(<<) -->
            <a class="page-link" href="${firstPage}">&lt;&lt;</a>
        </li>
        
        <li> <!-- 이전 페이지로 이동(<) -->
            <a class="page-link" href="${prevPage}">&lt;</a>
        </li>
    </c:if>

            
            <!-- 페이지 목록 -->
    <c:forEach var="page" begin="${pInfo.startPage}" end="${pInfo.endPage}">
        <c:choose>
            <c:when test="${pInfo.currentPage == page}">
            <li>
                <a class="page-link">${page}</a>
            </li>
            </c:when>
            
            <c:otherwise>
            <li>
                <a class="page-link" href="${pageUrl}?cp=${page}">${page}</a>
            </li>
            </c:otherwise>
        </c:choose>
    </c:forEach>
            
            
            <%-- 현재 페이지가 마지막 페이지 미만인 경우 --%>
    <c:if test="${next < pInfo.maxPage}">
        <li> <!-- 다음 페이지로 이동(>) -->
            <a class="page-link" href="${nextPage}">&gt;</a>
        </li>
        <li><!-- 마지막 페이지로 이동(>>) -->
            <a class="page-link" href="${lastPage}">&gt;&gt;</a>
        </li>
        
    </c:if>

</ul>
</div>



    <!-- 검색창 -->
<div class="my-5">
    <form action="${contextPath }/search.do" method="GET" class="text-center" id="searchForm">
        <select name="sk" class="form-control" style="width: 100px; display: inline-block;">
            <option value="title">글제목</option>
            <option value="content">내용</option>
            <option value="titcont">제목+내용</option>
            <option value="writer">작성자</option>
        </select>
        <input type="text" name="sv" class="form-control" style="width: 25%; display: inline-block;">
        <button class="form-control btn btn-primary" style="width: 100px; display: inline-block;">검색</button>
    </form>


</div>
</div>
<jsp:include page="../common/footer.jsp"></jsp:include>


<script>
// 게시글 상세보기 기능 (jquery를 통해 작업)
</script>
</body>
</html>

댓글남기기