빅데이터 Java 개발자 교육 - 32일차 게시판 만들기 실습 [JSP, JSTL 활용하기]

Jun_Gyu·2023년 3월 15일
0
post-thumbnail

어제 배웠던 내용들에 이어서 이번에는 웹 화면에서 받은 정보를가지고 Oracle DB에 데이터를 저장하는 실습을 진행하기로 하였다.

실습 주제는 "게시판 만들기"다.


어제에 이어서 기능을 구현해 줄 JSP는 위와같이 6가지가 되겠다.


Oracle 셋팅


먼저 시퀀스를 생성해주고,


만들었던 시퀀스를 가지고 테이블을 생성해주도록 하자. 사진에서 표시해둔 빨간 세가지가 UI에서 사용자가 직접 입력하게 될 데이터들이라서 표시해두었다.

오늘 Oracle에서는 이정도만 셋팅해주도록 하겠다.



eclipse 셋팅

dto 만들기

먼저 데이터를 받아들일 dto를 만들도록 하자.

// Board

package dto;

import java.util.Date;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString(exclude = {"regdate"}) // 'regdate'의 정보는 출력되지 않게 하겠다는 뜻.
// 위의 기능을 사용하기 위해서는 지금처럼 어노테이션을 모두 직접 입력해주어야 함.
@NoArgsConstructor
@AllArgsConstructor

public class Board {

	private long no;
	private String title;
	private String content;
	private String writer;
	private long hit;

	private Date regdate;

}

평소라면 @Data를 사용하였겠지만, 오늘은 @ToString 을 사용해보고자 위와같이 구성해주었다.


Mapper생성 (insert)

// BoardMapper
package mapper;

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import dto.Board;

@Mapper
public interface BoardMapper {

	
	@Insert( value ={ 
			"  INSERT INTO board  ",
				"  ( title, content, writer )  ",
				"  VALUES(  #{obj.title}, #{obj.content}, #{obj.writer}  ) "
	} )
	public int insertBoard(@Param("obj") Board brd);
}

그동안 많이 만들었던 Mapper이다. 일단은 데이터 입력기능을 구현하고자 Insert만 구현해놓은 상태이다.


BoardInsertServlet 생성

// BoardInsertServlet	

package controller;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(urlPatterns = { "/board/insertone.do" }) // 원래라면 이렇게 구성해주어야 함!
public class BoardInsertServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public BoardInsertServlet() {
		super();
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		// view(jsp)로 정보를 전달
		request.setAttribute("title", "게시판글쓰기"); // title 항목에 "게시판 글쓰기" 값을 대입.

		// view(jsp)를 표시.
		request.getRequestDispatcher("/WEB-INF/boardinsert1.jsp").forward(request, response);

	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
	}

}

현재는 doGet 메소드부터 구성해주었다.
아직 boardinsert1.jsp 가 만들어지지 않았으니, 화면구성을 해줄 JSP를 만들러 가보도록 하자.



boardinsert1.jsp 생성

/* boardinsert1.jsp */

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri ="http://java.sun.com/jsp/jstl/core" %> // JSTL 추가!
    
<!DOCTYPE html>
<html lang = "ko">
	<head>
		<meta charset="UTF-8">
		<title>${title}</title>
	</head>

	<body>
		<h2>${title}</h2>
		<form action="insertone.do" method="post">
		제목 : <input type="text" name="title" placeholder="제목입력"><br/>
		내용 : <textarea rows="6" name="content" placeholder="내용입력"> </textarea><br/>
		작성자 : <input type="text" name="writer" placeholder="작성자입력"><br/>
		<input type="submit" value="글쓰기"/>
		</form>
	</body>
	
</html>

JSP에는 게시판 작성을 위해 사용자가 입력 할 title,content,writer의 입력칸을 생성해주었고, 쓴 글을 등록할 수 있게 등록 버튼을 구성해주었다.


결과는 위처럼 나오게 된다. 이번에는 위의 UI와, 미리 만들어두었던 Mapper를 이용하여 Oracle DB로 데이터를 전송해보도록 하겠다.

BoardInsertServlet으로 다시 돌아가보자.

