본문 바로가기

학원/복기

[MyBatis] 조인예제(2) / association 엘리먼트의 속성

MYREPLY 테이블과 MYUSER 테이블을 조인해보자

 

 

[MYREPLY 테이블]

 

[MYUSER 테이블]

 

 

 

DTO 클래스

 

MYREPLY 테이블과 MYUSER 테이블의 컬럼값을 저장하기 위한 클래스
→ 1:1 관계의 테이블 조인에 대한 검색결과 저장 

 

[MyReplyUser]

package xyz.itwill.dto;

public class MyReplyUser {
	//MYREPLY 테이블(댓글정보)의 검색행을 객체로 제공받아 저장하기 위한 필드 - 검색행 1개
	private MyReply reply; 
	
	//MYUSER 테이블(회원정보)의 검색행을 객체로 제공받아 저장하기 위한 필드 - 검색행 1개
	private MyUser user;
	
	public MyReplyUser() {
		// TODO Auto-generated constructor stub
	}

	public MyReply getReply() {
		return reply;
	}

	public void setReply(MyReply reply) {
		this.reply = reply;
	}

	public MyUser getUser() {
		return user;
	}

	public void setUser(MyUser user) {
		this.user = user;
	}
}

 

 

이렇게 기존의 클래스를 재사용하면 새로운 클래스를 쉽게 만들 수 있고, 유지보수에도 좋다.

 

 

xml 매퍼에서 select를 등록해주자

<resultMap type="MyReplyUser" id="myReplyUserResultMap1">
	<association property="reply" javaType="MyReply">
		<id column="reply_no" property="replyNo"/>
		<result column="reply_id" property="replyId"/>
		<result column="reply_content" property="replyContent"/>
		<result column="reply_date" property="replyDate"/>
		<result column="reply_comment_no" property="replyCommentNo"/>
	</association>
	<association property="user" javaType="MyUser">
		<id column="user_id" property="userId"/>
		<result column="user_name" property="userName"/>
	</association>
</resultMap>
	
<select id="selectReplyUserList1" resultMap="myReplyUserResultMap1">
	select reply_no, reply_id, reply_content, reply_date, reply_comment_no, user_id
		, user_name from myreply join myuser on reply_id=user_id order by reply_no desc
</select>

 

인터페이스 매퍼

public interface MyReplyMapper {
	//...
    	//...
	List<MyReplyUser> selectReplyUserList1();
}

 

DAO에 메소드 추가

public List<MyReplyUser> selectReplyUserList1() {
	SqlSession sqlSession=getSqlSessionFactory().openSession(true);
	try {
		return sqlSession.getMapper(MyReplyMapper.class).selectReplyUserList1();
	} finally {
		sqlSession.close();
	}
}

 

jsp 작성해 목록 확인 

[replyUserListSelect1.jsp]

<%@page import="xyz.itwill.dao.MyReplyDAO"%>
<%@page import="xyz.itwill.dto.MyReplyUser"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	List<MyReplyUser> replyUserList=MyReplyDAO.getDAO().selectReplyUserList1();
%>    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>MYBATIS</title>
<style type="text/css">
table {
	border: 1px solid black;
	border-collapse: collapse;
}

td {
	border: 1px solid black;
	text-align: center;
	padding: 3px;
}

.no { width: 100px; }
.name { width: 150px; }
.content { width: 300px; }
.date { width: 200px; }
.comment { width: 100px; }
</style>
</head>
<body>
	<h1>댓글목록</h1>
	<hr>
	<table>
		<tr>
			<td class="no">댓글번호</td>
			<td class="name">댓글작성자</td>
			<td class="content">댓글내용</td>
			<td class="date">댓글작성일</td>
			<td class="comment">게시글번호</td>
		</tr>
		<% for(MyReplyUser replyUser : replyUserList) { %>
		<tr>
			<td><%=replyUser.getReply().getReplyNo() %></td>
			<td><%=replyUser.getUser().getUserName() %>[<%=replyUser.getReply().getReplyId() %>]</td>
			<td><%=replyUser.getReply().getReplyContent() %></td>
			<td><%=replyUser.getReply().getReplyDate() %></td>
			<td><%=replyUser.getReply().getReplyCommentNo() %></td>
		</tr>
		<% } %>
	</table>
