오늘의 코딩순서
(폴더: oBootMybatis01)
2. 직원부서조회(Join/Mail 전송)
1. 기본 틀
- index.html + EmpDept.class
2. 페이징 작업 - 메인 페이지 + List
- listEmpDept.jsp
+ EmpController.class + EmpService.interface + EmpServiceImpl.class + EmpDao.interface+ EmpDaoImpl.class + EmpDept.xml(신규작성) + configuration.xml(추가)
3. 메일 보내기
- application.yml + mailResult.jsp + EmpController.class
3. PL/SQL 연동 - 부서입력
==> return 값 없이, call by reference로 값 전해주기
- writeDept.jsp + DeptVO.class
+ EmpController.class + EmpService.interface + EmpServiceImpl.class
+ Dept Dao.interface + DeptDaoImpl.class + Dept.xml + configuration.xml
+ Dept_Insert3.sql
4. PL/SQL 연동 - 부서조회
==> parameter를 DTO 방식이 아닌, Map 방식으로 넘겨주기
- writeDeptCursor.jsp
+ EmpController.class + EmpService.interface + EmpServiceImpl.class
+ Dept Dao.interface + DeptDaoImpl.class + Dept.xml
+ Dept_Insert3.sql
오늘의 코딩 포인트
2. 직원부서조회(Join/Mail 전송)
1. 기본 틀
- index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>회원 관리</h1>
<a href="/listEmpStart">회원 목록(기본 CRUD)</a><p>
<a href="/listEmpDept">직원부서조회(Join/Mail전송)</a><p>
<a href="/writeDeptIn">PL/SQL(부서입력) </a><p>
<a href="/writeDeptCursor">PL/SQL(부서조회 Cursor) </a><p>
<a href="/memberJpa/new">JPA Member(CRUD) </a><p>
<a href="/interCeptorForm">interCeptor(가로채기) </a><p>
<a href="/upLoadFormStart">UpLoad(이미지 올리기) </a><p>
<a href="/ajaxForm">Ajax Form Test </a><p>
<a href="/transactionInsertUpdate">Transaction Test</a><p>
</body>
</html>
- EmpDept.class => Emp TBL과 Dept TBL을 Join하는 목적의 DTO
package com.oracle.oBootMybatis01.model;
import lombok.Data;
// Emp TBL과 Dept TBL을 Join하는 목적의 DTO
@Data
public class EmpDept {
// Emp 용
private int empno;
private String ename;
private String job;
private int mgr;
private String hiredate;
private int sal;
private int comm;
private int deptno;
// Dept용 (많다는 가정)
private String dname;
private String loc;
}
2. 페이징 작업 - 메인 페이지 + List
- listEmpDept.jsp
Tip)- SMTP( Simple Mail Transfer Protocol)
- 인터넷을 통해 이메일 메시지를 보내고 받는 데 사용되는 통신 표준 프로토콜
- 이메일을 송수신하는 서버를 SMTP 서버라고 함
- 중계전달자 역할을 함으로써 메일 서버 간의 송수신 뿐만 아니라 메일 클라이언트에서 서버로 보낼 때 사용되는 프로토콜
- 인터넷에서 이메일을 교환할 때 그 과정을 정렬해줌
- SMTP( Simple Mail Transfer Protocol)
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ include file="header.jsp" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2>회원 부서정보</h2>
<a href="mailTransport">Mail Test(SMTP)</a>
<table>
<tr>
<th>사번</th> <th>이름</th> <th>업무</th>
<th>부서</th> <th>근무지</th>
</tr>
<c:forEach var="empDept" items="${listEmpDept}">
<tr>
<td>${empDept.empno}</td> <td>${empDept.ename}</td>
<td>${empDept.job}</td> <td>${empDept.deptno}</td>
<td>${empDept.loc}</td>
</c:forEach>
</table>
</body>
</html>
- EmpController.class
package com.oracle.oBootMybatis01.controller;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import com.oracle.oBootMybatis01.model.Dept;
import com.oracle.oBootMybatis01.model.Emp;
import com.oracle.oBootMybatis01.model.EmpDept;
import com.oracle.oBootMybatis01.service.EmpService;
import com.oracle.oBootMybatis01.service.Paging;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Controller
@RequiredArgsConstructor
@Slf4j
public class EmpController {
private final EmpService es;
// << 2.직원부서조회=> Emp TBL과 Dept TBL을 Join >>
// (0813) 현장 HW 1-1
// Service ,DAO -> listEmpDept
// Mapper만 ->EmpDept.xml(tkListEmpDept)
@GetMapping(value = "listEmpDept")
public String listEmpDept(Model model) {
System.out.println("EmpController listEmpDept Start...");
List<EmpDept> listEmpDept = es.listEmpDept();
model.addAttribute("listEmpDept", listEmpDept);
return "listEmpDept";
}
}
- EmpService.interface
package com.oracle.oBootMybatis01.service;
import java.util.List;
import com.oracle.oBootMybatis01.model.Dept;
import com.oracle.oBootMybatis01.model.Emp;
import com.oracle.oBootMybatis01.model.EmpDept;
public interface EmpService {
// (0813) 현장 HW 1-2
List<EmpDept> listEmpDept();
}
- EmpServiceImpl.class
package com.oracle.oBootMybatis01.service;
import java.util.List;
import org.springframework.stereotype.Service;
import com.oracle.oBootMybatis01.dao.DeptDao;
import com.oracle.oBootMybatis01.dao.EmpDao;
import com.oracle.oBootMybatis01.model.Dept;
import com.oracle.oBootMybatis01.model.Emp;
import com.oracle.oBootMybatis01.model.EmpDept;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class EmpServiceImpl implements EmpService {
private final EmpDao ed;
private final DeptDao dd;
// 서로 다른 Interface(DAO)를 받은 것이기 때문에 두 개 이상 가능
// << 2.직원부서조회=> Emp TBL과 Dept TBL을 Join >>
// (0813) 현장 HW 1-3
@Override
public List<EmpDept> listEmpDept() {
List<EmpDept> empDeptList = null;
System.out.println("EmpServiceImpl listEmpDept Start...");
empDeptList = ed.listEmpDept();
System.out.println("EmpServiceImpl listEmpDept empDeptList->"+empDeptList.size());
return empDeptList;
}
}
- EmpDao.interface
package com.oracle.oBootMybatis01.dao;
import java.util.List;
import com.oracle.oBootMybatis01.model.Emp;
import com.oracle.oBootMybatis01.model.EmpDept;
public interface EmpDao {
// (0813) 현장 HW 1-4
List<EmpDept> listEmpDept();
}
- EmpDaoImpl.class
package com.oracle.oBootMybatis01.dao;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import org.springframework.stereotype.Repository;
import com.oracle.oBootMybatis01.model.Emp;
import com.oracle.oBootMybatis01.model.EmpDept;
import lombok.RequiredArgsConstructor;
@Repository
@RequiredArgsConstructor
public class EmpDaoImpl implements EmpDao {
// Mybatis DB 연동
private final SqlSession session;
// << 2.직원부서조회=> Emp TBL과 Dept TBL을 Join >>
// (0813) 현장 HW 1-5
@Override
public List<EmpDept> listEmpDept() {
System.out.println("EmpDaoImpl listEmpDept Start...");
List<EmpDept> empDept = null;
try {
empDept = session.selectList("tkListEmpDept");
System.out.println("EmpDaoImpl listEmpDept empDept.size()->"+empDept.size());
} catch (Exception e) {
System.out.println("EmpDaoImpl delete Exception->"+e.getMessage());
}
return empDept;
}
}
- EmpDept.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="com.oracle.oBootMybatis01.EmpDeptMapper">
<select id="tkListEmpDept" resultType="EmpDept">
SELECT e.empno, e.ename, e.job, d.deptno, d.loc
FROM emp e, dept d
WHERE e.deptno=d.deptno
ORDER BY empno
</select>
</mapper>
- configuration.xml (Left Outer Join) (이걸로 사용하기
<?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="com.oracle.oBootMybatis01.EmpDeptMapper">
<select id="tkListEmpDept" resultType="EmpDept">
SELECT e.empno, e.ename, e.job, d.deptno, d.loc
FROM emp e, dept d
WHERE e.deptno=d.deptno(+)
ORDER BY empno
</select>
</mapper>
+++ OUTER JOIN 활용방법 => 0627 일지 참고
- configuration.xml (Join 없는 버전)
<?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="com.oracle.oBootMybatis01.EmpDeptMapper">
<select id="tkListEmpDept3" resultType="EmpDept">
SELECT e.empno, e.ename, e.job, d.deptno, d.loc
FROM emp e, dept d
WHERE e.deptno=d.deptno
ORDER BY empno
</select>
</mapper>
- configuration.xml (Right Outer Join)
<?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="com.oracle.oBootMybatis01.EmpDeptMapper">
<select id="tkListEmpDept4" resultType="EmpDept">
SELECT e.empno, e.ename, e.job, d.deptno, d.loc
FROM emp e, dept d
WHERE e.deptno(+)=d.deptno
ORDER BY empno
</select>
</mapper>
3. 메일 보내기
- application.yml => 여기서 비번은 구글 앱 비밀번호 만들기에서 임시로 만든 비번
https://myaccount.google.com/apppasswords?pli=1&rapt=AEjHL4NfvtLF1HDYgCM8_SCrd3TUQ205tkjl8xhWINgJKGRdfhosKkYHH1slBLeoIr3bo_DxqJBk3gOIZDK-AktkMKhcyywcqI89U_F9tYe1y5fXgcHHQqw
server:
port: 8387
# Oracle Connect
spring:
datasource:
driver-class-name: oracle.jdbc.OracleDriver
url: jdbc:oracle:thin:@localhost:1521/xe
username: scott
password: tiger
#JPA Setting
jpa:
show-sql: true
hibernate:
ddl-auto: update
# View Resolver
mvc:
view:
prefix: /WEB-INF/views/
suffix: .jsp
# gmail Transfer
mail:
host: smtp.gmail.com
port: 587
username: rollout147@gmail.com
password: bbwt lmdi vhew burk
properties:
mail:
smtp:
auth: true
starttls.enable: true
# Mybatis
mybatis:
config-location: classpath:configuration.xml
mapper-locations: classpath:mappers/*.xml
- mailResult.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ include file="header.jsp" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>Mail 전송 결과</h1>
<c:if test="${check==1}">성공적으로 전송되었습니다</c:if>
<c:if test="${check!=1}">메일전송에 실패했습니다</c:if>
<c:if test="${check==null}">메일전송에 실패했습니다</c:if>
</body>
</html>
- EmpController.class
Tip)- Mime(Multipurpose intenet mail extension): 전자 우편을 위한 인터넷 표준 포맷
package com.oracle.oBootMybatis01.controller;
import java.util.List;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import com.oracle.oBootMybatis01.model.Dept;
import com.oracle.oBootMybatis01.model.Emp;
import com.oracle.oBootMybatis01.model.EmpDept;
import com.oracle.oBootMybatis01.service.EmpService;
import com.oracle.oBootMybatis01.service.Paging;
import jakarta.mail.internet.MimeMessage;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Controller
@RequiredArgsConstructor
@Slf4j
public class EmpController {
private final EmpService es;
private final JavaMailSender mailSender;
// 2.직원부서조회 => Mail 보내기
@RequestMapping(value="mailTransport")
public String mailTransport(HttpServletRequest request, Model model) {
System.out.println("mailSending...");
String tomail = "rollout147@naver.com"; // 받는 사람 이메일
System.out.println(tomail);
String setfrom = "rollout147@gmail.com"; // 보내는 사람 이메일
String title = "mailTransport 입니다"; // 메일 제목
try {
// Mime: 전자우편 Internet 표준 Format
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper messageHelper = new MimeMessageHelper(message, true, "UTF-8");
messageHelper.setFrom(setfrom); // 보내는사람을 생략하면 정상작동 안함
messageHelper.setTo(tomail); // 받는사람 이메일 주소
messageHelper.setSubject(title); // 메일 제목은 생략이 가능함
String tempPassword = (int) (Math.random() * 999999) + 1 + "";
messageHelper.setText("임시 비밀번호입니다 : " + tempPassword); // 메일내용
System.out.println("임시 비밀번호입니다 : " + tempPassword);
mailSender.send(message);
model.addAttribute("check",1); //정상 전달
// DB 로직
} catch (Exception e) {
System.out.println("mailTransport e.getMessage()->"+e.getMessage());
model.addAttribute("check", 2); // 메일 전달 실패
}
return "mailResult";
}
}
3. PL/SQL 연동 - 부서입력
Tip) return 값 없이, call by reference로 값 전해주기
- 스프링에서 Call by Reference를 이용하면 메서드 내부에서 객체의 상태를 변경하고, 그 변경된 상태를 반환하지 않고도 메서드 외부에서 확인할 수 있음
==> 이는 객체의 참조가 메서드에 전달되기 때문에 가능한 것이며, Java의 객체 다루기 방식에 기반한 자연스러운 동작 - Java에서 객체(클래스의 인스턴스) 타입의 경우, 메서드 호출 시 객체의 **참조값(Reference)**이 복사되어 전달됨.
즉, 메서드 내부에서 객체의 속성(필드)을 변경하면 그 변화가 메서드를 호출한 쪽에서도 반영된다는 뜻임
- writeDept.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%><%@ include file="header.jsp" %>
<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
function chk() {
/* if (!frm.empno.value) {
alert("사번을 입력한 후에 확인하세요");
frm.empno.focus();
return false;
} else location.href="confirm.do?empno="+frm.empno.value; */
}
</script>
</head>
<body>
<h2>부서정보 입력</h2>
<c:if test="${msg!=null}">${msg}</c:if>
<form action="writeDept" method="post" name="frm">
<table>
<tr><th>부서번호</th><td><input type="number" name="deptno"
required="required" maxlength="2" >
<input type="button" value="중복확인:미구현" onclick="chk()"> </td></tr>
<tr><th>부서이름</th><td><input type="text" name="dname"
required="required"> </td></tr>
<tr><th>부서위치</th><td><input type="text" name="loc"
required="required"></td></tr>
<tr><td colspan="2">
<input type="submit" value="확인"></td></tr>
</table>
입력된 부서번호 :<c:if test="${dept.odeptno!=null}">${dept.odeptno}</c:if><p>
입력된 부서명 :<c:if test="${dept.odname!=null}">${dept.odname}</c:if><p>
입력된 부서위치 :<c:if test="${dept.oloc!=null}">${dept.oloc}</c:if><p>
<%-- ${deptVO.Oloc} --%>
<h2>부서 정보 List</h2>
<table>
<tr><th>부서명</th><th>부서이름</th><th>근무지</th></tr>
<c:forEach var="listDept" items="${listDept}">
<tr><td>${listDept.odeptno }</td>
<td>${listDept.odname }</td>
<td>${listDept.oloc }</td>
</tr>
</c:forEach>
</table>
</form>
</body>
</html>
- DeptVO.class
package com.oracle.oBootMybatis01.model;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class DeptVO {
//입력
private int deptno;
private String dname;
private String loc;
//출력
private int odeptno;
private String odname;
private String oloc;
}
- EmpController.class
package com.oracle.oBootMybatis01.controller;
import java.util.List;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import com.oracle.oBootMybatis01.model.Dept;
import com.oracle.oBootMybatis01.model.DeptVO;
import com.oracle.oBootMybatis01.model.Emp;
import com.oracle.oBootMybatis01.model.EmpDept;
import com.oracle.oBootMybatis01.service.EmpService;
import com.oracle.oBootMybatis01.service.Paging;
import jakarta.mail.internet.MimeMessage;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Controller
@RequiredArgsConstructor
@Slf4j
public class EmpController {
private final EmpService es;
private final JavaMailSender mailSender;
// PL/SQL 연동
// 1. Procedure Test 입력화면
@RequestMapping(value = "writeDeptIn")
public String writeDeptIn(Model model) {
System.out.println("writeDeptIn Start...");
return "writeDept3";
}
// 2. Procedure를 통해 Dept 입력 후 VO 전달
@RequestMapping(value = "writeDept")
public String writeDept(DeptVO deptVO, Model model) {
es.insertDept(deptVO);
if (deptVO == null) {
System.out.println("deptVO NULL");
} else {
System.out.println("deptVO.getOdeptno()->"+deptVO.getOdeptno());
System.out.println("deptVO.getOdname()->"+deptVO.getOdname());
System.out.println("deptVO.getOloc()->"+deptVO.getOloc());
model.addAttribute("msg", "정상 입력 되었습니다");
model.addAttribute("dept", deptVO);
}
return "writeDept3";
}
- EmpService.interface
package com.oracle.oBootMybatis01.service;
import java.util.List;
import com.oracle.oBootMybatis01.model.Dept;
import com.oracle.oBootMybatis01.model.DeptVO;
import com.oracle.oBootMybatis01.model.Emp;
import com.oracle.oBootMybatis01.model.EmpDept;
public interface EmpService {
// (0813) 현장 HW 1-2. Emp TBL과 Dept TBL을 Join
List<EmpDept> listEmpDept();
// PL/SQL 연동
void insertDept(DeptVO deptVO);
}
- EmpServiceImpl.class
package com.oracle.oBootMybatis01.service;
import java.util.List;
import org.springframework.stereotype.Service;
import com.oracle.oBootMybatis01.dao.DeptDao;
import com.oracle.oBootMybatis01.dao.EmpDao;
import com.oracle.oBootMybatis01.model.Dept;
import com.oracle.oBootMybatis01.model.DeptVO;
import com.oracle.oBootMybatis01.model.Emp;
import com.oracle.oBootMybatis01.model.EmpDept;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class EmpServiceImpl implements EmpService {
private final EmpDao ed;
private final DeptDao dd;
// 서로 다른 Interface(DAO)를 받은 것이기 때문에 두 개 이상 가능
// PL/SQL 연동
@Override
public void insertDept(DeptVO deptVO) {
System.out.println("EmpServiceImpl insertDept Start...");
dd.insertDept(deptVO);
}
}
- DeptDao.interface
package com.oracle.oBootMybatis01.dao;
import java.util.List;
import com.oracle.oBootMybatis01.model.Dept;
import com.oracle.oBootMybatis01.model.DeptVO;
public interface DeptDao {
// Emp TBL과 Dept TBL을 Join
List<Dept> deptSelect();
// PL/SQL 연동
void insertDept(DeptVO deptVO);
}
- DeptDaoImpl.class
package com.oracle.oBootMybatis01.dao;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import org.springframework.stereotype.Repository;
import com.oracle.oBootMybatis01.model.Dept;
import com.oracle.oBootMybatis01.model.DeptVO;
import lombok.RequiredArgsConstructor;
@Repository
@RequiredArgsConstructor
public class DeptDaoImpl implements DeptDao {
// Mybatis 연동
private final SqlSession session;
// 2.직원부서조회
// PL/SQL 연동
@Override
public void insertDept(DeptVO deptVO) {
System.out.println("DeptDaoImpl insertDept Start...");
session.selectOne("procDeptInsert", deptVO);
}
}
- Dept.xml
Tip) mode와 jdbcType의 대소문자는 꼭 이대로 써야함- statementType
<?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="com.oracle.oBootMybatis01.DeptMapper">
<select id="procDeptInsert" parameterType="DeptVO" statementType="CALLABLE">
{
call Dept_Insert3(
#{deptno , mode=IN , jdbcType=INTEGER}
, #{dname , mode=IN , jdbcType=VARCHAR}
, #{loc , mode=IN , jdbcType=VARCHAR}
, #{odeptno , mode=OUT , jdbcType=INTEGER}
, #{odname , mode=OUT , jdbcType=VARCHAR}
, #{oloc , mode=OUT , jdbcType=VARCHAR}
)
}
</select>
</mapper>
- configuration.xml
<?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>
<typeAliases>
<typeAlias alias="Emp" type="com.oracle.oBootMybatis01.model.Emp"/>
<typeAlias alias="Dept" type="com.oracle.oBootMybatis01.model.Dept"/>
<typeAlias alias="EmpDept" type="com.oracle.oBootMybatis01.model.EmpDept"/>
<typeAlias alias="DeptVO" type="com.oracle.oBootMybatis01.model.DeptVO"/>
</typeAliases>
</configuration>
- Dept_Insert3.sql ==> 프로시저
create or replace PROCEDURE Dept_Insert3
(vdeptno IN dept.deptno%type, vdname IN dept.dname%TYPE, vloc in dept.loc%type,
p_deptno OUT dept.deptno%type, p_dname OUT dept.dname%TYPE, p_loc OUT dept.loc%TYPE)
IS
BEGIN
INSERT INTO dept VALUES(vdeptno, vdname, vloc);
commit;
DBMS_OUTPUT.ENABLE;
-- %TYPE 데이터형 변수 사용
SELECT deptno, dname, loc
INTO p_deptno, p_dname, p_loc
FROM dept
WHERE deptno = vdeptno
;
-- 결과값 출력
DBMS_OUTPUT.PUT_LINE('부서번호:'||p_deptno);
DBMS_OUTPUT.PUT_LINE('부서이름:'||p_dname);
DBMS_OUTPUT.PUT_LINE('부서위치:'||p_loc);
END
;
4. PL/SQL 연동 - 부서조회
==> parameter를 DTO 방식이 아닌, Map 방식으로 넘겨주기
∴ configuration.xml이 필요없음
항목 | Map 방식 | DTO 방식 |
정의 | ||
parameter 형식 | random으로 자유롭게 정의 | - Table 기준으로 선언함 - 필요시 참조 Column도 입력 가능 |
언제 사용? | 1. 규정을 정하기 힘들 때 2. 팀원과의 소통이 원활하지 않을 때 (ex. 다른 회사팀과의 협력) 3. 사용 빈도 낮음 |
1. 규정이 있을 때 기준에 의거하여 사용함 2. 사용 빈도 높음 |
장점 | 1. 개발시간이 짧음 2. 필요 데이터를 여러 DTO에 나눠 담을 때는 각각의 VO에 담아서 전부 전달하기 어려우므로, Map에 필요한 데이터만 담아서 전달함 3. 단일 Key값을 갖는 경우에는 Controller에서 Collections.singletonMap로 응답을 반환하기도 함 4. 밑의 단점이 부각되지 않는 상황이라면 오히려 좋아지는 케이스도 있음 |
1. 명확하여 유지보수가 쉬움(추천↑↑)⭐ 2. 추가적으로 정적 팩토리 메소드를 구현할 수 있음 3. 빌더 패턴을 적용할 수 있어서 유용함 |
단점 | 1. 유지보수가 어려움 2. 직관성이 떨어짐 3. 안정성이 떨어짐 4. 코드 가독성이 떨어짐 5. 타입캐스팅을 필요로 하여 비용이 증가함 6. 컴파일 에러를 유발할 수 없음 7. String 텍스트를 Key로 사용함 8. 불변성을 확보할 수 없음 |
개발시간이 김 |
- writeDeptCursor.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ include file="header.jsp" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2>부서 정보 Procedure Cursor List</h2>
<table>
<tr><th>부서명</th> <th>부서이름</th> <th>근무지</th></tr>
<c:forEach var="listDept" items="${deptList}">
<tr>
<td>${listDept.deptno }</td>
<td>${listDept.dname }</td>
<td>${listDept.loc }</td>
</tr>
</c:forEach>
</table>
</body>
</html>
- EmpController.class
Tip)- parameter를 DTO로 넘겨주는 방식과 Map 방식으로 넘겨주는 방식의 차이⭐⭐
package com.oracle.oBootMybatis01.controller;
import java.util.HashMap;
import java.util.List;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import com.oracle.oBootMybatis01.model.Dept;
import com.oracle.oBootMybatis01.model.DeptVO;
import com.oracle.oBootMybatis01.model.Emp;
import com.oracle.oBootMybatis01.model.EmpDept;
import com.oracle.oBootMybatis01.service.EmpService;
import com.oracle.oBootMybatis01.service.Paging;
import jakarta.mail.internet.MimeMessage;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Controller
@RequiredArgsConstructor
@Slf4j
public class EmpController {
private final EmpService es;
private final JavaMailSender mailSender;
// PL/SQL 연동 후 부서 조회
// DTO방식이 아닌, Map 방식 적용
@GetMapping(value = "writeDeptCursor")
public String writeDeptCursor(Model model) {
System.out.println("EmpController writeDeptCursor Start...");
// 부서범위 조회
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("sDeptno", 10);
map.put("eDeptno", 55);
es.selListDept(map);
//DAO의 map이 이 map로 넘어감
List<Dept> deptLists = (List<Dept>) map.get("dept");
// Dept.xml의 #{dept 임
for(Dept dept : deptLists) {
System.out.println("dept.getDname()->"+dept.getDname());
System.out.println("dept.getLoc()->"+dept.getLoc());
}
System.out.println("deptList Size->"+deptLists.size());
model.addAttribute("deptList", deptLists);
return "writeDeptCursor";
}
}
- EmpService.interface
package com.oracle.oBootMybatis01.service;
import java.util.HashMap;
import java.util.List;
import com.oracle.oBootMybatis01.model.Dept;
import com.oracle.oBootMybatis01.model.DeptVO;
import com.oracle.oBootMybatis01.model.Emp;
import com.oracle.oBootMybatis01.model.EmpDept;
public interface EmpService {
// (0813) 현장 HW 1-2. Emp TBL과 Dept TBL을 Join
List<EmpDept> listEmpDept();
// PL/SQL 연동
void insertDept(DeptVO deptVO);
void selListDept(HashMap<String, Object> map);
}
- EmpServiceImpl.class
package com.oracle.oBootMybatis01.service;
import java.util.HashMap;
import java.util.List;
import org.springframework.stereotype.Service;
import com.oracle.oBootMybatis01.dao.DeptDao;
import com.oracle.oBootMybatis01.dao.EmpDao;
import com.oracle.oBootMybatis01.model.Dept;
import com.oracle.oBootMybatis01.model.DeptVO;
import com.oracle.oBootMybatis01.model.Emp;
import com.oracle.oBootMybatis01.model.EmpDept;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class EmpServiceImpl implements EmpService {
private final EmpDao ed;
private final DeptDao dd;
// 서로 다른 Interface(DAO)를 받은 것이기 때문에 두 개 이상 가능
// PL/SQL 연동 후 부서 조회
@Override
public void selListDept(HashMap<String, Object> map) {
System.out.println("EmpServiceImpl selListDept Start...");
dd.selListDept(map);
}
}
- Dept Dao.interface
package com.oracle.oBootMybatis01.dao;
import java.util.HashMap;
import java.util.List;
import com.oracle.oBootMybatis01.model.Dept;
import com.oracle.oBootMybatis01.model.DeptVO;
public interface DeptDao {
// Emp TBL과 Dept TBL을 Join
List<Dept> deptSelect();
// PL/SQL 연동
void insertDept(DeptVO deptVO);
void selListDept(HashMap<String, Object> map);
}
- DeptDaoImpl.class
package com.oracle.oBootMybatis01.dao;
import java.util.HashMap;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import org.springframework.stereotype.Repository;
import com.oracle.oBootMybatis01.model.Dept;
import com.oracle.oBootMybatis01.model.DeptVO;
import lombok.RequiredArgsConstructor;
@Repository
@RequiredArgsConstructor
public class DeptDaoImpl implements DeptDao {
// Mybatis 연동
private final SqlSession session;
// PL/SQL 연동 후 부서 조회
@Override
public void selListDept(HashMap<String, Object> map) {
System.out.println("DeptDaoImpl selListDept Start...");
//ResultMap은 DB 컬럼명과 DTO의 변수 명이 다를 때 사용
session.selectOne("procDeptList", map);
//xml의 dept값이 map에 들어감
}
}
- Dept.xml
Tip)- resultMap
<?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="com.oracle.oBootMybatis01.DeptMapper">
<resultMap type="Dept" id="DeptResult">
<result property="deptno" column="deptno"/>
<result property="dname" column="dname"/>
<result property="loc" column="loc"/>
</resultMap>
<select id="procDeptList" parameterType="java.util.Map" statementType="CALLABLE">
{
call Dept_Cursor3(
#{sDeptno , mode=IN , jdbcType=INTEGER}
, #{eDeptno , mode=IN , jdbcType=INTEGER}
, #{dept , mode=OUT , jdbcType=CURSOR
, javaType=java.sql.ResultSet
, resultMap=DeptResult}
)
</select>
</mapper>
- Dept_Cursor3.sql
CREATE OR REPLACE PROCEDURE Dept_Cursor3
(sdeptno IN dept.deptno%TYPE, edeptno IN dept.deptno%TYPE,
Dept_Cursor OUT SYS_REFCURSOR
)
IS
BEGIN
OPEN Dept_Cursor
FOR
SELECT deptno, dname, loc
FROM dept
WHERE deptno
BETWEEN sdeptno AND edeptno
;
END Dept_Cursor3
;
질문목록
수업교재
오늘의 숙제
'Spring' 카테고리의 다른 글
2024_08_19_월~08_20_화 (0) | 2024.08.19 |
---|---|
2024_08_14_수 (0) | 2024.08.14 |
2024_08_12_월 (0) | 2024.08.12 |
2024_08_08_목~08_12_월 (0) | 2024.08.08 |
2024_08_07_수~08_08_목 (0) | 2024.08.07 |