[목차]

9. EL

 

 

[내용]

9. EL (Expression Language) : jsp는 문서내 <tag>와 java code를 혼용되게 사용하여 유지보수에 어려움이 있어

                                      java code의 사용을 줄이기 위해 개발된 언어.(code를 더 단순화 시킴)

    1) 연산자

     - 산술

${3+4}
${5/4}, ${5 div 4}
${5%4}, ${5 mod 4}

     - 관계

${3>4}, ${3 gt 4}
${3<=4}, ${3 le 4}

     - 논리

${5>4 and 3<2}

     - 3항

${5>4 ? 10:20}

 

    2) life cycle이 다른 내장객체에 따른 데이터 공유

<%
	request.setAttribute("a","air"); // 현재 페이지에서 유효
	session.setAttribute("b","book"); // 설정시간 동안 유효
	application.setAttribute("c","cat"); // 서비스가 유지되는 동안 사용. (지양)
%>
<%= request.getAttribute("a") %>
${requestScope.a}
${a} // requestScope는 생략가능

<%= session.getAttribute("b") %>
${sessionScope.b}

<%= application.getAttribute("c") %>
${applicationScope.c}

 

    3) 지시자

<%@ page isELIgnored="true" %> // EL를 파싱하지않도록 설정. default는 false.

 

    4) Parameter

    - jsp

<%= request.getParameter("userName") %>
<%
	String ir = request.getParameter("irum");
	String[] su = request.getParameterValues("sung");
%>
<%= request.getHeader("host") %>

    - EL

${param.userName}
${param.irum}
${param["irum"]}
${paramValues.sung[0] }
${paramValues.sung["1"] }
${header.host}
${header["host"]}

 

    5) collection

<%
	ArrayList list = new ArrayList();
	list.add("kor");
	list.add("eng");
	request.setAttribute("list", list);
%>

    - jsp

<%
	ArrayList list2 = (ArrayList)request.getAttribute("list");

	out.println(list.get(0));
	out.println(list.get(1));
%>

    - EL

${list[0]}
${list["1"]}

 

10. JSTL(Jsp Standard Tag Library) : jsp에 기능을 더 한 tag 라이브러리(메소드)

 

    1) driver 추가

/context/WEB_INF/lib경로에 jstl-1.2.jar 추가

    2) 지시자 추가

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>

    3) 변수
     - 문자열

<c:set var="변수" value="값" scope="page"/> // scope에 request, session, application, page 사용 가능
<c:out value="${변수}"></c:out>

<c:set var="변수" scope="session">값</c:set>
<c:out value="${변수}"></c:out>

     - 배열

<c:set var="aa" value="${header['User-Agent']}" scope="page"/>
<c:out value="${aa}"></c:out>
<c:remove var="aa" scope="page"/>
<c:out value="${aa}"></c:out>

 

     - 숫자

<c:set var="num1" value="10"></c:set>
<c:set var="num2">20.5</c:set>
${num1+num2}

 

    4) 조건문 if

<c:set var="bb" value="${'star' }"/>
<c:out value="${bb }"></c:out>

<c:if test="${bb == 'star' }">
	// 실행문
</c:if>
<c:set var="cc" value=""/>
<c:out value="${cc }"></c:out>

<c:if test="${cc != '' && cc ne null}">
	// 실행문
</c:if>

 

    5) 조건문 choose

<c:choose>
	<c:when test="${bb eq 'moon' }">
		실행값1
	</c:when>
	<c:when test="${bb eq 'star' }">
		실행값2
	</c:when>
	<c:otherwise>나머지경우</c:otherwise>
</c:choose>
<c:choose>
	<c:when test="${empty param.name }">
		<form>
			<input type="text" name="name">
			<input type="submit" value="확인">
		</form>
	</c:when>
	<c:when test="${param.name == 'admin' }">
		관리자
	</c:when>
	<c:otherwise>
		<c:out value="${param.name }"/>
	</c:otherwise>
</c:choose>

 

    6) 반복문 for each

<c:forEach var="cc" begin="1" end="10" step="1">
	<c:out value="${cc }"/>
	${cc }
</c:forEach>
<c:forEach var="i" begin="1" end="9">
3 * ${i } = ${3*i }<br>
</c:forEach>

 

    7) 이중 for

<c:forEach var="h" items="${headerValues}">
	<c:out value="${h.key}"></c:out>
	<c:forEach var="i" items="${h.value}">
		<c:out value="${i}">&nbsp;</c:out>
	</c:forEach>
</c:forEach>

 

    8) collection

<% 
	HashMap map = new HashMap();
	map.put("name","홍길동");
	map.put("today",new Date());
%>

     - map

<c:set var ="m" value="<%=map%>"/>

<c:forEach var = "mbc" items="${m}">
	${mbc.key} : ${mbc.value}
</c:forEach>

     - 배열

<c:set var ="arr" value="<%=new int[]{1,2,3,4,5}%>"/>

<c:forEach var = "i" items="${arr}" begin="2" end="4" step="1">
	${i}
</c:forEach>

 

    6) 문자열 분할

<c:forTokens var="animal" items="horse,tiger,lion,pig,cat" delims=",">
	동물:${animal }
</c:forTokens>

<c:forTokens var="animal" items="horse,tiger*lion,pig*cat" delims=",*" varStatus="num">
	${num.count}) ${animal}
</c:forTokens><br>

 

    7)  숫자 및 날짜 출력 서식

    - 지시자

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
숫자
<fmt:formatNumber value="12345.678" type="number"/>
통화
<fmt:formatNumber value="12345.678" type="currency" currencySymbol="W"/>
백분율
<fmt:formatNumber value="12345.678" type="percent"/><br>
소수 이하
<fmt:formatNumber value="12345.678" pattern="#,##0.00"/>
 // 000.0은 무효라도 표시.(001.1)
 // ###.#은 0 값이 자리숫 첫번째에 존재하면 표시하지않는다. (1.1)

<c:set var="now" value="<%= new Date() %>"></c:set>
<c:out value="${now}"></c:out>

날짜
<fmt:formatDate value="${now}" type="date"/>
<fmt:formatDate value="${now}" type="both" dateStyle="full" pattern="yyyy년MM월dd일"/>
<fmt:formatDate value="${now}" type="both" dateStyle="full" pattern="yyyy-MM-dd"/>
시간
<fmt:formatDate value="${now}" type="time"/>

[목차]

8. Ajax

 

 

 

8. Ajax(Asynchronous Javascript And XML)

client request
--------->


response
<---------
server
1) 클라이언트의 뷰페이지에서 요청을
   보낸다.
2) XMLHttpRequest객체가 생성.
3) 요청처리.
6) 응답받은 메시지를 자바스크립트에서
   처리.(응답되는 데이터를 가지고 부분
   화면을 변경하기 위해서 javascript와
   DOM(JQuey) 사용)
7) 페이지를 업데이트.
4) 서버에서 request를 받는다.
5) request에 대한 처리(DBMS액세스)
    후 클라이언트에 응답을 보낸다.
    (데이터, 문자열, xml, json)

 

    [jsp]

    1) 버튼을 누르면 ajax요청을 하기 위해서 runAjax함수 호출.

<body>
	<form name = "myform">
		<input type="text" name="id">
		<button type="button" onclick="runAjax()">Ajax테스트</button>
	</form>
	<div id="result"></div>
</body>

 

    2) 비동기통신 처리를 할 수 있는 자바스크립트 객체를 생성 - XMLHttpRequest

<script type="text/javascript">
	function runAjax(){
		var xhr = new XMLHttpRequest();


    3-1) 요청설정

		open("request타입",url,true-async, false-sync)

     -GET

		xhr.open("GET","servlet 경로?id="+myform.id.value, true);

    - POST

		xhr.open("POST","/serverweb/ajaxtest_post.do", true);

    3-2) 요청보내기 - 비동기 통신으로 요청을 보낸다.

     -GET

		send(); // get방식
		xhr.send();

    - POST

		send("문자열"); // post방식
		xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
		xhr.send("id="+myform.id.value);

    => 요청헤더에 content-type을 변경.
    => form태그를 이용해서 요청하고 있지 않지만 form태그를 이용해서 요청하는 것처럼  key=value의 형식으로

        인코딩을 적용 .
    => ajax요청을 submit버튼을 눌러 요청할때 처럼 key를 이용해서 value를 추출해야 하므로 반드시 설정해야

        하는 정보.

 

    [servlet]

    4) 서버에서 request를 수신 - 처리

String id = request.getParameter("id");
String msg="";
if(id.equals("이미 존재하는 ID")) { // DBMS에서 처리
	msg="사용불가능 id";
}else {
	msg="사용가능 id";
}

 

    5) 클라이언트에 응답하기 위한 메시지를 만들어서 응답

        (문자열이 하나인 경우 변수처리해서 보낸다. json라이브러리를 이용해서 json객체를 만들어서 응답)

    - GET

response.setContentType("text/html;charset=UTF-8");
PrintWriter pw= response.getWriter();
pw.print(msg);

    - POST

response.setContentType("text/html;charset=UTF-8");
response.setHeader("cache-control", "no-cache, no-store");
PrintWriter pw= response.getWriter();
pw.print(msg);


    => response의 헤더 값을 변경.
    => html을 요청하는 것이 정적 리소스를 요청하는 작업이고 요청이 될때마다 서버에서 작업을 수행하고 실행해서

         결과를 가져오는데 이를 비효율적이라 판단해서 기본설정이 동일한 요청이 들어왔을떄 캐쉬에서 저장하고

         있는 파일을 보여준다.
         결과를 캐쉬에 저장하면 다음 요청에 대한 결과가 제대로 나오지 않을 수 있다. 그래서 응답결과를 캐쉬에 저장

         하지 말고 서버에서 바로바로 요청해서 보여줄 수 있도록 헤더값에 설정.

    [jsp]

    6) 서버와 비동기 통신을 하면서 XMLHttpRequest가 갖고 있는 readyState값이 지속으로 변경
       변경될때 마다 onreadystatechange이벤트가 발생하며 이 이벤트를 처리하기 위해서 익명함수를 콜백으로 정의

		xhr.onreadystatechange = function(){ // 함수 자동호출
			if(xhr.readyState == 4 && xhr.status==200){
			// 비동기 통신이 정상처리, http응답도 정상처리
				document.getElementById("result").innerHTML = xhr.responseText;
			}
		}
	}
</script>
		xhr.onreadystatechange = readyCallback;
	}
	function readyCallback(){
		if(xhr.readyState == 4 && xhr.status==200){
			document.getElementById("result").innerHTML = xhr.responseText;
		}
	}
</script>

    * readyState

    0: request가 초기화되지 않은 상태

    1: 서버와 연결이 된 상태

    2: 요청을 받은 상태

    3: 요청을 처리하고 있는 상태

    4: 요청처리가 끝나고 응답 대기 상태

 

    * status

    200 : 정상완료

    404 : 페이지가 존재하지 않는 경우

 

    * 서버응답 처리 객체

    responseText : String데이터를 get으로 응답받은 경우 사용

    response​XML : XML데이터를 get으로 응답받은 경우 사용

[목차]

6. 쿠키

7. 세션

 

