JSP

#1 JSP Project 07(Blog) - 글쓰기/메인화면목록

H-V 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;");
	}
}

잘적어진다!