본문 바로가기
국비학원/수업기록

국비 지원 개발자 과정_Day57

by 루팽 2023. 2. 17.

<HelloServlet.java복습>

package com.day1;

import java.io.IOException;
import java.io.*;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;

/*
 form 전송시 클라이언트측의 요청을 서블릿이 듣는다(받는다)
 method="get"이면 doGet호출
 method="post이면 doPost호출
 
 자바가 서블릿이 되기위한 조건은 반드시 HttpServlet을 상속받는 것이다
 상속을 받으면 doGet과 doPost를 오버라이딩 할 수 있는데
 이 함수의 파라미터를 통해서 request 요청 객체와 response 응답 객체를 주입받는다
 톰캣 서버에서 주입해줌
 
 웹서비스를 위해서는 URL 등록이 필수 -> 브라우저가 실행 주체이니까
 프로젝트에 필요한 URL등록은 annotation과 web.xml문서를 통해서 가능하다
 이 중 annotation은 자동이고 편하지만 수동처리와 비교해서 추가작업이 불가능한 단점이 있다
 xml문서를 통해서 객체를 등록하고 주입받는다
 이유는 spring 사용시 메이븐 레포를 이용한 프로젝트 생성인 경우에 xml문서로 환경설정함
 클래스 사이의 객체주입 관계도 xml문서로 처리 가능함
*/
public class HelloServlet extends HttpServlet {
	Logger logger = Logger.getLogger(HelloServlet.class);

	@Override
	public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		System.out.println("doGet 호출");
		String mem_id = req.getParameter("mem_id");
		logger.info("사용자가 입력한 아이디는 " + mem_id + " 입니다.");
		logger.info("doGet 호출 성공");
		res.setContentType("text/html;charset=UTF-8");
		PrintWriter out = res.getWriter();
		String msg = "안녕하세요";
		// 브라우저에서 요청[GET방식]시 응답으로 나가는 문자열
		// 문자열(1. 텍스트파일: 숫자의 경우 문자로 변환 후 쓴다 / 2. 바이너리파일: 데이터를 있는 그대로 읽고 쓴다)
		// text메인타입 html서브타입 - 브라우저가 번역 - 태그는 없고 내용만 출력
		out.print("<font size=28px color=red>"+msg+"</font>"); // 리소스
	}

	// POST방식은 단위테스트가 불가하다 -> Postman사용하면 가능
	//
	@Override
	public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		System.out.println("doPost 호출");
		logger.info("doPost 호출 성공");
		res.setContentType("text/html;charset=UTF-8");
		PrintWriter out = res.getWriter();
		out.print("<h3>doPost</h3>호출");
	}
}

/*
 * 웹서비스[요청하고 응답받기] 제공을 위한 언어
 * 요청을 어디에 하는가? -> 브라우저에 URL로 요청
 * 	HTTP(Hyper Text Transfer Protocol) - 텍스트를 전송하는 프로토콜이다
 * 	-> 이미지, 동영상도 출력 가능한 이유? -> 마임타입때문에!
 * 	HTTPS = HTTP + TLS(암호화 모듈 추가)
 * 
 * 요청 방식에는 몇가지가 있는지? 
 * 	GET: 클라이언트가 서버에게 URL에 해당하는 자료의 전송을 요청한
 * 	HEAD: GET 요청으로 반환될 데이터 중 헤더 부분에 해당하는 데이터만 요청
 * 	POST: 클라이언트가 서버에서 처리할 수 있는 자료를 보냄
 * 	PATCH: 클라이언트가 서버에게 지정한 URL의 데이터를 부분적으로 수정할 것을 요청
 * 	PUT: 클라이언트가 서버에게 지정한 URL에 지정한 데이터를 저장할 것을 요청
 * 	DELETE: 클라이언트가 서버에게 지정한 URL의 정보를 제거할 것을 요청
 * 	TRACE: 클라이언트가 서버에게 송신한 요청의 내용을 반환해 줄 것을 요청 - log4j.properties에서 mybatis sql문 출력하는데 사용
 * 	CONNECT: 클라이언트가 특정 종류의 프록시 서버에게 연결을 요청
 * 	OPTIONS: 해당 URL에서 지원하는 요청 메세지의 목록을 요청
 * 
 * 요청을 위해서는 무엇이 준비되어 있어야 하나?
 * 
 * 
 * get 방식
 * 	서버측의 리소스(html, css, js)를 가져오기 위해 설계됨
 * 	퀴리스트링으로 전송(소용량)
 * 	노출된다(보안x)
 * 	데이터 공유에 유리 -> 사이트도메인?상품아이디=qwer1234
 * 	검색에 주로 사용
 * 
 * post 방식
 * 	서버에 데이터를 올리기(쓰기) 위해 설계됨
 * 	전송데이터 크기의 제한이 없음(대용량도 가능)
 *	데이터를 메시지의 body에 담아서 전송한다
 * 	보안에는 유리하지만 공유에는 불리하다
 * 	글쓰기, 로그인, 회원가입에 주로 사용
 */

 