</body>
</html>

 


association 엘리먼트의 속성

 

association 엘리먼트에 대해 더 알아보자

 

resultMap 속성 : resultMap 엘리먼트의 식별자를 속성값으로 설정한다.
다른 resultMap 엘리먼트의 매핑정보를 이용하여 검색행의 컬럼값이 저장된 객체를 제공받아 필드에 저장한다.

 

이처럼 resultMap 엘리먼트의 매핑 정보를 재사용할 수 있다.

<resultMap type="MyReply" id="myReplyResultMap">
	<id column="reply_no" property="replyNo"/>
	<result column="reply_id" property="replyId"/>
	<result column="reply_content" property="replyContent"/>
	<result column="reply_date" property="replyDate"/>
	<result column="reply_comment_no" property="replyCommentNo"/>
</resultMap>

<resultMap type="MyReplyUser" id="myReplyResultMap2">
	<association property="reply" resultMap="myReplyResultMap"/>
</resultMap>

 

select 속성 : select 엘리먼트의 식별자를 속성값으로 설정한다.

→ select 엘리먼트로 검색행의 컬럼값이 저장된 객체를 제공받아 필드에 저장한다.

 

column 속성 : SELECT 명령에 전달될 값이 저장된 검색행의 컬럼명을 속성값으로 설정한다.

→ 검색행의 컬럼값을 select 속성값으로 설정된 select 엘리먼트의 prameterType 속성값으로 전달하여 SQL 명령에서 사용할 수 있다. 

 

 

DAO 클래스의 메소드에서 사용하지 않고 association 엘리먼트에서만 사용하기 위한 SELECT 명령이기 때문에 인터페이스 기반의 매퍼 파일에서 추상메소드로 선언하지 않아도 된다. 

 

parameterType 속성값으로 전달받은 값을 사용하여 단일행이 검색되도록 SELECT 명령을 작성해준다.

<resultMap type="MyReplyUser" id="myReplyUserResultMap2">
	<association property="user" select="selectMyUser" column="reply_id"/>
</resultMap>
	
<!-- DAO 클래스의 메소드에서 사용하지 않고 association 엘리먼트에서만 사용하기 위한 SELECT 명령 -->
<!-- => Interface 기반의 매퍼 파일에서 추상메소드로 선언하지 않음 -->
<!-- => parameterType 속성값으로 전달받은 값을 사용하여 단일행이 검색되도록 SELECT 명령 작성 -->
<select id="selectMyUser" resultType="MyUser" parameterType="string">
	select user_id, user_name from myuser where user_id=#{userId}
</select>
	
<!-- 테이블 조인 명령을 사용하지 않고 resultMap 엘리먼트의 매핑정보를 이용하여 2개 
이상의 테이블에 대한 검색결과를 객체로 제공받아 사용 가능 -->
<select id="selectReplyUserList2" resultMap="myReplyUserResultMap2">
	select reply_no, reply_id, reply_content, reply_date, reply_comment_no from myreply order by reply_no desc
</select>

 

이 속성을 사용하면 테이블 조인 명령을 사용하지 않아도 된다는 장점이 있다.

 

 

jsp 문서로 댓글목록 확인해보기

 

[replyUserListSelect2.jsp]

<%@page import="xyz.itwill.dao.MyReplyDAO"%>
<%@page import="xyz.itwill.dto.MyReplyUser"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	List<MyReplyUser> replyUserList=MyReplyDAO.getDAO().selectReplyUserList2();
%>    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>MYBATIS</title>
<style type="text/css">
table {
	border: 1px solid black;
	border-collapse: collapse;
}

td {
	border: 1px solid black;
	text-align: center;
	padding: 3px;
}

.no { width: 100px; }
.name { width: 150px; }
.content { width: 300px; }
.date { width: 200px; }
.comment { width: 100px; }
</style>
</head>
<body>
	<h1>댓글목록</h1>
	<hr>
	<table>
		<tr>
			<td class="no">댓글번호</td>
			<td class="name">댓글작성자</td>
			<td class="content">댓글내용</td>
			<td class="date">댓글작성일</td>
			<td class="comment">게시글번호</td>
		</tr>
		<% for(MyReplyUser replyUser : replyUserList) { %>
		<tr>
			<td><%=replyUser.getReply().getReplyNo() %></td>
			<td><%=replyUser.getUser().getUserName() %>[<%=replyUser.getReply().getReplyId() %>]</td>
			<td><%=replyUser.getReply().getReplyContent() %></td>
			<td><%=replyUser.getReply().getReplyDate() %></td>
			<td><%=replyUser.getReply().getReplyCommentNo() %></td>
		</tr>
		<% } %>
	</table>