/* BoardInsertServlet.java */

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 사용자가 입력한 항목 3개를 받아서 
		// dB에 추가 및 적잘한 페이지로 이동시켜야 함. (절대로 post로 보내면 안됨. get으로만 보내야 한다!)
        
        BoardMapper mapper = MyBatisContext.getSqlSession().getMapper(BoardMapper.class);
        
		String title = request.getParameter("title");
		String content = request.getParameter("content");
		String writer = request.getParameter("writer");

		Board brd = new Board();
		brd.setTitle(title);
		brd.setWriter(content);
		brd.setContent(writer);
		
		// Mapper로 정보를 전송하여 DB로 보냄.
		int ret = mapper.insertBoard(brd);
		if(ret == 1) { // 성공했을 때 => 게시판 목록 이동
			// 주소창을 selectlist.do로 변경시키고, 엔터키를 누름. GET
			response.sendRedirect("selectlist.do");
		}
		else { // 실패했을때 => 다시 글쓰기 화면으로 이동
			// 주소창을 insertone.do로 변경시키고 엔터키를 자동화 GET
			response.sendRedirect("insertlist.do");
		}
	}

}

doGet에서는 대부분의 데이터를 처리하게 되며, doGet에서 처리하지 못하는 기능들을 doPost로 보내주게 된다.

ex)
doGet : 회원가입 데이터 입력 및 전송
doPost : "이미 존재하는 ID입니다", "사용가능한 ID입니다" 등등..


고로 아까 작업했던 doGet은 웹페이지를 꾸미는 용도로,

doPost는 MyBatis를 통해서 Oracle로 데이터를 전송하도록 코드를 구성해주었다. request를 이용하여 JSP에서 입력받은 값들을 모두 불러온 뒤,

데이터 전송의 성공, 실패 여부에 따라 출력되는 화면이 각각 달라지도록 구성을 해주었다.

현재로써는 selectlist.do가 없기 때문에 추후에 알맞은 Servlet을 생성해주어야 한다.



직접 한번 데이터를 넣어보겠다.

DB에 데이터가 잘 입력된 모습을 볼 수 있다.

이번에는 게시글들을 조회할 수 있도록 Mapper에 새로운 기능들을 추가하고자 한다.

게시글 조회하기

Mapper기능 추가 (select)

/*------------------------------------------------------------------------------------------------------*/
	
	@Select( value = { // 10개씩 게시글 조회
			"  SELECT b.* FROM  ",
					"  ( SELECT b.*, ROW_NUMBER() OVER( ORDER BY no DESC ) rown FROM BOARD b ) b  ",
			"   WHERE   ",
					"  rown >= #{start} AND rown <= #{end} ",
			"  ORDER BY no DESC  ",
	} )
	public List<Board> selectBoardList(@Param("start") int start, @Param("end") int end );

/*------------------------------------------------------------------------------------------------------*/

	@Select( { // 10개씩 페이지 갯수 생성
		"  SELECT  ",
		"  COUNT(*)  ",
		"  FROM board  "
	} )
	public long countBoardList();
    
/*------------------------------------------------------------------------------------------------------*/

기능은 10개단위로 게시글 데이터를 불러오고, 페이지 번호를 나눌 수 있도록 쿼리문을 작성했다.

그렇다면 이번에는 selectlist.do의 주소값을 구현하기 위해서 한번 Servlet을 구성해보도록 하겠다.

BoardSelectServlet 생성

// BoardSelectServlet

package controller;

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

import config.MyBatisContext;
import dto.Board;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import mapper.BoardMapper;

@WebServlet(urlPatterns = { "/board/selectlist.do" })
public class BoardSelectServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public BoardSelectServlet() {
		super();
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		BoardMapper mapper = MyBatisContext.getSqlSession().getMapper(BoardMapper.class);

		// 1. mapper를 통해서 결과값 가져오기
		List<Board> list = mapper.selectBoardList(1, 10); 
		long total = mapper.countBoardList();
		// 36 => 4
		// 30 => 3	

		// 2. view(jsp)로 전달할 값
		request.setAttribute("pages", ( (total - 1) / 10 )+ 1); // 페이지 수
		request.setAttribute("list", list); // 게시글 목록 

		// 3. view로 표시할 jsp
		request.getRequestDispatcher("/WEB-INF/boardselectlist1.jsp").forward(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

	}

}

URL의 값은 selectlist.do로, view를 구성해 줄 JSP의 이름은 boardselectlist1.jsp로 결정하였다.

아직 JSP를 만든 상태가 아니기 대문에 지금 한번 만들러 가보도록 하자.

boardselectlist1.jsp 생성

/* boardselectlist1.jsp */

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri ="http://java.sun.com/jsp/jstl/core" %>

