-
#1 JSP Project 07(Blog) - 글쓰기/메인화면목록JSP 2021. 7. 1. 20:53
210630 유투버 '데어프로그래밍'님 강의 참조
saveForm/list.jsp 디자인하기 (글쓰기에 썸머노트 활용!), 필요 코드 넣기--> 글쓰기/메인화면(목록)
- 썸머노트 적용전에 테스트하기
- 헤더에 섬머노트용 코드 추가
<link href="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote.min.css" rel="stylesheet"> <script src="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote.min.js"></script>
- 실제 적용 코드
*saveForm <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ include file="../layout/header.jsp" %> <div class="container"> <form action="/blog/board?cmd=save" method="POST"> <input type = "hidden" name="userId" value="${sessionScope.principal.id}"/> <div class="form-group"> <label for="title">Title:</label> <input type="text" class="form-control" placeholder="title" id="title" name="title"> </div> <div class="form-group"> <label for="content">Content:</label> <textarea id = "summernote" class="form-control" rows="5" id="content" name="content"></textarea> </div> <button type="submit" class="btn btn-primary">Submit</button> </form> </div> <script> $('#summernote').summernote({ placeholder: 'You can write here.', tabsize: 2, height: 400 }); </script> </body> </html>
*sessionScope는 로그인시 내가 세션을 principal로 줬기때문에 거기에 대한 값을 찾는 기능
*list.jsp <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ include file="../layout/header.jsp" %> <div class="container"> <div class="m-2"> <form class="form-inline d-flex justify-content-end" action="/blog/board"> <input type="hidden" name="cmd" value="search" /> <input type="hidden" name="page" value="0" /> <input type="text" name="keyword" class="form-control mr-sm-2" placeholder="Search"> <button class="btn btn-primary m-1">검색</button> </form> </div> <div class="progress col-md-12 m-2"> <div class="progress-bar" style="width: 70%"></div> </div> <div class="card col-md-12 m-2"> <div class="card-body"> <h4 class="card-title">제목</h4> <a href="#" class="btn btn-primary">상세보기</a> </div> </div> <br /> <ul class="pagination justify-content-center"> <li class="page-item disabled"><a class="page-link" href="#">Previous</a></li> <li class="page-item"><a class="page-link" href="#">Next</a></li> </ul> </div> </body> </html>
글쓰기/메인화면 완료하기
-BoardController- BoardSerive - SaveReqDto - BoardDao 코딩
@Data public class SaveReqDto { private int userId; private String title; private String content; }
@WebServlet("/board") public class BoardController extends HttpServlet { ... protected void doProcess(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String cmd = request.getParameter("cmd"); BoardService boardService = new BoardService(); // http://localhost8080/blog/board?cmd=saveForm HttpSession session = request.getSession(); // 글쓰기는 유저만 가능하도록 세션 부여! // 서비스 호출 if (cmd.equals("saveForm")) { User principal = (User) session.getAttribute("principal"); if (principal != null) { response.sendRedirect("board/saveForm.jsp"); } else { response.sendRedirect("user/loginForm.jsp"); } } else if (cmd.equals("save")) { int userId = Integer.parseInt(request.getParameter("userId")); String title = request.getParameter("title"); String content = request.getParameter("content"); SaveReqDto dto = new SaveReqDto(); dto.setUserId(userId); dto.setTitle(title); dto.setContent(content); boardService.글쓰기(dto); } } }
public class BoardService { private BoardDao boardDao; public BoardService() { boardDao = new BoardDao(); } public int 글쓰기(SaveReqDto dto) { return boardDao.save(dto); } }
public class BoardDao { public int save(SaveReqDto dto) { // 회원가입 // Admin은 DB에서 따로 변경하면 쉽다. // 1) 쿼리문 준비 String sql = "INSERT INTO board (userid, title, content, createDate) VALUES(?,?,?,now())"; PreparedStatement pstmt = null; // 2) DB커넥션 연결 Connection conn = DBConn.getConnection(); // try { // 3) pstmt = conn.prepareStatement(sql); pstmt.setInt(1, dto.getUserId()); pstmt.setString(2, dto.getTitle()); pstmt.setString(3, dto.getContent()); int result = pstmt.executeUpdate(); return result; } catch (Exception e) { e.printStackTrace(); } finally { // try-catch 상관없이 무조건 실행. // 코드가 길어지니 DBconn에서 함수로 따로 관리 DBConn.close(conn, pstmt); } return -1; } }
글쓰기 DB처리 완료 글쓰기에 제한 걸기
- 글쓰기는 회원만 가능하도록하고 중요한 두군데를 꼭 막아야한다 1) Controller(세션체크) 2)각각의 페이지(예:saveForm.jsp)를 직접 url요청하면 막기
- 필터를 만들어서 각페이지에 매번 코딩하는것보다 필터가 처리하도록 한다
- web.xml에 필터 추가 (*톰켓이 뻗는 경우가 생기면, 데어프로그래밍님의 깃허브에서 코드 복붙하자!)
모든 jsp페이지에 권한걸기용 - ForbiddenUrlConfig 세팅
public class ForbiddenUrlConfig implements Filter{ @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; if(request.getRequestURI().equals("/blog/") || request.getRequestURI().equals("/blog/index.jsp")) { chain.doFilter(request, response); }else { PrintWriter out = response.getWriter(); out.print("Wrong connection"); out.flush(); } } }
*현재 이렇게만 세팅하면 모든 jsp페이지가 락이 걸린다. (sendRedirect는 무조건 필터를 타기 때문이다)
*해결방법은 RequestDispatcher! -> RequestDispatcher는 톰켓이 res,resp을 재사용하여 내부적으로 redirect 시킴
- index.jsp 수정
<% RequestDispatcher dis = request.getRequestDispatcher(""board?cmd=list""); dis.forward(request, response); // 톰켓이 생성하는 request와 response를 재사용한다. 다시 접근하는게 아니라 내부적으로 움직인다는 뜻. %>
- Controller에 index.jsp 로 리다이렉트 제외하고 모든것을 index.jsp 처럼 수정
url로 쳐서 들어가는것은 다 막혀있다 글목록 보기
- BoardController 세팅
@WebServlet("/board") public class BoardController extends HttpServlet { ... } else if (cmd.equals("list")) { //글목록 들고오기 List<Board> boards = boardService.글목록보기(); //DB에서 받아온 데이터 request.setAttribute("boards", boards); //데이터를 담아서 REQ를 유지한체 REQD로 처리 RequestDispatcher dis = request.getRequestDispatcher("board/list.jsp"); dis.forward(request, response); }
- BoardService 세팅
public class BoardService { .. public List<Board> 글목록보기(){ return boardDao.findAll(); } }
-BoardDao 세팅
public class BoardDao { public List<Board> findAll() { // User의 select문 가져오자 // 1) 쿼리문 준비 String sql = "SELECT * FROM board ORDER BY id DESC"; PreparedStatement pstmt = null; // 2) DB커넥션 연결 Connection conn = DBConn.getConnection(); ResultSet rs = null; List<Board> boards = new ArrayList<>(); try { // 3) pstmt = conn.prepareStatement(sql); rs = pstmt.executeQuery(); while (rs.next()) { //rs,next()는 DB에서 커서를 이동 Board board = Board.builder() .id(rs.getInt("id")) .title(rs.getString("title")) .content(rs.getString("content")) .readCount(rs.getInt("readCount")) .userId(rs.getInt("userId")) .createDate(rs.getTimestamp("createDate")) .build(); boards.add(board); } return boards; ....
- 현재까지세팅으로 들고온 데이터를 list.jsp에 뿌리기
*글목록 페이징 전 중요포인트 세션
- 세션은 클라이언트가 어떤 요청시에 그 요청을 응답하면서 서버에서 만들어서 배부(예:로그인)
- 세션은 클라이언트가 특정 요청시에 배부받았던 세션을 계속해서 들고 있음, 즉 그 세션을 DB에서 매칭을 하면서 이 클라이언트가 어느상태인지를 파악함
- 세션을 통해 STATELESS -> STATEFUL 처럼 운용이 가능함
글목록 페이징하기
- 이전/다음을 누르면 작동하도록 list.jsp에 코드 수정
- 페이징을 받을 수 있도록 BoardController에 "list" 코드 추가
@WebServlet("/board") public class BoardController extends HttpServlet { ... } else if (cmd.equals("list")) {
- 메인화면인 index.jsp에 초기 페이징 코드 수정
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <% RequestDispatcher dis = request.getRequestDispatcher("board?cmd=list&page=0"); dis.forward(request, response); // 톰켓이 생성하는 request와 response를 재사용한다. 다시 접근하는게 아니라 내부적으로 움직인다는 뜻. %>
- list함수를 통해 페이지를 받을 수 있도록 BoardService의 글목록보기() 함수 수정
public class BoardService { ... public List<Board> 글목록보기(int page){ return boardDao.findAll(page); } }
- BoardDao에서 페이징 수를 위한 코드 삽입
public class BoardDao { public int count() { String sql = "SELECT count(*) FROM board"; Connection conn = DBConn.getConnection(); PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = conn.prepareStatement(sql); rs = pstmt.executeQuery(); if(rs.next()) { return rs.getInt(1); } } catch (Exception e) { e.printStackTrace(); } finally { // 무조건 실행 DBConn.close(conn, pstmt, rs); } return -1; }
- list.jsp에 jstl의 param이라는 함수를 통해 페이지 수를 받아와서 그대로 적용
<ul class="pagination justify-content-center"> <c:choose> <c:when test="${param.page == 0}"> <li class="page-item disabled"><a class="page-link" href="#">Previous</a></li> </c:when> <c:otherwise> <li class="page-item"><a class="page-link" href="/blog/board?cmd=list&page=${param.page-1}">Previous</a></li> </c:otherwise> </c:choose> <c:choose> <c:when test="${lastPage == param.page}"> <li class="page-item disabled"><a class="page-link" href="#">Next</a></li> </c:when> <c:otherwise> <li class="page-item"><a class="page-link" href="/blog/board?cmd=list&page=${param.page+1}">Next</a></li> </c:otherwise> </c:choose> </ul>
- BoardController에 페이지가 없으면 버튼이 비활성화 되도록 세팅
} else if (cmd.equals("list")) { //글목록 들고오기 int page = Integer.parseInt(request.getParameter("page")); // 최초 : 0, Next : 1, Next: 2 List<Board> boards = boardService.글목록보기(page); request.setAttribute("boards", boards); // 계산 (전체 데이터수랑 한페이지몇개 - 총 몇페이지 나와야되는 계산) 3page라면 page의 맥스값은 2 // page == 2가 되는 순간 isEnd = true // request.setAttribute("isEnd", true); int boardCount = boardService.글개수(); int lastPage = (boardCount-1)/4; // 2/4 = 0, 3/4 = 0, 4/4 = 1, 9/4 = 2 ( 0page, 1page, 2page) request.setAttribute("lastPage", lastPage); RequestDispatcher dis = request.getRequestDispatcher("board/list.jsp"); dis.forward(request, response); } } }
- 페이지 계산을하는 서비스
public class BoardService { ... public int 글개수() { return boardDao.count(); }
개수에 따른 버튼 활성화/비활성화 작동 - 퍼센트 계산해서 페이징 바 표시 (컨트롤러/list.jsp)
*BoardController double currentPosition = (double) page/(lastPage)*100; request.setAttribute("currentPosition", currentPosition);
**중요포인트! 페이징수 및 퍼센트 수는 반드시 setAttribute로 뿌려줘야한다!!
- <script> 제목에 쓰면 홈페이지 뻗는 현상 처리 -->Board 에 간단 코드 추가
public class Board { ... public String getTitle() { return title.replaceAll("<","<").replaceAll(">", ">"); } }
잘적어진다! 'JSP' 카테고리의 다른 글
#1 JSP Project 09(Blog) - 게시판 댓글 (0) 2021.07.05 #1 JSP Project 08(Blog) - 게시판 - 상세보기/조회수/삭제/수정 (0) 2021.07.04 #1 JSP Project 06(Blog) - 로그인/로그아웃 (0) 2021.06.30 #1 JSP Project 05(Blog) - Ajax(회원가입 계속) (0) 2021.06.30 #1 JSP Project 04(Blog) - 회원가입 (0) 2021.06.27