* http : 요청을 하고 응답이 클라이언트에게 전송이 되면 서버에서 발생한 모든 정보가 지워진다.(stateless)

 

 * 상태유지 기술
 - 세션
 - 쿠키

 

 

[내용]

7. 쿠키(Cookie) : 클라이언트에 저장되는 텍스트 조각  

client(브라우저) request
------------>
getCookie
server(sevlet) setAttrubute()
------------>
request객체 getAttribute()
------------>
jsp
setCookie
<------------

response
   

 

    1) setCookie

//Servlet
Cookie cookie1 = new Cookie("name","value"); // Cookie객체 생성 및 데이터 저장

cookie1.setMaxAge(60*60*24); // 쿠키에 유효시간 설정(단위 : 초)
// setMaxAge(-1) : 브라우저 종료시 까지 유지
// setMaxAge(0) : 제거

response.addCookie(cookie1); // response에 쿠키 저장

RequestDispatcher rd = request.getRequestDispatcher("context제외된 경로"); // 요청재지정
rd.forward(request, response);

 

    2) getCookie

//Servlet
Cookie[] cookies = request.getCookies(); //request에서 쿠키정보 꺼내기(배열로 리턴됨)

// 쿠키의 name정보를 이용해서 작업하기
String name = "";
for(int i=0;i<cookies.length;i++) {
	if(cookies[i].getName().equals("name")) { // 쿠키의 배열에서 key값인 "name"의 value값 get
		name = cookies[i].getValue();
	}
}

request.setAttribute("name", name); // 쿠키에서 뺀 데이터를 request에 공유

RequestDispatcher rd = request.getRequestDispatcher("context가 제외된 경로"); // 요청 재지정 - forward
rd.forward(request, response);
// jsp
<% 
	String name = (String)request.getAttribute("name");
%>
<%= name %>

7. 세션(Session)
 - 사용자가 브라우저를 키고 사용하는 동안 정보가 유지된다.
 - 서버메모리에 저장된다.
 - 내부적으로 쿠키처럼 처리.


    1) 세션 사용
        ① request에서 세션정보 추출
        ② 세션이 없는 경우
            -> 세션 만들기
           세션이 있는 경우
           -> 세션id와 일치하는 세션에 저장된 정보를 확인.
        ③ 세션 id를 response에 보낸다.

    2) 세션객체 만들기
     - 세션 id를 request에서 꺼내서 작업하는 것이므로 request객체에서 기존의 세션 정보를 가져오거나 새로

        만들어주는 메소드를 제공.
   
    ① getSession()
      - 새로운 세션은 만들때 사용하는 메소드
      - request객체에서 세션 id를 추출하는 데 만약 세션이 만들어져 있지않은 상태면 세션을 새로 생성해서 리턴
         ex) 로그인하기 위해서 로그인 버튼을 클릭하고 요청되는 로그인 서블릿에서 로그인이 성공하면 세션을 새로

              만든다.

    ② getSession(boolean)
      - 기존에 작업하는 세션이 있는 지 확인하기 위해서 사용
      - getSession(true) - getSession()과 동일하게 동작
      - getSession(false) - 기존에 사용하던 세션이 있으면 섹션객체를 리턴하고 없으면 새로만들지 않고 null을 리턴.

 

//servlet
String id = request.getParameter("id");      
HttpSession ses = request.getSession(); //데이터 공유 - 세션
ses.setAttribute("id", id);

RequestDispatcher rd = request.getRequestDispatcher("context가 제외된 경로"); //요청 재지정  - forward
rd.forward(request, response);
//jsp
<%
	String id = (String)session.getAttribute("id");
%>
<%= id %>

 

<tip>

   * Chrome 개발자도구 F12 - Application - Cookies : 쿠키 데이터 확인 가능.

[목차]

5. JSP

    1) MVC 패턴

    2) 요청재지정

    3) 데이터 공유 

    4) JSP

    5) 스크립트 요소 

 

[내용]

5. JSP

    [서블릿 & DAO 연동 코드작성]
    1) 서블릿을 작성.
    2) 서블릿을 작성시 등록한 urlpattern에 매핑된 path를 요청 View(서블릿을 요청하는 최초 실행되는 클라이언트

        화면)의 <form>태그 action속성이나 <a>태그 href속성에 연결.
    3) 서블릿에서 요청정보 추출 후 sysout 테스트 진행.
    4) DTO 클래스 작성.
    5) DAO 클래스 작성.(서블릿에서 호출하는 비지니스 메소드를 가진)
       - 메소드내 sysout으로 출력하여 sysout 테스트.
    6) 서블릿에서 DAO메소드 호출
    7) DAO 코드 작성.
        ① insert, delete, update는 실행결과 행 출력
        ② select
        while문을 작성하고 while문 안에서 sysout출력.
       출력되면 칼럼을 가져와서 출력.
    8) 서블릿에서 dao호출한 리턴결과를 출력.

 

//servlet
MyEmpDAO dao = new MyEmpDAO();
ArrayList<MyEmpDTO> list = dao.getMemberList();
out.println("list.get(i).getDeptno()");
//dao
public ArrayList<MyEmpDTO> getMemberList(){
	ArrayList<MyEmpDTO> list = new ArrayList<MyEmpDTO>(); 
	System.out.println("dao요청");
	String sql = "select * from myemp";
	Connection con = null;
	PreparedStatement ptmt = null;
	ResultSet rs = null;
	try {
		con = DBUtil.getConnect();
		ptmt = con.prepareStatement(sql);
		rs = ptmt.executeQuery();
		while(rs.next()) {
			MyEmpDTO emp = new MyEmpDTO(rs.getString(1), rs.getString(2), rs.getString(3), 
            rs.getString(4), rs.getString(5), rs.getInt(6), rs.getString(7)); 
			list.add(emp);
		}
		System.out.print(list.size());
	} catch (SQLException e) {
		e.printStackTrace();
	}finally {
		DBUtil.close(rs, ptmt, con);
	}
	return list;
}

 

 

    1) MVC 패턴 : Model View Controller로 각 역할을 구분하고 분리해서 작업할 수 있도록 개발하는 패턴
                      : 서블릿, jsp를 이용해서 웹을 개발할때 각 역할별로 분리해서 작업.

Model View Controller
DAO Html Servlet

 


    2) 요청재지정 : MVC패턴 적용을 위한 설정.
                       : 최초로 요청된 web appliction파일(서블릿)이 실행된 후 요청받은 서블릿이 응답되지 않고

                         view파일(jsp)이 응답되도록 설정하는 것
                       : 서블릿에서 뷰를 분리.
        ① forward : servlet에서 사용
            1) 문법

RequestDisptcher rd =  request.getRequestDisptcher("요청 재지정할 application의 context명을 뺀 나머지 path");
rd.forward(request객체, response객체);
RequestDisptcher rd =  request.getRequestDisptcher("/basic/result.jsp");
rd.forward(request, response);

            2) 실행흐름
            - 클라이언트가 서블릿을 요청하는 경우 서블릿이 실행되고 forward로 지정한 web application이

            재요청되어 실행.
            - 이때 재지정되는 요청은 새로운 요청이 만들어지면서 요청되는 것이 아니라 서블릿 요청의 연장.
            - 한번의 요청으로 두개의 web application이 실행된다. (서블릿, jsp파일이 실행)

 

        ② include : jsp에서 사용

//servlet
out.print("머리말");
System.out.println("include연습  - include 서블릿 실행");
//1. 데이터 공유
MyEmpDTO user = new MyEmpDTO("003", "이이", null, "", "", 0, "");
request.setAttribute("myuser", user);
//2. 요청 재지정 - include
RequestDispatcher rd = request.getRequestDispatcher("/jspbasic/page.jsp");
rd.include(request, response);
out.print("꼬리말");

        => 머리말 + jsp 실행내용 + 꼬리말로 실행된다.

 

         - jsp

<jsp:include page="../top.jsp"></jsp:include>

 


    3) 데이터 공유
     - 한번의 요청으로 서블릿과 jsp가 실행되어 같은 request객체를 사용하기 때문에 데이터를 공유할 수 있다.
     - 같은 request를 사용

     - 서블릿에서 Request객체에 저장
     - jsp에서 Request객체에서 값을 가져옴
     - 공유되는 데이터를 attribute라한다.
     - 자바에서 사용할 수 있는 모든 객체를 공유할 수 있다.

     - http 프로토콜 특성으로 한번의 요청을 서버에서 처리하면서 저장한 값은 클라이언트에게 응답하는 순간

       메모리에서 없어진다. 즉 상태정보가 유지 되지않는다.

        ① 데이터 저장 : 서블릿에서 처리

request객체.setAttribute("저장할 attribute의 이름", 저장할 객체);
out.print("servlet 출력"); // forward 사용 시 실행은 되나 출력되지않음.
//1. 데이터 공유
MyEmpDTO user = new MyEmpDTO("003", "이이", null, "", "", 0, ""); // 공유할 객체
request.setAttribute("myuser", user); // 데이터 공유
//2. 요청 재지정 - forward
RequestDispatcher rd = request.getRequestDispatcher("/jspbasic/page.jsp");
rd.forward(request, response);

 

        ② 데이터 가져오기 : jsp에서 처리

Object객체 = (공유객체 타입)request객체.getAttribute("서블릿에서 저장한 attribute의 이름");
//공유 객체로 casting
<%
	MyEmpDTO user = (MyEmpDTO)request.getAttribute("myuser");
%>
<%= user.getName() %>

 

        ③ 데이터 지우기

removeAttribute("name");

 

 

 

    4) JSP : html에서 java code를 사용하기 위한 언어.
             : 이클립스 내부에서 java의 코드를 html문자열로 변환.

 

    * 서버로 인식하는 위치 (context)

    C:\Java\work\webwork\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\serverweb

 

    * jsp 경로

C:\Java\work\webwork\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\work\Catalina\localhost\serverweb\org\apache\jsp\jsp

    

    * jsp파일은 자동으로 하기와 같이 변환된다.

public void _jspInit() { ... }
public void _jspDestroy() { ... }
public void _jspService(final javax.servlet.http.HttpServletRequest request,
final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException { ... }

 

    [Servlet 동작] 
        1) 요청정보 추출 
        2) 비지니스 메소드 호출 
        3) 데이터를 공유 
        4) 요청재지정 
        5) 서블릿에서 공유한 데이터를 꺼내서 출력하기 [jsp] 

* html 파일 
모든 클라이언트에게 항상 고정된 동일한 화면만 서비스(정적 html문서) 

* jsp파일 
모든 클라이언트의 상황에 따라 다른 화면을 서비스할 수 있다.(동적 html)

 

 

    5) 스크립트 요소
        ① 스크립트릿 ( <% %>)

         - 자바코드를 사용할 수 있는 스크립트 요소.
         - 자바명령문을 정의할 수 있는 곳
         - ; 을 문자의 끝에 추가해야한다.
         - 자바와 동일하게 java.lang패키지는 자동으로 인식하지만 다른 패키지를 사용하는 경우 import한다. 

         - .jsp문서 내에서 선언되는 모든 지역변수를 사용할 수 있다.
         - jsp문서내 자바코드는 지양해야한다.
         - 자바코드는 서블릿이 공유하는 데이터를 꺼내서 출력하기 위한 코드만 정의해야한다.
         - jsp목적이 로직과 뷰를 위한 코드가 혼재되어 있는 부분을 없애기 위해서 만들어진 기술
         - 자바코드를 쓰지 않기 위해서 EL & JSTL(표준태그)

