[Spring] ResultMap을 이용한 일대다 관계 처리

ResultMap

  • 복잡한 결과 매핑을 간편하게 해주기위해 만들어진 태그다.
  • myBatis에서 제공하는 자동 매핑으로 해결이 어려운 경우를 위해 구조를 설계할 수 있도록 만들어졌다.

    정의만 보면 아리까리하니까 어떨때 사용하는지 차근차근 예를 들어 알아봅세다~

ResultMap이 필요한 경우

  • ResultMap은 다음과 같은 데이터 구조를 불러올 때 적합하다.

    • 계층형 데이터 구조

    • 이러한 데이터를 가지고 sql문을 실행한 결과를 가지고 다음과 같은 같은 화면을 출력하고자 할때 resultmap을 사용한다.

    • join을 이용해서 위의 화면을 출력하는 것은 가능은 하지만 어렵다. 조건들이 많이 등장할 것이며, 코드는 지저분하게 표시된다.

    • 따라서 데이터를 화면과 같은 구조로 불러오고 싶은 경우 join 대신 ResultMap을 이용하면 좋다 ^_^

  • 위와 같은 구조에서 시험 문제의 입장으로 바라본다면 다음과 같이 구성되어 있다고 생각할 수 있다.

  • 따라서 시험 문제와 보기의 관점에서 각각 저장할 클래스를 만들어 myBatis가 구조를 이해할 수 있도록 구성한다.

  • class Choice : 보기 클래스 => 1:n관계에서 n에 해당

public class Choice{
    private int no; //보기번호
    private String text; //보기내용
}
  • class Quiz : 문제 클래스 => 1:n관계에서 1에 해당
public class Quiz{
    private int no; //문제번호
    private String text; //문제내용
    private List<Choice> choices; //문제에 딸려오는 보기목록
}
  • 그리고 이 Quiz 클래스를 myBatis에 ResultMap으로 등록하여 구문과 같이 연결해두면 계층형 데이터를 쉽게불러올 수 있다.
<mapper namespace="quiz">

    <resultMap type="com.hakademy.vo.Quiz" id="quiz">
		<result column="no" property="no"/>
		<result column="text" property="text"/>
		<collection column="no" 
                                    property="choices" 
                                    javaType="java.util.List" 
                                    ofType="com.hakademy.vo.Choice" 
                                    select="getChoiceList"></collection>
	</resultMap>
	
    <select id="getQuizList" resultMap="quiz">
        select * from quiz order by no asc
    </select>
    
    <select id="getChoiceList" parameterType="int" resultType="com.hakademy.vo.Choice">
        select * from choice where quiz = #{quiz}
    </select>

</mapper>

출처http://www.sysout.co.kr/home/webbook/page/read/643;jsessionid=54B3D5320E73A41FC4088D5E3D322141

수업시간에 배운것 적용하기!!

예제1

  • TABLE BUYER(1)과 PROD(N)의 관계는 1:N이다.

(1) vo 설정(BuyerVO, ProdVO)

  • @Repository처리 제발 해주시궜어요??
  • private List prodVO; 를 설정해주는것이 하이라이트,,!
package kr.or.ddit;

import java.util.List;

import org.springframework.stereotype.Repository;

// 자바빈 클래스
// 롬복 @Data 해주면 눈에 보이지않아도 getter/setter됨. 근데 잘안씀

@Repository
public class BuyerVO {
	
	private String buyerId;
	private String buyerName;
	private String buyerLgu;
	private String buyerBank;
	private String buyerBankno;
	private String buyerBankname;
	private String buyerZip;
	private String buyerAdd1;
	private String buyerAdd2;
	private String buyerComtel;
	private String buyerFax;
	private String buyerMail;
	private String buyerCharger;
	private String buyerTelext;
	
