어제 배웠던 내용들에 이어서 이번에는 웹 화면에서 받은 정보를가지고 Oracle DB에 데이터를 저장하는 실습을 진행하기로 하였다.
어제에 이어서 기능을 구현해 줄 JSP는 위와같이 6가지가 되겠다.
먼저 시퀀스를 생성해주고,
만들었던 시퀀스를 가지고 테이블을 생성해주도록 하자. 사진에서 표시해둔 빨간 세가지가 UI에서 사용자가 직접 입력하게 될 데이터들이라서 표시해두었다.
오늘 Oracle에서는 이정도만 셋팅해주도록 하겠다.
먼저 데이터를 받아들일 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
을 사용해보고자 위와같이 구성해주었다.
// 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
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 */
<%@ 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
로 보내주게 된다.
고로 아까 작업했던 doGet
은 웹페이지를 꾸미는 용도로,
doPost
는 MyBatis를 통해서 Oracle로 데이터를 전송하도록 코드를 구성해주었다. request
를 이용하여 JSP에서 입력받은 값들을 모두 불러온 뒤,
데이터 전송의 성공, 실패 여부에 따라 출력되는 화면이 각각 달라지도록 구성을 해주었다.
현재로써는 selectlist.do
가 없기 때문에 추후에 알맞은 Servlet을 생성해주어야 한다.
직접 한번 데이터를 넣어보겠다.
DB에 데이터가 잘 입력된 모습을 볼 수 있다.
이번에는 게시글들을 조회할 수 있도록 Mapper에 새로운 기능들을 추가하고자 한다.
/*------------------------------------------------------------------------------------------------------*/
@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
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 */
<%@ 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가 적용된 주소로 들어가서 확인해보면..
와 같이 적용이 된 것을 확인할 수 있다.
위에서 우리는 한 페이지당 게시글 수가 10개씩 차도록 페이지를 만들어주었다.
하지만, 번호를 직접 클릭하여 들어갈 수 있는것은 아니기 때문에, 이번에는 직접 번호를 눌러서 들어갈 수 있도록 기능을 추가해보고자 한다.
/* boardselectlist1.jsp */
<body>
<hr />
<c:forEach var="i" begin="1" end="${pages}">
<a href= "selectlist.do?page=${i}">${i}</a>
</c:forEach>
</body>
다음으로는 BoardSelectServlet.java
의 doGet
메소드 수정이다
/* 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 */
<%@ 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}">
를 추가해주었다!
/*------------------------------------------------------------------------------------------------------*/
@Select ( value = {
" SELECT * ",
" FROM board ",
" WHERE ",
" no = #{no} "
} )
public Board selectBoardOne(@Param("no")long no);
/*------------------------------------------------------------------------------------------------------*/
제목을 누르면 해당 글 번호를 입력받아 조회가 가능하도록 구현할 예정이다.
/* 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*/
<%@ 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
값으로 이동할 수 있도록 위와같이 코드를 구성해주었다.