본문 바로가기
[ View ]/JSP

[ JSP ] Mybatis 응용 예제(한 줄 메모장)

by 환이s 2023. 3. 17.
728x90

이전 포스팅에서 Mybatis 개념 및 설정 방법에 대해서 알아봤습니다.

오늘은 Mybatis를 응용해서 한 줄 메모장을 만들어서  메모 목록, 메모 보기, 수정, 삭제 기능을 넣어보겠습니다. 

 

 

■  한 줄 메모장

 

한 줄 메모장 구현은 MVC 패턴으로 진행됩니다.

 

MVC 패턴에 대해서 궁금하신 분들은 아래 포스팅을 참고해 보세요!

 

 model 종류 및 내장 객체 응용

 

[ JSP ] model 종류 및 내장 객체 응용

이전 포스팅에서 내장 객체의 종류 및 각 메서드에 대해서 알아봤습니다. 오늘은 model의 종류와 내장 객체를 응용해서 활용성을 알아보겠습니다. ■ JSP 개발 방식 JSP의 개발 방식은 두 가지 있습

drg2524.tistory.com

 

각 기능의 역할은 다음과 같습니다.

Contoller

MemoController.java

Model

MemoDTO.java
MemoDAO.java

View

memo.jsp : ajax 요청 페이지, 메모입력
memo_list.jsp : 메모목록
memo_view.jsp : 메모 보기, 수정, 삭제 기능

 

그럼 먼저 데이터를 담아두기 위한  MEMO Table을 만들어봅시다.


■  SQL

 

<SQL>

create table memo(
idx number not null primary key,
writer varchar2(50) not null,
memo varchar2(300) not null,
post_date date default sysdate
);

 

테이블 생성 후 insert문으로 간단한 데이터를 넣어줍니다.

 

<insert>

insert into memo (idx, writer, memo) values(1,'kim','첫번째 메모');
insert into memo (idx, writer, memo) values(2,'김철수','두번째 메모');
insert into memo(idx, writer, memo)
values ((select nvl(max(idx)+1,1) from memo),'lee','세번째 메모');

세 번째 데이터는 idx 값을 직접 넣어주지 않고 nvl 함수를 활용해서 max(idx)+1 값을 넣어주었습니다. 

그럼 만약에 칼럼값이 null이라면 치환 값인 1이 나와야겠죠?

 

SQL 함수를 공부하고 계신 분들이라면 아래 포스팅을 참고하시면 도움이 되실 거예요!

 

 SQL 함수 정리

 

[ SQL ] SQL 함수 정리

오늘은 SQL을 활용하기 전 자주 사용하는 함수들을 정리하는 글을 써보려 합니다. 어떤 일을 수행하는 기능으로써 주어진 인수를 입력받아 처리하여 그 결과를 반환하는 일을 수행하려면 함수를

drg2524.tistory.com

 

 

Table 생성을 하고 데이터를 추가했습니다. 그럼 이제 View단으로 넘어가서  ajax 요청 페이지 및 메모 입력 페이지, DTO 페이지를 만들어 봅시다.


■  MemoDTO.java

 

DTO에서는 getter/setter , 생성자, toString 정도만 생성해 줍니다.

package memo.dto;

public class MemoDTO {

private int idx;

private String writer;

private String memo;

private String post_date;

//getter,setter, 생성자, toString

public int getIdx() {

return idx;

}

public void setIdx(int idx) {

this.idx = idx;

}

public String getWriter() {

return writer;

}

public void setWriter(String writer) {

this.writer = writer;

}

public String getMemo() {

return memo;

}

public void setMemo(String memo) {

this.memo = memo;

}

public String getPost_date() {

return post_date;

}

public void setPost_date(String post_date) {

this.post_date = post_date;

}

public MemoDTO() {

}

public MemoDTO(int idx, String writer, String memo, String post_date) {

this.idx = idx;

this.writer = writer;

this.memo = memo;

this.post_date = post_date;

}

@Override

public String toString() {

return "MemoDTO [idx=" + idx + ", writer=" + writer + ", memo=" + memo + ", post_date=" + post_date + "]";

}

}

 