JSP 스크립트 요소

  <% %> 스크립틀릿(Scriptlet)

  JSP에서 자바코드 작성할 때 사용(service() 안에 들어간다)

  변수 선언은 가능하지만 메소드 선언을 불가

  선언된 변수는 지역변수이다 → 초기화를 생략할 수 없다

 

 

  <%! %> 선언문(Declaration)

  이곳에서 선언된 것은 모두 전역변수이다 → 초기화 생략가능

  메소드 선언 가능하다

  하지만 쓰지 않음!!(이름 등 확정할 수 없기에 인스턴스화할 수 없다!)

  a.jsp → a_jsp.java(톰캣서버기준)

  WAS제품마다 자바로 바꾸는 명명규칙에 다르다(a_XXX.java)

  따라서 인스턴스화가 불가함!

 

 

  <%= ”” %> 표현식(Expression)

  어떤 값을 출력하고자 할 때 사용

  <%out.print(””);%>와 같음

 

  <%@ page import=”java.util.Map” contentTypr=”text/html;charset=UTF-8” %> 페이지 다이렉티브(Directive)

  JSP에대한 설정 정보를 지정할 때 사용

 

  <%-- --> 주석

  JSP에서 주석을 처리하는 방법

 

웹서비스 흐름도

사용자 요청 → servlet(UI엔 별로, 요청받음) → java → oracle →java →servlet → jsp(view계층 담당-출력, 응답) → 사용자에게 응답

 

크기로 따졌을때(자바가 베이스)

java > servlet > jsp

 

서블릿 생명주기

톰캣에선 서블릿을 싱글톤으로 관리(기능이 같으니까-ex. 로그인)

이 요청이 처음이면 init() → service(), doGet(), doPost() → destroy()

두 번째라면 service()부터 시작

 

<서블릿 생명주기 - LifeCycleServlet.java>

package com.day1;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;

/*
 * GenericServlet(service() 제공) <- HttpServlet(doGet, doPost)하위클래스라서 더 많은기능
 * WebServlet 어노테이션이 있는 서블릿은 컨트롤 계층을 담당함
 * 서블릿은 구조상 뷰계층을 담당하지 않는다
 */
@WebServlet("/lifecycle") // spring의 @Controller[컨트롤계층] + @RequestMapping[URL패턴정의]
public class LifeCycleServlet extends HttpServlet {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	Logger logger = Logger.getLogger(LifeCycleServlet.class);	

	@Override
	protected void service(HttpServletRequest arg0, HttpServletResponse arg1) throws ServletException, IOException {
		/*
		 * 입력, 처리, 출력을 담당함
		 * 사용자의 요청을 받는 메소드
		 * HTTP 메소드를 참조하여 doGet()을 호출할지, doPost()를 호출할지 결정
		 * 요청이 있을때 마다 호출됨
		 */
		logger.info("service 호출");
	}

	@Override
	public void destroy() {
		/*
		 * 서블릿이 메모리에서 제거될 때 서블릿 컨테이너에의해 자동 호출됨
		 * 서블릿의 일생동안 단 한번 호출됨
		 */
		logger.info("destroy 호출");
	}

	@Override
	public void init() throws ServletException {
		/*
		 * 서블릿이 초기화될 때 자동 호출되는 메소드
		 * 서블릿의 초기화 작업 담당
		 * 개발자가 호출하는 메소드 아님
		 * 서블릿의 일생동안 단 한번 호출됨
		 */
		logger.info("init 호출");
	}
}

 