	// BuyerVO: ProdVO = 1:N 관계
	private List<ProdVO> prodVO;
	
	
	public String getBuyerId() {
		return buyerId;
	}
	public void setBuyerId(String buyerId) {
		this.buyerId = buyerId;
	}
	public String getBuyerName() {
		return buyerName;
	}
	public void setBuyerName(String buyerName) {
		this.buyerName = buyerName;
	}
	public String getBuyerLgu() {
		return buyerLgu;
	}
	public void setBuyerLgu(String buyerLgu) {
		this.buyerLgu = buyerLgu;
	}
	public String getBuyerBank() {
		return buyerBank;
	}
	public void setBuyerBank(String buyerBank) {
		this.buyerBank = buyerBank;
	}
	public String getBuyerBankno() {
		return buyerBankno;
	}
	public void setBuyerBankno(String buyerBankno) {
		this.buyerBankno = buyerBankno;
	}
	public String getBuyerBankname() {
		return buyerBankname;
	}
	public void setBuyerBankname(String buyerBankname) {
		this.buyerBankname = buyerBankname;
	}
	public String getBuyerZip() {
		return buyerZip;
	}
	public void setBuyerZip(String buyerZip) {
		this.buyerZip = buyerZip;
	}
	public String getBuyerAdd1() {
		return buyerAdd1;
	}
	public void setBuyerAdd1(String buyerAdd1) {
		this.buyerAdd1 = buyerAdd1;
	}
	public String getBuyerAdd2() {
		return buyerAdd2;
	}
	public void setBuyerAdd2(String buyerAdd2) {
		this.buyerAdd2 = buyerAdd2;
	}
	public String getBuyerComtel() {
		return buyerComtel;
	}
	public void setBuyerComtel(String buyerComtel) {
		this.buyerComtel = buyerComtel;
	}
	public String getBuyerFax() {
		return buyerFax;
	}
	public void setBuyerFax(String buyerFax) {
		this.buyerFax = buyerFax;
	}
	public String getBuyerMail() {
		return buyerMail;
	}
	public void setBuyerMail(String buyerMail) {
		this.buyerMail = buyerMail;
	}
	public String getBuyerCharger() {
		return buyerCharger;
	}
	public void setBuyerCharger(String buyerCharger) {
		this.buyerCharger = buyerCharger;
	}
	public String getBuyerTelext() {
		return buyerTelext;
	}
	public void setBuyerTelext(String buyerTelext) {
		this.buyerTelext = buyerTelext;
	}
	
	public List<ProdVO> getProdVO() {
		return prodVO;
	}
	public void setProdVO(List<ProdVO> prodVO) {
		this.prodVO = prodVO;
	}
	
	
	public List<LprodVO> getLprodVO() {
		return lprodVO;
	}
	public void setLprodVO(List<LprodVO> lprodVO) {
		this.lprodVO = lprodVO;
	}
	@Override
	public String toString() {
		return "BuyerVO [buyerId=" + buyerId + ", buyerName=" + buyerName + ", buyerLgu=" + buyerLgu + ", buyerBank="
				+ buyerBank + ", buyerBankno=" + buyerBankno + ", buyerBankname=" + buyerBankname + ", buyerZip="
				+ buyerZip + ", buyerAdd1=" + buyerAdd1 + ", buyerAdd2=" + buyerAdd2 + ", buyerComtel=" + buyerComtel
				+ ", buyerFax=" + buyerFax + ", buyerMail=" + buyerMail + ", buyerCharger=" + buyerCharger
				+ ", buyerTelext=" + buyerTelext + ", prodVO=" + prodVO + ", lprodVO=" + lprodVO + "]";
	}
	
	
}
package kr.or.ddit;

import java.util.Date;

import org.springframework.format.annotation.DateTimeFormat;

