[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>
Author And Source
이 문제에 관하여([Spring] ResultMap을 이용한 일대다 관계 처리), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@vgo_dongv/Spring-일대다-관계저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)