2021년 01월 05일

업데이트:


프로젝트 구성

로그인 필터

마이페이지나 공지사항 작성 페이지는 일반 회원으로 로그인하거나, 관리자 계정으로 로그인 해야지만 접근할 수가 있다. 필터 처리를 따로 해주지 않을 시 주소창에 마이페이지 주소를 치면 로그인을 하지 않아도 접근할 수 있다.

  • 미 로그인 시 마이페이지 접근
    20210105_01


로그인을 해야만 접근할 수 있는 페이지들을 필터 처리해준다.

LoginFilter.java

@WebFilter(urlPatterns = {"/member/myPage.do", "/member/changePwd.do", "/member.secession.do",
        "/member/updateMember.do", "/member/updatePwd.do", "/member/updateStatus.do"})
 //  urlPatterns : 주소를 여러개 쓰고 싶을 때
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 매개 변수를 HttpServletRequest로 다운 캐스팅
		HttpServletRequest req = (HttpServletRequest)request;
		HttpServletResponse res = (HttpServletResponse)response;
		
		// Session 얻어오기
		HttpSession session = req.getSession();
		
		Member loginMember = (Member)session.getAttribute("loginMember");
		
		if(loginMember == null) {// 로그인이 되어 있지 않은 경우
			
			// 메인 페이지로 강제 이동(redirect)
			res.sendRedirect(req.getContextPath());
			
		} else {
			chain.doFilter(request, response);
			// 이어져 있는 필더(다음 필터) 호출
			// 다음 필터가 없으면 Servlet 또는 JSP로 이동한다.
		}
	}
}



  • 필터 적용 시 부적절한 접근이면 메인 페이지로 돌아오게 된다.
    20210105_02


게시판 연결

  • 헤더 Board 클릭 시 홈페이지 이동
    20210105_03

header.jsp

Board 클릭 시 Board 페이지로 넘어가도록 href로 경로를 잡아준다.

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



Board 테이블 생성

20210105_02


View 만들기

DROP VIEW V_BOARD;
CREATE OR REPLACE VIEW V_BOARD
AS
SELECT BOARD_NO,  BOARD_TITLE, BOARD_CONTENT, MEMBER_ID,
READ_COUNT, BOARD_CREATE_DT, BOARD_MODIFY_DT, CATEGORY_NM, BOARD_STATUS
FROM BOARD
JOIN MEMBER ON(BOARD_WRITER = MEMBER_NO)
JOIN CATEGORY USING(CATEGORY_CD);




BoardController.java

  • 아래 코드 작성 시 헤더 board를 클릭하면 흰 화면으로 이동한다.
    20210105_04


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

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String uri = request.getRequestURI(); // 요청이 들어오는 주소  /wsp/board/list.do
		String contextPath = request.getContextPath(); //  /wsp
		String command = uri.substring( (contextPath + "/board").length()); // /wsp/board의 길이만큼 잘라내기
		
		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 = "게시판 목록 조회 과정에서 오류 발생";
            }
        }catch (Exception e) {
			e.printStackTrace();
			path = "/WEB-INF/views/common/errorPage.jsp";
			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);
	}
}



페이징 처리하기

PageInfo.java

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; // 페이징바 끝 페이지 번호
	
	
	public PageInfo(int currentPage, int listCount) {
		super();
		this.currentPage = currentPage;
		this.listCount = listCount;
		
		// 전달받은 값과 명시적으로 선언된 값을 이용하여
		// makePageInfo() 수행
		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 void makePageInfo() {
		// maxPage : 총 페이지 수 == 마지막 페이지
		// 총 게시글 수 100개, 한 페이지에 보여지는 게시글 수 10개
		// -> 총 페이지 수는 ? 101 / 10 = 10.1(올림처리) -> 11page
		
		maxPage = (int)Math.ceil((double)listCount / limit);
		
		// startPage : 페이징바 시작 번호
		// 페이징바에 페이지를 10개씩 보여줄 경우
		// 1, 11, 21, 31, . . . . 
		// 현재 페이지 11p -> 시작 페이지 11
		// 현재 페이지 15p -> 시작 페이지 11
		// 현재 페이지 20p -> 시작 페이지 11
		startPage = (currentPage -1) / pageSize * pageSize +1;
					// (11 - 1) / 10 * 1- + 1 = 11
					// (15 - 1) / 10 * 1- + 1 = 11
					// (20 - 1) / 10 * 1- + 1 = 11
		
		
		// endPage : 페이징바의 끝 번호
		// 페이징바에 페이지를 10개씩 보여줄 경우
		// 10, 20, 30, 40 . . . . .
		// 현재 페이지 11p -> 끝 페이지 20
		// 현재 페이지 15p -> 끝 페이지 20
		// 현재 페이지 20p -> 끝 페이지 20
		endPage = startPage + pageSize - 1;
		
		// 총 페이지의 수가 end 페이지보다 작을 경우
		if(maxPage <= endPage) {
			endPage = maxPage;
		}
	}
}



게시글 전체 조회

  • 헤더 board 버튼 클릭 시 게시글 페이지로 이동
    20210105_05


BoardController.java

// 현재 페이지를 얻어옴
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);
}



페이징 처리(BoardService.java)

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

// cp가 null일 경우
// 주소창에 보여지는 ?cp=n 부분을 정함
int currentPage = cp == null ? 1 : Integer.parseInt(cp);

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

close(conn);

// 얻어온 현재 페이지와, DB에서 조회한 전체 게시글 수를 이용하여
// PageInfo 객체 생성
return new PageInfo(currentPage, listCount);
}



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;
}



board-query.xml

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


<!-- 지정된 페이지 게시글 목록 조회 -->
<!--
    V_BOARD에서 최신글 중 11번째 부터 20번째 글을 모두 조회
    인라인 뷰 : FROM 절에 작성된 서브쿼리
    ROWNUM에 별칭을 주면 가상 컬럼이 아니라 실제 컬럼이 된다.
    -->
<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 ?

<!-- V.* : V 로 지정된 SELECT 구문 모든 컬럼을 조회 -->
</entry>



페이징 처리 (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;
}



BoardDAO.java

/** 게시글 목록 조회 DAO
    * @param conn
    * @param pInfo
    * @return bList
    * @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;
}



게시글이 없을 때, 시간 처리 (boardList.jsp)

<%-- 게시글 목록 출력 --%>
<tbody>
    <c:choose>
        <c:when test="${empty bList}">
            <tr>
                <td colspan="6">존재하는 게시글이 없습니다.</td>
            </tr>
        </c:when>
        
        <c:otherwise> <%-- 조회된 게시글 목록이 있을  --%>
            <c:forEach var="board" items="${bList}">
                <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>



Pagination(boardList.jsp)

  • 첫 번째 페이지
    20210105_06

  • 페이지 이동 시
    20210105_07


<%-- 로그인이 되어있는 경우 --%>
<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}" />

<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>

댓글남기기