// 자바빈 클래스
public class ProdVO {
	private String prodId;
	private String prodName;
	private String prodLgu;
	private String prodBuyer;
	private int prodCost;
	private int prodPrice;
	private int prodSale;
	private String prodOutline;
	// 오라클에서 CLOB 자료형일지라도 String으로 쓴다.
	private String prodDetail;
	private String prodImg;
	private int prodTotalstock;
	@DateTimeFormat(pattern="yy-MM-dd")
	private Date prodInsdate;
	private int prodProperstock;
	private String prodSize;
	private String prodColor;
	private String prodDelivery;
	private String prodUnit;
	private int prodQtyin;
	private int prodQtysale;
	private int prodMileage;
	public String getProdId() {
		return prodId;
	}
	public void setProdId(String prodId) {
		this.prodId = prodId;
	}
	public String getProdName() {
		return prodName;
	}
	public void setProdName(String prodName) {
		this.prodName = prodName;
	}
	public String getProdLgu() {
		return prodLgu;
	}
	public void setProdLgu(String prodLgu) {
		this.prodLgu = prodLgu;
	}
	public String getProdBuyer() {
		return prodBuyer;
	}
	public void setProdBuyer(String prodBuyer) {
		this.prodBuyer = prodBuyer;
	}
	public int getProdCost() {
		return prodCost;
	}
	public void setProdCost(int prodCost) {
		this.prodCost = prodCost;
	}
	public int getProdPrice() {
		return prodPrice;
	}
	public void setProdPrice(int prodPrice) {
		this.prodPrice = prodPrice;
	}
	public int getProdSale() {
		return prodSale;
	}
	public void setProdSale(int prodSale) {
		this.prodSale = prodSale;
	}
	public String getProdOutline() {
		return prodOutline;
	}
	public void setProdOutline(String prodOutline) {
		this.prodOutline = prodOutline;
	}
	public String getProdDetail() {
		return prodDetail;
	}
	public void setProdDetail(String prodDetail) {
		this.prodDetail = prodDetail;
	}
	public String getProdImg() {
		return prodImg;
	}
	public void setProdImg(String prodImg) {
		this.prodImg = prodImg;
	}
	public int getProdTotalstock() {
		return prodTotalstock;
	}
	public void setProdTotalstock(int prodTotalstock) {
		this.prodTotalstock = prodTotalstock;
	}
	public Date getProdInsdate() {
		return prodInsdate;
	}
	public void setProdInsdate(Date prodInsdate) {
		this.prodInsdate = prodInsdate;
	}
	public int getProdProperstock() {
		return prodProperstock;
	}
	public void setProdProperstock(int prodProperstock) {
		this.prodProperstock = prodProperstock;
	}
	public String getProdSize() {
		return prodSize;
	}
	public void setProdSize(String prodSize) {
		this.prodSize = prodSize;
	}
	public String getProdColor() {
		return prodColor;
	}
	public void setProdColor(String prodColor) {
		this.prodColor = prodColor;
	}
	public String getProdDelivery() {
		return prodDelivery;
	}
	public void setProdDelivery(String prodDelivery) {
		this.prodDelivery = prodDelivery;
	}
	public String getProdUnit() {
		return prodUnit;
	}
	public void setProdUnit(String prodUnit) {
		this.prodUnit = prodUnit;
	}
	public int getProdQtyin() {
		return prodQtyin;
	}
	public void setProdQtyin(int prodQtyin) {
		this.prodQtyin = prodQtyin;
	}
	public int getProdQtysale() {
		return prodQtysale;
	}
	public void setProdQtysale(int prodQtysale) {
		this.prodQtysale = prodQtysale;
	}
	public int getProdMileage() {
		return prodMileage;
	}
	public void setProdMileage(int prodMileage) {
		this.prodMileage = prodMileage;
	}
	
