스프링에 서브쿼리 적용해보기

사원정보 출력 Project

EmpController.java

  • Service 사용자 요청을 받아서 데이터베이스 연동하고 JSP로 결과값 전송하기
Tip

MVC

  • Model (java) : Service
    • Spring에서는 Controller라는 이름이다.
    • 요청을 받아서 기능을 제어하는 프로그램이다.
  • View (JSP) : 화면출력
  • Controller : Model+jsp
    • Spring에서는 DispatcherServlet : Front Controller이다.
    • 요청을 받아서 Model+JSP를 연결해주는 역할이다.
  • @Controller 어노테이션 : Model

EmpVO.java

package com.haeni.dao;
import java.util.*;

public class EmpVO {
	private int empno;
	private String ename;
	private String job;
	private Date hiredate;
	private int sal;
	private int deptno;
	private String dname;
	private String loc;
	public int getEmpno() {
		return empno;
	}
	public void setEmpno(int empno) {
		this.empno = empno;
	}
	public String getEname() {
		return ename;
	}
	public void setEname(String ename) {
		this.ename = ename;
	}
	public String getJob() {
		return job;
	}
	public void setJob(String job) {
		this.job = job;
	}
	public Date getHiredate() {
		return hiredate;
	}
	public void setHiredate(Date hiredate) {
		this.hiredate = hiredate;
	}
	public int getSal() {
		return sal;
	}
	public void setSal(int sal) {
		this.sal = sal;
	}
	public int getDeptno() {
		return deptno;
	}
	public void setDeptno(int deptno) {
		this.deptno = deptno;
	}
	public String getDname() {
		return dname;
	}
	public void setDname(String dname) {
		this.dname = dname;
	}
	public String getLoc() {
		return loc;
	}
	public void setLoc(String loc) {
		this.loc = loc;
	}
	
}

interface EmpMapper

  • empListData : JOIN을 대체하는 서브쿼리
@Select("SELECT empno,ename,job,hiredate,sal,deptno,"
			+ "(SELECT dname FROM dept d WHERE e.deptno=d.deptno) as dname,"
			+ "(SELECT loc FROM dept d WHERE e.deptno=d.deptno) as loc"
			+ "FROM emp e")
	public List<EmpVO> empListData(); // 마이바티스에서 getConnection, disConnection 자동 구현 해줌
  • empGroupData : 클릭된 이름의 같은 부서 사람들 정보 가져오기
@Select("SELECT empno,ename,job,hiredate,sal,deptno "
			+ "FROM emp "
			+ "WHERE deptno=(SELECT deptno FROM dept WHERE ename=#{ename})")
	public List<EmpVO> empGroupData(String ename);
Note

SubQuery

  • SQL문장을 하나 묶어서 사용한다.
  • JOIN , 복잡한 쿼리 문장이 있는 경우 , SQL 문장이 많이 수행되는 경우 사용한다.
  • 여러 쿼리문장을 작성하는 것보다 하나의 서브쿼리 문장을 전송하는 것이 속도가 더 빠르다.
  • 종류 :
    1. 단일행 서브쿼리 : 조건문에서 WHERE 뒤에 많이 사용한다.
    2. 다중행 서브쿼리 : 조건문에서 WHERE 뒤에 많이 사용한다.
    3. 스칼라 서브쿼리 : 컬럼을 대체하는 프로그램
    4. 인라인 뷰(TOP-N) : 테이블을 대체하는 프로그램이다.
  • 실행 과정
    1. 서브쿼리가 먼저 실행되고 결과값을 메인쿼리에 전송한다. (( ) 우선 처리)
  • ALL / ANY = MIN /MAX
    • ALL : 전체 중에 가장 큰것/작은 것보다 큰것/작은것
    • ANY : 전체 중에 가장 큰것/작은 것

EmpDAO

  • @Autowired : 스프링에서 구현된 객체 받기
package com.haeni.dao;

import java.util.List;

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

public class EmpDAO {
	@Autowired
	private EmpMapper mapper;
	public List<EmpVO> empListData()
	{
		return mapper.empListData();
	};
	public List<EmpVO> empGroupData(String ename)
	{
		return mapper.empGroupData(ename);
	};
}

EmpController.java

  • @Autowired : 스프링에서 생성된 객체 EmpDAO 가져오기
    • @Autowired가 있으면 config xml 파일에서 등록된 id를 찾아서 메모리 할당된 것을 찾아준다.
    • 어디서 호출하더라고 똑같은 주소를 찾아준다. (한 사람 당, DAO는 한 번만 생성됨 => 싱글턴)
  • emp/list.do를 호출하면 /emp/list.jsp 반환하기