<!DOCTYPE html>
<html lang = "ko">
	<head>
		<meta charset="UTF-8">
		<title>Insert title here</title>
	</head>
	
	<body>
	<a href="insertone.do">글쓰기로 이동</a>
		<br />
		<c:forEach var="obj" items="${list}"> 
			<span style="color:red">${obj.no}</span> | 
			<span style="color:orange">${obj.title}</span> | 
			<span style="color:darkyellow">${obj.writer}</span> | 
			<span style="color:green">${obj.hit}</span> | 
			<span style="color:blue">${obj.regdate}</span>|
			<br />
              </c:forEach>
		<hr />
		<c:forEach var="i" begin="1" end="${pages}">
			${i}
		</c:forEach>
		<hr />
		
	</body>
</html>

이번에는 JSTL을 추가한 뒤 <c:forEach>Core 태그를 사용해 배열과 반복문을 함께 구성해주었다.

BoardSelectServlet.java에서 List<Board>형태로 받아온 데이터들을 차례대로 반복해주고자, 위와 같은 방식으로 코드를 구성해주었다.

위의 JSP가 적용된 주소로 들어가서 확인해보면..

와 같이 적용이 된 것을 확인할 수 있다.



Pagenation 기능 추가

위에서 우리는 한 페이지당 게시글 수가 10개씩 차도록 페이지를 만들어주었다.

하지만, 번호를 직접 클릭하여 들어갈 수 있는것은 아니기 때문에, 이번에는 직접 번호를 눌러서 들어갈 수 있도록 기능을 추가해보고자 한다.

boardselectlist1.jsp 코드 추가

/* boardselectlist1.jsp */

	<body>
		<hr />
		<c:forEach var="i" begin="1" end="${pages}">
			<a href= "selectlist.do?page=${i}">${i}</a>
		</c:forEach>
	</body>

다음으로는 BoardSelectServlet.javadoGet 메소드 수정이다

BoardSelectServlet.java 코드 수정

/* BoardSelectServlet.java */

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		BoardMapper mapper = MyBatisContext.getSqlSession().getMapper(BoardMapper.class);
/*----------------------------------------------------------------------------------------------*/
		int page = 1;
		if(request.getParameter("page") != null) {
			// get에는 ?page=1 일경우 1의 값을 읽는방법
			page = Integer.parseInt(request.getParameter("page"));
		}

		// 1. mapper를 통해서 결과값 가져오기 (pagenation 기능)
		List<Board> list = mapper.selectBoardList((10 * page) - 9, 10 * page);
		long total = mapper.countBoardList();

		// 2. view(jsp)로 전달할 값
		request.setAttribute("pages", ((total - 1) / 10) + 1); // 페이지 수
		request.setAttribute("list", list); // 게시글 목록
/*----------------------------------------------------------------------------------------------*/
		// 3. view로 표시할 jsp
		request.getRequestDispatcher("/WEB-INF/boardselectlist1.jsp").forward(request, response);
	}
}

코드 수정은 주석처리가 된 사이 부분에서 진행되었다.
간단하게 설명하자면, 맨 처음 페이지의 기본값을 1로 설정해주었으며, 입력되는 page값에 따라서 각각의 페이지마다 서로 다른 10개의 데이터를 표시하도록 해주었다.



다음은 boardselectlist1.jsp에서 추가된 코드다.

boardselectlist1.jsp 코드추가

/* boardselectlist1.jsp */

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri ="http://java.sun.com/jsp/jstl/core" %>

<!DOCTYPE html>
<html lang = "ko">
	<head>
		<meta charset="UTF-8">
		<title>Insert title here</title>
	</head>
	
	<body>
	<a href="insertone.do">글쓰기로 이동</a>
		<br />
		
		<c:forEach var="obj" items="${list}"> 
			<span style="color:red">${obj.no}</span> | 
			<span style="color:orange">${obj.title}</span> | 
			<span style="color:darkyellow">${obj.writer}</span> | 
			<span style="color:green">${obj.hit}</span> | 
			<span style="color:blue">${obj.regdate}</span>|
			<br />
		</c:forEach>
		<hr />
		<c:forEach var="i" begin="1" end="${pages}">
			<a href= "selectlist.do?page=${i}">${i}</a>
		</c:forEach>
	</body>
</html>

결과를 실행하면 아래와 같이 표시된다.
아래의 1부터 12페이지까지 눌러 10개씩 List를 조회 할 수 있다.