<hello.jsp>

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<form id="f_test" method="post" action="/day1/hello.kh">
		<!-- 전송버튼에 대한 이벤트처리가 없는 요청이 서버에 전달되는 이유는? -> 버튼 타입이 submit이기에 -->
		<button>버튼전송</button>
		
		<!-- input type="button"은 타입이 submit이 아니라서 전송X! -->
		<input type="button" id="btnSend" value="인풋전송">
		
		<script type="text/javascript">
			const btnSend = document.querySelector("#btnSend");
			btnSend.addEventListener('click', () => {
				alert("인풋전송 버튼 클릭") // 창은 뜨지만 실제 전송은 안되고있음
				document.querySelector("#f_test").submit() // 인풋 타입버튼은 submit을 해줘야 서버에 전달된다
			})
		</script>
	</form>
</body>
</html>

 

<MimeHtmlServlet2.java 복습>

package com.day1;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.log4j.Logger;

/*
 * 서블릿은 java라도 브라우저에 출력할 수 있다 - 화면을 그리는데 서블릿을 사용함(마임타입때문에 가능!)
 * 
 * <서블릿을 경유하여 응답페이지를 jsp로 가져가는 실습>
 * 	처음부터 mimeHtmlResult.jsp를 직접 호출하는 것이 아니라,
 * 	아래에있는 url, 즉 /day1/html2.do로 요청했을 때
 * 	아래의 코드 res.sendRedirect("./mimeHtmlResult.jsp");를 만나서
 * 	주소창이 변경되는 것을 관찰한 뒤 서블릿에서 세션에 담은 정보를
 * 	mimeHtmlResult.jsp 페이지에서 유지되는지 확인하는 실습이다
 */
@WebServlet("/day1/html2.do") // 웹에서 접근 가능한 맵핑 주소 설정
public class MimeHtmlServlet2 extends HttpServlet {
	Logger logger = Logger.getLogger(MimeHtmlServlet.class);
	
	@Override
	public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		logger.info("doGet 호출");
		/*
		 * 요청객체로 세선객체를 생성함 - 요청객체가 있어야만 세션사용이 가능함
		 * 세션은 시간을 연장할 수 있다
		 * 서블릿에서는 scope가 지원되고 객체의 유지 정도가 다르다
		 * 	page scope - 그 페이지 안에서만 기억해줌(불편함, 안씀)
		 * 	request scope - 요청이 유지되는 동안에만 유지된다 - URL주소가 그대로이면 유지, 바뀌면 잃어버림
		 * 	session scope - URL주소가 바뀌어도 유지됨! - 톰캣은 기본 30분세팅
		 * 									중요한 정보는 모두 세션(서버쪽 캐시메모리)에 보관한다
		 * 	application scope - 죽지않음(사용하면 안됨! - 서버가 다운되니까)
		 */
		HttpSession session = req.getSession();
		
		// String
		String myName = new String("이순신");
		// int
		int age = 35;
		// Map
		Map<String, Object> rMap = new HashMap<>();
		rMap.put("mem_id", "tomato");
		rMap.put("mem_pw", "111");
		rMap.put("mem_name", "토마토");
		// List<Map>
		List<Map<String, Object>> mList = new ArrayList<>();
		if(rMap != null) {
			rMap.clear();
		}
		rMap = new HashMap<>();
		rMap.put("mem_id", "tomato");
		rMap.put("mem_pw", "111");
		rMap.put("mem_name", "토마토");
		mList.add(rMap);
		rMap = new HashMap<>();
		rMap.put("mem_id", "kiwi");
		rMap.put("mem_pw", "222");
		rMap.put("mem_name", "키위");
		mList.add(rMap);
		rMap = new HashMap<>();
		rMap.put("mem_id", "banana");
		rMap.put("mem_pw", "333");
		rMap.put("mem_name", "바나나");
		mList.add(rMap);
		
		// 세션을 이용해 이름값을 jsp로 넘겨줌
		session.setAttribute("myName", myName);
		session.setAttribute("age", age);
		session.setAttribute("rMap", rMap);
		session.setAttribute("mList", mList);
		
		res.sendRedirect("./mimeHtmlResult.jsp");
	}
}

 