@RequestMapping("emp/list.do")
	public String emp_list(Model model)
	{
		List<EmpVO> list=dao.empListData();
		model.addAttribute("list",list); // request.setAttribute("list",list)
		return "list";
	}
  • 같은 부서에서 근무하는 사원 목록 결과 sublist.jsp로 전송하기
@RequestMapping("emp/sublist.do")
	public String emp_sublist(String ename,Model model)
	{
		if(ename==null)
			ename="KING";
		List<EmpVO> list = dao.empGroupData(ename);
		model.addAttribute("list",list);
		return "sublist";
	}

config

application-context.xml

<context:component-scan base-package="com.sist.*"/>
  • 데이터베이스 정보를 마이바티스로 전송하기
      1. 정보를 모아서 처리하기 : BasicDataSource
      1. getConnection/disConnection
      1. mapper 인터페이스 구현
<bean id="ds" class="org.apache.commons.dbcp.BasicDataSource"
	p:driverClassName="oracle.jdbc.driver.OracleDriver"
	p:url="jdbc:oracle:thin:@localhost:XE"
	p:username="hr"
	p:password="happy"
/>
<bean id="ssf"
	class="org.mybatis.spring.SqlSessionFactoryBean"
	p:dataSource-ref="ds"
/>
<bean id="mapper"
	class="org.mybatis.spring.mapper.MapperFactoryBean"
	p:mapperInterface="com.haeni.dao.EmpMapper"
	p:sqlSessionFactory-ref="ssf"
/>
Tip

데이터 구조

  • 데이터베이스(≒폴더) : XE , ora , orcl , pubs…
  • 테이블(≒파일)
  • ViewResolver : JSP를 찾아서 request를 전송하기
    • DispatcherServlet과 WebApplicationContext(Container)
    • WebApplicationContext
      • HandlerMapping : 클래스 찾기
      • ViewResolver : JSP찾기
        **ViewResolver**
        (prefix)main/main(suffix)
        /mian/main.jsp
      
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/emp/"
p:suffix=".jsp"
/>
Tip

무료로 설치 가능한 버전

  • 오라클 : XE
  • JAVA : openjdk 15
  • STS : 3.9.14
    • 스프링 5.0 (STS 4:Spring Boot)

view

list.jsp

  • 리액트
    • ES 5.0 => text/javascript
    • ES 6.0 => text/babel => react (ES6) => jsx(javascript+XML)
      • jsx : 1. 대소문자 구분 , 2. 여는태그/닫는태그 동일 , 3. 태그를 사용할 경우 소문자로 시작
  • 리액트는 문법 사항이 까다롭지만, ajax가 포함되어 있다는 장점이 있다.
<%@ 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="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<style type="text/css">
.row {
   margin: 0px auto;
   width:900px;
}
</style>
<script src="https://unpkg.com/react@15/dist/react.js"></script>
<script src="https://unpkg.com/react-dom@15/dist/react-dom.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.js"></script>
</head>
<body>
	<div class="container">
		<div class="row" id="root">
		
		</div>
	</div>
	<!-- 리액트 스크립트  -->
	<script type="text/babel">
		class Emp extends React.Component{
			render()
			{
				return (
					<table className="table table-striped">
						<thead>
							<tr className="sucess">
								<th>사번</th>
								<th>이름</th>
								<th>직위</th>
								<th>입사일</th>
								<th>부서명</th>
								<th>근무지</th>
							</tr>						
						</thead>
						<tbody>
							<c:forEach var="vo" items="${list}">
								<tr>
								<td>${vo.empno}</td>
								<td>${vo.ename}</td>
								<td>${vo.job}</td>
								<td><fmt:formatDate value="${vo.hiredate}" pattern="yyyy-MM-dd"/></td>
								<td>${vo.dname}</td>
								<td>${vo.loc}</td>
								</tr>
							</c:forEach>
						</tbody>
					</table>
				)
			}
		}
		ReactDOM.render(<Emp/>,document.getElementById('root'))
	</script>
</body>
</html>

list2.jsp

  • 리액트 없이 사원 목록 출력하기
  • ajax로 sublist.do의 호출 결과를 <div id="print"></div> 에 출력하기

sublist.jsp

  • empGroupData 쿼리 결과 표로 출력하기