그렇다면 이번에는 글 제목을 클릭해서 해당하는 글의 상세한 정보를 조회할 수 있도록 해보겠다.

글 제목을 클릭해야 하니 방금 구성해준 boardselectlist1.jsp의 글 제목에 코드를 추가하고 가겠다.

/* boardselectlist1.jsp */
<c:forEach var="obj" items="${list}"> 
			<span style="color:red">${obj.no}</span> | 
			<span style="color:orange"><a href="selectone.do?no=${obj.no}">${obj.title}</a></span> | 
			<span style="color:darkyellow">${obj.writer}</span> | 
			<span style="color:green">${obj.hit}</span> | 
			<span style="color:blue">${obj.regdate}</span>|
			<br />
		</c:forEach>

<a href="selectone.do?no=${obj.no}">를 추가해주었다!



글 한개 조회하기

Mapper기능 추가 (select)

/*------------------------------------------------------------------------------------------------------*/
	
	@Select ( value = {
			"  SELECT  * ",
			"  FROM board  ",
			"  WHERE  ",
					"  no = #{no}  "
	} )
	public Board selectBoardOne(@Param("no")long no);
	
/*------------------------------------------------------------------------------------------------------*/

제목을 누르면 해당 글 번호를 입력받아 조회가 가능하도록 구현할 예정이다.

BoardSelectOneServlet 생성

/* BoardSelectOneServlet */

package controller;

import java.io.IOException;

import config.MyBatisContext;
import dto.Board;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import mapper.BoardMapper;

@WebServlet(urlPatterns = { "/board/selectone.do" })
public class BoardSelectOneServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public BoardSelectOneServlet() {
		super();
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		BoardMapper mapper = MyBatisContext.getSqlSession().getMapper(BoardMapper.class);

		long no = Long.parseLong(request.getParameter("no"));
		
		// 1. mapper를 이용하여 게시글 1개 가져오기
		Board board = mapper.selectBoardOne(no);
		
		// 2. view로 전송
		request.setAttribute("brd", board);
		
		// 3. view 표시
		request.getRequestDispatcher("/WEB-INF/boardselectone1.jsp").forward(request, response);

	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
	}

}

Board 타입으로 전달받은 내용을 boardselectone1.jsp 에서 전체적으로 표시하고자 한다.



boardselectone1.jsp 생성

/*boardselectone1.jsp*/

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>Insert title here</title>
	</head>
	
	<body>
		<h3>게시글 조회</h3>
		<br />
		글 번호 : ${brd.no} <br />
		글 제목 : ${brd.title} <br /> 
		글 내용 : ${brd.content} <br /> 
		글쓴이  : ${brd.writer} <br /> 
		조회수  : ${brd.hit} <br />
		등록일자 : ${brd.regdate} <br />
		
		<br />
			<a href="selectlist.do"><input type="button" value="목록"></a>
			<input type="button" value="수정" />
			<input type="button" value="삭제" />
			<input type="button" value="이전글" />
			<input type="button" value="다음글" />
	</body>
</html>

한번 실행시켜보도록 하자.


처음에는 /selectlist.do화면으로 시작하여
제목을 누르게 되면 해당 게시글의 넘버값을 불러와 새로운 주소/selectone.do?no=OOO를 불러오게 되고,

위와 같이 게시글을 조회할 수 있게된다.

그리고 목록을 누르게 되면,


다시 /selectlist.do를 불러온다.

삭제 & 이전, 다음글 버튼 활성화하기

위의 배운내용들 토대로 한번 실습을 진행해보도록 하자.

먼저 삭제기능부터 해보도록 하겠다.

삭제

/*------------------------------------------------------------------------------------------------------*/

	@Delete ( value = {
			"  Delete board  ",
			"  WHERE no =#{no}  "
	} )
	public int deleteBoardOne(@Param("no")long no);
	
/*------------------------------------------------------------------------------------------------------*/

먼저 Mapper에 쿼리문을 추가한 뒤,



/* BoardDeleteOneServlet */

package controller;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import mapper.BoardMapper;

import java.io.IOException;

import config.MyBatisContext;