http는 비상태(stateless) 프로토콜 → 유지되지 않음

 

Scope

변수에 접근할 수 있는 범위

Page < Request < Session < Application 순으로 커짐

 

Page scope

사용자가 페이지(a.jsp) 요청 → a.jsp 에서 res.sendRedirect(’b.jsp’), URL(주소창)이 바뀜(기존의 요청이 끊어지고 새로운 요청이 열림) → b.jsp → 사용자에게 응답

a페이지에서 myCar = new Sonara() 생성해도 b페이지에서 myCar 사용 불가!

페이지 내에서 지역변수처럼 사용

 

Request scope

요청이 유지되는 동안에(URL이 바뀌지 않으면) 사용가능

주소창이 바뀌지 않는다면 a페이지에서 myCar = new Sonara() 생성해도 b페이지에서 myCar 사용 가능!

http요청을 WAS가 받아서 웹 브라우저에게 응답할 때까지 변수가 유지되는 경우 사용

RequestDispatcher view = req.getRequestDispatcher(”b.jsp”);

view.forward(req, res); → 주소번지 원본을 넘겨주기에 유지됨

setAttribute(”이름”, “값”); → 값 넘기기

getAttribute(”이름”) → 값 꺼내기, 리턴타입은 object

 

Session scope

웹 브라우저별로 변수가 관리되는 경우 사용

세션 객체가 생성돼서 소멸될때까지 상태유지

Request와 달리 여러 개의 요청이 들어와도 계속 남아있음

 

Application scope

웹 어플리케이션이 시작되고 종료될 때까지 변수가 유지되는 경우 사용

 

 

<RequestScope로 값 공유 - RequestScope.java>

package com.day2;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;

/*
 * http://localhost:9000/day2/a로 요청을 하면
 * RequestScope 서블릿 클래스의 doGet메소드 안에서 sendRedirect대신에
 * forward 메소드가 호출되므로 주소는 그대로인데
 * 실제 출력 페이지는 http://localhost:9000/day2/b.jsp를 찾고있다
 * 이것이 sendRedirect("b.jsp")로 이동할 때와 forward로 이동하 때의 차이점이다
 * sendRedirect로 페이지 이동시에는 값을 유지하려면 쿠키나 세션을 사용해야하지만
 * forward로 이동시에는 forward() 첫번째 파라미터인 request 객체에 담아서 넘길(유지시킬) 수 있다
 */
@WebServlet("/day2/a")
public class RequestScope extends HttpServlet {
	Logger logger = Logger.getLogger(RequestDispatcher.class);

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		logger.info("doGet 호출");
		Map<String, Object> rMap = new HashMap<>();
		rMap.put("mem_id", "tomato");
		req.setAttribute("rMap", rMap);
		RequestDispatcher view = req.getRequestDispatcher("b.jsp");
		/*
		 * day2/a로 요청한 경우 doGet메소드를 경유하게되고 이 요청을 받았을 때
		 * 톰캣으로부터 서블릿이 생성되고 그 서블릿은 요청객체와 응답객체를 갖게되는데
		 * b.jsp 페이지에서 응답이 나갈 때 파라미터에 요청객체 원본이 전달되니까
		 * 화면에서도 그 값을 공유할 수 있다
		 */
		view.forward(req, resp);
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
	}
}

 

<RequestScope로 값 공유 - b.jsp>

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@page import="java.util.Map"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>b.jsp</title>
</head>
<body>
	<h2>b.jsp</h2>
	<%
	/*
	* 테스트 시나리오
	* 서블릿을 경유하여 forward 메소드 호출의 결과 페이지로 b.jsp가 출력될 때
	* rMap이 null이 아니므로 주의할 것
	* 즉 b.jsp페이지를 직접 호출하면 출력값은 null이 될 것 이다
	*/
	Map<String, Object> rMap = (Map<String, Object>)request.getAttribute("rMap");
	out.print(rMap.get("mem_id"));
	%>
	<hr>
	<!-- 익스프레션으로 출력하기 -->
	<%=rMap.get("mem_id") %>
	
	<!-- 
	 200번 - 성공
	 300번 - 재요청 - 304
	 400번 - 클라이언트측 실수, 에러
	 500번 - 서버 에러
	 -->