<% 
	// jsp문서에 작성하는 모든 태그나 코드의 작성은_jspService메소드 내부에 만들어진다. 
	out.println("<h2>hello</h2>"); // out 객체는 자동생성된 객체이므로 사용가능하다. 
%> 

        - 자동완성하여 객체 타입 설정시 자동 import된다.

<%@page import="basic.MyEmpDTO"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" import="java.util.Random, java.util.ArrayList"%>

        ② 표현식(<%= %>)

         - 기본형변수, 문자열을 반환하거나 해당 타입으로 선언된 변수를 출력.
          변수의 값을 출력하기 위해서 사용. out.print()메소드의 매개변수로 전달되므로 ;을 쓰지않는다.
           <%= 값 or 값을 리턴하는 메소드 호출문 or 연산식%>
          - 표현식은 jsp가 서블릿으로 변환될때 out.print() 메소드의 매개변수로 전달되는 코드
          - 표현식을 정의할때는 ;을 추가하지않는다. ;을 추가하면 out.print(값;);

          - 표현식은 서블릿에서 발생한 값을 웹페이지에 출력할 목적으로 사용하는 jsp스크립트 요소
          - 사용가능한 타입이 제한
          - 서블릿으로 변환될때 print메소드의 매개변수로 전달되기 때문에
          - 기본형, 스트링으로 변환될 수 있는 변수의 값, 메소드의 호출결과, 연산식등을 사용할 수 있다.

<%
	String str = "hello";
%>
<%= str %>
// out.print(str);로 자동변환된다.
<%= str; %>
// ;사용 시 out.print(str;);로 자동변환된다.

        ③ 선언문

         - 멤버를 선언하기 위해 사용.
         - jps문서의 멤버변수, 메소드를 정의하기 위해서 사용(jsp파일에서 java code를 최소화해야함으로 거의

         사용하지않는다)

<%! int num=100000; %>
<%! public void test(){
		System.out.println("test");
	}
%>


        ④ 지시자 - 컨테이너에게 넘겨줄 정보를 선언.


        ⑤ 주석문

<!-- HTML주석문(클라이언트에 전송) -->
<%-- jps주석문(jsp문법에 해당하는 코드를 주석으로 처리하는  용도 : 클라이언트에 전송 되지않는다. --%>
<%
	//	자바주석문
	/* 
		자바 여러줄 주석문 : 클라이언트에 전송 되지않는다.
	*/
%>

 

'BACK END > Servlet' 카테고리의 다른 글

[Servlet] Servlet 정리6 - EL, JSTL  (0) 2021.01.04
[Servlet] Servlet 정리5 - Ajax  (0) 2021.01.03
[Servlet] Servlet 정리4 - Cookie, Session  (0) 2021.01.02
[Servlet] Servlet 정리2 - JDBC  (0) 2020.12.28
[Servlet] Servlet 정리1  (0) 2020.12.28

[목차]

4. JDBC

    1) 오라클 드라이버 로딩 

    2) DB서버에 연결하기(Connection 설정)

    3) SQL문 실행을 담당하는 객체를 생성 

    4) SQL문 실행 

    5) 자원반납 

* DAO(Data Access Object)

* DBUtil

* DTO(Date To Object)

 

[내용]

[오라클에 접속해서 JBC를 사용하기 전에 해야할 일]

    1) 오라클 드라이버를 다운로드 받는다. 
    - 제조사 홈페이지를에서 다운로드 받는다 
    - 오라클 JDBC 위치 : 오라클 설치시 해당경로에 설치된다.(11g XE)

C:\oraclexe\app\oracle\product\11.2.0\server\jdbc\lib\ojdbc6.jar

    2) 이클립스 설정 
    ① [Package Explorer]창에서 [Project] 오른쪽 클릭 
    ② 오른쪽 클릭창 - [Build path] - [Configure Build patch] 
    ③ 대화상자에서 세번째 탭인 [Libaries] Tab 선택 
    ④ [Add External JARs] 선택 후 상기의 오라클 JDBC 위치의 [ojdbc6.jar ] 선택 -> [Apply]

 

 

4. JDBC  : 자바에서 DBMS 연동을 위한 표준 API(java에서 SQL을 실행하기 위해서 제공되는 표준 API) 
 - driver : 오라클회사에서 자바로 오라클을 접속하기 위해 내부에서 처리해야하는 기능을 구현해 놓은 클래스들을 라이브러리로 만들어 놓은것(ojdbc~.jar)

oracle.jdbc.driver OracleDriver.class

 - API를 이용해서 작업 
 - 자바 프로그램으로 insert, delete, update, select를 실행. 

 


    1) 오라클 드라이버 로딩 
    [오라클 드라이버명]

    oracle.jdc.driver.OracleDriver

 

    java.lang패키지에 Class라는 클래스를 이용해서 오라클 드라이버의 핵심 클래스를 메모리에 로딩 
    핵심클래스를 드라이버클래스라 하며 드라이버 클래스는 어떤 DBMS를 쓰느냐에 따라서 달라진다.

public static Class<?> forName(String className) throws ClassNotFoundException
Class.forName("패키지를 포함한 오라클 드라이버 클래스명");
Class.forName("oracle.jdc.driver.OracleDriver");

 

 

    2) DB서버에 연결하기(Connection 설정) 
    => java.sql패키지의 API를 이용 
    DriverManager의 getConnection메소드를 이용해서 DB서버에 연결.

public static Connection getConnection(String url, String user, String password) throws SQLException

    ① static메소드이므로 클래스이름으로 액세스 
    ② throws하고 있는 SQLException에 대한 처리 
    ③ 매개변수 
    url : 연결문자열(접속하기 위한 정보를 하나의 문자열로 만들어 놓은 것, 어떤 DBMS를 쓰느냐에 따라서 다른 

          현상의 문자열을 작성 - 제조사 홈페이지 참고)

    user : 사용자계정 (기본값 : scott) 
    password : 계정 패스워드

 

    [오라클 url]

jdbc:oracle:thin: @ip:port: 데이터베이스서비스명
프로토콜 DBMS가 설치되어있는 PC의 ip와 port 오라클 설치 시 셋팅하는 값으로 달라질 수 있다.(express버전은 xe)
jdbc:oracle:thin: @192.168.0.19:1521: xe

 

    ④ 리턴타입 
    java.sql.Connection이 리턴 
    DriverManager클래스의 getConnection메소드는 DB서버에 연결하고 연결정보를 객체로 만들어서 리턴한다. 
    매개변수에 어떤 DBMS를 사용하냐에 따라 다른 Connection객체의 오버라이딩 메소드가 실행됨.(다형성 적용)

 

    ⑤ 사용방법

Connection con = DriverManager.getConnection(url, user, password);
// oracle.jdbc.driver.T4CConnection 리턴

 

 

    3) SQL문 실행을 담당하는 객체를 생성 
    [상속구조]

Statement  : 정적SQL을 실행할 때 사용(보안취약 - SQL Injection공격 취약)
 
PrspareStatement  : 동적 SQL을 실행할 때 사용(secure coding에 적합 - 정부권고사항)
 
CallableStatement  : 각 DBMS에 특화된 SQL로 작성된 명령문을 실행 : 오라클 (PL-SQL)

    Statement객체 이용 
    Connection객체가 갖고 있는 createStatement메소드를 이용

    [형식]

Statement stmt = con.createStatement();
//stmt객체는 오라클 드라이버에 포함되어 있는 클래스 객체가 리턴
String sql = "select * from mydept where deptno='"+deptno+"' and deptname ='"+deptname+"'";

 

 * sql insaction

select * from mydept where deptno=002 -- and deptname='인사'; 
select * from mydept where deptno='' or '1'='1'-- 

   -- 주석문 뒤의 조건문이 다 맞지않아도 검색된다. 
    => Statement는 보안취약

 

    ② PreparedStatement객체 이용

    - Connection객체의 prepareStatement메소드를 이용해서 생성 
    - PreparedStatement객체를 만들때 미리 sql문을 파싱 후 외부에서 값만 입력받아서 매핑. 
    - Statement의 단점 보완(보안) 
    - 컬럼명은 입력값으로 처리하지 못한다. 
    - 외부에서 입력받아 처리해야하는값은 ?로 대신해서 sql문을 만든다. 
  
        1) sql문을 전달하여 PreparedStatement객체를 생성

String sql = "select * from mydept where deptno = ? and deptname = ?"; 
PrepaeredStatement ptmt = con.prepareStatement(sql); 


        2) ?에 값을 셋팅 
        외부에서 전달받은 값을 ?에 설정해야 sql문이 완성 
        PrepaeredStatement객체에 있는 set~~~메소드를 이용해서 ?에 값을 셋팅 
        set~~~메소드는 타입과 연결이 되는 메소드로 ResultSet의 get~~~메소드와 동일한 방법으로 해석

ptmt.setString(A,"B") // A : ?의 순서, B : ?에 셋팅할 값 
ptmt.setString(1,"002") // 첫번째 물음표에 문자열 "002"를 셋팅 한다.  
                        // (오라클 타입 : varchar2, char) 

 

 

    4) SQL문 실행 
    ① Statement를 사용 
        1) executeUpdate(sql) : insert, delete, update 명령문을 실행. 
        매개변수로 sql을 전달하면 실행결과로 몇개의 row가 반영되었는 지 리턴.

int result = stmt.executeUpdate(sql명령문);
// 몇개의 행이 삽입, 삭제, 수정되었는 지 리턴.

 

        2) executeQuery(sql) : select 명령문을 실행 
        실행한 후 조회된 테이블을 리턴, DBMS에서 조회된 테이블을 사용하기 위해 모델링된 자바의 객체가 ResultSet.

        실제로는 어떤 DBMS가 사용되었는지에 따라 다른 ResultSet객체가 리턴.

        - sql-plus프로그램을 이용해서 select문을 실행할때 결과로 보여지는 2차원 표의 데이터를 자바에서 이용할 수

        있도록 모델링한 클래스가 ResultSet.

        2-1) select문을 실행하면 ResultSet을 리턴하기 때문에 ResultSet타입의 변수를 선언해서 결과를 참조

ResultSet rs = stmt.executeQuery(sql명령문);

        2-2) ResultSet에 있는 테이블의 데이터를 읽기 위해서 ResultSet에서 제공하는 메소드를 이용해서 작업 
        Cursor를 다음 레코드로 이동하면서 레코드 개수만큼 반복작업을 실행. 
        ResultSet에 있는 next()를 호출하면 다음 레코드를 커서를 이동할 수 있다. next()는 커서를 이동했을 때 레코드가

        존재하면 true를 리턴하고 없으면 false를 리턴.

 

while(rs.next()){ // 레코드 개수만큼 실행
	// 레코드의 각 컬럼을 읽는다.
}

        2-3) 한 번에 하나의 칼럼만 읽을 수 있다. ResultSet의 get~~~메소드를 이용해서 칼럼값을 가져온다. 
        타입에 따라서 구분 
        - 오라클의 타입이 varchar2나 char인 경우 : java의 String

        getString(칼럼명) or getString(칼럼의 순서 index)

        칼럼의 순서 index : 원본 테이블에 정의된 칼럼의 순서가 아니라 조회된 테이블의 칼럼순서로 1부터 시작.

 

        - 오라클 타입이 number(정수) : java의 int 
        getInt(칼럼명) or getInt(칼럼index)

 

        - 오라클 타입이 date : java.sql.Date클래스

