계층형 쿼리
MyBatis 동적 SQL 정리
MyBatis는 동적 SQL을 조립하는 구조를 지원해줌
SQL 조립 규칙을 매퍼 XML 파일에 정의할 수 있음
-<where> : where절 앞뒤에 내용을 더 추가하거나 삭제할 때 사용
-<if> : 조건 만족 시 SQL을 조립
-<choose> : 여러 선택 항목에서 조건 만족 시 SQL을 조립
-<foreach> : 컬렉션이나 배열에 대해 반복 처리
-<set> : UPDATE절의 SET절 앞 뒤에 내용을 더 추가하거나 삭제 시 사용
입력값 검증을 위한 라이브러리
1) https://mvnrepository.com/ 에서 hibernate-validator 검색 ->
Home » org.hibernate » hibernate-validator 클릭
2) 5.4.2.Final 버전 클릭 -> 중간 코드 복사
-> pom.xml에 붙여넣기
3) 프로젝트 우클릭 - Run As - 4번 클릭
-> build Success 나오면 설치 성공
스프링 MVC 프레임워크에서 Bean(자바빈 클래스, VO) 기능을 이용하여 요청 파라미터 값이 바인딩(=메모리에 올라감) 된 도메인 클래스(=메모리에 올라간 VO객체)의 입력값 검증을 함
예시) detail.jsp에서 수정 시 입력값 검증하기
package kr.or.ddit;
import java.util.List;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;
//자바빈 클래스
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;
@NotEmpty
private String buyerComtel;
private String buyerFax;
@NotEmpty
@Email
private String buyerMail;
@NotEmpty
private String buyerCharger;
private String buyerTelext;
//상품분류명
private String lprodNm;
//Buyer : ProdVO = 1: N 관계
private List<ProdVO> ProdVO;
//getter/setter 메소드
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) {
ProdVO = prodVO;
}
public String getLprodNm() {
return lprodNm;
}
public void setLprodNm(String lprodNm) {
this.lprodNm = lprodNm;
}
@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 + ", lprodNm=" + lprodNm + ", ProdVO=" + ProdVO + "]";
}
}
<?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">
<resultMap type="lprodVO" id="lprodMap">
<id property="lprodGu" column="LPROD_GU" />
<result property="rnum" column="RNUM" />
<result property="lprodNm" column="LPROD_NM" />
<collection property="buyerVO" resultMap="buyerMap">
</collection>
</resultMap>
<resultMap type="buyerVO" id="buyerMap">
<result property="buyerId" column="BUYER_ID"/>
<result property="buyerName" column="BUYER_NAME"/>
<result property="buyerLgu" column="BUYER_LGU"/>
</resultMap>
<!-- 상품분류 별 거래처 목록 -->
<!--
parameter :
{keyWord=캐주,currentPage=1,size=10}
-->
<select id="list" parameterType="hashMap" resultMap="lprodMap">
SELECT ROWNUM RNUM, T.LPROD_GU, T.LPROD_NM
, T.BUYER_ID, T.BUYER_NAME, T.BUYER_LGU
FROM
(
SELECT ROW_NUMBER() OVER(ORDER BY LPROD_NM, BUYER_ID) RNUM
, L.LPROD_GU
, L.LPROD_NM
, B.BUYER_ID
, B.BUYER_NAME
, B.BUYER_LGU
FROM LPROD L INNER JOIN BUYER B
ON(L.LPROD_GU = B.BUYER_LGU)
WHERE 1 = 1
<if test="keyWord!=null and keyWord!=''">
AND (L.LPROD_GU LIKE '%'||#{keyWord}||'%'
OR L.LPROD_NM LIKE '%'||#{keyWord}||'%'
OR B.BUYER_ID LIKE '%'||#{keyWord}||'%'
OR B.BUYER_NAME LIKE '%'||#{keyWord}||'%')
</if>
) T
WHERE T.RNUM BETWEEN #{currentPage}*7-6 AND #{currentPage}*7
</select>
<!-- 상품분류 별 거래처 목록의 totalCount -->
<select id="listCount" parameterType="hashMap" resultType="int">
SELECT COUNT(*)
FROM LPROD L INNER JOIN BUYER B
ON(L.LPROD_GU = B.BUYER_LGU)
WHERE 1 = 1
<if test="keyWord!=null and keyWord!=''">
AND (L.LPROD_GU LIKE '%'||#{keyWord}||'%'
OR L.LPROD_NM LIKE '%'||#{keyWord}||'%'
OR B.BUYER_ID LIKE '%'||#{keyWord}||'%'
OR B.BUYER_NAME LIKE '%'||#{keyWord}||'%')
</if>
</select>
<!-- 거래처 상세 정보 -->
<select id="detail" parameterType="String" resultType="buyerVO">
SELECT (SELECT L.LPROD_NM FROM LPROD L WHERE L.LPROD_GU = B.BUYER_LGU) LPROD_NM
, B.BUYER_ID
, B.BUYER_NAME
, B.BUYER_LGU
, BUYER_BANK
, BUYER_BANKNO
, BUYER_BANKNAME
, BUYER_ZIP
, BUYER_ADD1
, BUYER_ADD2
, BUYER_COMTEL
, BUYER_FAX
, BUYER_MAIL
, BUYER_CHARGER
, BUYER_TELEXT
FROM BUYER B
WHERE B.BUYER_ID = #{buyerId}
</select>
</mapper>
package kr.or.ddit;
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;
@Repository
public class LprodDao {
@Autowired
SqlSessionTemplate sqlSessionTemplate;
public List<LprodVO> list(Map<String, Object> map){
return this.sqlSessionTemplate.selectList("lprod.list", map);
}
//상품분류 별 거래처 목록 행의 수
public int listCount(Map<String, Object> map) {
return this.sqlSessionTemplate.selectOne("lprod.listCount", map);
}
//거래처 상세 정보
public BuyerVO detail(String buyerId) {
return this.sqlSessionTemplate.selectOne("lprod.detail", buyerId);
}
}
package kr.or.ddit;
import java.util.List;
import java.util.Map;
public interface LprodService {
//메소드 시그니처 처리
//상품분류 별 거래처 목록
public List<LprodVO> list(Map<String, Object> map);
//상품분류 별 거래처 목록 행의 수
public int listCount(Map<String, Object> map);
//거래처 상세 정보
BuyerVO detail(String buyerId);
}
package kr.or.ddit;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class LprodServiceImpl implements LprodService {
@Autowired
LprodDao lprodDao;
@Override
public List<LprodVO> list(Map<String, Object> map){
return this.lprodDao.list(map);
}
//상품분류 별 거래처 목록 행의 수
@Override
public int listCount(Map<String, Object> map) {
return this.lprodDao.listCount(map);
}
//거래처 상세 정보
@Override
public BuyerVO detail(String buyerId) {
return this.lprodDao.detail(buyerId);
}
}
@RequestMapping 정리
///lprod/detail?buyerId=P10101 요렇게 넘어온다
//리턴 타입 : String => 뷰 파일의 경로와 파일 이름을 나타내기 위해 사용
@RequestMapping(value = "detail", method = RequestMethod.GET)
public String detail(Model model, @RequestParam String buyerId) {
logger.info("buyerId : " + buyerId);
BuyerVO buyerVO = this.lprodService.detail(buyerId);
//buyerVO이 null이면 오류를 보자
if(buyerVO! = null) {
logger.info("buyerVO : " + buyerVO.toString());
}
model.addAttribute("buyerVO", buyerVO);
//forward
//반환값이 lprod/detail이므로 lprod폴더의 detail.jsp를 리턴
return "/lprod/detail";
}
//detail.jsp에서 $("#buyerVO").submit();로 보내면 받는다!
//수정 요청 매핑
@RequestMapping(value = "/detail", method = RequestMethod.POST)
public String detailPost(@Validated BuyerVO buyerVO, BindingResult result) {
logger.info("buyerVO : " + buyerVO.toString());
//validation 중에 문제가 발생된다면 true
logger.info("result.hasErrors() : " + result.hasErrors());
//validation 문제가 발생된다면
//allErrors = globalErrors + fieldErrors
if(result.hasErrors()) {
List<ObjectError> allErrors = result.getAllErrors();
List<ObjectError> globalErrors = result.getGlobalErrors();
List<FieldError> fieldErrors = result.getFieldErrors();
//validation 중에 어떤 오류가 나왔는지 확인..
for(int i = 0; i<allErrors.size(); i++) {
ObjectError objectError = allErrors.get(i);
logger.info("objectError : " + objectError);
}
for(ObjectError objectError : globalErrors) {
logger.info("objectError : " + objectError);
}
for(FieldError fieldError : fieldErrors) {
logger.info("fieldError : " + fieldError.getDefaultMessage());
}
//문제가 발생되면 수정프로세스는 중단되고 되돌아감
return "lprod/detail";
}//end if
//수정 비즈니스 로직 처리 후
//상세 페이지로 되돌아감
return "redirect:/lprod/detail?buyerId="+buyerVO.getBuyerId();
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>상품분류 별 거래처 목록</title>
<!-- Custom fonts for this template-->
<link href="/resources/sbadmin2/vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">
<link
href="https://fonts.googleapis.com/css?family=Nunito:200,200i,300,300i,400,400i,600,600i,700,700i,800,800i,900,900i"
rel="stylesheet">
<!-- Custom styles for this template-->
<link href="/resources/sbadmin2/css/sb-admin-2.min.css" rel="stylesheet">
<script type="text/javascript">
function fn_submit() {
var frm = document.searchForm;
console.log("frm.size : " + frm.size.value);
console.log("frm.keyWord : " + frm.keyWord.value);
frm.submit();
}
</script>
</head>
<body id="page-top">
<!-- Page Wrapper -->
<div id="wrapper">
<!-- Sidebar -->
<jsp:include page="../includes/aside.jsp"></jsp:include>
<!-- End of Sidebar -->
<!-- Content Wrapper -->
<div id="content-wrapper" class="d-flex flex-column">
<!-- Main Content -->
<div id="content">
<!-- Topbar -->
<jsp:include page="../includes/header.jsp"></jsp:include>
<!-- End of Topbar -->
<!-- Begin Page Content 본문 시작 -->
<div class="container-fluid">
<div class="card o-hidden border-0 shadow-lg my-5">
<div class="card-body p-0">
<!-- Nested Row within Card Body -->
<div class="row">
<div class="col-lg-5 d-none d-lg-block bg-register-image"></div>
<div class="col-lg-7">
<div class="p-5">
<div class="text-center">
<h1 class="h4 text-gray-900 mb-4">${buyerVO.buyerName}</h1>
</div>
<form:form modelAttribute="buyerVO" class="user" method="post" action="/lprod/detail">
<div class="form-group row">
<div class="col-sm-6 mb-3 mb-sm-0">
<form:input path="buyerId" class="form-control form-control-user" id="buyerId" placeholder="" />
</div>
<div class="col-sm-6">
<form:input path="lprodNm" class="form-control form-control-user" id="lprodNm" placeholder="" />
</div>
</div>
<div class="form-group">
<form:input path="buyerMail" class="form-control form-control-user" id="buyerMail" placeholder="" />
<font color="red"><form:errors path="buyerMail" /></font>
</div>
<div class="form-group row">
<div class="col-sm-6 mb-3 mb-sm-0">
<form:input path="buyerComtel" class="form-control form-control-user" id="buyerComtel" />
<font color="red"><form:errors path="buyerComtel" /></font>
</div>
<div class="col-sm-6">
<form:input path="buyerCharger" class="form-control form-control-user" id="buyerCharger" />
<font color="red"><form:errors path="buyerCharger" /></font>
</div>
</div>
<a href="#" id="btnEdit" class="btn btn-primary btn-user btn-block">
수정
</a>
<a href="#" id="btnConfirm" style="display:none;" class="btn btn-success btn-icon-split btn-block">
<span class="icon text-white-50">
<i class="fas fa-check"></i>
</span>
<span class="text">확인</span>
</a>
<a href="#" id="btnCancel" style="display:none;" class="btn btn-danger btn-icon-split btn-block">
<span class="icon text-white-50">
<i class="fas fa-trash"></i>
</span>
<span class="text">취소</span>
</a>
<hr>
<a href="/lprod/list" class="btn btn-google btn-user btn-block">
<i class="fab fa-google fa-fw"></i> 목록보기
</a>
</form:form>
<hr>
<div class="text-center">
<a class="small" href="forgot-password.html">Forgot Password?</a>
</div>
<div class="text-center">
<a class="small" href="login.html">Already have an account? Login!</a>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- /.container-fluid 본문 끝-->
</div>
<!-- End of Main Content -->
<!-- Footer -->
<jsp:include page="../includes/footer.jsp"></jsp:include>
<!-- End of Footer -->
</div>
<!-- End of Content Wrapper -->
</div>
<!-- End of Page Wrapper -->
<!-- Scroll to Top Button-->
<a class="scroll-to-top rounded" href="#page-top">
<i class="fas fa-angle-up"></i>
</a>
<!-- Logout Modal-->
<div class="modal fade" id="logoutModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel"
aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">수정 요청</h5>
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">Select "Logout" below if you are ready to end your current session.</div>
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-dismiss="modal">취소</button>
<a class="btn btn-primary" id="modalConfirm" href="#">확인</a>
</div>
</div>
</div>
</div>
<!-- Bootstrap core JavaScript-->
<script src="/resources/sbadmin2/vendor/jquery/jquery.min.js"></script>
<script src="/resources/sbadmin2/vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Core plugin JavaScript-->
<script src="/resources/sbadmin2/vendor/jquery-easing/jquery.easing.min.js"></script>
<!-- Custom scripts for all pages-->
<script src="/resources/sbadmin2/js/sb-admin-2.min.js"></script>
<!-- Page level plugins -->
<script src="/resources/sbadmin2/vendor/chart.js/Chart.min.js"></script>
<!-- Page level custom scripts -->
<script src="/resources/sbadmin2/js/demo/chart-area-demo.js"></script>
<script src="/resources/sbadmin2/js/demo/chart-pie-demo.js"></script>
<script type="text/javascript">
$(function(){
$(".form-control-user").prop("readonly",true);
//수정버튼 클릭 시 수정버튼 사라지고, 확인/취소버튼 보임
$("#btnEdit").on("click",function(){
$(".form-control-user").prop("readonly",false);
//수정 대상이 아닌 요소 처리
//단, disabled -> true(X, 요소가 비활성됨) => form으로 안넘어감..
//readonly를 쓰자!
$("#buyerId").prop("readonly",true);
$("#lprodNm").prop("readonly",true);
//수정버튼 사라지고
$("#btnEdit").css("display", "none");
//확인/취소버튼 보임
$("#btnConfirm").css("display", "block");
$("#btnCancel").css("display", "block");
});
//취소버튼 클릭 시 새로고침 처리
$('#btnCancel').on("click",function(){
location.reload();
});
//확인버튼 클릭 시 수정 요청
$("#btnConfirm").on("click",function(){
$(".modal-body").html("해당 글을 수정 하시겠습니까?");
$("#logoutModal").modal("show");
});
//모달 확인 버튼 클릭 시 수정 프로세스 진행
$("#modalConfirm").on("click",function(){
$("#buyerVO").submit();
});
});
</script>
</body>
</html>