</body>
</html>

 

<WEB-INF접근 - ViewPage.java>

package com.day2;

import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/day2/b")
public class ViewPage extends HttpServlet {
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String path = "b";
		RequestDispatcher view = req.getRequestDispatcher("/WEB-INF/views/day2/"+path+".jsp");
		view.forward(req, resp);
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
	}
}

 

<WEB-INF접근 - b.jsp>

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>b.jsp[WEB-INF]</title>
</head>
<body>
	<h2>b.jsp[WEB-INF] 페이지입니다.</h2>
</body>
</html>
<!-- 
	WEB-INF 아래 있는 jsp페이지는 절대로 URL 접근이 불가하다
	반드시 서블릿을 경유하여 RequestDispatcher를 사용하여 요청해야함
	그러면 WEB-INF 아래 있는 경로이더라도 페이지 호출이 가능할 것이다
	다만 scope는 request scope를 갖게 된다는 점만 주의!
 -->

 

로그인 테스트 흐름도

1. intro 아래 index.jsp 실행

2. 아이디와 비밀번호를 입력받는다

3. 로그인 버튼을 누른다 -> 자바스크립트의 login() 호출

4. login.do 호출한다 -> 로그인 처리를 하는 서블릿 호출 - doGet(), doPost()

5. com.mvc.dao.MemberDao 클래스의 인스턴스화

6. 메소드 호출 - 로그인처리

7. MemberDao의 login(Map[member_id(사용자가 입력한 아이디)와 mem_pw(사용자가 입력한 비번)가 있음]) 호출

8. 리턴타입으로 Map을 받아온다(mem_id, mem_name)

9. 8번에서 돌려받은 Map에서, 오라클 서버에서 조회된 아이디와 이름을 세션에 담기

10. 페이지 이동은 sendRedirect나 forward 둘 다 모두 가능하다 단, forward로 응답을 처리한 경우, 인증 후에 다른 서비스를 forward로 처리하는 것이 불가하다(주의!)

 

<Servlet, JSP, 오라클 연결 - index.jsp>

<%@page import="java.util.Map"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%
	String smem_id = (String) session.getAttribute("smem_id");
	String smem_name = (String) session.getAttribute("smem_name");
	out.print("세션에서 꺼내온 값 => " + smem_id + ", " + smem_name);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Web application</title>
<%@ include file="../common/easyUI_common.jsp"%>
<style type="text/css">
a {
	text-decoration: none;
}
</style>
<script>
	const login =() =>{
		/*
		테스트: com.mvc.dao.MemberDao.java
		xml: com.mybatis.mapper에 member.xml
		SELECT mem_name FROM book_member
		WHERE mem_id =:id
		AND mem_pw =:pw
		*/
		// 사용자가 입력한 아이디 가져오기
		const user_id = $("#_easyui_textbox_input1").val();
		// 사용자가 입력한 비밀번호 가져오기
		const user_pw = $("#_easyui_textbox_input2").val();
		alert(user_id + user_pw);
	}