while(rs.next()){
// 레코드 개수만큼 실행.
// 커서를 하나씩 다음으로 이동.
// 다음 레코드가 있는 경우 true, 없으면 false리턴
	rs.getString("name"); => name컬럼으로 정의되어 있는 칼럼의 입력된 값을 읽어서 출력
	rs.getString(2); => 조회된 테이블의 2번째 칼럼의 입력된 데이터를 읽어서 출력
}
String url = "jdbc:oracle:thin:@127.0.0.1:1521:xe";
String user = "scott";
String password = "tiger";
String sql = "select * from mydept where deptno='"+deptno+"' and deptname ='"+deptname+"'";

try {
	//1. 드라이버 로딩
	Class.forName("oracle.jdbc.driver.OracleDriver");
	//2. DB연결
	Connection con = DriverManager.getConnection(url, user, password);
	//3. sql문법 객체생성
	Statement stmt = con.createStatement();
	//4. sql문 실행
	ResultSet rs = stmt.executeQuery(sql);
	ResultSetMetaData md= rs.getMetaData();
	int columCount = md.getColumnCount();
	System.out.println("칼럼 수 : "+columCount);
	while(rs.next()) {
		for(int i=1;i<=columCount;i++) {
			System.out.print(rs.getString(i)+"\t");
		}
		System.out.println();
	}
} catch (ClassNotFoundException e) {
	e.printStackTrace();
} catch (SQLException e) {
	e.printStackTrace();
}

 

    ② PrepaeredStatement

        1) excuteUpdate() : insert, delete, update 
        2) excuteQuery() : select 
         => 리턴유형, 실행, 처리 모두 Statement메소드와 동일하지만 sql을 매개변수로 전달하지않는다.

String url = "jdbc:oracle:thin:@127.0.0.1:1521:xe";
String user = "scott";
String password = "tiger";
String sql = "select * from mydept where deptno=? and deptname =?";
System.out.println(sql);
try {
	//1. 드라이버 로딩
	Class.forName("oracle.jdbc.driver.OracleDriver");
	//2. DB 연결
	Connection con = DriverManager.getConnection(url, user, password);
	//3. sql문법 객체생성
	PreparedStatement ptmt = con.prepareStatement(sql);
	//4. 외부에서 전달받을 값 설정
	ptmt.setString(1, deptno);
	ptmt.setString(2, deptname);
	//5. sql문 실행
	ResultSet rs = ptmt.executeQuery();
	
	ResultSetMetaData md= rs.getMetaData();
	int columCount = md.getColumnCount();
	
	while(rs.next()) {
		for(int i=1;i<=columCount;i++) {
			System.out.print(rs.getString(i)+"\t");
		}
		System.out.println();
	}
} catch (ClassNotFoundException e) {
	e.printStackTrace();
} catch (SQLException e) {
	e.printStackTrace();
}

 

* like 사용

String sql = "select * from mydept where loc like ?"; 
ptmt.setString(1, "%"+loc+"%");

 

    5) 자원반납 
    - 클라이언트가 점유해서 사용하던 자원을 반납해야한다.(메모리 해제) 
    - Connection, Statement, ResultSet 메모리해제. close메소드를 이용. 
    - 가장 마지막에 생성된 객체부터 메모리 해제한다.

String url = "jdbc:oracle:thin:@127.0.0.1:1521:xe";
String user = "scott";
String password = "tiger";
String sql = "select * from mydept where deptno=? and deptname =?";
Connection con = null;
PreparedStatement ptmt = null;
ResultSet rs = null;
System.out.println(sql);
try {
	Class.forName("oracle.jdbc.driver.OracleDriver");
	con = DriverManager.getConnection(url, user, password);
	ptmt = con.prepareStatement(sql);
	ptmt.setString(1, deptno);
	ptmt.setString(2, deptname);
	rs = ptmt.executeQuery();
	while (rs.next()) {
		System.out.print(rs.getString(1) + "\t");
		System.out.print(rs.getString(2) + "\t");
		System.out.print(rs.getString(3) + "\t");
		System.out.print(rs.getString(4) + "\t");
		System.out.print(rs.getString(5) + "\t");
	}
} catch (ClassNotFoundException e) {
	e.printStackTrace();
} catch (SQLException e) {
	e.printStackTrace();
} finally {
	try {
		if (con != null) con.close();
		if (ptmt != null) ptmt.close();
		if (rs != null) rs.close();
	} catch (SQLException e) {
		e.printStackTrace();
	}
}

 

* DAO(Data Access Object) : 동일한 테이블을 액세스하는 기능은 하나의 객체로 정의하고 사용

class 테이블명DAO{
	public void insert(){
	}
	public void update(){
	}
	public void delete(){
	}
	public void select(){
	}
}
public class MyDeptDAO {
	//insert
	public void insert(String deptno, String deptname, String loc, String tel, String mgr) {
		String sql = "insert into mydept values(?, ?, ?, ?, ?)";
		Connection con = null;
		PreparedStatement ptmt = null;
		try {
			con = DBUtil.getConnect();
			ptmt = con.prepareStatement(sql);
			ptmt.setString(1, deptno);
			ptmt.setString(2, deptname);
			ptmt.setString(3, loc);
			ptmt.setString(4, tel);
			ptmt.setString(5, mgr);
			int result =ptmt.executeUpdate();
			System.out.println(result+"개 행 삽입 성공");
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			DBUtil.close(null, ptmt, con);
		}
	}
	public void delete(String deptno) {
		String sql="delete from mydept where deptno=?";
		Connection con = null;
		PreparedStatement ptmt = null;
		try {
			con = DBUtil.getConnect();
			ptmt = con.prepareStatement(sql);
			ptmt.setString(1, deptno);
			int result = ptmt.executeUpdate();
			System.out.println(result+"개의 데이터가 삭제되었습니다.");
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			DBUtil.close(null, ptmt, con);
		}
	}
	public void select(String deptno, String deptname) {
		String sql = "select * from mydept where deptno=? and deptname =?";
		Connection con = null;
		PreparedStatement ptmt = null;
		ResultSet rs = null;
		try {
			con = DBUtil.getConnect();
			ptmt = con.prepareStatement(sql);
			
			ptmt.setString(1, deptno);
			ptmt.setString(2, deptname);
			
			rs = ptmt.executeQuery();
			
			ResultSetMetaData md= rs.getMetaData();
			int columCount = md.getColumnCount();
			
			while(rs.next()) {
				for(int i=1;i<=columCount;i++) {
					System.out.print(rs.getString(i)+"\t");
				}
				System.out.println();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			DBUtil.close(rs, ptmt, con);
		}
	}
	public void update(String deptno, String deptname) {
		StringBuffer sql=new StringBuffer();
		Connection con = null;
		PreparedStatement ptmt = null;
		sql.append("update mydept ");
		sql.append("set deptname=?");
		sql.append("where deptno=?");
		try {
			con = DBUtil.getConnect();
			ptmt = con.prepareStatement(sql.toString());
			ptmt.setString(1, deptname);
			ptmt.setString(2, deptno);
			int result = ptmt.executeUpdate();
			System.out.println(result+"개 행이 업데이트 되었습니다.");
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			DBUtil.close(null, ptmt, con);
		}
	}
}

 

* DBUtil : DB연동과 관련된 기능을 유틸리티처럼 제공하는 클래스 
    1) Driver Loading 
    2) DB서버 연결 
    3) 자원반납 
    => Utility처럼 사용할 것으로 static으로 구현

public class DBUtil {
		// 1. 드라이버 로딩
		// => 메소드마다 드라이버를 로딩하는 작업을 구현하지않고 클래스 로더가 클래스를
		// 로딩할때 한번만 실행되도록 하기 위해서
		// static 블럭안에 드라이버 로딩 코드를 작성한다.
		static {
			try {
				Class.forName("oracle.jdbc.driver.OracleDriver");
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
		}
		// 2. DB서버 연결
		// SQL문을 실행할때마다 연결을 해야한다.
		public static Connection getConnect(){
			Connection con = null;
			String url = "jdbc:oracle:thin:@127.0.0.1:1521:xe";
			String user = "scott";
			String password = "tiger";
			try {
				con = DriverManager.getConnection(url, user, password);
			} catch (SQLException e) {
				e.printStackTrace();
			}
			return con;
		}
		// 3. 자원반납
		public static void close(ResultSet rs, Statement stmt, Connection con) {
			try {
				if(rs != null) rs.close();
				if(stmt != null) stmt.close();
				if(con != null) con.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		// 4. Connection, Statement, ResultSet을 반납하는 메소드 각각 작성가능.
	}

 

* DTO(Date To Object) : Data를 객체로 변환. 테이블의 row로 객체를 생성 (테이블명+VO  or 테이블명+DTO)

class 테이블명DTO{
	변수
	
	생성자()
	
	toString()
	
	getter/setter()
}
public class MyDeptDTO {
	private String deptno;
	private String deptname;
	private String loc;
	private String tel;
	private String mgr;
	public MyDeptDTO() {
		
	}
	public MyDeptDTO(String deptno, String deptname, String loc, String tel, String mgr) {
		super();
		this.deptno = deptno;
		this.deptname = deptname;
		this.loc = loc;
		this.tel = tel;
		this.mgr = mgr;
	}
	@Override
	public String toString() {
		return "MyDeptDTO [deptno=" + deptno + ", deptname=" + deptname
		+ ", loc=" + loc + ", tel=" + tel + ", mgr="+ mgr + "]";
	}
	public String getDeptno() {
		return deptno;
	}
	public void setDeptno(String deptno) {
		this.deptno = deptno;
	}
	public String getDeptname() {
		return deptname;
	}
	public void setDeptname(String deptname) {
		this.deptname = deptname;
	}
	public String getLoc() {
		return loc;
	}
	public void setLoc(String loc) {
		this.loc = loc;
	}
	public String getTel() {
		return tel;
	}
	public void setTel(String tel) {
		this.tel = tel;
	}
	public String getMgr() {
		return mgr;
	}
	public void setMgr(String mgr) {
		this.mgr = mgr;
	}
}
@WebServlet(name = "deptInsert", urlPatterns = { "/dept/Insert.do" })
public class DeptInsertServlet extends HttpServlet {
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
							throws ServletException, IOException {
		System.out.println("서블릿 요청");
		request.setCharacterEncoding("UTF-8");
		response.setContentType("text/html;charset=UTF-8");
		
		//1. 사용자가 입력한 값을 추출
		PrintWriter out = response.getWriter();
		String deptno = request.getParameter("deptno");
		String deptname = request.getParameter("deptname");
		String loc = request.getParameter("loc");
		String tel = request.getParameter("tel");
		String mgr = request.getParameter("mgr");
		
		//2. 비지니스 메소드 호출
		MyDeptDAO dao = new MyDeptDAO();
		MyDeptDTO dept = new MyDeptDTO(deptno, deptname, loc, tel, mgr);
		System.out.println("servelt => "+dept);
		int result = dao.insert(dept);
		//int result = dao.insert(deptno, deptname, loc, tel, mgr);
		
		//3. 결과값 출력
		String msg = "";
		if(result>0) {
			msg = result+"개 행 삽입 성공";
		}else {
			msg = "삽입 실패("+result+")";
		}
		out.println("<h1>"+msg+"</h1>");
	}
}
[html] request
--------->
<--------
response
[Servlet]
요청정보추출
비지니스 메소드 call
결과처리
[DAO]
sql처리
insert(),
update(),
delete(), select()
[DBUtil]
드라이버로딩
Connection생성
자원반납

[DBMS]
  [DTO]
변수
생성자
getter/setter
toString()
 

 

[목차]

1. 서블릿 작성 규칙 

2. 서블릿 요청방법(서블릿 실행방법) 

3. 서블릿 요청정보 추출

4. JDBC

 

[내용]

서블릿
 - 클라이언트의 요청을 처리하기 위한 기술
 - 클라이언트가 요청하면 서버에서 실행되며 DB에 대한 처리, 서버의 리소스를 이용해서 만들어진 결과를 클라이언트에 응답한다.
 - 서버에 의해서 호출되기 때문에 서버가 인식하는 위치에 있어야 하며 서버가 찾아서 실행할 수 있도록 정해진 규칙에 따라 작성되어야한다.
(Context/WEB_INF/classes폴더)

 

 

1. 서블릿 작성 규칙
    1) 표준화된 폴더 구조 안에 서블릿 클래스가 위치해야한다.
    서블릿이 저장될 폴더 - classes폴더(서블릿 디렉토리)

    [표준화된 폴더 구조]

Context WEB_INF web.xml
    lib
    classes
  html, image, css, jsp  

   => classes 폴더에 서블릿이 없으면 서버가 찾을 수 없다.  (매핑 시엔 가능)

    2) 서버에 의해서 호출될 것이므로 반드시 public으로 작성해야한다.