	@Override
	public String toString() {
		return "ProdVO [prodId=" + prodId + ", prodName=" + prodName + ", prodLgu=" + prodLgu + ", prodBuyer="
				+ prodBuyer + ", prodCost=" + prodCost + ", prodPrice=" + prodPrice + ", prodSale=" + prodSale
				+ ", prodOutline=" + prodOutline + ", prodDetail=" + prodDetail + ", prodImg=" + prodImg
				+ ", prodTotalstock=" + prodTotalstock + ", prodInsdate=" + prodInsdate + ", prodProperstock="
				+ prodProperstock + ", prodSize=" + prodSize + ", prodColor=" + prodColor + ", prodDelivery="
				+ prodDelivery + ", prodUnit=" + prodUnit + ", prodQtyin=" + prodQtyin + ", prodQtysale=" + prodQtysale
				+ ", prodMileage=" + prodMileage + "]";
	}
	
	
}

(2) mapper.xml 설정

  • 한 거래처당 구매한 n개의 물건들의 목록을 출력하는 쿼리문 작성
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="buyer">

	<resultMap type="buyerVO" id="buyerMap">
		<id property="buyerId" column="BUYER_ID" />
		<result property="buyerName" column="BUYER_NAME" />
		<collection property="prodVO" resultMap="prodMap">
		</collection>
	</resultMap>

	<resultMap type="prodVO" id="prodMap">
		<result property="prodBuyer" column="PROD_BUYER" />
		<result property="prodId" column="PROD_ID" />
		<result property="prodName" column="PROD_NAME" />
		<result property="prodSale" column="PROD_SALE" />
		<result property="prodDetail" column="PROD_DETAIL" javaType="java.lang.String" jdbcType="CLOB" />
	</resultMap>
	
	<select id="list" resultMap="buyerMap">
		SELECT B.BUYER_ID
		     , B.BUYER_NAME
		     , P.PROD_ID
		     , P.PROD_NAME
		     , P.PROD_BUYER
		     , P.PROD_SALE
		     , P.PROD_DETAIL
		FROM   BUYER B, PROD P
		WHERE  B.BUYER_ID = P.PROD_BUYER
		ORDER BY BUYER_ID ASC
	</select>
  
	
 </mapper>

ResultMap 설정 상세 설명

  • 메인 select 구문
    • 이 구문을 실행한 결과를 myBatis가 자동으로 resultmap에 맞게 처리하게 된다.
<select id="list" resultMap="buyerMap">
		SELECT B.BUYER_ID
		     , B.BUYER_NAME
		     , P.PROD_ID
		     , P.PROD_NAME
		     , P.PROD_BUYER
		     , P.PROD_SALE
		     , P.PROD_DETAIL
		FROM   BUYER B, PROD P
		WHERE  B.BUYER_ID = P.PROD_BUYER
		ORDER BY BUYER_ID ASC
</select>
    

ResultMap 설정

  • type : 매핑될 클래스명. 보통 alias에서 설정해놓음
  • id : 외부에서 지정할 이름을 작성한다.
  • column : 불러올 데이터베이스 항목명을 작성한다.
  • property : 불러온 항목을 저장할 클래스 내의 멤버변수명을 작성한다.
  • 만약 데이터가 여러 개라면 컬렉션을 지정할 수 있는데, 이 때는 collection 항목을 배치하여 매핑 관계를 설정한다.
    • 여러개(n에해당)의 데이터를 resultmap에 담아서 그것을 다시 1에 해당하는 resultMap의 property로 지정하여 설정
<resultMap type="buyerVO" id="buyerMap">
		<id property="buyerId" column="BUYER_ID" />
		<result property="buyerName" column="BUYER_NAME" />
		<collection property="prodVO" resultMap="prodMap">
		</collection>
	</resultMap>

	<resultMap type="prodVO" id="prodMap">
		<result property="prodBuyer" column="PROD_BUYER" />
		<result property="prodId" column="PROD_ID" />
		<result property="prodName" column="PROD_NAME" />
		<result property="prodSale" column="PROD_SALE" />
        // proDetail은 db에서 데이터타입이 clob라 Stirng으로 처리해준다.
		<result property="prodDetail" column="PROD_DETAIL" javaType="java.lang.String" jdbcType="CLOB" />
	</resultMap>

