정리
ResultMap이란?
- 복잡한 결과 매핑(조인 등)을 수행할 때 간편하게 수행이 가능하도록 만들어주기 위해 사용하는 태그
- type : java의 객체자료형(DTO)의 이름을 작성
- id : 본인이 사용할 직관적인 이름 부여
- id 태그의 column : 테이블 간의 참조키로 활용되는 컬럼명(기본키 컬럼)
- id 태그의 property : 컬럼에 해당하는 DTO의 멤버변수(프로퍼티)명
- result 태그의 column : 일반 컬럼명
- result 태그의 property : 컬럼에 해당하는 DTO의 멤버변수명
예시
<resultMap type="buyerVo" id="buyerMap">
<result property="buyerId" column="BUYER_ID"/>
<collection property="prodVoList" resultMap="prodMap"></collection>
</resultMap>
<resultMap type="prodVo" id="prodMap">
<result property="prodId" column="PROD_ID"/>
</resultMap>
<select id="getProdList" parameterType="prodVo" resultMap="buyerMap">
</select>
resultMap에 있는 result나 id값은 모든 칼럼을 Mapping해줘야한다
모두 작성하기 어려우니 해당 SQL문을 사용하여 복사 붙여넣기로 넣어주도록 한다
사용시 테이블명과 사용자 명을 알맞게 고쳐주고 사용하도록 할것
SELECT COLUMN_NAME
, DATA_TYPE
, CASE WHEN DATA_TYPE='NUMBER' THEN 'private int ' || FN_GETCAMEL(COLUMN_NAME) || ';'
WHEN DATA_TYPE IN('VARCHAR2','CHAR') THEN 'private String ' || FN_GETCAMEL(COLUMN_NAME) || ';'
WHEN DATA_TYPE='DATE' THEN 'private Date ' || FN_GETCAMEL(COLUMN_NAME) || ';'
ELSE 'private String ' || FN_GETCAMEL(COLUMN_NAME) || ';'
END AS CAMEL_CASE
, '<result property="'||FN_GETCAMEL(COLUMN_NAME)||'" column="'||COLUMN_NAME||'"/>' RESULTMAP
FROM ALL_TAB_COLUMNS
WHERE TABLE_NAME = 'PROD' -- 테이블 명
AND OWNER = 'JSPTEST'; -- 사용자 명
JSP
list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<script type="text/javascript" src="/resources/js/jquery.min.js"></script>
<div class="col-md-12 card">
<div class="card-header">
<h3>상품 목록</h3>
<a href="/lprod/create">상품 등록</a>
<form action="/lprod/list" class="row"
style="justify-content: space-between;">
<select name="gubun" class="form-control" style="width: 300px;">
<option value="" selected>선택</option>
<option value="lprodGu"
<c:if test="${param.gubun=='lprodGu'}">selected</c:if>>상품분류번호</option>
<option value="lprodNm"
<c:if test="${param.gubun=='lprodNm'}">selected</c:if>>상품분류명</option>
</select>
<div class="input-group input-group-sm" style="width: 150px;">
<input type="text" name="keyword" class="form-control float-right"
placeholder="Search"
value="<c:if test="${param.keyword!=null}">${param.keyword}</c:if>">
<div class="input-group-append">
<button type="submit" class="btn btn-default" style="height: 31px;">
<i class="fas fa-search"></i>
</button>
</div>
</div>
</form>
</div>
<div class="card-body row" style="justify-content: space-between;">
<div style="width: 45%; margin-right: 20px;">
<table class="table table-bordered" id="prodTable">
<thead>
<tr>
<th>순번</th>
<th>상품코드</th>
<th>상품분류명</th>
<th>수량</th>
</tr>
</thead>
<tbody>
<c:if test="${fn:length(data.content)==0}">
<tr>
<td colspan="4">해당하는 조건의 상품이 없습니다</td>
</tr>
</c:if>
<c:forEach items="${data.content}" var="vo">
<tr data-lprod-gu="${vo.lprodGu}" class="click">
<td>${vo.rnum}</td>
<td><a href="/lprod/detail?lprodId=${vo.lprodId}">${vo.lprodGu}</a></td>
<td>${vo.lprodNm}</td>
<td>${vo.cnt}</td>
</tr>
</c:forEach>
</tbody>
</table>
<div class="card-footer clearfix">${data.pagingArea}</div>
</div>
<!--
[가로]행=로우=튜플=레코드
[세로]열=필드=컬럼=애트리뷰트=속성
-->
<div style="width: 45%; overflow: scroll; height: 550px;" id="prod">
</div>
</div>
</div>
<script>
$('#prod').hide();
$('.click').on('click',function(){
let gu = $(this).data("lprodGu");
// console.log($(this));
$('#prodTable tr').css({"background": "white"});
$(this).css({"background": "#007bff"});
// console.log(gu);
//AJAX(Asynchronous JavaScript and Xml,에이잭스)
/*
- Asynchronous Javascript And Xml(비동기식 자바스크립트와 xml)의 약자
- 자바스크립트를 이용해 서버와 브라우저가 비동기 방식으로 데이터를 교환할 수 있는
통신 기능
- 브라우저가 가지고있는 XMLHttpRequest 객체를 이용해서 전체 페이지를 새로
고치지 않고도 페이지의 일부만을 위한 데이터를 로드하는 기법
- 즉, 쉽게 말하자면 자바스크립트를 통해서 서버에 데이터를 비동기 방식으로
요청하는 것이다.
*/
//달러.ajax() : 비동기 AJAX 요청을 수행
//달러.ajaxSetup() : 향후 AJAX 요청에 대한 기본 값을 설정
//달러.ajax() 메서드를 사용하면 AJAX의 다양한 설정을 미리 할 수 있고,
// 응답이 성공했을 때의 처리, 응답이 실패했을 때츼 처리를 단락 형태로
// 구분하여 처리할 수 있음.
// 이들 작업이 완료된 후에 처리해야 할 것이 있으면 추가로 작업할 수 있도록 구분함
$.ajax({
url : "/lprod/prodListAjax",
type : "Post",
data : JSON.stringify({"prodLgu":gu}),
dataType : "json",
contentType : 'application/json; charset=utf-8',
success : function(res){
// console.log(res);
$('#prod').show();
let str = "<table class='table table-striped'>";
str += "<thead>";
str += "<tr>";
str += "<th>상품코드</th>";
str += "<th>상품명</th>";
str += "<th>거래처</th>";
str += "<th>판매가</th>";
str += "</tr>";
str += "</thead>";
str += "<tbody>";
if(res.length==0){
str+="<td colspan='4'>상품이 없습니다</td>";
};
// res의 리스트를 순회하며 테이블의 행을 생성합니다.
res.forEach(function(buyer, index) {
buyer.prodVoList.forEach(function(prod, id){
let prodSale = prod.prodSale;
// /\B (?= (\d{3})+ (?!\d))/g
// 전방 탐색 기호(lookahead) (?=)
// + : 1개 이상 => ,를 붙이려면 (\d{3}) 무조건 숫자가 3개가 있어야 붙일 수 있음
// (?!\d) => \d : 숫자, (?!) : 부정형 전방 탐색
// 그 외
// (?<=) 긍정형 후방탐색
// (?<!) 부정형 후방탐색
prodSale = prodSale.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
str += "<tr>";
str += "<td>" + prod.prodId + "</td>"; // 상품코드
str += "<td>" + prod.prodName + "</td>"; // 상품분류명
str += "<td>" + buyer.buyerName + "</td>";
str += "<td>" + prodSale + "</td>";
str += "</tr>";
})
});
str += "</tbody>";
str += "</table>";
$('#prod').html(str);
}
})
})
</script>
JAVA
ProdVO.java
package kr.or.ddit.vo;
import java.util.Date;
import lombok.Data;
@Data
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 prodOu;
private String prodDetail;
private String prodImg;
private int prodTotalstock;
private Date prodInsdate;
private String prodOutline;
private int prodProperstock;
private String prodSize;
private String prodColor;
private String prodDelivery;
private String prodUnit;
private int prodQtyin;
private int prodQtysale;
private int prodMileage;
}
BuyerVO.java
package kr.or.ddit.vo;
import java.util.List;
import lombok.Data;
@Data
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 ;
// 거래처 : 상품 = 1 : N
// resultMap으로 설정
private List<ProdVO> prodVoList;
}
LprodController.java
package kr.or.ddit.controller;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import kr.or.ddit.service.LprodService;
import kr.or.ddit.util.ArticlePage;
import kr.or.ddit.vo.BuyerVO;
import kr.or.ddit.vo.LprodVO;
import kr.or.ddit.vo.ProdVO;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@RequestMapping("/lprod")
@Controller
public class LprodController {
@Autowired
LprodService service;
@RequestMapping(value="/create", method=RequestMethod.GET)
public ModelAndView create() {
ModelAndView mav = new ModelAndView();
mav.setViewName("lprod/create");
return mav;
}
@RequestMapping(value="/list", method=RequestMethod.GET)
public ModelAndView list(@RequestParam(value="currentPage",required=false,defaultValue="1") int currentPage,
@RequestParam(required=false) Map<String,Object> map) {
ModelAndView mav = new ModelAndView();
if(map.get("keyword")==null) {
map.put("keyword","");
}
if(map.get("gubun")==null) {
map.put("gubun","");
}
//전체 글 수
int total = this.service.getTotal(map);
log.info("list->total : " + total);
//한 화면에 보여지는 행의 수
int size = 10;
map.put("size", size);
map.put("currentPage", currentPage);
mav.setViewName("lprod/list");
List<LprodVO> list = this.service.list(map);
map.remove("size");
map.remove("currentPage");
mav.addObject("data", new ArticlePage<LprodVO>(total, currentPage, size, list, map));
return mav;
}
@RequestMapping(value="/detail", method=RequestMethod.GET)
public ModelAndView detail(LprodVO vo) {
ModelAndView mav = new ModelAndView();
mav.setViewName("lprod/detail");
vo = this.service.detail(vo);
mav.addObject("vo", vo);
return mav;
}
@RequestMapping(value="/delete", method=RequestMethod.GET)
public ModelAndView delete(LprodVO vo) {
ModelAndView mav = new ModelAndView();
// /로 시작하는 경우는 절대 경로
// 그냥 시작할경우 상대 경로
mav.setViewName("redirect:/lprod/list");
int result = this.service.delete(vo);
return mav;
}
@RequestMapping(value="/update", method=RequestMethod.POST)
public ModelAndView update(LprodVO vo) {
ModelAndView mav = new ModelAndView();
int result = this.service.update(vo);
mav.setViewName("redirect:/lprod/detail?lprodId="+vo.getLprodId());
return mav;
}
@RequestMapping(value="/createPost", method=RequestMethod.POST)
public ModelAndView createPost(LprodVO lvo) {
ModelAndView mav = new ModelAndView();
log.info("LprodVo"+lvo);
int result = this.service.createPost(lvo);
System.out.println("createPost -> result : "+result);
mav.setViewName("redirect:/lprod/list");
return mav;
}
@ResponseBody
@PostMapping("/prodListAjax")
public List<BuyerVO> getProdList(Model model, @RequestBody ProdVO vo){
List<BuyerVO> list = this.service.getProdList(vo);
log.info("list >>"+list);
return list;
}
}
LprodService.java
package kr.or.ddit.service;
import java.util.List;
import java.util.Map;
import kr.or.ddit.vo.BuyerVO;
import kr.or.ddit.vo.LprodVO;
import kr.or.ddit.vo.ProdVO;
public interface LprodService {
public int createPost(LprodVO lvo);
public List<LprodVO> list(Map<String, Object> map);
public LprodVO detail(LprodVO vo);
public int update(LprodVO vo);
public int delete(LprodVO vo);
public int getTotal(Map<String,Object> map);
public List<BuyerVO> getProdList(ProdVO vo);
}
LprodServiceImpl.java
package kr.or.ddit.service.impl;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import kr.or.ddit.dao.LprodDao;
import kr.or.ddit.service.LprodService;
import kr.or.ddit.vo.BuyerVO;
import kr.or.ddit.vo.LprodVO;
import kr.or.ddit.vo.ProdVO;
@Service
public class LprodServiceImpl implements LprodService {
@Autowired
LprodDao dao;
@Override
public int createPost(LprodVO lvo) {
return this.dao.createPost(lvo);
}
@Override
public List<LprodVO> list(Map<String, Object> map) {
return this.dao.list(map);
}
@Override
public LprodVO detail(LprodVO vo) {
return this.dao.detail(vo);
}
@Override
public int update(LprodVO vo) {
return this.dao.update(vo);
}
@Override
public int delete(LprodVO vo) {
return this.dao.delete(vo);
}
@Override
public int getTotal(Map<String, Object> map) {
return this.dao.getTotal(map);
}
@Override
public List<BuyerVO> getProdList(ProdVO vo) {
return this.dao.getProdList(vo);
}
}
LprodDao.java
package kr.or.ddit.dao;
import java.util.List;
import java.util.Map;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import kr.or.ddit.vo.BuyerVO;
import kr.or.ddit.vo.LprodVO;
import kr.or.ddit.vo.ProdVO;
@Repository
public class LprodDao {
@Autowired
SqlSessionTemplate sst;
public int createPost(LprodVO lvo) {
return this.sst.insert("lprod.createPost", lvo);
}
public List<LprodVO> list(Map<String, Object> map) {
return this.sst.selectList("lprod.list", map);
}
public LprodVO detail(LprodVO vo) {
return this.sst.selectOne("lprod.detail", vo);
}
public int update(LprodVO vo) {
return this.sst.update("lprod.update", vo);
}
public int delete(LprodVO vo) {
return this.sst.delete("lprod.delete", vo);
}
public int getTotal(Map<String, Object> map) {
return this.sst.selectOne("lprod.getTotal", map);
}
public List<BuyerVO> getProdList(ProdVO vo) {
return this.sst.selectList("lprod.getProdList", vo);
}
}
Mybatis
Type Alias
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--
[마이바티스] 스프링에서 "_"를 사용한 컬럼명을 사용 시(BOOK 테이블의 BOOK_ID)
카멜케이스로 읽어줌(bookId)
ex) 테이블 컬러명이 member_id인 경우 jsp화면단에서 이 값을 사용 시 memberId로 사용
-->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!-- 자주 사용하는 타입의 별칭을 세팅 -->
<typeAliases>
<typeAlias type="kr.or.ddit.vo.BookVO" alias="bookVo" />
<typeAlias type="kr.or.ddit.vo.LprodVO" alias="LprodVo" />
<typeAlias type="kr.or.ddit.vo.JdbcBoardVO" alias="boardVo" />
<typeAlias type="kr.or.ddit.vo.BuyprodVO" alias="buyprodVo" />
<typeAlias type="kr.or.ddit.vo.ProdVO" alias="prodVo" />
<typeAlias type="kr.or.ddit.vo.BuyerVO" alias="buyerVo" />
</typeAliases>
</configuration>
lprod_SQL.xml
<?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="lprod">
<insert id="createPost" parameterType="LprodVo">
<selectKey resultType="String" order="BEFORE" keyProperty="lprodGu">
select #{gubun}|| lpad((to_number(nvl(max(substr(lprod_gu,3)),0))+1),2,0)
from lprod
where substr(lprod_gu,1,2)=#{gubun}
</selectKey>
insert into lprod
values((select nvl(max(lprod_id),0)+1 from lprod), #{lprodGu}, #{lprodNm})
</insert>
<sql id="idchk">
<if test="gubun != null or gubun != ''">
<choose>
<when test="gubun == 'lprodGu'">
where lprod_gu like '%' || #{keyword} || '%'
</when>
<when test="gubun == 'lprodNm'">
where lprod_nm like '%' || #{keyword} || '%'
</when>
</choose>
</if>
<if test="gubun == null or gubun == ''">
where lprod_nm like '%' || #{keyword} || '%'
or lprod_gu like '%' || #{keyword} || '%'
</if>
</sql>
<!-- 전체 글 수 -->
<select id="getTotal" resultType="int" parameterType="hashMap">
SELECT COUNT(*) FROM LPROD
<include refid="idchk"/>
</select>
<select id="list" parameterType="hashMap" resultType="lprodVo">
with t as(
select ROW_NUMBER() OVER(ORDER BY lprod_gu DESC) RNUM, lprod_gu, lprod_id, lprod_nm ,count(prod_lgu) cnt
from lprod
left outer join prod on prod_lgu = lprod_gu
<include refid="idchk"/>
group by lprod_gu, lprod_id, lprod_nm
)
select t.*
from t
WHERE T.RNUM BETWEEN (#{currentPage}*#{size}) - (#{size}-1) AND (#{currentPage}*#{size})
</select>
<select id="detail" parameterType="lprodVo" resultType="lprodVo">
select *
from lprod
where lprod_id=#{lprodId}
</select>
<update id="update" parameterType="lprodVo">
update lprod
set lprod_gu = #{lprodGu},
lprod_nm = #{lprodNm}
where lprod_id = #{lprodId}
</update>
<delete id="delete" parameterType="lprodVo">
delete lprod
where lprod_id = #{lprodId}
</delete>
<!-- ResultMap이란?
복잡한 결과 매핑(조인 등)을 수행할 때 간편하게 수행이 가능하도록 만들어주기 위해 사용하는 태그
type : java의 객체자료형(DTO)의 이름을 작성
id : 본인이 사용할 직관적인 이름 부여
id 태그의 column : 테이블 간의 참조키로 활용되는 컬럼명(기본키 컬럼)
id 태그의 property : 컬럼에 해당하는 DTO의 멤버변수(프로퍼티)명
result 태그의 column : 일반 컬럼명
result 태그의 property : 컬럼에 해당하는 DTO의 멤버변수명
-->
<resultMap type="buyerVo" id="buyerMap">
<result property="buyerId" column="BUYER_ID"/>
<result property="buyerName" column="BUYER_NAME"/>
<result property="buyerLgu" column="BUYER_LGU"/>
<result property="buyerBank" column="BUYER_BANK"/>
<result property="buyerBankno" column="BUYER_BANKNO"/>
<result property="buyerBankname" column="BUYER_BANKNAME"/>
<result property="buyerZip" column="BUYER_ZIP"/>
<result property="buyerAdd1" column="BUYER_ADD1"/>
<result property="buyerAdd2" column="BUYER_ADD2"/>
<result property="buyerComtel" column="BUYER_COMTEL"/>
<result property="buyerFax" column="BUYER_FAX"/>
<result property="buyerMail" column="BUYER_MAIL"/>
<result property="buyerCharger" column="BUYER_CHARGER"/>
<result property="buyerTelext" column="BUYER_TELEXT"/>
<collection property="prodVoList" resultMap="prodMap"></collection>
</resultMap>
<resultMap type="prodVo" id="prodMap">
<result property="prodId" column="PROD_ID"/>
<result property="prodName" column="PROD_NAME"/>
<result property="prodLgu" column="PROD_LGU"/>
<result property="prodBuyer" column="PROD_BUYER"/>
<result property="prodCost" column="PROD_COST"/>
<result property="prodPrice" column="PROD_PRICE"/>
<result property="prodSale" column="PROD_SALE"/>
<result property="prodOutline" column="PROD_OUTLINE"/>
<result property="prodDetail" column="PROD_DETAIL"/>
<result property="prodImg" column="PROD_IMG"/>
<result property="prodTotalstock" column="PROD_TOTALSTOCK"/>
<result property="prodInsdate" column="PROD_INSDATE"/>
<result property="prodProperstock" column="PROD_PROPERSTOCK"/>
<result property="prodSize" column="PROD_SIZE"/>
<result property="prodColor" column="PROD_COLOR"/>
<result property="prodDelivery" column="PROD_DELIVERY"/>
<result property="prodUnit" column="PROD_UNIT"/>
<result property="prodQtyin" column="PROD_QTYIN"/>
<result property="prodQtysale" column="PROD_QTYSALE"/>
<result property="prodMileage" column="PROD_MILEAGE"/>
</resultMap>
<select id="getProdList" parameterType="prodVo" resultMap="buyerMap">
SELECT A.PROD_ID, A.PROD_NAME, A.PROD_LGU, A.PROD_BUYER, A.PROD_COST
, A.PROD_PRICE, A.PROD_SALE, A.PROD_OUTLINE, A.PROD_DETAIL, A.PROD_IMG
, A.PROD_TOTALSTOCK, A.PROD_INSDATE, A.PROD_PROPERSTOCK, A.PROD_SIZE
, A.PROD_COLOR, A.PROD_DELIVERY, A.PROD_UNIT, A.PROD_QTYIN, A.PROD_QTYSALE
, A.PROD_MILEAGE
, B.BUYER_ID, B.BUYER_NAME, B.BUYER_LGU, B.BUYER_BANK, B.BUYER_BANKNO
, B.BUYER_BANKNAME, B.BUYER_ZIP, B.BUYER_ADD1, B.BUYER_ADD2
, B.BUYER_COMTEL, B.BUYER_FAX, B.BUYER_MAIL, B.BUYER_CHARGER
, B.BUYER_TELEXT
FROM BUYER B, PROD A
WHERE B.BUYER_ID = A.PROD_BUYER
and a.PROD_LGU = #{prodLgu}
</select>
</mapper>
'Spring' 카테고리의 다른 글
[Spring] daum 우편번호 Api 사용하기 (0) | 2024.08.02 |
---|---|
[Spring] 상품별 장바구니 목록 prod-cart-member (0) | 2024.07.31 |
[Spring] buyprod 상세보기 (0) | 2024.07.31 |
[Spring] buyprod - 모달창으로 상세 보기 (0) | 2024.07.30 |
[Spring] JSON (0) | 2024.07.30 |