    3) 서블릿 클래스가 되기 위해서 무조건 서블릿 클래스를 상속받아야한다.

Servlet(interface)   
 
Generic Servlet(abstact class) 서블릿의 일반적인 내용이 정의된 서블릿 클래스. 
destory(), init(), service() 
HttpServlet(abstact class) http프로토콜에 특화된 내용이 정의된 서블릿 클래스.
service(), do~~() 
사용자 정의 Servlet  

 

    4) 서버가 내부에서 호출할 메소드를 오버라이딩
    - 서버가 자동으로 호출하는 메소드를 call back메소드
    - 클라이언트가 요청을 하면 서버가 요청을 분석해서 서블릿 디렉토리에 존재하는 (미리 만들어서 저장해놓은)
    서블릿 클래스를 찾아서 적절한 상황에 해당 메소드를 자동으로 호출할 것이므로 그 상황에 맞게처리하고 
     싶은 내용을 각 메소드를 오버라이딩해서 구현한다.
    - 서버가 서블릿의 life cycle을 관리(객체가 생성돠고 객체를 메모리에서 해제하는 모든 작업)
    - 오버라이딩할 메소드는 life cycle과 연관되어 있는 메소드

 

    [오버라이딩할 메소드]
     - init() : 서블릿 객체가 초기화될때 호출되는 메소드.
     - service() : 클라이언트가 요청할때마다 호출되는 메소드
      => 클라이언트의 요청을 처리하는 메소드로 요청을 받고 처리할 내용을 구현.
      ex) 로그인, 게시판 목록보기, 메일읽기, 장바구니 조회, 구매, 예약, 예약정보 확인...

    doGet() : 클라이언트가 get방식으로 요청할때 호출되는 메소드.
    doPost() : 클라이언트가 post방식으로 요청할때 호출되는 메소드.
    destory() : 서블릿 객체가 소멸될때 호출되는 메소드.


    [객체 소멸 case]
    - 서블릿 클래스가 컴파일될 경우
    - WAS가 재부팅될 경우
    - context가 reload될 경우

 

* WAS 처리 동작

실행하려는 서블릿 객체가 메모리에 Loading되어 있는지 확인
(클라이언트 개수와 상관없이 한 서블릿당 1 객체로 운영)
---------------------------------------->
No : 서블릿 객체생성 ->init() -> 
쓰레드 생성 -> 응답, 요청객체 생성
service() -> doGet() or doPost() ->
비지니스 로직
----------------------------------------->
Yes

 

    5) 서블릿을 등록
     - 서버가 요청을 분석해서 서블릿 디렉토리에서 서블릿을 찾아서 실행할 수 있도록 등록.
     - 설정파일에 등록(web.xml)

     - 실제 작업은 anotation으로 설정.(servlet 3.0이상)

     - web.xml파일은 xml형식의 파일이며, 태그로 작성하며, 작성규칙(DTD - xml안에서 정의할 엘리먼트(태그)의 순서

     정의해야하는 필수 엘리먼트, 속성 등이 명시되어 있는 파일)에 따라 정확하게 등록해야한다.

        서블릿 클래스 등록
         => 무엇을

<servlet>
	<servlet-name>서블릿명(alias)</servlet-name>
	<servlet-class>서블릿클래스의 실제 경로(패키지를 포함한 서블릿클래스)</servlet-class>
</servlet>

 

ex) basic패키지에 작성한 FisrtServlet을 first라는 서블릿명으로 등록.

<servlet>
	<servlet-name>first</servlet-name>
	<servlet-class>basic.FisrtServlet</servlet-class>
</servlet>

 

        ② 서블릿 매핑
         => 어떻게
         => 등록된 서블릿을 어떻게 요청할 것인지 등록(어떤 url로 요청할 것인지)
         => 반드시<servlet>엘리먼트 다음에 위치해야한다. 즉 <servlet>엘리먼트와 함께 한 쌍으로 정의해야한다.
         => 위에서 등록한 서블릿을 어떻게 요청할 것인지 등록하는 엘리먼트

<servlet-mapping>
	<servlet-name>위에서 정의한 서블릿의 이름</servlet-name>
	<url-patten>요청할 서블릿의 path</url-patten>
           (반드시 /나 .으로 시작해야한다)
</servlet-mapping>

ex) 위에서 fisrt라는 이름으로 등록한 서블릿을 first.do

<servlet-mapping>
	<servlet-name>first</servlet-name>
	<url-pattern>/first.do</url-pattern>
</servlet-mapping>

 

        ③ @어노테이션 이용 서블릿 매핑하기

 Project Explorer창에서 Project 오른쪽 클릭 -> New -> Servlet -> Class name입력 -> Name(alias) 입력 ->
 URL mapping 입력 -> 오버라이딩할 메소드 or 생성자 선택

@WebServlet(name = "alias", urlPatterns = { "/URL" })
public class PostFormServlet2 extends HttpServlet {
	protected void doPost(HttpServletRequest request, HttpServletResponse response) 
                                             throws ServletException, IOException {
	}
}

 

2. 서블릿 요청방법(서블릿 실행방법)
    [일반 html문서]
    => http://서버ip:port/context명/정적파일명
       (프로토콜)

 

    [서블릿]
    => http://서버ip:port/context명/서블릿매핑명(web.xml <url-patten>에 등록한 path)

        

    1) get방식으로 요청
    => 클라이언트가 입력한 내용을 요청헤더에 저장하여 서버로 전송하는 방식 (255Byte미만)

    => 외부에 노출되어도 상관없는 데이터 송부시 사용.

    => 인코딩/디코딩 작업이 필요없어 처리속도가 빠름.

    => name1=value1&name2=value2,   공백은 +, %16진수로 전달.(영문, 숫자, 일부 특수문자 제외), ?뒤에 Query 

         String입력하여 전달가능.


        ① 주소표시줄에 입력해서 요청하는 방식
         => 테스트용으로 사용되거나 첫 번째 페이지에서 요청하는 경우


        ② 하이퍼링크로 요청  => 텍스트나 이미지를 클릭해서 서블릿을 요청

<a href="http://서버ip:port/context명/서블릿매핑명">서블릿 요청</a> 
<a href="/context명/서블릿 요청url">서블릿 요청</a> 
<a href="/serverweb/서블릿 매핑명">서블릿 요청</a>


        ③ <form>태그의 method속성을 get으로 정의하고 submit버튼을 눌러서 요청하는 경우
         => method속성을 생략하면 get방식(default)

<form action="요청할 web application파일의 path" method="get">
	<input type="text" name="id" />
	<input type="password" name="pass">
	<input type="submit" value="서블릿요청">
</form>

        => submit버튼을 누르면 <form></form>태그 사이에 정의된 모든 양식 태그의 namevalueaction속성

            정의된 서블릿에 요청(실행)하며 등록된 서블릿에게 method속성 요청방식(get)으로 전송한다.

 

    2) post방식으로 요청
        ① <form>태그의 method속성을 post로 정의하고 submit버튼을 눌러서 요청하는 경우

<form action="요청할 web application파일의 path" method="post">
	<input type="text" name="id" />
	<input type="password" name="pass">
	<input type="submit" value="서블릿요청">
</form>

        => submit버튼을 누르면 <form></form>태그 사이에 정의된 모든 양식 태그의 name과 value가 action속성에

             정의된 서블릿으로 요청(실행)하며 등록된 서블릿에게 method속성 요청방식(post) 방식으로 전송한다.

 

 

3. 서블릿 요청정보 추출

public class 서블릿 클래스명 extends HttpServlet{
	public 서블릿 클래스명() { // 생성자
	}
    
	public void init() { // 생성자 호출 후 한번만 호출
	}
	
	public void service(HttpServletRequest req, HttpServletResponse res) 
	throws ServletException, IOException{ 
	// 상위클래스의 service 메소드에서 메소드 요청방식에 따라 doGet,doPost를 자동으로 호출함으로
	// 오버라이딩할 경우 사용자에 맞게 doGet(), doPost()를 연결하여야 한다.
		if(req.getMethod().equals("GET")) {
			doGet(req,res);
		}else {
			doPost(req,res);
		}
	}
	
	public void doGet(HttpServletRequest req, HttpServletResponse res)
	throws ServletException, IOException{
	}
	
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
	throws ServletException, IOException {	
		req.setCharacterEncoding("UTF-8"); //요청정보에 문자셋을 적용하여 한글을 셋팅
		resp.setContentType("text/html;charset=UTF-8");
		//text/html; : MIME타입(응답형식), charset=UTF-8 : 응답데이터에 적용할 문자셋
		
		//응답정보를 클라이언트로 전송하기 위한 스트림객체를 response에서 구하기
		PrintWriter out = resp.getWriter();
		//요청정보를 추출
		String id = req.getParameter("id"); // name(key)으로 값(value) 추출
		String pass = req.getParameter("pass");
		String[] item = req.getParameterValues("item"); // value가 여러개일 경우 배열로 받는다.
	}
    