</body>
</html>

 


commentUserListSelect2.jsp 를 이용해서 게시글을 출력해보자

 

 

[MYCOMMENT] 테이블

 

 

DTO 클래스를 만들어준다

 

MYCOMMENT 테이블과 MYREPLY 테이블의 컬럼값을 저장하기 위한 클래스
=> 1:N 관계의 테이블 조인에 대한 검색결과를 저장할 목적의 클래스

 

[MyCommentReply]

package xyz.itwill.dto;

import java.util.List;

public class MyCommentReply {
	//MYCOMMENT 테이블(게시글정보)의 검색행을 객체로 제공받아 저장하기 위한 필드 - 검색행 1개
	private MyComment1 comment;
	
	//MYREPLY 테이블(댓글정보)의 검색행을 객체로 제공받아 저장하기 위한 필드 - 검색행 0개 이상
	private List<MyReply> replyList;
	
	public MyCommentReply() {
		// TODO Auto-generated constructor stub
	}

	public MyComment1 getComment() {
		return comment;
	}

	public void setComment(MyComment1 comment) {
		this.comment = comment;
	}

	public List<MyReply> getReplyList() {
		return replyList;
	}

	public void setReplyList(List<MyReply> replyList) {
		this.replyList = replyList;
	}
}

 

 

 

xml 기반의 매퍼파일  만들기

 

먼저 조인을 하지 않고 만들어 보자.

 

 

[MyCommentMapper.xml]

 

게시글번호를 전달받아 MYCOMMENT 테이블에 저장된 게시글정보를 검색하여 MyComment1 객체로 제공하는 엘리먼트를 선언한다. (검색행은 1개이다)

<select id="selectComment" parameterType="int" resultType="MyComment1">
	select comment_no, comment_id, comment_content, comment_date from mycomment where comment_no=#{commentNo}
</select>

 

게시글번호를 전달받아 MYREPLY 테이블에 저장된 댓글정보를 검색하여 MyReply 객체로 제공하는 엘리먼트를 선언한다. (검색행은 0개 이상이다) 

<select id="selectCommentNoReplyList" parameterType="int" resultType="MyReply">
	select reply_no, reply_id, reply_content, reply_date, reply_comment_no
		from myreply where reply_comment_no=#{replyCommentNo} order by reply_no desc
</select>

 

 

인터페이스 매퍼파일

 

[MyCommentMapper] 

public interface MyCommentMapper {
	//...
    	//...
	MyComment1 selectComment(int commentNo);
	List<MyReply> selectCommentNoReplyList(int commentNo);
}

 

 

DAO 

 

[MyCommentDAO]

	public MyComment1 selectComment(int commentNo) {
		SqlSession sqlSession=getSqlSessionFactory().openSession(true);
		try {
			return sqlSession.getMapper(MyCommentMapper.class).selectComment(commentNo);
		} finally {
			sqlSession.close();
		}
	}
	
	public List<MyReply> selectCommentNoReplyList(int commentNo) {
		SqlSession sqlSession=getSqlSessionFactory().openSession(true);
		try {
			return sqlSession.getMapper(MyCommentMapper.class).selectCommentNoReplyList(commentNo);
		} finally {
			sqlSession.close();
		}
	}

 

jsp문서 연결 

 

[commentUserListSelect2.jsp]

<%@page import="xyz.itwill.dao.MyCommentDAO"%>
<%@page import="xyz.itwill.dto.MyCommentUser2"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	List<MyCommentUser2> commentUserList=MyCommentDAO.getDAO().selectCommentUserList2();
%>    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>MYBATIS</title>
<style type="text/css">
table {
	border: 1px solid black;
	border-collapse: collapse;
}

td {
	border: 1px solid black;
	text-align: center;
	padding: 3px;
}