■  memo.jsp

 

한 줄 메모장에서는 이름과 메모를 작성하고 확인 버튼을 클릭 시 저장하는 코드를 구현합니다.

그러면 <input> 태그와 <input> 태그 타입을 button 타입으로 설정해서 값을 보냅니다.

이 작업에서 요청을 보내는 과정을 자바 스크립트에서 구현합니다.

 

이름 : <input id="writer" size="10"> <br>

메모 : <input id="memo" size="40">

<input type="button" id="btnSave" value="확인">

 

결과 테이블을 표출하기 위해 id 값을 설정합니다.

<div id="result"></div>

 

값을 전송하기 위해 자바 스크립트 코드를  ajax 방식으로 구현합니다.

여기서 사용되는 이벤트는 click()입니다.

 

<script type="text/javascript">

$(function() {

list();

$('#btnSave').click(function() {

insert();

});

 

그럼 이제 list()를 생성해서 ajax 방식으로 Controller에 전달할 수 있게 코드를 만듭니다.

 

function list() {

//검색옵션과 검색할 키워드를 전달

var param="searchkey="+$("#searchkey").val()+"&search="+$("#search").val();

$.ajax({

type: "post",

url: "${path}/memo_servlet/list.do",

data:param,

success: function(result) {

$("#result").html(result);

}

});

}

 

url에서 전송 방식은 memo_servlet /list.do로 지정했습니다.

 

여기서 list.do

페이지를 별도로 생성하는 게 아니라 값을 전달하고 받을 수 있는 연결 다리

생각하시면 좋을 거 같습니다. 

 

여기까지만 작업하면 너무 간단하는 생각에 기능을 좀 더 추가해서 검색 옵션을 추가해 봅시다.

 

<select id="searchkey">

<option value="writer">이름</option>

<option value="memo">메모</option>

<option value="writer_memo">이름+메모</option>

</select>

<input id="search" value="${search}">

<input type="button" id="btnSearch" value="조회">

 

id ="search"의 value 값을 EL 식을 추가했습니다.

그 이유는 검색 옵션과 검색할 키워드를 전달하기 위해서입니다.

 

//검색옵션과 검색할 키워드를 전달

var param="searchkey="+$("#searchkey").val()+"&search="+$("#search").val();

검색 옵션에서는 이 한 줄이 정말 큰 역할을 해줍니다.

 

다음으로 들어오는 데이터를 보내주는 코드를 구현합니다.

 

function insert() {

var writer =$("#writer").val();

var memo =$("#memo").val();

var param ="writer="+writer+"&memo"+memo;

$.ajax({

type:"post",

url:"${path}/memo_servlet/insert.do",

data:param,

success: function() { //call back 함수

list();

$("#writer").val("");

$("#memo").val("");

}

});

}

 

여기까지 memo.jsp 페이지 작업을 끝냈습니다. 

 

<memo.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>

<script src="../include/jquery-3.6.3.min.js"></script>

<%@ include file="../include/header.jsp" %>

<script type="text/javascript">

$(function() {

list();

$('#btnSave').click(function() {

insert();

});

//검색버튼 클릭

$("#btnSearch").click(function() {

list();

 

});

});

function list() {

//검색옵션과 검색할 키워드를 전달

var param="searchkey="+$("#searchkey").val()+"&search="+$("#search").val();

$.ajax({

type: "post",

url: "${path}/memo_servlet/list.do",

data:param,

success: function(result) {

$("#result").html(result);

}

});

}

function insert() {

var writer =$("#writer").val();

var memo =$("#memo").val();

var param ="writer="+writer+"&memo"+memo;

$.ajax({

type:"post",

url:"${path}/memo_servlet/insert.do",

data:param,

success: function() { //call back 함수

list();

$("#writer").val("");

$("#memo").val("");

}

});

}

</script>

</head>

<body>

<h2>한줄메모장</h2>

이름 : <input id="writer" size="10"> <br>

메모 : <input id="memo" size="40">

<input type="button" id="btnSave" value="확인">

<br>

<select id="searchkey">

<option value="writer">이름</option>

<option value="memo">메모</option>

<option value="writer_memo">이름+메모</option>

</select>

<input id="search" value="${search}">

<input type="button" id="btnSearch" value="조회">

<div id="result"></div>

</body>

</html>

 

다음으로 Controller를 만들어 봅시다.

Servlet -> doGet에서 작업합니다.


■  MemoController.java

 

memo.jsp 에서 전송방식을 list.do , insert.do 값을 넣어주었습니다.

사람마다 코드 구현은 다르지만 저는 이 값을 if문으로 처리합니다. 

 

<MemoController.java>

@WebServlet("/memo_servlet/*") //공통 uri

public class MemoController extends HttpServlet {

private static final long serialVersionUID = 1L;

protected void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

//사용자가 요청한 주소

String uri=request.getRequestURI();

MemoDAO dao=new MemoDAO();

if(uri.indexOf("list.do") != -1) { //세부 uri

//검색옵션 + 검색키워드

String searchkey = request.getParameter("searchkey");

String search= request.getParameter("search");

 

List<MemoDTO> list=dao.listMemo(searchkey,search);//메모 목록 리턴

//request 영역에 저장

request.setAttribute("list", list);

//포워딩

String page="/memo/memo_list.jsp";

RequestDispatcher rd=request.getRequestDispatcher(page);

rd.forward(request, response);

}else if(uri.indexOf("insert.do") != -1) {

String writer = request.getParameter("writer");

String memo = request.getParameter("memo");

MemoDTO dto = new MemoDTO();

dto.setWriter(writer);

dto.setMemo(memo);

 

//DAO에 레코드 저장요청

dao.insertMemo(dto);

 

Controller에서는 실질적인 코드 작업이 들어갑니다.

 

그래서 어떻게 데이터를 처리할 건지 먼저 정하고 구현하시는 게 좋습니다.

 

if문을 보시면 -1아니면 처리할 수 있게 했습니다. 

 

indexOf()는 찾을 내용을 인덱스 처리해서 반환해 줍니다. 만약 내용이 없다면 -1을 반환해 줍니다.

그럼 반대로 내용이 있다면 0을 반환해 주겠죠

 

해석해 보면 "찾을 내용"이 -1이 아니면? 코드 실행할 수 있게 구현했습니다.

 

다음으로 DAO를 생성합니다.


■  MemoDAO.java

 

DAO에서는 데이터를 담아주기 위해 List <>(), Map <>()을 사용하는데,

여기서 주의할 점은 ArratList <>()는 에러가 발생합니다.

 

그 이유는 Mybatis시스템상 타입을 고정시켜 놨기 때문입니다.

 

Mybatis에서 파라미터(입력매개변수)는 1개만 전달할 수 있습니다.

 

그럼 Mybatis를 사용하기 위해 먼저 

SqlSession session=MybatisManager.getInstance().openSession();

위 코드를 꼭 구현하셔야 합니다.

 

그럼 나머지 코드들도 알아봅시다.

public class MemoDAO {

//여기서는 List대신 ArrayList를 쓰면 에러가 난다. (mybatis 시스템상 타입을 고정시켜 놨다.)

public List<MemoDTO> listMemo(String searchkey, String search){

SqlSession session=MybatisManager.getInstance().openSession();

List<MemoDTO> list=null;

try {

if(searchkey.equals("writer_memo")) { //이름 + 메모 검색

list=session.selectList("memo.listAll",search); //search는 검색키워드

}else {

Map<String,String> map = new HashMap<>();

map.put("searchkey", searchkey);

map.put("search", search);

//mybatis에서 파라미터(입력매개변수)는 1개만 전달할 수 있음

list=session.selectList("memo.list",map);

}

// insert 때 보다 select때 처리가 더 좋다.

for(MemoDTO dto : list) {

String memo = dto.getMemo();

memo=memo.replace(" ", "&nbsp;&nbsp;"); //공백문자처리(스페이스 2개 변환)

memo=memo.replace("<", "&lt"); // less Than ~보다 작다

memo=memo.replace(">", "&gt"); // Greater Than ~보다 크다

//키워드 색상 처리

if(searchkey.equals("memo")) {

if(memo.indexOf(search) != -1) {

memo=memo.replace(search, "<font color='red'>"+ search+"</font>");

}

}

dto.setMemo(memo);

}

 

 

} catch (Exception e) {

e.printStackTrace();

} finally {

if(session != null) session.close();//mybatis 객체 닫기

}

return list;

}

 

위 코드에서 session 객체에서 제공해 주는 selectList() 메서드를 통해서 mapper 파일에 요청을 했습니다. 

 

list=session.selectList("memo.listAll",search); //search는 검색키워드

 

"memo.listAll"에서 memo mapper에서 지정한 namespace입니다.

listAllselect문으로 보내는 id 값입니다.

 

그럼 바로 mapper 파일에서 작업을 해도 되지만, 

Controller에서 insert.do 작업도 했기 때문에 DAO에 레코드 저장 요청을 보냈던,

insertMemo() 메서드도  구현을 해야 합니다.

 

public void insertMemo(MemoDTO dto) {

//mybatis 실행 객체 생성

SqlSession session=MybatisManager.getInstance().openSession();

 

session.insert("memo.insert", dto); //레코드 추가, Mybatis에서는 파라미터를 1개밖에 허용 안 한다

session.commit(); // Mybatis는 수동커밋, 자동커밋을 막았다.

 

}

※Mybatis는 자동 커밋이 안되기 때문에 수동 커밋 처리를 해주셔야 합니다.

 

Mybatis에 대해서 아직 생소하신 분들은 이전 포스팅을 참고해 보세요!

 

 Mybatis 개념 및 설정

 

[ JSP ] Mybatis 개념 및 설정

오늘은 SQL을 좀 더 쉽게 접근하게 해 주고 코드도 간결하게 만들어주는 Mybatis에 대해서 포스팅해 보겠습니다. ■ Mybatis란? Mybatis는 개발자가 지정한 SQL, 저장 프로시저를 지원하는 프레임워크(Jav

drg2524.tistory.com

 


■  Mybatis

 

다음으로 mapper 파일에서 <select> , <insert> 작업을 합니다.

이전 포스팅에서 알아본 것처럼 mapper 파일은 SQL문을 작성하는 파일입니다.

 

 <select>

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="memo">

<!-- select에서 resultType="" 반드시 필요하다. -->

<select id="listAll" resultType="memo.dto.MemoDTO">

select idx,writer,memo,to_char(post_date, 'yyyy-mm-dd hh24:mi:ss') post_date

from memo

where writer like '%'||#{search}||'%' or memo like '%'||#{search}||'%'

order by idx desc

</select>

 

<select id="list" resultType="memo.dto.MemoDTO">

select idx,writer,memo,to_char(post_date, 'yyyy-mm-dd hh24:mi:ss') post_date

from memo

where ${searchkey} like '%'||#{search}||'%'

order by idx desc

</select>

 

<insert>

<!-- parameterType=""은 생략 가능하다. -->

<!-- #{변수}: 따옴표 포함 ex) #{writer}=> writer='kim', ${변수} : 따옴표 미포함 -->

<insert id="insert" parameterType="memo.dto.MemoDTO">

insert into memo(idx, writer, memo)

values ((select nvl(max(idx)+1,1)from memo), #{writer}, #{memo})

</insert>

 

mapper 파일 처리까지 완료되면 Controller에서 포워딩 처리 했던 memo_list.jsp 페이지를 생성합니다.

 

즉, 결과를 표출하는 View 단 페이지를 생성합니다.

 


■  memo_list.jsp

 

View 단 페이지에서는 코드량을 줄이기 위해 EL 기법, JSTL을 활용해서 코드를 구현했습니다.

 

<%@ 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>

<script src="../include/jquery-3.6.3.min.js"></script>

<%@ include file="../include/header.jsp" %>

</head>

<body>

<table border="1" width="100%">

<tr>

<th>번호</th>

<th>이름</th>

<th width="50%">메모</th>

<th>날짜</th>

</tr>

<c:forEach var="row" items="${list}">

<tr>

<td>${row.idx}</td>

<td>${row.writer}</td>

<td><a href="${path}/memo_servlet/view.do?idx=${row.idx}">${row.memo}</a></td>

<td>${row.post_date}</td>

</tr>

</c:forEach>

</table>

</body>

</html>

 

지금까지의 코드는 테이블 생성해서 결과 화면을 출력합니다.

 

여기서 추가로 진행해야 하는 건 memo_view.jsp 페이지를 생성해서 메모 클릭 시 내용을 좀 더 명확하게 볼 수 있고,

수정과 삭제 기능을 추가해야 합니다. 

 

위 코드에서 <a> 태그를 통해서 memo_view 페이지로 전달될 수 있게 구현했습니다.

<td><a href="${path}/memo_servlet/view.do?idx=${row.idx}">${row.memo}</a></td>

 


■  memo_view.jsp ( 수정, 삭제 기능 추가)

메모를 수정하고, 삭제하려면 어떤 기능이 필요할까요? 간단하게 생각해 보자면 button입니다.

 

button 클릭 시 해당 이벤트가 발생할 수 있게 설정하기 위해 onclick() 처리를 하면 됩니다.

그럼 당연히 Controller, DAO에서 기능 추가를 해야 합니다.

 

<View 단>

<%@ 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>

<script src="../include/jquery-3.6.3.min.js"></script>

<%@ include file="../include/header.jsp" %>

<script type="text/javascript">

function updateMemo() {

var writer=$("#writer").val();

var memo=$("#memo").val();

if(writer==""){

alert("이름을 입력하세요");

$("#writer").focus();

return;

}

if(memo==""){

alert("메모를 입력하세요");

$("#memo").focus();

return;

}

document.form1.action="${path}/memo_servlet/update.do";

document.form1.submit();

 

}

function deleteMemo() {

if(confirm("삭제하시겠습니까?")){

document.form1.action="${path}/memo_servlet/delete.do";

document.form1.submit();

}

}

</script>

</head>

<body>

<h2>메모 수정</h2>

<form name="form1" id="form1" method="post">

<table border="1" width="550px">

<tr>

<td>이름</td>

<td><input name="writer" id="writer" value="${dto.writer}"></td>

</tr>

<tr>

<td>메모</td>

<td><input name="memo" id="memo" size="40" value="${dto.memo}"></td>

</tr>

<tr>

<td colspan="2" align="center">

<input type="hidden" name="idx" id="idx" value="${dto.idx}">

<input type="button" value="수정" onclick="updateMemo()">

<input type="button" value="삭제" onclick="deleteMemo()">

</td>

</tr>

</table>

</form>

</body>

</html>

 

<Controller>

}else if(uri.indexOf("view.do") != -1) {

int idx= Integer.parseInt(request.getParameter("idx"));

System.out.println("글번호:"+idx);

MemoDTO dto = dao.viewMemo(idx);

//request 영역에 저장

request.setAttribute("dto", dto);

String page = "/memo/memo_view.jsp";

//포워딩

RequestDispatcher rd = request.getRequestDispatcher(page);

rd.forward(request, response);

}else if(uri.indexOf("update.do") != -1) {

//글번호 hidden으로 넘어온 idx 처리

int idx = Integer.parseInt(request.getParameter("idx"));

String writer = request.getParameter("writer");

String memo = request.getParameter("memo");

MemoDTO dto = new MemoDTO();

dto.setIdx(idx);

dto.setWriter(writer);

dto.setMemo(memo);

dao.updateMemo(dto); //레코드 수정

//단순 페이지 이동

response.sendRedirect(request.getContextPath()+"/memo/memo.jsp");

 

}else if(uri.indexOf("delete.do") != -1) {

int idx = Integer.parseInt(request.getParameter("idx"));

dao.deleteMemo(idx);

 

response.sendRedirect(request.getContextPath()+"/memo/memo.jsp");

}

}

기능이 하나씩 추가가 되면 else if문 처리를 해주시면 됩니다. 

 

(저처럼  Controller에서 먼저 메서드를 생성하시고 그 후에 DAO 작업을 하셔도 됩니다. 각자의 스타일이라서 자신한테 맞는 방법을 찾아서 하시면 될 거 같습니다. )

 

dao.updateMemo(dto); //레코드 수정

dao.deleteMemo(idx);

 

다음으로 DAO에서 기능 추가를 해봅시다.

 

<DAO>

public MemoDTO viewMemo(int idx) {

SqlSession session=MybatisManager.getInstance().openSession();

MemoDTO dto=session.selectOne("memo.view", idx);

//selectOne() 레코드 1개만 가져올 때

//selectList() 레코드 2개 이상 가져올 때(목록을 가져올 때)

session.close();

return dto;

}

public void updateMemo(MemoDTO dto) {

SqlSession session=MybatisManager.getInstance().openSession();

session.update("memo.update", dto);

session.commit();

session.close();

 

}

public void deleteMemo(int idx) {

SqlSession session=MybatisManager.getInstance().openSession();

session.update("memo.delete", idx);

session.commit();

session.close();

 

}

 

}

여기서 주의할 점은 update, delete 처리를 SQL에 보내야 합니다.

그렇다면 각 기능마다 Sqlsession 객체를 생성해야 합니다. 

 

그럼 다음으로 mapper 파일에 보내는 id값에 SQL update, delete 처리를 합니다.

 

<Mapper 파일>

<!-- parameterType="type" 은 생략 가능하다 -->

<select id="view" parameterType="int" resultType="memo.dto.MemoDTO">

select * from memo where idx=#{idx}

</select>

 

 

<update id="update" parameterType="memo.dto.MemoDTO">

update memo set writer=#{writer}, memo=#{memo}

where idx=#{idx}

</update>

 

<delete id="delete" parameterType="int">

delete from memo

where idx=#{idx}

</delete>

 

지금까지 한 줄 메모장 코드 구현을 끝냈습니다.

 

그럼 이제 결과로 알아봅시다.

(실행은 첫 페이지인 memo.jsp에서 합니다.)

 

 

입력단에서 <div> 태그 id="result"SQL Table을 출력해서 보여줍니다.

 

그럼 여기서 데이터를 추가해 보겠습니다.

 

 

insert가 제대로 작동하는 걸 확인하고 이제 수정, 삭제 기능을 확인해 봅시다.

해당 메모를 클릭하시면 view 단 페이지가 열립니다.

 

먼저 수정 기능을 확인해 봅시다.

 

 

 

다음은 삭제 기능입니다.

 

삭제 기능은 버튼 클릭 시 confirm() 객체에서 먼저 알림이 전송해 주고 이어서 진행하면 됩니다.

 

 

삭제 기능까지 제대로 작동하는 걸 확인했습니다.


마치며

 

오늘은 지금까지 배워온 지식을 바탕으로 한 줄 메모장을 만들어 봤습니다.

주의할 점은 정말 많지만 특히, spelling 조심합시다!

코드량이 많아질수록 spelling 확인 안 하고 넘어가서 시간 버리는 일이 많이 발생합니다.

그럼 다음 응용 예제로 뵙겠습니다.

728x90

'[ View ] > JSP' 카테고리의 다른 글

[ JSP ] 페이지 나누기  (0) 2023.03.22
[ JSP ] Mybatis 응용 예제(방명록)  (0) 2023.03.19
[ JSP ] Mybatis 개념 및 설정  (0) 2023.03.16
[ JSP ] JSTL(Jsp Standard Tag Library)  (2) 2023.03.15
[ JSP ] EL(Expression Language)  (0) 2023.03.14