	public void destroy() {//객체 소멸시 호출.
	}
}

    1) setCharacterEncoding("UTF-8") : 요청정보에 문자셋을 적용하여 한글을 셋팅
    2) setContentType("text/html;charset=UTF-8") :
         text/html; : MIME타입(응답형식)

         charset=UTF-8 : 응답데이터에 적용할 문자셋


    3) PrintWriter out = resp.getWriter() : 응답정보를 클라이언트로 전송하기 위한 스트림객체를 response에서 구하기 
    4) 요청정보를 추출
      String id = req.getParameter("name") : name(key)으로 값(value) 추출
      String[] item = req.getParameterValues("name") : value가 여러개일 경우 배열로 받는다.

 

    5) String str = req.getQueryString() : get방식에서만 사용가능하며, 요청정보의 ? 다음 문자열 전체를 받아온다.

    6) ServletInputstream in= req.getInputStream() : post방식에서 사용. 요청정보의 몸체와 연결된 입력스트림을

        받아온다.

ServletInputstream in= req.getInputStream();
int len = req.getContextLength();
byte[] buffer = new byte[len];
in.readLine(buffer,0,len);
String str = new String(buffer);

 

 

 

<tip>

* 웹구조

Web browser
(client)
request
(header+body)
--------------->

<---------------
response
WAS
(Web Server 
+ Contationer)
--------------->
<---------------
Servlet 서버의 자원
--------------->
<---------------

DBMS

 

 

* 비지니스 로직 분리

                   Servlet
1. 클라이언트의 요청정보를 추출
2. 비지니스 메소드 호출
3. 클라이언트에 응답할 메시지를 생성
매개변수
--------------->

<---------------
리턴값
비지니스 로직

 

* import가 되지않을때

 

Project Explorer창 - Dynamic 파일 오른쪽 클릭 - Build Patch - Configure Build Patch  -Libraries - Add library - Server Run time - Next - finish - Apply 



* 이클립스 창 확대 단축키 : ctrl + M

* error
404 - 파일을 찾을 수 없다.
405 - 요청한 방식의 메소드가 없을 경우

 

[목차]

10. DDL

11. DML

12. 제약조건

13. Sequence

 

[내용]

10. DDL(Date Definition Language) : 테이블 생성, 수정, 삭제, 자동 commit

    1) 테이블 생성 

create table 테이블명(
     칼럼명 데이터 타입(크기)
      ....            );
create table board( 
no number, 
id varchar2(20), 
title varchar2(20), 
content varchar2(2), 
hit number, 
regdate date);
create table myemp(
empno char(5), ename varchar2(10), hiredate date, sal number(10), memo varchar2(10));

 

    2) 테이블 변경 - 추가

alter table 테이블명
add (칼럼명 데이터타입(크기));
alter table board
add (email varchar2(20));

 

 

    3) 테이블 변경 - 수정

alter table 테이블명
modify (칼럼명 데이터타입(크기));

 

alter table board
modify (content varchar2(20));

 

    4) 테이블 삭제

drop table 테이블명;
drop table emp2;


  
11. DML(Data Manipulation Language) : 데이터 조작어

    1) insert into : data 추가

insert into 테이블명
values(값,...);
insert into board values(1,'jang','test','test1',0,sysdate,null);

insert into board values(2,'kim','title','ccocnocnco',0,sysdate,'kwdd@naver.com');

insert into board values(6,'choi','oracle','안녕하세요?????',0,sysdate, null);
insert into myemp values('00001', 'scott', sysdate, 3000,'신입');

     - 선택 칼럼의 데이터만 입력하기

insert into emp (empno, ename, hiredate) values(1111,'이이이',sysdate);
insert into emp (empno, ename, hiredate, deptno) values(7777,'율곡', sysdate, 100);


    2) update

update 테이블
set
where
update board
set title ='oracle'
where no=1;
update board
set title='oracle', hit=hit+1
where no=4;

 

    - set절 서브쿼리 이용하여 조건에 맞는 값 update

update myemp
set sal=(select sal
         from emp
         where empno=7934)
where empno=7369;

 

update myemp
set sal=(select avg(sal)
		from emp
		where mgr=7698)
where ename is null;
update myemp
set sal =sal+300
where sal<(select avg(sal)
           from emp
           where mgr=7698);
-> where절 서브쿼리 이용 조건에 맞는 값 update

 


    3) delete

delete (into) from 테이블명
where
delete from board
where no=5;
delete board
where id is null;

    - where절 서브쿼리 이용 조건에 맞는 값 delete

delete from myemp
where sal>(select avg(sal)
           from myemp);

 

    4) 삽입된 데이터 저장하기

commit;

 


12. 제약조건

    - 테이블 생성시 제약조건 추가

create table 테이블명(
칼럼명 데이터타입(크기) 제약조건,
  ....                 );
create table emp2(id varchar2(10) primary key,
                  name varchar2(10) not null,
                  pass varchar2(10));
create table emp2(
    empno number(5),
    ename varchar2(10) not null,
    deptno varchar2(10),
    sal number,
    tel varchar2(10),
    job varchar2(10),
    constraints emp2_empno_pk primary key(empno));


    - 테이블에 적용된 제약 조건 확인

desc user_contraints
select OWNER,CONSTRAINT_NAME, CONSTRAINT_TYPE, TABLE_NAME
from user_constraints;
OWNER
---------------------------------------------------------------------------------------------------------------------
CONSTRAINT_NAME                                              CO TABLE_NAME
------------------------------------------------------------ -- -----------------------------------------------------
SCOTT
SYS_C006997                                                  P  EMP

SCOTT
SYS_C007004                                                  C  EMP2

SCOTT
BOARD_ID_PK                                                  P  BOARD

SCOTT
EMP2_ID_FK                                                   R  EMP2

SCOTT
EMP2_SAL_CK                                                  C  EMP2

SCOTT
SYS_C007013                                                  P  DEPT2

SCOTT
EMP2_JOB_CK                                                  C  EMP2

     - 제약 조건 변경 (primary key)

alter table board
add constraint board_no_pk primary key(no);

 

     - 제약 조건 변경 (unique key)

alter table emp2
add constraint emp2_tel_uk unique(tel);

 

     - 제약 조건 변경 (check)

alter table 테이블
add constraint 제약조건명 check(조건);
alter table emp2
add constraint emp2_sal_ck check(sal between 5000 and 7000);

alter table emp2
add constraint emp2_job_ck check(job in('developer', 'siger', 'teacher'));

 

     - 제약 조건 변경 (foreign key)

alter table 테이블명
add constraiont 제약조건명 foreign key(칼럼) references 테이블명2(칼럼2);
                        primary key(칼럼);
alter table emp2
add constraint emp2_deptno_fk foreign key(deptno) references dept2(decode);
alter table emp2
add constraint emp2_id_fk foreign key(id) references board(id);

 

    - 제약조건 삭제

alter table emp2
drop constraint emp2_empno_pk;

 

 

13. Sequence
    - 시퀀스 생성

create sequence 시퀀스명;
create sequence board_seq;

 

    - 시퀀스 시작값 설정

create sequence tb_order_seq
start with 2020111100;

    - 현재 시퀀스 확인.

select 시퀀스명.currval form dual;
select tb_order_seq.currval from dual;
->현재 sequence 확인.

    - 다음 시퀀스

select board_seq.nextval from dual;
insert into board(no, title,regdate,hit)
            values(board_seq.nextval, 'text', sysdate,0);

 

14. on delete cascade :  미사용 권장

   - on delete cascade추가하여 foreign 제약조건 추가.

alter table tb_order
add constraint order_fk foreign key(id) references tb_customer(id) on delete cascade;

 

- on delete cascade foreign키 삭제 시 error 발생

drop table tb_customer;

- on delete cascade constraint 삭제

drop table tb_customer cascade constraints;
alter table tb_order
add constraint id_notnull not null(id);
-> error

alter table tb_order
modify id varchar2(10) not null;
-> not null 조건 추가
create table myemp
as
select empno, ename,sal, mgr, hiredate
from emp
where 1=1;
-> 테이블 생성
-> 데이터 들어감

create table myemp2
as
select empno, ename,sal, mgr, hiredate
from emp
where 1=2;
-> 테이블 생성
-> 데이터 안들어감
insert all
     into myemp values(7777,'aaaaa',1000,7475,sysdate)
     into myemp2 values(7777,'aaaaa',1000,7475,sysdate)
select * from dual;
-> myemp, myemp2에 date insert
insert all
     into myemp2 values(1111,'bbbb',1000,7475,sysdate)
     into myemp2 values(2222,'ccccc',1000,7475,sysdate)
select * from dual;
-> myemp2에 2개 date insert

   - Data Dictionary : 읽기전용
   - rollback;

   - 모든 테이블 삭제

SELECT 'DROP TABLE "' || TABLE_NAME || '" CASCADE CONSTRAINTS;' FROM user_tables;

9. 서브쿼리(subquery) : 여러개의 select 문장을 하나로 합쳐있는것
 1) 서브쿼리
  - select문에 삽입된 select문, sql문에 삽입된 다른 sql문
  - select문에만 사용되지않고 insert, update, delete, select문 모두 사용가능
  - 바깥쪽의 쿼리를 메인쿼리 or 기본쿼리라 한다.
  - sql문에 삽입된 쿼리를 서브쿼리라 하며 반드시 괄호로 묶어 주어야한다.
  - 서브쿼리가 메인쿼리 실행전에 한번 싱행된다.
  - 서브쿼리의 결과가 메인쿼리에서 실행된다.
  - select문에서는 select, from, where, having절 모두에서 삽입가능.
  
 2) 서브쿼리의 종류
     ① 단일행 서브쿼리 : 서브쿼리의 실행결과가 행하나, 열 하나로 리턴되는 것, 메인쿼리에서 비교할 때 = 연산자를

      이용하는 것이 가능

select ename, sal, hiredate, deptno
from emp
where sal>=(select max(sal)
            from emp
            where deptno=20);
select *
from emp
where job=(select job
           from emp
           where ename='SMITH');
select ename, deptno, sal
from emp
where sal>(select max(sal)
           from emp
           where deptno=20);
select employee_id, first_name||' '||last_name name, hire_date
from employees
where hire_date like '05%'
       and hire_date < (select hire_date
       			from employees
       			where first_name = 'Lisa');

	   
or
where to(hire_date,'YYYY')='2005'
select e.first_name, e.salary, d.department_name
from employees e, departments d
where e.department_id = d.department_id
      and d.department_name = 'Sales'
	  and salary < (select avg(salary)
	                 from employees
	                 where department_id=100
	                 group by department_id);
select m.employee_id, m.last_name, m.hire_date, m.salary
from employees e, employees m
where e.last_name = 'De Haan'
      and e.manager_id = m.employee_id;
	  
	  
select employee_id, last_name, hire_date, salary
from employees
where e.last_name = (select manager_id
                     from employees
                     where last_name = 'De Haan');
select d.department_name, avg(e.salary)
from employees e, departments d
where e.department_id = d.department_id
group by d.department_name
having avg(e.salary) <= (select avg(salary)
	                     from employees
	                     where department_id = 30
	                     group by department_id);

 

     ② 다중행 서브쿼리 : 서브쿼리의 실행결과가 열은 하나지만 행이 여러개 반환되는 것. = 연산자를 이용할 수 없다.
         1) in 연산자

select ename, sal, deptno
from emp
where sal in(select sal
             from emp
             where job='MANAGER');
select *
from emp
where deptno in (select deptno
              from emp
              where job='MANAGER');
select ename, empno
from emp
where deptno in (select deptno
                from emp
                where ename like '%T%');