.no { width: 100px; }
.name { width: 150px; }
.content { width: 250px; }
.date { width: 200px; }
</style>
</head>
<body>
	<h1>게시글 목록</h1>
	<hr>
	<table>
		<tr>
			<td class="no">게시글번호</td>
			<td class="name">게시글작성자</td>
			<td class="content">게시글내용</td>
			<td class="date">게시글작성일</td>
		</tr>
		<% for(MyCommentUser2 commentUser : commentUserList) { %>
		<tr>
			<td><%=commentUser.getComment().getCommentNo() %></td>
			<%-- <td><%=commentUser.getUser().getUserName()%>[<%=commentUser.getComment().getCommentId() %>]</td> --%>
			<td><%=commentUser.getUser().getUserName()%>[<%=commentUser.getUser().getUserId() %>]</td>
			<%-- <td><%=commentUser.getComment().getCommentContent() %></td> --%>
			<td>
				<a href="commentReplySelect1.jsp?commentNo=<%=commentUser.getComment().getCommentNo()%>">
					<%=commentUser.getComment().getCommentContent() %>
				</a>
			</td>
			<td><%=commentUser.getComment().getCommentDate() %></td>
		</tr>
		<% } %>
	</table>
</body>
</html>

 

[commentReplySelect1.jsp]

<%@page import="xyz.itwill.dto.MyReply"%>
<%@page import="java.util.List"%>
<%@page import="xyz.itwill.dao.MyCommentDAO"%>
<%@page import="xyz.itwill.dto.MyComment1"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	if(request.getParameter("commentNo")==null) {//전달값(게시글번호)이 없는 경우
		//게시글목록을 출력하는 페이지로 이동
		response.sendRedirect("commentUserListSelect2.jsp");
		return;
	}

	//전달값(게시글번호)을 반환받아 저장
	int commentNo=Integer.parseInt(request.getParameter("commentNo"));
	
	//게시글번호를 이용하여 MYCOMMENT 테이블에 저장된 게시글을 검색하여 DTO 객체로 반환하는 DAO 클래스의 메소드 호출
	MyComment1 comment=MyCommentDAO.getDAO().selectComment(commentNo);
	
	//게시글번호를 이용하여 MYREPLY 테이블에 저장된 댓글목록을 검색하여 List 객체로 반환하는 DAO 클래스의 메소드 호출
	List<MyReply> replyList=MyCommentDAO.getDAO().selectCommentNoReplyList(commentNo);
%>    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>MYBATIS</title>
<style type="text/css">
table {
	border: 1px solid black;
	border-collapse: collapse;
}

td {
	border: 1px solid black;
	text-align: center;
	padding: 3px;
}

.no { width: 100px; }
.name { width: 150px; }
.content { width: 300px; }
.date { width: 200px; }
.comment { width: 100px; }
</style>
</head>
<body>
	<h1>게시글과 댓글목록</h1>
	<hr>
	<%-- 게시글 출력 --%>
	<table>
		<tr>
			<td width="200">게시글번호</td>
			<td width="300"><%=comment.getCommentNo() %></td>
		</tr>
		<tr>
			<td width="200">게시글작성자</td>
			<td width="300"><%=comment.getCommentId() %></td>
		</tr>
		<tr>
			<td width="200">게시글내용</td>
			<td width="300"><%=comment.getCommentContent() %></td>
		</tr>
		<tr>
			<td width="200">게시글작성일</td>
			<td width="300"><%=comment.getCommentDate() %></td>
		</tr>
	</table>
	<br>
	
	<%-- 댓글목록 출력 --%>
	<table>
		<tr>
			<td class="no">댓글번호</td>
			<td class="name">댓글작성자</td>
			<td class="content">댓글내용</td>
			<td class="date">댓글작성일</td>
			<td class="comment">게시글번호</td>
		</tr>
		<% if(replyList.isEmpty()) { %>
			<tr>
				<td colspan="5">댓글이 존재하지 않습니다.</td>
			</tr>
		<% } else { %>
			<% for(MyReply reply : replyList) { %>
			<tr>
				<td><%=reply.getReplyNo() %></td>
				<td><%=reply.getReplyId() %></td>
				<td><%=reply.getReplyContent() %></td>
				<td><%=reply.getReplyDate() %></td>
				<td><%=reply.getReplyCommentNo() %></td>
			</tr>
			<% } %>
		<% } %>
	</table>
</body>
</html>