ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • #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("<","&lt;").replaceAll(">", "&gt;");
    	}
    }

    잘적어진다!

     

     

     

Designed by Tistory.