select *
from emp
where sal in (select min(sal)
             from emp
              group by deptno);

         2) all 연산자 : 모두 만족해야한다.
         >all(서브쿼리) : 서브쿼리의 모든 값보다 커야함. 서브쿼리의 최대값보다 큰값.

select ename, sal, deptno
from emp
where sal >all(select sal
             from emp
             where job='MANAGER')
order by sal;

         <all(서브쿼리) : 서브쿼리의 최소값보다 작은 값.

select ename, sal, deptno
from emp
where sal <all(select sal
             from emp
             where job='MANAGER')
order by sal;


   
         3) any : 결과 값 중 한개만 만족하면 됨.
         >any(서브쿼리) : 서브쿼리의 어느값중 하나만 만족하면 됨. 서브쿼리의 최소값보다 큰 값.

select ename, sal, deptno
from emp
where sal >any (select sal
             from emp
             where job='MANAGER')
order by sal;


         <any(서브쿼리) : 서브쿼리의 최대값보다 작은 값.

select ename, sal, deptno
from emp
where sal <any (select sal
             from emp
             where job='MANAGER')
order by sal;


     ③ 다중 열(컬럼) 서브쿼리 : 서브쿼리의 칼럼을 다수로 가져가 비교

select *
from emp
where (deptno, sal) in (select deptno, min(sal)
             from emp
              group by deptno);
select employee_id, last_name, salary, department_id
from employees
where (department_id, salary) in (select department_id, max(salary)
                 from employees
                 group by department_id)
order by salary desc

     => deptno도 같아야 할 경우

     => 칼럼 수가 하나면 deptno가 달라도 조회된다.


     ④ 상호연관 서브쿼리
     - 메인쿼리의 칼럼을 서브쿼리에서 사용해야하는 경우.
     - 메인쿼리의 row가 어떤 칼럼값을 가지고 있느냐에 따라서 서브쿼리의 결과가 달라진다.
     [실행순서]
     1) 메인쿼리에서 현재 작업중인 row의 칼럼값을 가져온다.
     2) 메인쿼리에서 가져온 값을 이용해서 서브쿼리를 진행.
     3) 서브쿼리에서 실행한 결과를 다시 메인쿼리로 전달 후 메인쿼리를 실행.
     4) 메인쿼리에서 사용하는 테이블의 전체 row에 대해서 1~3번까지의 작업을 반복수행.

select ename, sal, deptno
from emp main
where sal > (select avg(sal)
from emp e
where e.deptno = main.deptno);

    ⑤ View

    - view생성 권한부여

conn system/manager
grant create view to scott;

    - view생성

create view myempview
as
select d.dname, e.ename, e.sal, e.hiredate
from emp e, dept d
where e.deptno= d.deptno;

 

    - view생성시에는 컬럼에 alias가 꼭 필요.

create view maxsaldata
as
select deptno, max(sal) maxsal
from emp
group by deptno;
create view avgsal
as
select deptno, avg(sal) 평균급여
from emp
group by deptno;

 

    - view 사용

select e.deptno, e.empno, e.ename, e.sal, s.평균급여
from emp e, avgsal s
where e.deptno=s.deptno(+);


    ⑥ inline view
     - from절에 정의하고 사용하는 서브쿼리.
     - 서브쿼리를 이용해서 from절에서 사용할 가상의 테이블을 정의할 수 있는 데, 이를 inline view라 한다.
     - 하나의 테이블에 데이터가 많이 있는 경우 from정에 정의하면 비효율적일 수 있으므로 필요한 행과 열만

        from절에서 사용할 수 있도록 한다.
     [정의방법]

select
from (select
      from
      where
      group by
      having      )alias
select e.deptno, e.empno, e.ename, e.sal, avgt.avgsal
from emp e, (select deptno, avg(sal) avgsal
             from emp
             group by deptno) avgt
where e.deptno = avgt.deptno and
      e.sal>avgt.avgsal;

     => from절에 삽입되는 서브쿼리를 사용하는 경우 반드시 서브쿼리 뒤에 alias를 정의해야한다.(테이블명으로 사용)

          서브쿼리안에서도 계산의 결과로 만들어지는 칼럼은 반드시 alias를 정의해야한다.(칼럼명으로 사용)
 

    ⑦ ton-n 서브쿼리
    - row num을 활용해서 순위와 연관있는 서브쿼리.
  

    - rownum사용

select rownum, ename, sal
from emp;
select 월, 입사자수
from (select substr(hire_date,4,2) 월, count(*) 입사자수
      from employees
      group by substr(hire_date,4,2)
      order by 입사자수 desc)
where rownum<4
order by 월;


select to_char(hire_date,'MM') 월, count(employee_id) 입사자수
from employees
group by to_char(hire_date,'MM')
order by 입사자수 desc
select first_name, salary, department_name
from (select e.first_name, e.salary, d.department_name
from employees e, departments d
where department_name = 'IT'
       and e.department_id = d.department_id
order by salary desc)
where rownum<4;
select rownum, ename, sal
from emp
where rownum<4
order by sal desc;

    ->원하는 결과 X

 

select rownum, ename, sal
from (select *
      from emp
      order by sal desc)
where rownum <4;

    ->원하는 결과 O

 

    1) row_number() over (order by '순위 기준 칼럼' desc) 
     -> 동률자 순차적 순번

select row_number() over (order by sal desc) 순위, ename, sal, deptno
from emp;
      순위 ENAME                       SAL     DEPTNO
---------- -------------------- ---------- ----------
         1 KING                       5000         10
         2 FORD                       3000         20
         3 SCOTT                      3000         20
         4 JONES                      2975         20
         5 BLAKE                      2850         30
         6 CLARK                      2450         10
         7 ALLEN                      1600         30
         8 TURNER                     1500         30
         9 MILLER                     1300         10
        10 ADAMS                      1300         20
        11 WARD                       1250         30
        12 MARTIN                     1250         30
        13 JAMES                       950         30
        14 SMITH                       800         20
        15 율곡                        500         90
        16 이이이                      500

 

    2) rank() over (order by '순위 기준 칼럼' desc)

    -> 동률자 같은 순번 + 다음 순서 동률자 계산O

select rank() over (order by sal desc) 순위, ename, sal, deptno
from emp; 
     순위 ENAME                       SAL     DEPTNO
--------- -------------------- ---------- ----------
        1 KING                       5000         10
        2 FORD                       3000         20
        2 SCOTT                      3000         20
        4 JONES                      2975         20
        5 BLAKE                      2850         30
        6 CLARK                      2450         10
        7 ALLEN                      1600         30
        8 TURNER                     1500         30
        9 MILLER                     1300         10
        9 ADAMS                      1300         20
       11 WARD                       1250         30
       11 MARTIN                     1250         30
       13 JAMES                       950         30
       14 SMITH                       800         20
       15 율곡                        500         90
       15 이이이                      500

    

    3) dense_rank() over (order by '순위 기준 칼럼' desc) 
    -> 동률자 같은 순번 + 다음 순서 동률자 계산

select dense_rank() over (order by sal desc) 순위, ename, sal, deptno
from emp; 
      순위 ENAME                       SAL     DEPTNO
---------- -------------------- ---------- ----------
         1 KING                       5000         10
         2 FORD                       3000         20
         2 SCOTT                      3000         20
         3 JONES                      2975         20
         4 BLAKE                      2850         30
         5 CLARK                      2450         10
         6 ALLEN                      1600         30
         7 TURNER                     1500         30
         8 MILLER                     1300         10
         8 ADAMS                      1300         20
         9 WARD                       1250         30
         9 MARTIN                     1250         30
        10 JAMES                       950         30
        11 SMITH                       800         20
        12 율곡                        500         90
        12 이이이                      500

 

    4) ntile('그룹 갯수') over (order by '순위 기준 칼럼' desc) 
     -> 그룹갯수의 수로 균등한 숫자로 순위 줌. 전체 레코드/그룹개수 
     -> 나머지는 위에 부터 순차적으로 들어감.

select ntile(3) over (order by sal desc) 순위, ename, sal, deptno
from emp; 
      순위 ENAME                       SAL     DEPTNO
---------- -------------------- ---------- ----------
         1 KING                       5000         10
         1 FORD                       3000         20
         1 SCOTT                      3000         20
         1 JONES                      2975         20
         1 BLAKE                      2850         30
         1 CLARK                      2450         10
         2 ALLEN                      1600         30
         2 TURNER                     1500         30
         2 MILLER                     1300         10
         2 ADAMS                      1300         20
         2 WARD                       1250         30
         3 MARTIN                     1250         30
         3 JAMES                       950         30
         3 SMITH                       800         20
         3 율곡                        500         90
         3 이이이                      500

 

    5) 위에 합수 over 구문에 partition by '그룹핑' 하여 그 그룹안에서 각각 순위를 정한다.

select rank() over( partition by deptno order by sal desc) 순위, ename, sal, deptno
from emp;
      순위 ENAME                       SAL     DEPTNO
---------- -------------------- ---------- ----------
         1 KING                       5000         10
         2 CLARK                      2450         10
         3 MILLER                     1300         10
         1 SCOTT                      3000         20
         1 FORD                       3000         20
         3 JONES                      2975         20
         4 ADAMS                      1300         20
         5 SMITH                       800         20
         1 BLAKE                      2850         30
         2 ALLEN                      1600         30
         3 TURNER                     1500         30
         4 MARTIN                     1250         30
         4 WARD                       1250         30
         6 JAMES                       950         30
         1 율곡                        500         90
         1 이이이                      500



8. 조인(join) : 여러 테이블을 연결해서 필요한 데이터를 조회하는 방법
    - 오라클 조인 : 여러테이블 연결조건을 where절에 정의
    - ANSI 조인(표준)

    1) 개요 : 정규화된 여러 테이블의 데이터를 이용해서 데이터를 조회해야하는 경우 테이블 조인을 한다.
    - 조인은 관계형 데이터 베이스에서의 중요기능.
    - 기본키와 외래키 관계를 이용해서 테이블을 조인해야한다.
    - 조인을 하는 경우 반드시 조인 조건 정의.
  
    2) 조인 사용방법
    - from절에 테이블을 정의할 때 alias를 이용해서 정의.

select d.dname, e.ename, e.sal
from emp e, dept d
where e.deptno=d.deptno and sal>2000;
select e.empno, e.ename, e.job, e.deptno, d.deptno, d.dname
from emp e, dept d
where e.deptno=d.deptno;
select d.deptno, d.dname, l.city
from dept d, locations l
where d.loc_code=l.loc_code;

     -> deptno : 기본키


  - select절에서 두 개 이상의 테이블에 있는 칼럼을 추가하는 경우 from절에서 정의한 alias를 이용해서 칼럼의 모호성 제거.
  - where절에서는 반드시 조인조건을 정의해야한다. 조인을하면 외래키 테이블의 외래키와 기본키 테이블의 기본키를 비교하고 일치하는 레코드의 원하는 값을 가져오므로 조건을 정의하지않으면 데이터를 조회할 수 없다.
  - 사용되는 모든 테이블의 조인조건을 정의해야한다. (테이블이 세개면 조인 조건은 두개 정의)

select e.ename, d.dname, e.sal, l.city
from emp e, dept d, locations l
where e.deptno=d.deptno and d.loc_code=l.loc_code;

    - 검색 조건 추가
      where 조인조건
      and 조건추가