</script>
</head>
<body>
	<h2>웹 어플리케이션 실습</h2>
	<div style="margin: 20px 0;"></div>
	<div class="easyui-layout" style="width: 1000px; height: 500px;">
		<!-- =============== 메뉴 구성 [로그인화면과 트리메뉴] 시작 =============== -->
		<div id="p" data-options="region:'west'" title="KH정보교육원"
			style="width: 200px; padding: 10px">
			<!-- =============== [[ 로그인 화면 ]] =============== -->
			<div id="d_login" align="center">
				<div style="margin: 3px 0"></div>
				<!-- create table member mem_id varchar2(10) DB에서 이런형식 -->
				<input id="tb_id" type="text" style="width: 170px">
				<script>
					$('#tb_id').textbox({
						iconCls : 'icon-man',
						iconAlign : 'right',
						prompt : '아이디'
					})
				</script>
				<div style="margin: 3px 0"></div>
				<input id="pb_pw" type="text" style="width: 170px">
				<script>
						$('#pb_pw').passwordbox({
							prompt : 'Password',
							showEye : true
						});
				</script>
				<div style="margin: 3px 0"></div>
				<a id="btn_login" href="javascript:login()">로그인</a>
				<script>
					$('#btn_login').linkbutton({
						iconCls : 'icon-man'
					});
				</script>
				<a id="btn_member" href="javascript:memberShip()">회원가입</a>
				<script>
					$('#btn_member').linkbutton({
						iconCls : 'icon-add'
					});
				</script>
			</div>
			<!-- =============== [[ 로그아웃 화면 ]] =============== -->
			<div id="d_logout" align="center"></div>
			<!-- =============== 메뉴 구성 [로그인화면과 트리메뉴] 끝 =============== -->
			<div style="margin: 3px 0"></div>
			<ul id="tre_gym" class="easyui-tree">
				<li data-options="state:closed"><span>회원관리</span>
					<ul>
						<li><a href="#">회원목록</a></li>
						<li><a href="#">회원등록</a></li>
						<li><a href="#">회원삭제</a></li>
					</ul></li>
				<li data-options="state:'closed'"><span>쪽지관리</span>
					<ul>
						<li><a href="#">받은쪽지함</a></li>
						<li><a href="#">보낸쪽지함</a></li>
					</ul></li>
				<li data-options="state:'closed'"><span>기타</span>
					<ul>
						<li><a href="#">우편번호검색기</a></li>
						<li><a href="#">게시판</a></li>
					</ul></li>
			</ul>
		</div>
		<!-- 메인화면 [게시판, 온라인시험, 쪽지관리(받은쪽지함, 보낸쪽지함), 회원관리(회원목록, 회원등록, 회원삭제), 우편번호검색기] 시작 -->
		<div data-options="region:'center', iconCls:'icon-ok'"
			title="TerrGYM2023">
			<div style="margin: 5px 0;"></div>
			Home > 회원관리 > 회원목록
			<hr>
			<div style="margin: 25px 0;"></div>
		</div>
		<!-- 메인화면 [게시판, 온라인시험, 회원관리, 우편번호검색기] 끝 -->
	</div>
</body>
</html>
<!-- 
	부트스트랩 - 리액트수업 -> Spring과 리액트 연계 수업 -> 프로젝트적용
		반응형 지원, CSS라이브러리 사용
		CSS - JS거의없음
	
	jEasyUI
		이벤트처리(jquery - 레거시시스템)
		자바스크립트 - 표준아님 -> jquery기반이라서
		자바스크립트 기반의 UI솔루션 사용하기 - 큰 도움
		개발자도구 활용 - 디버깅 -> 왜냐하면 html을 래핑하기때문에
		vue.js, reactjs
		jEasyUI는 html으로 화면처리, html+js 섞어쓰기, js(최소한의 태그선언 필요)로 화면처리 가능
		
	JSTL - 1.1 -> 1.2 -> 소개(사용x)
	
	로그인 테스트 흐름도
		1. intro 아래 index.jsp 실행
		2. 아이디와 비밀번호를 입력받는다
		3. 로그인 버튼을 누른다 -> 자바스크립트의 login() 호출
		4. login.do 호출한다 -> 로그인 처리를 하는 서블릿 호출 - doGet(), doPost()
		5. com.mvc.dao.MemberDao 클래스의 인스턴스화
		6. 메소드 호출 - 로그인처리
		7. MemberDao의 login(Map[member_id(사용자가 입력한 아이디)와 mem_pw(사용자가 입력한 비번)가 있음]) 호출
		8. 리턴타입으로 Map을 받아온다(mem_id, mem_name)
		9. 8번에서 돌려받은 Map에서, 오라클 서버에서 조회된 아이디와 이름을 세션에 담기
		10. 페이지 이동은 sendRedirect나 forward 둘 다 모두 가능하다
				단, forward로 응답을 처리한 경우, 인증 후에 다른 서비스를 forward로 처리하는것이 불가하다(주의!)
 -->

 

<Servlet, JSP, 오라클 연결 - member.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.mybatis.mapper.MemberMapper">
	<!-- 로그인 쿼리문 -->
	<select id="login" parameterType="map" resultType="map">
		SELECT mem_id,
		mem_name
		FROM book_member
		WHERE mem_id = #{mem_id}
		AND mem_pw = #{mem_pw}
	</select>

	<!-- 회원정보 가져오는 쿼리문 -->
	<select id="getMemberList" parameterType="java.util.HashMap"
		resultType="map">
		SELECT mem_no, mem_id, mem_pw, mem_name
		FROM book_member
		WHERE mem_id = #{mem_id}
		OR mem_pw = #{mem_pw}
	</select>