@WebServlet(urlPatterns = { "/board/deleteone.do" })
public class BoardDeleteOneServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    public BoardDeleteOneServlet() {
        super();
       
    }
    
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		BoardMapper mapper = MyBatisContext.getSqlSession().getMapper(BoardMapper.class);

		long ln = Long.parseLong(request.getParameter("no"));
		int ret = mapper.deleteBoardOne(ln);		
		
		if(ret == 1) { // 성공했을 때 => 게시판 목록 이동
			// 주소창을 selectlist.do로 변경시키고, 엔터키를 누름. GET
			response.sendRedirect("selectlist.do");
		}
		else { // 실패했을때 => 다시 글쓰기 화면으로 이동
			// 주소창을 insertone.do로 변경시키고 엔터키를 자동화 GET
			response.sendRedirect("insertlist.do?no=${no}");
		}
	}

}

삭제 기능을 수행하기 위해서 BoardDeleteOneServlet를 생성하여 위와 같이 구성해주었다.
값을 반환하는것이 아니라 단순하게 데이터를 지우는것이기 때문에, JSP로 반환할 필요는 없겠다.

그리고 삭제 버튼을 만들어둔 boardselectone1.jsp에는 삭제 버튼 코드를 다음과 같이 수정하였다.

<form action="deleteone.do" method="post" style="display:inline-block;">
				<input type="hidden" name="no" value="${brd.no}" />
				<input type="submit" value="삭제" />
			</form>

삭제 행위를 위한 주소를 BoardDeleteOneServlet의 url인 deleteone.do로 지정하였고, 삭제하고자하는 게시글의 번호를 숨겨 UI에는 표시되지 않도록 하였다.

이러한 방법으로 삭제 버튼의 기능을 구현하였다.



이전 & 다음 게시글

이번의 경우에는 url 주소값 selectone.do?no= 뒤에 게시글의 번호만 전달하면 되는 형태이기 때문에, 따로 Servlet을 생성하지 않고 기존에 사용하고 있던 BoardSelectOneServlet에서 기능을 추가하는 방법을 사용하였다.

먼저 기능 구현을 위한 Mapper의 쿼리문이다.

/*------------------------------------------------------------------------------------------------------*/

	@Select( value = {
			"  SELECT NVL( MAX(no),0 )  ",
			"  FROM board  ",
			"  WHERE  ",
				"  no < #{no}  "
			
	} )
	public long selectPrevBoardOne(@Param("no")long no);
	
/*------------------------------------------------------------------------------------------------------*/

	@Select( value = {
			"  SELECT NVL( MIN(no),0 )  ",
			"  FROM board  ",
			"  WHERE  ",
				"  no > #{no}  "
			
	} )
	public long selectNextBoardOne(@Param("no")long no);
	
/*------------------------------------------------------------------------------------------------------*/

조건문에 전달받은 게시글의 번호값에서 바로 옆에 있는 게시글의 번호를 가져올 수 있도록 쿼리문을 구성하였다. 또한 게시글의 시퀀스값만 나타내기 때문에 반환타입을 long으로 지정해주었다.

다음으로는 BoardSelectOneServlet이다.



protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		BoardMapper mapper = MyBatisContext.getSqlSession().getMapper(BoardMapper.class);

		long no = Long.parseLong(request.getParameter("no"));

		/* 게시글 하나 조회하기 */

		// 1. mapper를 이용하여 게시글 1개 가져오기
		Board board = mapper.selectBoardOne(no);
		// 2. view로 전송
		request.setAttribute("brd", board);

		// ------------------------- 아래는 추가한 부분

		/* 이전, 다음글 조회하기 */

		// 1. 이전, 다음글
		long prevNo = mapper.selectPrevBoardOne(no);
		long nextNo = mapper.selectNextBoardOne(no);
		// 2. no값 전송
		request.setAttribute("prevNo", prevNo);
		request.setAttribute("nextNo", nextNo);
        
		// ------------------------------------------
        
		// 3. view 표시
		request.getRequestDispatcher("/WEB-INF/boardselectone1.jsp").forward(request, response);

	}

위에서 언급한 바와 같이 기존의 Servlet에서 쿼리문 기능만 들고와서 추가하였다.
이전, 다음 게시글의 no값을 전달하고자 위와같이 코드를 구성하였다.



/*boardselectone1.jsp*/
		<a href="selectone.do?no=${prevNo}"><input type="button" value="이전글"></a>
		<a href="selectone.do?no=${nextNo}"><input type="button" value="다음글"></a>

마지막으로 jsp에 생성해두었던 버튼에 동작시 해당하는 게시글no값으로 이동할 수 있도록 위와같이 코드를 구성해주었다.


profile
시작은 미약하지만, 그 끝은 창대하리라

0개의 댓글