select e.empno, e.ename, e.sal, d.dname, d.loc_code
from emp e, dept d
where job='SALESMAN'
and e.deptno=d.deptno;
select ename, sal, hiredate
from emp e, dept d, locations l
where l.city = 'SEOUL'
        and e.deptno=d.deptno and d.loc_code=l.loc_code;
select e.ename, e.sal, e.job, e.hiredate, e.comm
from emp e, dept d, locations l
where e.deptno=d.deptno and d.loc_code=l.loc_code
and l.city='DALLAS' and e.sal>=1500;
select d.department_name, count(e.employee_id)
from employees e, departments d
where e.department_id = d.department_id
group by department_name;
select e.first_name || e.last_name || '의 연봉은 ' || e.salary
|| ' 입니다.' as 결과
from employees e,departments d
where e.department_id = d.department_id
and d.department_name = 'IT'
order by salary asc;
select e.employee_id, e.first_name, j.job_title, d.department_name
from employees e, departments d, locations l, jobs j
where e.department_id=d.department_id
and d.location_id = l.location_id
and e.job_id=j.job_id
and l.city ='Seattle';
select j.job_title job, sum(e.salary) 급여
from employees e, jobs j
where j.job_title not like '%Representative%'
      and j.job_id=e.job_id
group by j.job_title
having sum(e.salary)>30000
order by sum(e.salary);
select d.department_name 부서명, count(e.department_id) 인원수
from employees e, departments d
where e.department_id = d.department_id
      and hire_date <'2005-1-1'
group by d.department_name;
select d.department_id 부서번호, d.department_name 부서명, count(e.employee_id) 인원수,
 max(e.salary) 최고급여, min(e.salary) 최저급여, floor(avg(e.salary)) 평균급여, sum(e.salary) 급여총액
from employees e, departments d
where e.department_id = d.department_id
group by d.department_id, d.department_name
having count(e.department_id)>=3
order by 인원수 desc;
select j.job_title job, sum(e.salary) 급여
from employees e, jobs j
where j.job_title not like '%Representative%'
      and j.job_id=e.job_id
group by j.job_title
having sum(e.salary)>30000
order by sum(e.salary);
select d.department_name, floor(avg(salary)) 평균연봉
from employees e, departments d
where e.department_id=d.department_id
group by d.department_name
having avg(salary)>= 5000
order by 평균연봉 desc; 


  3) 조인의 종류(oracle 조인)
   ① Equip 조인 : 두개 이상의 테이블에서 칼럼 값이 정확하게 일치하는 경우 조회.
    조인조건 : where 기본테이블.기본키 = 외래키테이블.외래키
        (테이블은 alias 사용가능)

select e.ename d.dname
from emp e, dept d
where e.deptno = d.deptno


   ② outer 조인
   - 조인 적용했을 때 조인 조건을 만족하지않는 데이터를 조회하고 싶을때 사용.
   - (+) 연산자를 한쪽 칼럼에 초가해서  사용.
   - 만족하지 않아도 한쪽테이블의 모든 데이터를 조회해서 볼 수 있도록 자원.
   - (+)가 추가되면 만족되지 않는 조건을 임의로 추가해서 비교하므로 (+)가 투가되지않은 테입르의 레코드가 

     출력된다.
   [구문]

select 테이블명1(alias1명).칼럼며으 테이블2 alias2
from 테이블명1 alias1, 테이블명2 alias2
where 테이블명1(alias1).칼럼명(+) = 테이블명2(alias).칼럼명(+)

    - dept table에 null을 추가하여 emp table과 비교하여 emp table의 null data를 조회한다.

    - Equip 조인은 조인문에 detno가 일치하지않거나 null인 경우 조회되지않는다.

select e.empno, d.dname, e.ename, e.sal
from emp e, dept d
where e.deptno = d.deptno(+);
select nvl(m.ename,'관리자없음') 관리자명, count(e.empno) 인원수
from emp e, emp m
where e.mgr=m.empno(+)
group by m.ename;
select j.job_title, count(e.employee_id)
from employees e, jobs j
where e.job_id=j.job_id(+)
group by j.job_title;

    - emp table에 null을 추가하여 dept table과 비교하여 dept table의 null data를 조회한다.

select e.empno, d.dname, e.ename, e.sal
from emp e, dept d
where e.deptno(+) = d.deptno;
select d.department_name, count(e.employee_id)
from employees e, departments d
where e.department_id(+)=d.department_id
group by d.department_name
order by d.department_name;


   ③ non-Equip 조인(등급표 조인)
    - 두테이블에서 비교해야하는 칼럼 값이 정확하게 일치하지않고 사이 값인 경우 조인하는 방법. =연산자를 

      사용하지않은 조인.

select e.empno, e.sal, g.grade
from emp e, salgrade g
where e.sal between g.losal and g.hisal;


   ④ self 조인
    - 같은 테이블에서 조인하는 경우.
    - 하나의 테이블의 다른 칼럼을 가지고 조인하며 서로 다른 테이블인 것처럼 작업할 수 있다.
    - 조인조건은 equip조인과 동일하게 정의

select e.empno 사원번호, e.ename 사원명, e.mgr 관리자코드, m.ename 관리자명
from emp e, emp m
where e.mgr=m.empno;
select e.employee_id, e.first_name, nvl(m.first_name,'관리자 없음') 관리자명
from employees e, employees m
where e.manager_id = m.employee_id(+)
      and e.first_name like '_t%';
select e.first_name, e.salary
from employees e, employees m
where e.manager_id = m.employee_id
      and e.salary>m.salary;

 

 

[목차]

7. 함수

    1) 문자처리 함수 
        ① length() 
        ② sum(), max(), min(), count(), avg(), count(*) 
        ③ lower(), initcap(),upper() 
        ④ dual 
        ⑤ concat(A,B)
        ⑥ instr('문자열', '찾을 문자',m번째 부터 검색, 찾은 문자의 n번째 위치)  
        ⑦ substr('문자열', m번쨰 부터 짜름, n개 글자) 
        ⑧ replace('문자열', 바꿀문자, 바뀔문자) 
        ⑨ lpad('문자열', 전체 자리수, 공백문자)  
            rpad
        ⑩ ltrim('문자열', '지울문자') 
            rtrim
            trim
    2) 숫자자리 함수  
        ① round() 
        ② ceil() 
        ③ floor() 
    3) 날짜 함수  
        ① sysdate 
        ② months_between(A,B)  
        ③ add_month(A,B)  
        ④ next_day(A,B) 
        ⑤ last_day() 
    4) 변환함수  
        ① to_char(A,'9.99')  
        ② to_char(A,'YYYY-MM-DD')  
    5) 조건함수  
        ① decode(칼럼, 값1, 동일하면 출력할 값1 
                             값2, 동일하면 출력할 값2 
                       나머지 경우 출력할 값  )  
        ② case when 조건식1 then  출력할 값1 
            when 조건식2 then 출력할 값2 
            else 나머지 경우 출력할 값 
            end 별칭 
    6) null처리 함수  
        ① nvl(A,B)  
        ② nvl2(A,B)  

 

[내용]

7. 함수 
    1) 문자처리 함수

        ① length()

select ename, length(ename)
where length(ename)>=6;

        ② sum(sal), max(), min(), count(), avg(), count(*)

select ename, sal, max(sal)
from emp
group by ename;
select deptno, count(empno)
from emp
group by deptno;


        ③ lower(), initcap(첫글자만 대문자),upper()

select empno, ename, lower(job), deptno
from emp
where ename = 'SCOTT'


        ④ dual : test 1행짜리 테이블.

select *
from dual; 


        ⑤ concat(A,B) : || 문자열 연결. 
            concat(A, concat(B,C))

select concat(ename,concat('의 급여',concat(sal,'만원')))
from emp
where sal<1000;


        ⑥ instr('문자열', '찾을 문자',m번째 부터 검색, 찾은 문자의 n번째 위치) 
           -> 위치반환


         substr('문자열', m번쨰 부터 짜름, n개 글자) 
           -> 글자 추출 -1은 맨뒤.

select ename, hiredate
from emp
where substr(hiredate,1,2)=81;
select empno, ename, job, sal, deptno
from emp
where substr(ename,1,1) > 'K' and substr(ename,1,1) < 'Y';


        ⑧ replace('문자열', 바꿀문자, 바뀔문자)


        ⑨ lpad('문자열', 전체 자리수, 공백문자) 
           -> 왼쪽에 공백문자를 가짐, 전체 자리수에서 부족한 공백은 설정한 공백문자로 채운다.

            rpad : 오른쪽에 공백문자를 가짐.

select ename, job, lpad(sal,5,'*') as sal
from emp
where sal<=2000;

 

          ⑩ ltrim('문자열', '지울문자') : 왼쪽 문자를 지움

              rtrim('문자열', '지울문자') : 오른쪽 문자를 지움 
              trim(''from'문자열') : 양쪽 문자를 지움 

select ename, job, ltrim(lpad(sal,5,'*'),'*') as sal
from emp
where sal<=2000;
select ltrim(job,'A'), ltrim(sal,1)
from emp
where deptno=10;


    2) 숫자자리 함수 
         round() : 반올림

select deptno, round(avg(sal)) avg
from emp
where job<>'PRESIDENT'
group by deptno
having avg(sal)>1800
order by deptno;


         ceil()  : 올림 
         floor   : 버림 

    3) 날짜 함수 
        ① sysdate : 오늘날짜. 연산가능 
         months_between(최신날짜, 먼날짜) 
         add_month(,더할달수) 
        ④ next_day(지정일,'금') 요일 
        ⑤ last_day(지정일) : 마지막날

select e.first_name, e.salary, e.hire_date, d.department_name
from employees e, departments d
where e.department_id=d.department_id
      and months_between(sysdate,hire_date) >12*18;


    4) 변환함수 
         to_char(   ,'9.99') 
         to_char(   ,'YYYY-MM-DD')

select to_char(hiredate,'MM')월, count(*)입사자수
from emp
group by to_char(hiredate,'MM')
order by to_char(hiredate,'MM');


    5) 조건함수 
         decode(칼럼, 값1, 동일하면 출력할 값1

                             값2, 동일하면 출력할 값2

                       나머지 경우 출력할 값  )

select ename, deptno, decode(deptno, 10, '전산실',
                              20, '총무과',
                              30, '기획실',
                              '신입')
from emp;


         case when 조건식1 then  출력할 값1
            when 조건식2 then 출력할 값2
            else 나머지 경우 출력할 값
            end 별칭

select ename, sal, case when sal>=5000 then '1등급'
                 when sal>=2000 and sal<5000 then '2등급'
                 when sal>=1000 and sal<2000 then '3등급'
                 else '신입'
                 end  등급표
from emp;


    6) null처리 함수 
        ① nvl(칼럼or표현식, null인 경우 적용할 값 or 표현식(연산,함수호출))

select nvl(to_char(department_id),'No Department')부서번호, round(avg(salary),0)평균급여
from employees
group by department_id
having avg(salary) >6000;


        ② nvl2(칼럼 or 표현식, null이 아닌 경우 적용할 값, null인 경우 적용할 값)

select ename, mgr, nvl2(mgr,'담당','상위자') 관리자
from emp
order by 관리자;

+ Recent posts

1···67891011