</mapper>

 

<Servlet, JSP, 오라클 연결 - MyBatisConfig.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>
	<environments default="development">
		<environment id="development">
			<transactionManager type="JDBC" />
			<dataSource type="POOLED">
				<property name="driver" value="oracle.jdbc.OracleDriver" />
				<property name="url"
					value="jdbc:oracle:thin:@localhost:1521:orcl11" />
				<property name="username" value="scott" />
				<property name="password" value="tiger" />
			</dataSource>
		</environment>
	</environments>
	<mappers>
		<!-- 업무에따라 관리할 쿼리문을 담을 xml문서의 물리적인 위치와 파일명을 등록할것 -->
		<mapper resource="com/mybatis/mapper/test.xml" />
		<mapper resource="com/mybatis/mapper/member.xml" />
		<mapper resource="com/util/book.xml" />
		<mapper resource="com/util/member2.xml" />
	</mappers>
</configuration>

 

<Servlet, JSP, 오라클 연결 - MemberDao.java>

package com.mvc.dao;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.log4j.Logger;
import com.util.MyBatisCommonFactory;

public class MemberDao {
	// log4j 모듈을 활용해서 로그 출력 - 날짜와 시간, 클래스명, 라인번호, 링크
	// System.out.print()대신 사용(더 많은 정보 담고있음)
	Logger logger = Logger.getLogger(MemberDao.class);
	/*
	 * DAO클래스와 오라클 서버 사이에 MyBatis Layer에 필요한 설정 내용담기
	 * member.xml의 물리적인 위치와 오라클 서버의 정보가 담긴 MyBatisConfig.xml의
	 * 정보를 IO로 읽어오는 코드가 포함됨
	 * 마이바티스는 쿼리문을 xml문서에 따로 관리한다
	 * 자바로 관리하는것보다 컴파일을 하지 않아도 되고 버전 관리에도 효과적임
	 */
	MyBatisCommonFactory mcf = new MyBatisCommonFactory();

	public Map<String, Object> login(Map<String, Object> pMap) {
		Map<String, Object> rMap = null;
		// MyBatisConfig.xml문서를 통해 스캔한 오라클 서버정보로 연결통로 확보
		SqlSessionFactory sqlSessionFactory = null;
		// 위에서 SqlSessionFactory가 생성되면 쿼리문을 요청하는 selectOne 메소드가 필요한데
		// 그 메소드를 제공하는 클래스 및 commit, rollback 지원
		SqlSession sqlSession = null;
		try {
			// 공통코드에서 연결통로 확보
			sqlSessionFactory = mcf.getSqlSessionFactory();
			// 연결통로 확보로 생성된 객체로 SqlSession 로딩하기
			sqlSession = sqlSessionFactory.openSession();
			rMap = sqlSession.selectOne("login", pMap);
			logger.info(rMap);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return rMap;
	};
	public static void main(String args[]) {
		MemberDao mDao = new MemberDao();
		Map<String, Object> pMap = new HashMap<>();
		pMap.put("mem_id", "tomato");
		pMap.put("mem_pw", "123");
		Map<String, Object> rMap = mDao.login(pMap);
		System.out.println(rMap);
	}
}

 

<Servlet, JSP, 오라클 연결 - MyBatisCommonFactory.java>

package com.util;

import java.io.Reader;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.log4j.Logger;

public class MyBatisCommonFactory {
	Logger logger = Logger.getLogger(MyBatisCommonFactory.class);
//	MyBatis는 자바와 오라클 서버 사이에 위치하면서 DB연계를 지원하는 매핑서비스이다.
//	물리적으로 떨어져있는 서버와의 통신을위해 드라이버 클래스 로딩, 연결 통로 확보 코드가 반복적으로 작성됨
//	이것을 전담하는 SqlSessionFactory를 지원하고있음(MyBatis가)
//	스프링에선 SqlSessionFactoryBean
	public SqlSessionFactory sqlSessionFactory = null;
	//SqlSessionFactory객체를 생성해 주는 메소드 입니다.
	public void init() {
		try {
//			xml문서에 드라이버 클래스명, URL주소, 계정정보 담음
//			더하여 쿼리문을 xml문서에 따로 등록해서 관리하므로
//			쿼리문을 담고있는 xml문서의 물리적인 위치를 설정문서에 등록함
			String resource = "com\\util\\MyBatisConfig.xml";
			System.out.println("resource");
			Reader reader = Resources.getResourceAsReader(resource);
			logger.info("before sqlSessionFactory : "+sqlSessionFactory);
//			싱글톤패턴에서 객체 생성하기
			if(sqlSessionFactory == null) {
				sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader,"development");
			}
			logger.info("after sqlSessionFactory : "+sqlSessionFactory);
			System.out.println("after sqlSessionFactory : "+sqlSessionFactory);
		} catch (Exception e) {
			logger.info("[[ Exception ]] "+e.toString());
			System.out.println("[[ Exception ]] "+e.toString());
		}
	}// end of init
	public SqlSessionFactory getSqlSessionFactory() {
		System.out.println("11");
		init();
		return sqlSessionFactory;
	}
	public static void main(String[] args) {
		System.out.println("test");
		MyBatisCommonFactory mcf = new MyBatisCommonFactory();
		mcf.getSqlSessionFactory();
	}
}

 