여기까지했으면 약 70%는 끝났다고 볼 수 있다.

(3) dao, service, Controller 설정

  • dao
package kr.or.ddit;

import java.util.List;

import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

//매퍼 xml을 실행해주는 클래스
//어노테이션을 붙여서 이 클래스는 데이터에 접근하는 클래스라는 것을 
//Spring에게 알려줌 알게찌 스프링아?
//Spring이 데이터를 관리하는 클래스라고 인지해서 자바 빈으로 등록
@Repository
public class BuyerDao {

	/*
	 *  new 키워드를 통해 직접 생성 안함. 하쥐만 생성이 된다아아아악
	 *  의존성 주입(Dependency Injection - DI)을 통해 주입받음
	 *  스프링은 미리 만들어 놓은 sqlSessionTemplate 타입 객체를 BookDao 객체에 주입
	 *  이 과정은 자동으로 스프링에서 실행되며, 개발자가 직접 객체를 생성하지 않는다.(Ioc)
	 *  
	 */
	@Autowired
	SqlSessionTemplate sqlSessionTemplate;
	
	public List<BuyerVO> list(){
		// namespace.id
		return this.sqlSessionTemplate.selectList("buyer.list");
	}
	
	public List<BuyerVO> lprodlist(){
		return this.sqlSessionTemplate.selectList("buyer.lprodlist");
	}
}
  • service
package kr.or.ddit;

import java.util.List;

public interface BuyerService {
	public List<BuyerVO> list();
	
	public List<BuyerVO> lprodlist();
}
package kr.or.ddit;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

// 스프링에게 이 클래스는 서비스 클래스임을 알려줌. => 스프링이 자바빈으로 등록하여 관리
@Service
public class BuyerServiceImpl implements BuyerService {
	@Autowired
	BuyerDao buyerDao;
	
	@Override
	public List<BuyerVO> list() {
		return this.buyerDao.list();
	}

	@Override
	public List<BuyerVO> lprodlist() {
		return this.buyerDao.lprodlist();
	}

}
  • Controller
package kr.or.ddit;

import java.util.List;

import javax.inject.Inject;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@RequestMapping(value="/buyer")

@Controller
public class BuyerController {
	private static final Logger logger = 
			LoggerFactory.getLogger(BuyerController.class);
	// Inject나 AutoWired나 똑같음 암거나 쓰셍
	// DI(의존성주입), IoC(제어의 역전)
	@Inject
	BuyerService buyerService;
	
	@RequestMapping(value="/list")
	public String list(Model model) {
		
		List<BuyerVO> list= this.buyerService.list();
		
		model.addAttribute("list", list);
		logger.info("list: "+ list);
		
		// 뷰 경로 지정,forward방식
		return "buyer/list";
	}
	

(4) 출력-list.jsp

  • foreach로 맛깔나게 출력하는것이 포인트니라
    <%@ page language="java" contentType="text/html; charset=UTF-8"%>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
    <!DOCTYPE html>
    <html>
    <head>
    <title>거래처별 상품목록</title>
    </head>
    <body>
    	<table border="1">
    	<tr>
    		<th>번호</th>
    		<th>거래처명</th>
    		<th>상품명</th>
    		<th>가격</th>
    	</tr>
    	
    	<c:forEach var="buyerVO" items="${list}" varStatus="stat">
    	<!-- buyerVO.prodVO : N에 대한 데이터  -->
    		<c:forEach var="prodVO" items="${buyerVO.prodVO}">
    		<c:set var="cnt" value="${i=i+1}" />
    			<tr>
    				<td>${cnt}</td>
    				<td>${buyerVO.buyerName}</td>
    				<!-- prodVO는 여러개 -->
    				<td>${prodVO.prodName}</td>
    				<td>${prodVO.prodSale}</td>
    			</tr>
    		</c:forEach>
    	</c:forEach>
    	</table>
    </body>
    </html>
  

좋은 웹페이지 즐겨찾기