<Servlet, JSP, 오라클 연결 - MemberController.java>

package com.mvc.controller;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.mvc.dao.MemberDao;

@WebServlet("/intro/login")
public class MemberController extends HttpServlet {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// 오라클 서버에서 조회한 결과를 받아서 세션에 담기 위해 세션객체 생성하기
		HttpSession session = req.getSession();
		// 오라클 서버에 연동하는 일만 전담하는 XXXDao 클래스 인스턴스화
		MemberDao mDao = new MemberDao();
		// 사용자가 화면에 입력한 아이디 요청하기
		String mem_id = req.getParameter("mem_id");
		// 사용자가 화면에 입력한 아이디 요청하기
		String mem_pw = req.getParameter("mem_pw");
		// mybatis에 파라미터로 아이디와 비번을 Map에 담아서 넘기기위해 pMap 생성
		Map<String, Object> pMap = new HashMap<>();
		// 키값에 대응하는 사용자가 입력한 아이디와 비밀번호 Map에 담기
		pMap.put("mem_id", mem_id);
		pMap.put("mem_pw", mem_pw);
		// 오라클 서버에 연동하는 login메소드 호출 - 호출시 파라미터로 pMap 넘겨줌
		// pMap 안에 사용자가 입력한 아이디와 비밀번호가 있음
		Map<String, Object> rMap = mDao.login(pMap); // 처리 결과 Map으로 받아옴
		// 위에서 받아온 rMap에 들어있는, 오라클 서버에서 select문으로 조회한 결과를
		// 꺼내서 세션 객체에 저장함
		session.setAttribute("smem_id", rMap.get("MEM_ID"));
		session.setAttribute("smem_name", rMap.get("MEM_NAME"));
		// 로그인 화면을 가지고 있던 index.jsp 페이지로 다시 출력 내보냄
		// 이 때는 세션을 가지고 있으니 세션값을 꺼내서 XXX님 환영합니다. 라고 말할 수 있음
		resp.sendRedirect("./index.jsp");
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// 세션객체 생성
		HttpSession session = req.getSession();
		//오라클 서버에 연동하는 일만 전담하는 MemberDao 클래스
		MemberDao mDao = new MemberDao();
		// 사용자 입력값 담기
		String mem_id = req.getParameter("mem_id");
		String mem_pw = req.getParameter("mem_pw");
		// Map에 담기
		Map<String, Object> pMap = new HashMap<>();
		pMap.put("mem_id", mem_id);
		pMap.put("mem_pw", mem_pw);
		// login() 파라미터로 pMap 넘기기
		Map<String, Object> rMap = mDao.login(pMap);
		// 세션에 저장하기
		session.setAttribute("smem_id", rMap.get("MEM_ID"));
		session.setAttribute("smem_name", rMap.get("MEM_NAME"));
		// index로 보냄
		resp.sendRedirect("./index.jsp");
	}
}

댓글