🍀 세션의 역할

 

http - 새로 접속하는 개념. 이전의 클라이언트가 만들어 놓은 정보를 사용할 수 없다.

서버가 클라이언트에게 cookie 정보에 sessionid 를 심어 보낸다. (response)

예) 비회원 주문

sessionid 는 유효시간이 있다.

 

 

SessonMain.jsp

<%@page import="java.text.SimpleDateFormat"%>
<%@page import="java.util.Date"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
	
<%
SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");

long creationTime = session.getCreationTime();
String creationTimeStr = dateFormat.format(new Date(creationTime));

long lastTime = session.getLastAccessedTime();
String lastTimeStr = dateFormat.format(new Date(lastTime));
%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

	<h2>Session 설정확인</h2>
	
	<ul>
		<li>세션 유지시간 : <%=session.getMaxInactiveInterval()%></li>
		<li>세션 아이디 : <%=session.getId()%></li>
		<li>최초 요청 시각 : <%= creationTimeStr %></li>
		<li>마지막 요청 시간 : <%=lastTimeStr%>
		</li>
	</ul>
	
</body>
</html>

 

클라이언트 → 서버 → DTO → DAO → DB

클라이언트 ← 서버 ← DTO ← DAO ← DB

 

DTO, DAO 만들어서 아이디와 패스워드 비교

 

DTO를 만드는 기준 : DTO = 빈

빈을 만드는 기준과 같음.

 

* 패키지는 무조건 소문자로 만들기

* 프로젝트 만들때는 테이블 우선 만들기

* 테이블단위로 DAO, DTO가 만들어진다.

 

 

LoginForm.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>
<script>
	function validateForm(form) {
		if (!form.user_id.value) {
			alert("아이디를 입력하세요.");
			return false;
		}
		if (form.user_pw.value == "") {
			alert("패스워드를 입력하세요.");
			return false;
		}
	}
</script>
</head>
<body>
	<h2>로그인 페이지</h2>
	<%=request.getAttribute("LoginErrMsg") == null ? "" : request.getAttribute("LoginErrMsg")%>

	<%
	if (session.getAttribute("UserId") == null) {
	%>
	<form action="LoginProcess.jsp" method="post" name="LoginFrm"
		onsubmit="return validateForm(this)">
		아이디 : <input type="text" name="user_id" /><br /> 
		패스워드 : <input type="password" name="user_pw" /><br /> 
		<input type="submit" value="로그인하기" />
	</form>

	<%
	} else {
	%>
	<%=session.getAttribute("UserName")%>
	회원님, 로그인하셨습니다.
	<br>
	<a href="Logout.jsp"> [로그아웃] </a>
	<%
	}
	%>
</body>
</html>

 

MemberDTO.java

package membership;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter

//SQL의 테이블명과 일치하게 클래스를 만든다.
public class MemberDTO {
	private String id;
	private String pass;
	private String name;
	private String regidate;
	
}

 

MemberDAO.java

package membership;

import common.JDBConnect;

//DB에 접속해서 쿼리문 처리하는 역할
public class MemberDAO extends JDBConnect {

	public MemberDAO(String driver, String url, String id, String pwd) {
		super(driver, url, id, pwd);
	}
	// 여기까지 DB 접속

	// 명시한 아이디/패스워드와 일치하는 회원 정보 반환
	public MemberDTO getMemberDTO(String uid, String upass) {

		MemberDTO dto = new MemberDTO();
		String query = " select * from member where id = ? and pass = ? ";

		// 쿼리문은 예외처리가 항상 필요하다
		try {
			psmt = con.prepareStatement(query);
			psmt.setString(1, uid);
			psmt.setString(2, upass);
			rs = psmt.executeQuery();

			if (rs.next()) {
				dto.setId(rs.getString("id")); // 컬럼명 또는 숫자(1부터 시작)
				dto.setPass(rs.getString("pass")); // 가능하면 컬럼 이름으로 쓰는 것이 좋음, 그룹은 숫자로
				dto.setName(rs.getString(3));
				dto.setRegidate(rs.getString(4));
			}

		} catch (Exception e) {
			e.printStackTrace();
		}

		return dto;
	}

}

 

LoginProcess.jsp

<%@page import="membership.MemberDTO"%>
<%@page import="membership.MemberDAO"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@page import="membership.MemberDAO"%>
<!-- 로그인 아이디 패스워드 판단 -->
<%
String userId = request.getParameter("user_id");
String userPwd = request.getParameter("user_pw");

String oracleDriver = application.getInitParameter("OracleDriver");
String oracleURL = application.getInitParameter("OracleURL");
String oracleId = application.getInitParameter("OracleId");
String oraclePwd = application.getInitParameter("OraclePwd");

MemberDAO dao = new MemberDAO(oracleDriver,oracleURL,oracleId,oraclePwd);
MemberDTO memberDTO = dao.getMemberDTO(userId, userPwd);

dao.close();

if (memberDTO.getId() != null){
	// 아이디 체크 성공
	session.setAttribute("UserId", memberDTO.getId());
	session.setAttribute("UserName", memberDTO.getName());
	response.sendRedirect("LoginForm.jsp");
}else{
	// 실패
	request.setAttribute("LoginErrMsg", "로그인 실패");
	request.getRequestDispatcher("LoginForm.jsp").forward(request, response);
}

%>

 

DB에 있는 정보를 읽어와 아이디와 일치하는지 확인한 후 이름(별칭) 정보로 회원 로그인 성공 유무를 알려준다.

 

 

Logout.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%
session.removeAttribute("UserId");
session.removeAttribute("UserName");

// session.invalidate(); 모든 값을 삭제

response.sendRedirect("LoginForm.jsp");
%>

 

Link.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<table border="1" width="90%">
	<tr>
		<td align = "center">
		<%if (session.getAttribute("UserId") == null) { %>
		<a href = "../Session/LoginForm.jsp">로그인</a>
		<% }else{ %>
		<a href = "../Session/Logout.jsp">로그아웃</a>
		<% } %>
		
		&nbsp; &nbsp; &nbsp;
		<a href = "">게시판(페이징 x)</a>
		&nbsp; &nbsp; &nbsp;
		<a href = "">게시판(페이징 o)</a>
		</td>
	</tr>
</table>

 

헤더와 연결해 현재 로그인, 로그아웃 상태를 알 수 있게 해준다.

 

 

 

🍀 액션태그

 

3가지.

  1. 페이지 이동기능
  2. 페이지 읽고 쓰기
  3. 페이지 포함

 

include, forward, bean

 

✔︎ include → 페이지 포함

지시자 include 액션 include
페이지가 복사되어 하나의 파일로 포함된다 필요할 때 페이지를 포함해 처리
종속되어 움직인다 처리 후에는 연결이 끊긴다.

 

✔︎ forward → 페이지 이동

주소값이 머물러 있다.

 

 

✔︎ bean == 자바에서는 DTO , vo라고 부른다.

파라메터를 효율적으로 받기 위해서

// 빈(Bean) 객체 : DTO클래스
// 반드시 기본형 생성자가 정의되어 있어야 한다.
// 멤버는 private 해야한다.
// getter / setter를 정의한다.

// import 를 한번에 사용할 수 있다.



<jsp:useBean id="" class=""></jsp:useBean> 

<jsp:setProperty property="" name=""/> // 값 보내기
<jsp:getProperty property="" name=""/> // 값 읽기
name에는 id 값 입력 

위 세개는 한 세트처럼 쓰여진다.

 

UseBeanForm.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>
    <h2>액션 태그로 폼값 한 번에 받기</h2> 
    <form method="post" action="UseBeanAction.jsp"> 
        이름 : <input type="text" name="name" /> <br /> 
        나이 : <input type="text" name="age" /> <br /> 
        <input type="submit" value="폼값 전송" />
    </form>
</body>

 

UseBeanAction.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%-- <%
    String name = request.getParameter("name");
    String age = request.getParameter("age");
    %> --%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

<%-- <jsp:useBean id="person" class="common.Person"></jsp:useBean>

<jsp:setProperty property="name" name="person" value="hong"/>

<!-- 파라매터를 직접 받을 때 -->
<jsp:setProperty property="name" name="person" param="hong"/>  
이름 : <jsp:getProperty property="name" name="person"/>

<jsp:setProperty property="age" name="person" value="10"/>

<!-- 파라매터를 직접 받을 때 -->
<jsp:setProperty property="age" name="person" param="10"/>
나이 : <jsp:getProperty property="age" name="person"/> --%>


<!-- 파라매터를 한번에 넣을 때 -->
<jsp:useBean id="person" class="common.Person"></jsp:useBean>
<!-- 파라매터 이름과 setter 메소드 이름이 같고, 개수가 같을 때 * 로 한번에 읽어올 수 있다. -->
<jsp:setProperty property= "*" name="person" />

<!-- 넘어온 데이터를 get메소드로 읽는다. -->
이름 : <jsp:getProperty property="name" name="person"/>
<br>
나이 : <jsp:getProperty property="age" name="person"/>

</body>
</html>

 

Person.java

package common;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Person {
	
	
	// 빈(Bean) 객체 : DTO클래스
	// 반드시 기본형 생성자가 정의되어 있어야 한다.
	// 멤버는 private 해야한다.
	// getter / setter를 정의한다.
	
	private String name;
	private int age;
	public String getName() {
		return name;
	}

}

 

+web.xml 인코딩 처리로 한글 깨짐현상을 방지할 수 있다.

<filter>
    <filter-name>SetCharEncoding</filter-name>
    <filter-class>org.apache.catalina.filters.SetCharacterEncodingFilter</filter-class>
      <init-param>
        <param-name>encoding</param-name>
        <param-value>utf-8</param-value>
      </init-param>
  </filter>
  <filter-mapping>
    <filter-name>SetCharEncoding</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

 

 

 

 

🎉 게시판 만들기

이 코드는 통으로 그냥 외워라.

 

프로그램 만드는 두가지 방식 : 모델 1방식, 모델 2방식

모델 1방식 → 코드 다 한 곳에

모델 2방식 → 코드를 여러 곳에 분산, 로직 분리 (유지보수에 유리)

 

게시판 만들기는 모델 1방식으로 코딩 후 모델 2방식으로 바꿔본다.

오늘까지 만들었던 순서)

  1. SQL 디벨로퍼에서 테이블 만들고 데이터넣기, 커밋
  2. 그 다음으로 자바파일로 DTO, DAO 만들기
  3. 목록보기 화면 List.jsp
  4. 로그인 기능을 구현하며 만들었던 폼에 링크걸기

 

SQL

create table board (
num number primary key,
title varchar2(200) not null,
content varchar2(2000) not null,
id varchar2(10) not null,
postdate date DEFAULT sysdate not null,
visitcount number(6)
);

alter table board
add constraint board_mem_fk foreign key (id)
REFERENCES member(id);

-- 시퀀스 객체
create sequence seq_board_num
increment by 1
start with 1
minvalue 1;

insert into board (num, title, content, id, postdate, visitcount) 
   values (seq_board_num.nextval, '제목1입니다', '내용1입니다', 'musthave', sysdate, 0);

commit;

insert into board
   values (seq_board_num.nextval, '지금은 봄입니다', '봄의왈츠', 'musthave', sysdate, 0);
insert into board
   values (seq_board_num.nextval, '지금은 여름입니다', '여름향기', 'musthave', sysdate, 0);
insert into board
   values (seq_board_num.nextval, '지금은 가을입니다', '가을동화', 'musthave', sysdate, 0);
insert into board
   values (seq_board_num.nextval, '지금은 겨울입니다', '겨울연가', 'musthave', sysdate, 0);      

commit;

 

BoardDTO.java

package model1.board;


import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class BoardDTO {
private String num;
private String title;
private String content;
private String id;
private java.sql.Date postDate;
private String visitcount;
private String name; // 로그인했을 떄 필요한 이름
}

 

BoardDAO.java

package model1.board;

import common.JDBConnect;
import jakarta.servlet.ServletContext;

public class BoardDAO extends JDBConnect{

	public BoardDAO(ServletContext application) {
		super(application);
	}
	
	// 검색 조건에 맞는 게시물의 개수를 반환합니다.
	   
	// 검색 조건에 맞는 게시물 목록을 반환합니다.
	   
	// 검색 조건에 맞는 게시물 목록을 반환합니다(페이징 기능 지원).
	   
	// 게시글 데이터를 받아 DB에 추가합니다.
	   
	// 지정한 게시물을 찾아 내용을 반환합니다.
	   
	// 지정한 게시물의 조회수를 1 증가시킵니다.
	   
	// 지정한 게시물을 수정합니다.
	   
	// 지정한 게시물을 삭제합니다.

	

}

 

목록보기 화면 List.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>
	<jsp:include page="../Common/Link.jsp" />
	<form method="get">
		<table border="1" width="90%">
			<tr>
				<td align="center"><select name="searchField">
						<option value="title">제목</option>
						<option value="content">내용</option>
				</select> 
				<input type="text" name="searchWord" /> 
				<input type="submit" name="검색하기" /></td>
			</tr>
		</table>
	</form>
</body>
</html>

 

로그인 기능을 구현하며 만들었던 폼에 링크걸기 Link.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>
	<jsp:include page="../Common/Link.jsp" />
	<form method="get">
		<table border="1" width="90%">
			<tr>
				<td align="center"><select name="searchField">
						<option value="title">제목</option>
						<option value="content">내용</option>
				</select> 
				<input type="text" name="searchWord" /> 
				<input type="submit" name="검색하기" /></td>
			</tr>
		</table>
	</form>
</body>
</html>

 

대부분의 페이지가 DB와 연동 (이메일 등)

매번 매개변수를 초기화 해야하는 부담 → 생성자를 오버로딩 하는 방식으로 해결할 수 있다

가장 모듈화가 잘 된 방식이 이 방식.

 

코딩을 할 때는 모듈화가 중요하다. 잘 만들어진 모듈 하나는 열 개발자 안 부럽다.

→ 리팩토링이라고도 한다. 좀 더 코드를 최적화할 수 있는 형태를 생각, 모듈화 하듯

 

❗️앞으로 두고두고 중요한 개념이다

jsp의 내장객체인 application 을 읽을 수 있다면 매개변수는 한번에 읽어올 수 있다.

application 타입 → ServletContext application

 

JDBConnect.java

	public JDBConnect(ServletContext application) {
		String driver = application.getInitParameter("OracleDriver"); 
		
		try {
			Class.forName(driver);
			
			String url = application.getInitParameter("OracleURL");
			String id = application.getInitParameter("OracleId");
			String pwd = application.getInitParameter("OraclePwd");
			
			con = DriverManager.getConnection(url, id, pwd);
			
			System.out.println("DB 연결 성공(인수 생성자 2)");
			
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}

 

JDBCTest2.jsp

	<%
	JDBConnect jdbc3 = new JDBConnect(application);
	jdbc3.close();
	%>

테스트할 페이지에서는 매개변수인 application을 한번 더 호출해주면 된다.

 

 

 

전체코드)

JDBConnect.java

package common;

import java.sql.Statement;

import jakarta.servlet.ServletContext;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class JDBConnect {
	// Connection,
	// statement (쿼리문 쓸 때 필요한 객체, 많이 안쓴다.),
	// PreparedStatement (쿼리문 사용할 떄 필요한 객체 많이쓴다. 쿼리문을 쓸 때 융통성이 좋다.),
	// ResultSet (실행된 쿼리문의 결과를 받아올 떄 필요한 객체)

	public Connection con;
	public Statement stmt;
	public PreparedStatement psmt;
	public ResultSet rs;

	public JDBConnect() {
		String driver = "oracle.jdbc.driver.OracleDriver";
		String url = "jdbc:oracle:thin:@localhost:1521:XE";

		try {
			Class.forName(driver);
			con = DriverManager.getConnection(url, "musthave", "1234");

			System.out.println("DB 연결 성공 (기본 생성자)");

		} catch (SQLException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}

	}

	// 두번째 생성자 방식 - 매개변수로 개인 정보를 숨김
	public JDBConnect(String driver, String url, String id, String pwd) {
		try {
			// JDBC 드라이버 로드
			Class.forName(driver);

			// DB에 연결
			con = DriverManager.getConnection(url, id, pwd);

			System.out.println("DB 연결 성공(인수 생성자 1)");

		} catch (SQLException e) {
			e.printStackTrace();

		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}

	}
	
	public JDBConnect(ServletContext application) {
		String driver = application.getInitParameter("OracleDriver"); 
		
		try {
			Class.forName(driver);
			
			String url = application.getInitParameter("OracleURL");
			String id = application.getInitParameter("OracleId");
			String pwd = application.getInitParameter("OraclePwd");
			
			con = DriverManager.getConnection(url, id, pwd);
			
			System.out.println("DB 연결 성공(인수 생성자 2)");
			
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}

	public void close() {

		try {
			if (con != null) {
				con.close();
			}
		} catch (Exception e) {

		}
	}
}

 

JDBCTest2.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ page import="common.JDBConnect"%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

	<h2>JDBCTest1</h2>

	<%
	JDBConnect jdbc1 = new JDBConnect();
	jdbc1.close();
	%>

	<h2>JDBCTest2</h2>

	<%
	String driver = application.getInitParameter("OracleDriver");
	String url = application.getInitParameter("OracleURL");
	String id = application.getInitParameter("OracleId");
	String pwd = application.getInitParameter("OraclePwd");

	JDBConnect jdbc2 = new JDBConnect(driver,url,id,pwd);
	jdbc2.close();
	%>
	
	<h2>JDBCTest3</h2>
	<%
	JDBConnect jdbc3 = new JDBConnect(application);
	jdbc3.close();
	%>

</body>
</html>

 

기존 방식은 접속할때마다 접속할 수 있는 입구를 만들고, 접속을 끊으면 입구를 없애는 방식이었다.

요청이 있을 때마다 입구를 만드는 방식.

 

 

🍀 커넥션 풀 방식

미리 입구를 만들어 놓는다. 용량 낭비가 조금 있지만 바로 들어와서 이용할 수 있다.

커넥션 풀 방식에서는 web.xml 역할을 하는 것이 server.xml (서술배포자로의 역할을 한다)

server.xml 수정 - 구문 추가

 <Resource auth="Container"
              driverClassName="oracle.jdbc.OracleDriver"
              type="javax.sql.DataSource" 
              initialSize="0" // 초기 사이즈 (몇개 만들건지)
              minIdle="5" 
              maxTotal="20" // 최대 개수
              maxIdle="20"
              maxWaitMillis="5000" // 대기시간 5초 
              url="jdbc:oracle:thin:@localhost:1521:xe" 
              name="dbcp_myoracle" // 이름 속성에 들어간 값이 정해진 건 아니지만 프로그램에서 이름을 가져다 쓴다. 
              username="musthave"
              password="1234" />

이 정보가 Pull 방식을 쓸 수 있게 해주는 매개변수같이 동작한다.

 

❗️필수 구성 항목

  • driverClassName="oracle.jdbc.OracleDriver"
  • type="javax.sql.DataSource"
  • url="jdbc:oracle:thin:@localhost:1521:xe"
  • name="dbcp_myoracle" // 이름 속성에 들어간 값이 정해진 건 아니지만 프로그램에서 이름을 가져다 쓴다.
  • username="musthave"
  • password="1234"

 

name="dbcp_myoracle" // 이름 속성에 들어간 값이 정해진 건 아니지만 프로그램에서 이름을 가져다 쓰기 때문에 어떤 값이 있는지는 알아야한다. 떄문에 의미있는 이름을 짓는 것이 좋다.

 

context.xml 수정 - 구문 추가

<ResourceLink global="dbcp_myoracle" name="dbcp_myoracle" 
                  type="javax.sql.DataSource"/>

여기까지하고 톰켓서버 restart

 

 

DBConnPool.java

package common;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;

public class DBConnPool {
	public Connection con;
	public Statement stmt;
	public PreparedStatement psmt;
	public ResultSet rs;

	public DBConnPool() {

		// 커넥션 풀 방식

		try {
			// 기본 세팅
			Context initCtx = new InitialContext();
			Context ctx = (Context) initCtx.lookup("java:comp/env");
			DataSource source = (DataSource) ctx.lookup("dbcp_myoracle");

			con = source.getConnection(); // DB를 연결해주는 메서드

			System.out.println("DB 커넥션 풀 연결 성공");

		} catch (Exception e) {

		}
	}

	public void close() {

		try {
			if (con != null) {
				con.close();
			}
		} catch (Exception e) {

		}
	}
}

 

JDBCTest2.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ page import="common.JDBConnect"%>
<%@ page import= "common.DBConnPool" %>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

	<h2>JDBCTest1</h2>

	<%
	JDBConnect jdbc1 = new JDBConnect();
	jdbc1.close();
	%>

	<h2>JDBCTest2</h2>

	<%
	String driver = application.getInitParameter("OracleDriver");
	String url = application.getInitParameter("OracleURL");
	String id = application.getInitParameter("OracleId");
	String pwd = application.getInitParameter("OraclePwd");

	JDBConnect jdbc2 = new JDBConnect(driver,url,id,pwd);
	jdbc2.close();
	%>
	
	<h2>JDBCTest3</h2>
	<%
	JDBConnect jdbc3 = new JDBConnect(application);
	jdbc3.close();
	%>
	
	<h2>JDBCTest4</h2>
	<%
	DBConnPool pool = new DBConnPool();
	pool.close();
	%>

</body>
</html>

 

연결 테스트를 해보면 연결이 된 것을 확인할 수 있다.

 

 

🍀 DB 데이터를 서버에서 집어넣어보기

 

ExeUpdate.jsp

<%@page import="java.sql.PreparedStatement"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ page import="common.JDBConnect"%>
<%@ page import="java.sql.PreparedStatement"%> 

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<!-- 회원추가 -->
	<h2>회원 추가 테스트</h2>

	<%
	JDBConnect jdbc = new JDBConnect();

	String id = "test1";
	String pass = "1111";
	String name = "테스트1회원";

	// varchar2 타입 문자 처리 -> '"내용"' 코드가 까다로워 이렇게 쓰지 않는다
	// String sql = "insert into member (id, pass, name) values ('" + id + "', '" + pass + "', '" + name + "')";

	// PreparedStatement 방식 -> 컬럼의 개수에 맞게 ? 를 넣어준다. 
	// PreparedStatement 쿼리문을 실행하게 하는 메소드, 유연성이 있다. 
	String sql = "insert into member (id, pass, name) values (?, ?, ?)";

	PreparedStatement psmt = jdbc.con.prepareStatement(sql);
	// psmt.setString(순서, 정해주고 싶은 값);
	psmt.setString(1, id);  
	psmt.setString(2, pass);
	psmt.setString(3, name);
	
	// PreparedStatement 로 쿼리문 실행
	// executeQuery() -> select
	// executeUpdate() -> Insert, update, delete
	// 				   -> 반환값을 가진다. 0 or 0 보다 큰 값
	
	int result = psmt.executeUpdate();
	
	if (result > 0) {
		out.print(result + "행이 입력되었습니다.");
	} else {
		out.print("입력 실패");
	}
	
	jdbc.close(); // 사용중인 객체 close()

%>

</body>
</html>

 

JDBConnect.java

package common;

import java.sql.Statement;

import jakarta.servlet.ServletContext;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class JDBConnect {
	// Connection,
	// statement (쿼리문 쓸 때 필요한 객체, 많이 안쓴다.),
	// PreparedStatement (쿼리문 사용할 떄 필요한 객체 많이쓴다. 쿼리문을 쓸 때 융통성이 좋다.),
	// ResultSet (실행된 쿼리문의 결과를 받아올 떄 필요한 객체)

	public Connection con;
	public Statement stmt;
	public PreparedStatement psmt;
	public ResultSet rs;

	public JDBConnect() {
		String driver = "oracle.jdbc.driver.OracleDriver";
		String url = "jdbc:oracle:thin:@localhost:1521:XE";

		try {
			Class.forName(driver);
			con = DriverManager.getConnection(url, "musthave", "1234");

			System.out.println("DB 연결 성공 (기본 생성자)");

		} catch (SQLException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}

	}

	// 두번째 생성자 방식 - 매개변수로 개인 정보를 숨김
	public JDBConnect(String driver, String url, String id, String pwd) {
		try {
			// JDBC 드라이버 로드
			Class.forName(driver);

			// DB에 연결
			con = DriverManager.getConnection(url, id, pwd);

			System.out.println("DB 연결 성공(인수 생성자 1)");

		} catch (SQLException e) {
			e.printStackTrace();

		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}

	}
	
	public JDBConnect(ServletContext application) {
		String driver = application.getInitParameter("OracleDriver"); 
		
		try {
			Class.forName(driver);
			
			String url = application.getInitParameter("OracleURL");
			String id = application.getInitParameter("OracleId");
			String pwd = application.getInitParameter("OraclePwd");
			
			con = DriverManager.getConnection(url, id, pwd);
			
			System.out.println("DB 연결 성공(인수 생성자 2)");
			
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}

	public void close() {

		try {
			if (stmt != null) {
				stmt.close();
			}
			if (rs != null) {
				rs.close();
			}
			if (psmt != null) {
				psmt.close();
			}
			if (con != null) {
				con.close();
			}
		} catch (Exception e) {

		}
	}
}

다른 객체들을 사용할때도 다 null 이 아니면 close() 될 수 있도록 수정했다.

 

DB에도 데이터가 잘 들어간 것을 확인할 수 있다.

 

 

Insert, update, delete 비슷한 방식 처리

PreparedStatement 사용

 

select는 다른 방식

PreparedStatement 사용이 일반적이지만,

여기 예시에서는 Statement를 사용해보겠다.

 

 

🌀 select 해보기

 

ExeQuery.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ page import="common.JDBConnect"%>
<%@ page import="java.sql.Statement"%>
<%@ page import="java.sql.ResultSet"%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

	<h2>회원 목록 조회 테스트</h2>
	<%
	JDBConnect jdbc = new JDBConnect();

	String sql = "select * from member";

	Statement stmt = jdbc.con.createStatement();

	// Statement 로 쿼리문 실행
	// executeQuery() -> select
	// executeUpdate() -> Insert, update, delete
	// 				   -> 반환값을 가진다. 0 or 0 보다 큰 값

	// 실행할 때 쿼리실행문을 넣는다.
	// ResultSet 래코드의 개수만큼 참조 -> 그 안에는 컬럼 단위 
	// next() 메서드가 주소값을 참조하며 이동해 레코드를 읽어주는 역할 
	// 참조 가능한 레코드가 있을 땐 next() -> true 반환 
	// 없다면 flase 반환 
	// 그렇다면 false를 반환할때까지 while 문으로 돌리기
	ResultSet rs = stmt.executeQuery(sql);

	while (rs.next()) {
		String id = rs.getString("id");
		String pw = rs.getString("pass");
		String name = rs.getString("name");
		// java.sql.Date regidate = rs.getDate("regidate");
		String regidate = rs.getString("regidate");

		out.print(String.format("%s %s %s %s", id, pw, name, regidate) + "</br>");

	}

	jdbc.close();
	%>

</body>
</html>

 

  • executeQuery() -> select
  •                               → ResultSet : 조회된 결과

 

  • executeUpdate() -> Insert, update, delete
  •                                    -> 반환값을 가진다. 0 or 0 보다 큰 값

 

  • getInt(), getFloat(), getString(), getDate() 로 데이터를 받는다.

 

 

날짜 데이터 가져오는 방식)

날짜 연산이 필요할 땐 아래와 같이,

java.sql.Date regidate = rs.getDate("regidate");

그냥 날짜 데이터만 가지고 올 땐 아래와 같은 형식으로 사용한다.

String regidate = rs.getString("regidate");

 

 


 

🍀 회원가입 폼을 만들어서 실제 테이블에 저장해보기

 

 

🌀 회원가입 → 브라우저 화면에서 값을 입력해서 집어넣기

 

Member.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 action="MemberProcess.jsp" method = "post">

<label>아이디 : </label>
<input type = "text" name = "id">
<br>
<label>비밀번호 : </label>
<input type = "password" name = "pwd">
<br> 
<label>이름 : </label>
<input type = "text" name = "name">
<br>
<input type = "submit" value = "회원가입">

</form>

</body>
</html>

 

MemberProcess.jsp - 회원가입된 정보 DB에 집어 넣기

<%@page import="utils.JSFunction"%>
<%@page import="java.sql.PreparedStatement"%>
<%@page import="common.JDBConnect"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>

<%
String id = request.getParameter("id");
String pass = request.getParameter("pwd");
String name = request.getParameter("name");

JDBConnect jdbc = new JDBConnect();

String sql = "insert into member (id, pass, name) values (?, ?, ?)";

PreparedStatement psmt = jdbc.con.prepareStatement(sql);

psmt.setString(1, id);
psmt.setString(2, pass);
psmt.setString(3, name);

int result = psmt.executeUpdate();

if (result > 0){
	JSFunction.alertLocation("데이터 삽입 성공", "MemberList.jsp", out);
}

%>

회원가입이 완료되어 데이터가 DB에 들어가고, MemberList.jsp 페이지로 넘어간 모습이다.

 

 

🌀 회원 목록 보기

 

MemberList.jsp

<%@page import="java.sql.ResultSet"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@page import="java.sql.PreparedStatement"%>
<%@page import="common.JDBConnect"%>
    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2>회원 목록 보기</h2>
<%
JDBConnect jdbc = new JDBConnect();

String sql = "select * from member"; 

PreparedStatement psmt = jdbc.con.prepareStatement(sql);
ResultSet rs = psmt.executeQuery();

while (rs.next()){
	String id = rs.getString("id");
	String pass = rs.getString("pass");
	String name = rs.getString("name");
	String regidate = rs.getString("regidate");
	
	out.print(String.format("%s %s %s %s", id, pass, name, regidate) + "</br>");
}
%>
</body>
</html>

데이터가 들어간 것을 확인할 수 있다.

 

복습할 것)

제이쿼리 선택자 구성 방식

자바 컬렉션

 

 

🍪 Cookie

공지사항 팝업을 만들어보기

  • ‘하루동안 열지 않기’ 체크 박스, 닫기 버튼 구현
  • 제이쿼리 적용

 

Ajax → 자바스크립트를 통해 서버와 통신할 수 있게 하는 개념

$.ajax({
url : './PopupCookie.jsp',
type : 'get',
data : {inactiveToday : chkVal}, // 파라메터값 (키 : value) 형식
dataType : "text", // 어떤 형태로 데이터를 받을 건지 (쿠키는 대부분 text형식으로 받음)
success : function(resData) { // function안에 있는 매개변수의 이름은 어떤 것이든 상관없다

	if (resData != '') location.reload();

	}
});

 

url - 이동할 페이지이다. 이동한 페이지에서 데이터를 처리하고 다시 현페이지로 돌아온다. 필요한 경우 데이터를 전달할 수 있다.

type - 전달 방식을 의미한다. GET/POST가 있다.

data - 데이터 처리를 할 페이지에게 전달할 정도이다. 내가 전달하고 싶은 파라메터값. Array 형식일 때 위와 같이 적으면 된다.

dataType - 전달받는 인자의 형식.

success - 데이터 처리가 성공했을 경우 해당 함수(함수가 아니어도 되는듯 하다)를 실행한다. json으로 처리할 경우 데이터를 처리하는 페이지에서 전달해주는 값이 인자로 받아진다.

 

 

공지사항 팝업 창

 

PopupMain.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
	
	<%
	
	String popupMode = "on";
	
	Cookie[] cookies = request.getCookies();
	if (cookies != null){
		for (Cookie c : cookies){
			String cookieName = c.getName();
			String cookieValue = c.getValue();
			
			if (cookieName.equals("PopupClose")){
				popupMode = cookieValue;
			}
		}
	}
	%>
	
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>

<style>
div#popup {
	position: absolute;
	top: 100px;
	left: 50px;
	color: yellow;
	width: 270px;
	height: 100px;
	background-color: gray;
    display: <% if (popupMode.equals("on")) { %>block<% } else { %>none<% } %>;
}

div#popup>div {
	position: relative;
	background-color: #ffffff;
	top: 0px;
	border: 1px solid gray;
	padding: 10px;
	color: black;
}
</style>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script>
/* 닫기 버튼 */
$(function(){
	$("#closeBtn").click(function(){
		$("#popup").hide();
		
		/* 하루동안 열지 않음 버튼 체크 유무 알기 */
		/* 사용자 pc에서 그 정보를 보관하고 있어야 함 -> 그것이 쿠키 */
		/* 어떤 정보를 서버에서 관리할지, 쿠키로 관리할지 판단해야한다. */
		/* 체크가 되어있으면 1 안되어 있으면 null값 */
		let chkVal = $("input:checkbox[id=inactivetoday]:checked").val();
		
		
		// ajax
		// 서버에 요청
		// 페이지 이동이 일어나지 않는다. 새로고침이 일어남, main 화면에서 처리
		$.ajax({
			url : './PopupCookie.jsp', 
			type : 'get',
			data : {inactivetoday : chkVal},
			dataType : "text",
			success : function(resData) { // resData => "쿠키 : 하루동안 열지 않음"
				if (resData != ''){
					console.log(resData);  
					location.reload(); 
				}
			}
		});
	});
});
    
</script>

</head>
<body>

<%
// 태그 자체를 실행문으로 전체 처리
if(popupMode.equals("on")) {
%>

	<div id="popup">
		<h2 align="center">공지사항 팝업입니다.</h2>
		<div align="right">
			<form name="popFrm">
				<input type="checkbox" id="inactivetoday" value="1" /> 하루 동안 열지 않음
				<input type="button" value="닫기" id="closeBtn" />
			</form>
		</div>
	</div>
	<% } %>

</body>
</html>

 

PopupCookie.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>

<%
    String chkval = request.getParameter("inactivetoday");
    
    if (chkval != null && chkval.equals("1")){
    	Cookie cookie = new Cookie("PopupClose", "off");
    	cookie.setPath("/");
    	cookie.setMaxAge(3600 * 24);
    	response.addCookie(cookie);
    	// ajax 통신을 통해 요청된 text 타입 데이터를 보내주는 역할 (여기서의 역할)
    	out.println("쿠키 : 하루 동안 열지 않음");
    } else {
    	out.println("쿠키 설정 안됨");
    }
    %>

 

 

 

자동로그인 기능 구현해보기

+쿠키를 적용할 만한 기능들 검색해보기

 

페이지 이동 방식 → jsp, js에서 제공 ( js - location 객체 )

utils 패키지에 페이지 이동 방식에 대한 내용 정의

history, location 객체가 제공해주기 때문에 이를 이용할 것이다.

페이지를 이동하는 과정에서 페이지 이동 이유, 정보, 문제점 등을 메세지 창을 통해 전달

js alert 창을 이용해 제공.

 

out.print("<h1 style = 'color : red'>로그인 실패</h1>");

기능을 그대로 수행해준다.

 

IdsaveProcess 페이지에서는 아이디 저장하기 체크박스에 값이 있으면 쿠키를 만들어주고

체크가 안된 상태로 넘어온다면 쿠키를 만들지 않는다

 

가능하면 기능은 분리해서 사용

java 파일로 만든 기능을 jsp 파일에서 사용한다.

 

response 객체의 타입 → HttpServletResponse response

request 객체의 타입 → HttpServletRequest request

아이디 저장 체크 후 로그인에 성공하면 저렇게 아이디가 저장되고 쿠키가 생기는 것을 확인할 수 있다.

아이디 저장을 체크하지 않고 로그인에 성공하면 쿠키가 생기지 않는다.

그런데 이렇게 하면 뒤로가기를 했을 때 사용자가 입력했던 정보들이 다 노출된다.

이걸 어떻게 해결하지

뒤로 갔을 때 새로고침이 되는 함수를 만들어서.. (?)

 

페이지 뒤로 가기, 앞으로 가기 경로를 결정해주는 JSFunction.java 파일

package utils;

import jakarta.servlet.jsp.JspWriter;

public class JSFunction {
	// location.href = "페이지 경로" -> 특정페이지 지정
	// history.back(), history.forward() -> 뒤로가기, 앞으로 가기

	public static void alertLocation(String msg, String url, JspWriter out) {
		try {
			String script = ""
					+ "<script>"
					+ "alert('" + msg + "');" // alert('hello')
					+ "location.href = '" + url + "'"
					+ "</script>";
			
			out.print(script);
					
		}catch(Exception e) {
			
		}
	}

	public static void alertBack(String msg, JspWriter out) {
		try {
			String script = ""
					+ "<script>"
					+ "alert('" + msg + "');"
					+ "history.back();"
					+ "</script>";
					
			out.print(script);
			
		}catch(Exception e) {
			
		}

	}
}

 

쿠키를 생성, 삭제, 정보를 확인하는 CookieManager.java 파일

package utils;

import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

public class CookieManager {
	
	// 쿠키 생성
	public static void makeCookie(HttpServletResponse response, String cName, String cValue, int cTime) {
		Cookie cookie = new Cookie(cName ,cValue );
		cookie.setPath("/"); 
		cookie.setMaxAge(cTime); 
		response.addCookie(cookie);
	}
	
	// 쿠키 삭제
	public static void deleteCookie(HttpServletResponse response, String cName) {
		makeCookie(response, cName, "", 0);
	}
	
	// 쿠키 정보 확인
	public static String readCookie(HttpServletRequest request, String cName) {
		
		String cookieValue = "";
		
		Cookie[] cookies = request.getCookies(); 
		if (cookies != null) {
			for (Cookie c : cookies) {
				String cookieName = c.getName();
				if (cookieName.equals(cName)) {
					cookieValue = c.getValue();
				}
			}
		}
		
		return cookieValue;
	}
}

 

IdSaveMain.jsp

<%@page import="utils.CookieManager"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
	
	<%
	String loginId = CookieManager.readCookie(request, "loginId"); // "must" 받아오기
	
	String cookieCheck = "";
	if (!loginId.equals("")){
		cookieCheck = "checked";
	}
	
	%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

	<form action = "IdsaveProcess.jsp" method = "post">
		아이디 : <input type="text" name="user_id" value="<%=loginId %>" /> 
		<input type="checkbox" name="save_check" value="Y" <%= cookieCheck %> /> 아이디 저장하기 
		<br /> 
		패스워드 : <input type="text" name="user_pw" /> 
		<br /> 
		<input type="submit" value="로그인하기" />
	</form>

</body>
</html>

 

IdsaveProcess.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    
<%@ page import= "utils.JSFunction"%>
<%@ page import= "utils.CookieManager"%>

<%
String user_id = request.getParameter("user_id");
String user_pw = request.getParameter("user_pw");
String save_check = request.getParameter("save_check");

if (user_id.equals("must") && user_pw.equals("1234")){
	// 로그인 성공
	if (save_check != null && save_check.equals("Y")){
		// 쿠키 생성
		// 별도의 클래스를 만들어서 분리
		CookieManager.makeCookie(response, "loginId", user_id, 86400);
	}else{
		// 쿠키 삭제
		CookieManager.deleteCookie(response, "loginId");
	}
	
	JSFunction.alertLocation("로그인에 성공했습니다.", "IdSaveMain.jsp", out);
	
}else{
	// 로그인 실패 
	JSFunction.alertBack("로그인에 실패했습니다.", out);
}
%>

 

 

 

오라클데이터베이스를 활용해서 프로그램 만들기

 

(SQL)

system에서 musthave 1234 계정만들기,

권한 부여

create user musthave identified by 1234;

grant connect,resource,dba
to musthave;

 

테이블 만들기, 값 넣기 (SQL)

create table member (
id varchar2(10) not null,
pass varchar2(10) not null,
name varchar2(30) not null,
regidate date default sysdate not null,
primary key(id)
);

create table board (
num number primary key,
title varchar2(200) not null,
content varchar2(2000) not null,
id varchar2(10) not null,
postdate date DEFAULT sysdate not null,
visitcount number(6)
);

alter table board
add constraint board_mem_fk foreign key (id)
REFERENCES member(id);

-- 시퀀스 객체
create sequence seq_borad_num
increment by 1
start with 1
minvalue 1;

insert into member (id, pass, name) values ('musthave', '1234', '머스트해브');

insert into board (num, title, content, id, postdate, visitcount) 
   values (seq_borad_num.nextval, '제목1입니다', '내용1입니다', 'musthave', sysdate, 0);

commit;

 

ojdbc11 설치

모든 암세포는 맥북으로 오라클을 쓰는 순간 자라난다

 

jsp로 돌아와서

jdbcTest.jsp - 오라클와 연결이 되는지 확인하기

<%@page import="java.sql.DriverManager"%>
<%@page import="java.sql.Driver"%>
<%@page import="java.net.ConnectException"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@page import = "java.sql.*" %>
    <%
    //1. Connection 객체 생성
    Connection conn = null;
    
    // 이 정보를 이용해서 db에 접속
    String driver ="oracle.jdbc.driver.OracleDriver";
    String url = "jdbc:oracle:thin:@localhost:1521:XE"; // orcl 로 바꾸라카는데 나는 xe로 해야함.
    
    Boolean connect = false;
    
    try {
    	// 2. DriverManager 객체 생성
    Class.forName(driver);
    	conn = DriverManager.getConnection(url, "musthave", "1234");
    	
    	connect = true;
    	
    	// db 연결 종료
    	conn.close();
    	
    }catch(Exception e) {
    	
    }
    
    %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<% if (connect == true) { %>
<h1> 연결성공 </h1>
<%}else{ %>
      <h1>연결 실패</h1>
<% } %>
</body>
</html>

 

 

 

자바에서 DB와 연결하기 위해 사용하는 객체

  • Connection
  • statement (쿼리문 쓸 때 필요한 객체, 많이 안쓴다.)
  • PreparedStatement (쿼리문 사용할 떄 필요한 객체 많이쓴다. 쿼리문을 쓸 때 융통성이 좋다.)
  • ResultSet (실행된 쿼리문의 결과를 받아올 떄 필요한 객체)

 

자바스크립트에서 함수를 만들어 사용하듯 클래스를 만들어 다른 파일에서도 사용한다.

 

JDBConnect.java

package common;

import java.sql.Statement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class JDBConnect {
	// Connection,
	// statement (쿼리문 쓸 때 필요한 객체, 많이 안쓴다.),
	// PreparedStatement (쿼리문 사용할 떄 필요한 객체 많이쓴다. 쿼리문을 쓸 때 융통성이 좋다.),
	// ResultSet (실행된 쿼리문의 결과를 받아올 떄 필요한 객체)

	public Connection con;
	public Statement stmt;
	public PreparedStatement psmt;
	public ResultSet rs;

	public JDBConnect() {
		String driver = "oracle.jdbc.driver.OracleDriver";
		String url = "jdbc:oracle:thin:@localhost:1521:XE";

		try {
			Class.forName(driver);
			con = DriverManager.getConnection(url, "musthave", "1234");

			System.out.println("DB 연결 성공 (기본 생성자)");

		} catch (SQLException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}

	}

	// 두번째 생성자 방식 - 매개변수로 개인 정보를 숨김
	public JDBConnect(String driver, String url, String id, String pwd) {
		try {
			// JDBC 드라이버 로드
			Class.forName(driver);

			// DB에 연결
			con = DriverManager.getConnection(url, id, pwd);

			System.out.println("DB 연결 성공(인수 생성자 1)");

		} catch (SQLException e) {
			e.printStackTrace();

		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}

	}

	public void close() {

		try {
			if (con != null) {
				con.close();
			}
		} catch (Exception e) {

		}
	}
}

예외처리해서 꼭 종료까지 해야한다.

 

 

web.xml

<context-param> 라는 태그로 초기화 매개변수를 정의한다.

정의된 초기화 매개변수는 모든 서블릿과 JSP에서 ServletContext를 통해 접근가능하다.

이렇게 하면 어플리케이션의 설정정보를 중앙 집중적으로 관리할 수 있고 유지 보수가 용이하다.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://jakarta.ee/xml/ns/jakartaee" xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd" id="WebApp_ID" version="5.0">
  <display-name>firstjsp</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.jsp</welcome-file>
    <welcome-file>default.htm</welcome-file>
  </welcome-file-list>
  
  <context-param>
  <param-name>INIT_PARAM</param-name>
  <param-value>web.xml에 저장한 초기화 매개변수</param-value>
  </context-param>
  
  <!-- 오라클 설정정보 -->
    
  <context-param>
  <param-name>OracleDriver</param-name>
  <param-value>oracle.jdbc.driver.OracleDriver</param-value>
  </context-param>
  
  <context-param>
     <param-name>OracleURL</param-name>
     <param-value>jdbc:oracle:thin:@localhost:1521:XE</param-value>
  </context-param>
  
  <context-param>
  <param-name>OracleId</param-name>
  <param-value>musthave</param-value>
  </context-param>
  
  <context-param>
  <param-name>OraclePwd</param-name>
  <param-value>1234</param-value>
  </context-param>
  
  
</web-app>

 

JDBCTest2.jsp 연결을 테스트하는 파일

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    
    <%@ page import = "common.JDBConnect" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2>JDBCTest1</h2>

<%
JDBConnect jdbc1 = new JDBConnect();
jdbc1.close();
%>

<h2>JDBCTest2</h2>

<%
String driver = application.getInitParameter("OracleDriver");
String url = application.getInitParameter("OracleURL");
String id = application.getInitParameter("OracleId");
String pwd = application.getInitParameter("OraclePwd");

JDBConnect jdbc2 = new JDBConnect(driver,url,id,pwd);
jdbc2.close();
%>

</body>
</html>

연결성공 !

 

 

🍀 JSP 문법

 

  • JSP 표현식
<%= 내용 %>

 

 

 

 

🌀 내장객체 request 로 값을 보내고 받는 방식 이해하기

 

checkbox, radio의 경우 값을 여러 개 선택하면 여러 값이 들어있는 배열로 담아 출력한다.

→ 값을 직접 받는 것과는 다르게 처리해줘야 한다.

 

 

RequestMain.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>

<%
    // Date today = new Date();
    // 내장객체
    // request
    // respones
    // out
    // session
    // application
    // pageContext
    // Page
    // config
    // exception
    %>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

	<form action="RequestWebInfo.jsp" method="post">

		<!-- 값을 체크하는 name 속성, 'eng', 'han' 파라메터 역할을 한다 -->
		<!-- 서버로 값을 넘긴다 -->
		영어 : <input type="text" name="eng" value="Bye" /><br /> 한글 : <input
			type="text" name="han" value="잘 가" /><br /> <input type="submit"
			value="POST 방식 전송" />
	</form>
	<br>
	<br>
	<!-- 아이디와 이름은 작성된 값이 value값
	성별과 같은 선택형 폼은 값이 작성되어 넘어오는 것이 아니기때문에 반드시 폼 안에 value 속성이 들어가야 한다. -->

	<form action="RequestParameter.jsp" method="post">
		아이디 : <input type="text" name="id" value="" /><br /> 성별 : <input
			type="radio" name="sex" value="man" />남자 <input type="radio"
			name="sex" value="woman" checked="checked" />여자 <br /> 관심사항 : <input
			type="checkbox" name="favo" value="eco" />경제 <input type="checkbox"
			name="favo" value="pol" checked="checked" />정치 <input
			type="checkbox" name="favo" value="ent" />연예<br /> 자기소개:
		<textarea name="intro" cols="30" rows="4"></textarea>
		<br /> <input type="submit" value="전송하기" />
	</form>

</body>
</html>

 

RequestParameter.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>

<%
// 한글 꺠짐 방지
request.setCharacterEncoding("UTF-8");

// 값 받기

String id = request.getParameter("id");
String sex = request.getParameter("sex");

// checkbox, radio는 값을 하나로 본다
// 베열로 값을 받아온다
String[] favo = request.getParameterValues("favo");
// 배열에 있는 값을 하나씩 가지고 와야 한다
String favoStr = "";
for (int i = 0; i < favo.length; i++) {
	favoStr += favo[i] + ",";
}

String intro = request.getParameter("intro");
%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<ul>

		<li><%=id%></li>
		<li><%=sex%></li>
		<li><%=favoStr%></li>
		<li><%=intro%></li>

	</ul>
</body>
</html>

 


어제 했던 부분)

 

어제 처음으로 값을 전송하고 받아보는 예제를 작성해봤다.

오늘은 어제 이 내용을 바탕으로 응용 + 심화

 

RequestWepInfo.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>

<%
request.setCharacterEncoding("UTF-8");
String eng = request.getParameter("eng");
String han = request.getParameter("han");
%>


<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>RequestWepInfo 페이지 입니다.</title>
</head>
<body>

	<h1>RequestWepInfo.jsp 페이지</h1>
	영어 :
	<%=eng%>
	<br> 한글 :
	<%=han%>

</body>
</html>

 


 

🌀 Get 방식과 Post 방식의 차이

 

GET 방식 : URL에 파라메터 정보가 노출된다

http://localhost:9999/ImplicitObject/RequestWebInfo.jsp?eng=Hello&han=안녕

POST방식 : URL에 파라메터 정보가 노출되지 않는다

http://localhost:9999/ImplicitObject/RequestWebInfo.jsp

→ 보안적인 측면에서 POST 방식이 유리하다

 

 

🌀 response

페이지 이동 기능

서버페이지가 값을 보내고 직접 결과를 출력하지 않음

넘어오는 데이터를 처리만 해준다.

처리된 결과를 사용자에게 다시 알려준다

 

 

❗️ 페이지 이동 방식 두 가지 

  • request.getRequestDispatcher("이동할 페이지").forward(request,response)
  • response.sendRedirect("이동할 페이지")

 

페이지 이동 방식

 

가장 처음 페이지 URL : http://localhost:9999/ImplicitObject/ResponseMain.jsp

→ 로그인 성공시 (redirect 방식)

http://localhost:9999/ImplicitObject/ResponseWelcome.jsp

→ 로그인 실패 시 (forward 방식)

http://localhost:9999/ImplicitObject/ResponseLogin.jsp

로그인 실패면 main화면으로 가는데 URL 주소가 다르다 → 제어권

if(id.equals("must") && pwd.equals("1234")){
	// 로그인 성공 시
	response.sendRedirect("ResponseWelcome.jsp");
	
}else{
	// 로그인 실패 시
	request.getRequestDispatcher("ResponseMain.jsp").forward(request,response);
}

request 영역에 대한 제어권은 한 페이지가 가진다.

그 페이지에서 제어권을 넘기지 않으면 해당 페이지에 접근할 수 없다.

 

forward(request,response) → request, response에게 페이지 권한(제어권)을 넘겨준다. (위임)

request, response의 데이터를 읽어올 수 있다.

sendRedirect → 페이지 이동만 일어난다. 제어권을 넘겨주지 않음

다른 페이지의 데이터를 읽어올 수 없다.

 

쿼리스트링이 붙은 것은 데이터는 어떤 값으로 읽어오겠다고 지정을 하는 것 → get방식

 

내장객체) 어플리케이션 객체

 

getRealPath : 실제 저장된 파일 경로

 

톰켓에서 실제 데이터를 저장하고 있는 곳

jsp-workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/firstjsp/

 

 

🌀 영역객체

  • page
  • request
  • session
  • application

 

영역객체가 하는 일 → 사용자가 요청한 정보를 저장한다.

저장은 어디에 해야 가장 적절한지 판단

 

범위에 따라 영역객체를 4개로 나눠 놓았다.

 

 

✨ 영역객체의 범위

  • page

→ 1번, 2번, 3번 페이지가 있다면 각 페이지로 넘어갈 때 다른 페이지의 데이터는 사용할 수 없다.

 

Person.js

package common;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Person {
	
	
	// 빈(Bean) 객체 : DTO클래스
	// 반드시 기본형 생성자가 정의되어 있어야 한다.
	// 멤버는 private 해야한다.
	// getter / setter를 정의한다.
	
	private String name;
	private int age;
	public String getName() {
		return name;
	}
}

page 예제와 request 예제에서 사용하는 Person 타입.

 

PageContextMain.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>

<%@ page import="common.Person"%>

<%
    // 페이지 영역 사용
    pageContext.setAttribute("pageInteger", 1000);
    pageContext.setAttribute("pageString", "페이지 영역의 문자열");
    pageContext.setAttribute("pagePerson", new Person("홍길동", 20));
    %>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

	<%
	int pInteger = (Integer)pageContext.getAttribute("pageInteger");
	String pString = (String)pageContext.getAttribute("pageString");
	Person pPerson = (Person)pageContext.getAttribute("pagePerson");
	%>

	<ul>
		<li><%= pInteger %></li>
		<li><%= pString %></li>
		<li><%= pPerson.getName() %>, <%= pPerson.getAge() %></li>
	</ul>
	
	<h2>페이지 이동 후 page영역 읽어오기</h2>
	<a href = "PageLocation.jsp"> PageLocation.jsp 바로가기 </a>
</body>
</html>

 

  • request

→ 하나의 요청에 의해 호출된 페이지와 포워드(요청 전달)된 페이지까지 공유된다.

→ 페이지 이동 시 request 영역으로 제어권을 넘기기 위해선 forward 방식을 사용

→ 범위 : 제어권을 넘기는 페이지

 

RequestMain.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="common.Person" %>
<%
	request.setAttribute("requestString", "request영역의 문자열");
	request.setAttribute("requestPerson", new Person("안중근", 31)); 
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	
	<%
		request.removeAttribute("requestString");
		String rString = (String)request.getAttribute("requestString");
		Person rPerson = (Person)request.getAttribute("requestPerson");
	%>
	
	<p><%=rString %></p>
	<p><%=rPerson.getName() %>,<%=rPerson.getAge() %></p>
	
	<%
		request.getRequestDispatcher("RequestForward.jsp?paramHan=한글&paramEng=English")
		.forward(request,response);
	%>
</body>
</html>

 

SessionLocation.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@page import ="java.util.ArrayList" %>
    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2>페이지 이동 후 session 영역의 속성 읽기</h2>
<%
ArrayList<String> lists = (ArrayList<String>)session.getAttribute("lists");

// 향상된 for문
for(String str : lists) {
	out.print(str + "<br/>");
}

%>
</body>
</html>

모든 브라우저가 종료되면 데이터가 날아간다.

 

  • application

→ 어떤 페이지든 상관없이 모든 페이지에서 application 페이지에 저장된 정보를 이용할 수 있다.

동일 도메인에 한해 페이지 이동 중 생성된 정보를 application에 저장하면 프로그램이 종료되어도 남아있다.

→ 톰캣서버가 살아있는 동안 유효함. (서비스가 죽기 전까지 유효)

→ 모든 영역은 필요하면 데이터를 강제로 지울 수 있다.

→ 범위 : 모든 페이지

 

ApplicationMain.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    
    <%@page import = "java.util.HashMap" %>
    <%@page import = "java.util.Map" %>
    <%@page import = "common.Person" %>
    
    <%
    Map<String,Person> maps = new HashMap<>();
    maps.put("actor1", new Person("김길동", 30));
    maps.put("actor2", new Person("이순신", 20));
    application.setAttribute("maps", maps);
    %>
    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
application 영역에 속성 저장완료
</body>
</html>

 

ApplicationResult.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@page import = "java.util.Map" %>
    <%@page import = "common.Person" %>
    <%@page import = "java.util.Set" %>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

<%
Map<String,Person> maps = (Map<String,Person>)application.getAttribute("maps");

Set<String> keys = maps.keySet();
for (String key : keys){
	Person person = maps.get(key);
	out.print("이름 : " + person.getName() + ", 나이 : " +person.getAge());
	out.print("<br>");
}
%>

</body>
</html>

<!-- 실행하면 오류난다 -->

톰캣서버가 살아있는 동안은 데이터 정보가 남아있지만 톰캣서버를 죽였다 다시 살리면 오류가 뜬다.

 

 

사용자가 편리하게 사용할 수 있는 페이지 : 3페이지

영역객체에 데이터를 집어 넣을 때 : setAttribute

영역객체에 데이터를 읽어올때 : getAttribute

jsp에서는 자바문법을 다루기 때문에 꼭 컬렉션을 알아야한다.

잘 모르겠으면 자바 컬렉션을 공부할 것.

 

 

🍪 쿠키객체

톰캣에서 쿠키라는 객체를 제공

 

클라이언트와 서버 간 통신

통신규약 http

 

정보를 서버쪽에 저장할때도, 클라이언트쪽에 저장할 때도 있음.

클라이언트 쪽에서 서버가 전달한 정보를 저장하는 것을 ‘쿠키’라고 한다.

클라이언트 PC에 보관된 쿠키정보.

 

session → 서버에 저장

쿠키 → 클라이언트에 저장

 

  • 저장 위치: 세션은 서버에, 쿠키는 클라이언트에 저장됩니다.
  • 보안: 세션이 더 안전하며, 쿠키는 클라이언트에서 수정될 수 있습니다.
  • 용량: 세션은 더 많은 데이터를 저장할 수 있으며, 쿠키는 용량 제한이 있습니다.
  • 유효 기간: 세션은 대개 브라우저 세션 동안 유지되며, 쿠키는 설정된 만료 날짜까지 유지될 수 있습니다.

 

response + 쿠키정보 → 생성

request + 쿠키정보 → 가지고 오기

<%@ 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>

	<!-- 이 페이지를 실행하는 것 자체가 요청 -->
	<h1>쿠키 생성</h1>
	<%
Cookie cookie1 = new Cookie("myCookie1", "내가만든쿠키1");
cookie1.setPath(request.getContextPath()); // 경로를 루트로 설정
cookie1.setMaxAge(3600); // 쿠키 유효시간 1시간 <- 초단위
response.addCookie(cookie1); // 응답헤더에 쿠키 정보가 추가되는 동시에 클라이언트에게 넘어간다

Cookie cookie2 = new Cookie("myCooki1e2", "내가만든쿠키2");
cookie2.setPath(request.getContextPath()); // 경로를 루트로 설정
cookie2.setMaxAge(3600); // 쿠키 유효시간 1시간 <- 초단위
response.addCookie(cookie2);
%>

	<h1>쿠키정보 확인</h1>
	<%
	Cookie[] cookies = request.getCookies(); // 헤더영역에 저장된 쿠키정보를 가지고 온다
	if (cookies != null) {
		for (Cookie c : cookies) {
			String cookieName = c.getName();
			String cookieValue = c.getValue();

			out.print(cookieName + "<br>");
			out.print(cookieValue);
		}
	}
	%>

</body>
</html>

f12 키 누르고 어플리케이션 들어가서 쿠키 정보 확인해보기

이 날은 하루 종일 톰캣설치 때문에 쩔쩔맸다. 

맥을 쓰기 때문에 뭔가 설치하거나 환경변수를 설정할때 헤맬 상황을 대비해 미리 공부하고 프로그램 설치도 했었는데.. 

버전이 다 달라서 또 애를 먹고 있다. 자바는 그나마 버전이 범용이라 다행이지만 톰캣이나 스프링부트나.. 혼자 앞서가다가 버전이 달라 버전 충돌일어나고 꼬이는 일들이 몇번이나 발생했다. 잘하려고, 잘해보고 싶어서 수업에 피해주기 싫어서 나름 노력했는데 일이 잘 안풀리니 심란했다. 그래도 나와 비슷한 처지의 사람들이 블로그를 잘 정리해줘서 정말 고맙게 참고했다.

정작 나는 그러지 못하지만.. 그래도 어찌저찌 톰캣 설치! 


 

처음에는 8080포트로 고양이도 뜨고 잘 되는 듯 했지만 강사님이 실제 서버연결은 안된거라해 지우고 다시 깔려다보니 난관에 봉착했다..

터미널에서 cd 명령어도 안먹고 혼자 맨붕이 왔는데 알고보니 띄어쓰기를 제대로 안해서 그런거였다;;

 


firstjsp 라는 파일 만들기

webapp 에서 HelloJsp 라는 파일 만들기, 무조건 여기에 넣어야 한다. 파일들을

<h1>첫번째 jsp 입니다</h1>

IncludeMain 만들기

인클루드 지시자에 대해 배움


강의를 못따라가서 이렇게 들리는 걸 그냥 적어놓으며 나중에 남아 혼자 해봤다ㅋㅋㅠ

 

JSP 문법

내장객체

중요

// request

// respones

// session

// application

// pageContext

 

 

🌀 request

서버로 값을 넘겨주는 내장객체

폼으로 값을 받는 것은 최종값이 값으로 정해진다

 

 

값을 보내는 방식

  • Get : 데이터 조회 요청 (default)
  • Post : 데이터 생성 요청
  • Put : 데이터 수정 요청
  • Delete : 데이터 삭제 요청

 

 

클라이언트와 서버

request 객체는 클라이언트가 보낸 정보 저장, 서버가 요청한 정보도 읽어온다.

 

request 방식의 한글깨짐 현상 해결

request.setCharacterEncoding("UTF-8");

 

이 날은 톰캣설치의 혼란으로 (사실상 혼자만의 생쇼) 정리한게 이게 다 였다.. 

이제 무사히 설치를 했으니 다시 수업에 잘 집중하자!

컴퓨터 재시작 했을 때

colima start --memory 4 --arch x86_64

docker start oracle


맥북 톰캣 설치

/Applications/apache-tomcat-10.1.24 → 톰캣경로

/Applications/apache-tomcat-9.0.89

/Users/yunakang/apache-tomcat-10.1.24/bin


 

오늘은 ‘테이블 설계 후 데이터 집어넣기’를 해본다.

 

테이블 설계

 

✨ 논리적 설계

→ 말로 풀어갈 수 있음

-도서(객체)

-속성

  • 도서번호
  • 도서제목
  • 출판사
  • 가격
  • 도서단가
  • 목차

-고객(객체)

-속성

  • 고객번호
  • 고객이름
  • 주소
  • 전화번호

두 테이블이 관계를 맺을 수 있다 → 조인

도서와 고객은 주종관계

도서가 있어야 고객이 있다 → 도서가 주, 고객이 종

 

✨ 물리적 설계

→ 테이블 정의서

→ 커럼 이름 정하기

 

도서 컬럼명 - 타입(크기) - 제약조건

  • bookid - number(2) - pk
  • bookname - varchar2(10) - not null
  • publisher - varchar2(20) - not null
  • price - number(8) - not null

 

 

SQL 관계설정

 

 

erdcloud 에서 erd 작성해보기

  • 쿼리문을 자동으로 만들어준다

 

erdcloud에서 만들어준 쿼리문을 이용해 sql developer로 데이터를 넣고 원하는 형식으로 조회해보았다.

CREATE TABLE  subInfor  (
	 subcode 	varchar2(2)		NULL,
	 subname 	varchar2(20)		NOT NULL,
	 teacher 	varchar2(10)		NOT NULL
);

CREATE TABLE  studentInfor  (
	 no 	number(4)		NOT NULL,
	 name 	varchar2(10)		NOT NULL,
	 department 	varchar2(15)		NOT NULL
);

CREATE TABLE  CourseInfor  (
	 courseNo 	number(10)		NOT NULL,
	 no 	number(4)		NOT NULL,
	 subcode 	varchar2(2)		NULL
);


ALTER TABLE  subInfor  ADD CONSTRAINT  PK_SUBINFOR  PRIMARY KEY (
	 subcode 
);

ALTER TABLE  studentInfor  ADD CONSTRAINT  PK_STUDENTINFOR  PRIMARY KEY (
	 no 
);

ALTER TABLE  CourseInfor  ADD CONSTRAINT  PK_COURSEINFOR  PRIMARY KEY (
	 courseNo 
);






insert into studentInfor (no, name, department)
values (1, '홍길동' ,'컴공과');

insert into studentInfor (no, name, department)
values (2, '장길산' ,'토목과');

insert into studentInfor (no, name, department)
values (3, '임꺽정' ,'불문과');


insert into subInfor (subcode, subname, teacher)
values ('s1', 'java' ,'조용준');

insert into subInfor (subcode, subname, teacher)
values ('s2', '알고리즘' ,'이몽룡');

insert into subInfor (subcode, subname, teacher)
values ('s3', 'web' ,'성춘향');


insert into CourseInfor (courseNo, no, subcode)
values (1, 1 ,'s1');

insert into CourseInfor (courseNo, no, subcode)
values (2, 1 ,'s2');

insert into CourseInfor (courseNo, no, subcode)
values (3, 2 ,'s2');

insert into CourseInfor (courseNo, no, subcode)
values (4, 2 ,'s3');

commit;

select * from studentInfor;
select * from subInfor;
select * from CourseInfor;


-- 학번, 이름, 과목코드, 과목명, 교수명

select s.no, s.name, e.subcode, sb.subname, sb.teacher
from CourseInfor e join studentInfor s
on e.no = s.no
join subInfor sb
on e.subcode = sb.subcode;

 

조인을 통해 아래와 같은 결과를 출력할 수 있다.

 

 

문장 출력하기

-- 문장 출력하기
set serveroutput on;

 

 

🍀 반복문

-- 반복문의 종류
-- loop(무한반복문), for, while


-- 1부터 10까지 출력하기

-- loop 무한반복문
declare
  n number := 1;
begin
  loop 
  dbms_output.put_line(n);
  n := n + 1; 
  
  -- eixt (반복문 강제 종료)
  if (n > 10) then 
   exit;
  end if;
  
  end loop;
end;
/


-- for문 형식
declare
  
begin
 for 변수 in 시작값.. 끝값 loop
 
 end loop;
end;
/

-- for문
-- 실제로는 숫자를 넣는 경우는 거의 없다

declare
  
begin
 for n in 1..10 loop -- 1부터 10까지 1씩 증가한다. (10번 반복)
  dbms_output.put_line(n);
 end loop;
end;
/

-- 반복문을 사용해 사원들의 정보를 가져오기
-- select 구문은 하나만 가지고 올 수 있다
-- 때문에 반복문을 활용하면 된다.
declare
  vdept dept%rowtype;
begin
  
  for n in 1..4 loop
  
  select * into vdept
  from dept
  where deptno = 10 * n;
  
  dbms_output.put_line(vdept.deptno || ' : ' || vdept.dname || ' : ' || vdept.loc);
  
  end loop;

end;
/

-- while 문
declare
 
begin
while 조건식 loop 

end loop;
end;
/

-- while 문
declare
 n number := 1;
begin
 while n <= 10 loop 
  dbms_output.put_line(n);
  n := n + 1;
 end loop;
end;
/

-- while 문을 사용해 dept 테이블 4개 출력 
declare
 vdept dept%rowtype;
 n number := 1;
begin
 while n <= 4 loop

  select * into vdept
  from dept
  where deptno = 10 * n; 
  
  dbms_output.put_line(vdept.deptno || ' : ' || vdept.dname || ' : ' || vdept.loc);
 
  n := n + 1;
end loop;

end;
/

 

 

🍀 저장 프로시져

-- 저장 프로시져
-- 누구든 권한만 가지고 있으면 이 프로시져를 사용할 수 있다

create [or replace] procedure 프로시져명 [(매개변수1, 매개변수2, 매개변수3,...)]

is
 변수
begin

end;
/
-- 데이터 삭제 프로시져
create or replace procedure del_all

is

begin
 delete from emp01;
end;
/

select * from emp01;

-- 프로시져 실행
execute del_all;

 

 

  • 문제 풀어보기

— sel_all 이란 이름의 저장프로시져 만들기

— dept 테이블의 레코드 모두 조회해서 출력

create or replace procedure sel_all

is
 vdept dept%rowtype;
 n number := 1;
begin

 while n <= 4 loop

begin 
 select * into vdept
 from dept
 where deptno = 10 * n; 
 
 dbms_output.put_line(vdept.deptno || ' : ' || vdept.dname || ' : ' || vdept.loc);
 
 end;
 
 n := n + 1;
end loop;
 
end;
/

select * from dept;

execute sel_all;

 

 

🍀 매개변수를 사용하는 프로시저

-- 매개변수를 사용하는 프로시저
-- in, out, in out 총 3가지 형태
-- 기본은 in 타입, 필요하면 out 타입
-- in은 데이터를 받고, out은 데이터를 호출, in out은 둘다 가능

-- 특정데이터만 골라서 삭제하는 프로시저
create or replace procedure del_ename(vename emp01.ename%type)
is

begin
 delete from emp01
 where ename = vename;
end;
/

execute del_ename('SMITH');

select * from emp01;

-- 매개변수 in , out 타입
create or replace procedure sel_empno
(
 vempno in emp.empno%type,
 vename out emp.ename%type,
 vsal out emp.sal%type,
 vjob out emp.job%type
)

is 
 -- 변수
begin
 select ename,sal,job into vename, vsal, vjob
 from emp
 where empno = vempno;
end;
/

-- 실행
-- 바인드 변수
variable var_ename varchar2(15);
variable var_sal number;
variable var_job varchar2(9);


execute sel_empno(7788, :var_ename, :var_sal, :var_job);

print var_ename;
print var_sal;
print var_job;
-- 문제
-- 저장프로시저명 : sel_empname
-- 사워명으로 검색해서 해당사원의 직책을 얻어와서 print 명령어로 값을 출력

create or replace procedure sel_empname
(
 vename in emp.ename%type,
 vjob out emp.job%type
)

is

begin
 select job into vjob
 from emp
 where ename = vename;
end;
/

variable var_job varchar2(9);

execute sel_empname('SCOTT', :var_job);

print var_job;

 

🍀 시퀀스

-- 시퀀스(sequence)
-- 숫자를 자동으로 중복되지 않게 만들어 주는 객체
-- 테이블의 기본키(primary key)가 정의된 컬럼의 값으로 사용
-- 시퀀스명.nextval

create sequence 시퀀스명
start with 1 -- 몇 부터 시작할지 (1부터 하려면 생략 가능)
increment by 1 -- 얼마나 증가할지
maxvalue 1027-- 최대
minvalue 10-27-- 최소

 

시퀀스 생성

create sequence emp01_seq
start with 10
increment by 10
maxvalue 10000;

-- 시퀀스 객체의 구조를 확인
-- user_xxx 로 딕셔너리에 접근
desc user_sequences;

select SEQUENCE_NAME, MIN_VALUE, MAX_VALUE, INCREMENT_BY
from user_sequences;

select emp01_seq.nextval
from dual;
-- 실행할 때마다 값이 증가한다

drop table emp01;

create table emp01(
empno number(4) primary key,
ename varchar2(10),
hiredate date
);

insert into emp01
values (emp01_seq.nextval, 'hong', sysdate);

delete from emp01
where empno = 90;

select * from emp01;

새로 데이터가 만들어질 때마다 empno가 증가한다

-- 증가하는 sequence에 별칭 부여
insert into emp01
values ('eno' || emp01_seq.nextval, 'hong', sysdate);

 

 

🍀 인덱스

-- 인덱스(index)
-- 데이터의 조회 속도를 증가 시킨다.
-- 컬럼에 생성하는 객체
-- primary key 제약조건이 정의된 컬럼은 기본적으로 index 객체가 생성 되어있다

-- 조건 : 전체의 3~4% 내외 데이터 검색이 이뤄질 때 효과적이다
-- 인덱스 객체를 만드는 것도 용량을 차지하기 때문에 인덱스 객체가 필요한지 잘 판단하는 것이 중요
-- 실제로는 primary key를 더 많이 사용

drop table emp01;

create table emp01
as
select * from emp;

-- 자기 것을 복제
-- insert into emp01
-- select * from emp01;

select count(*) from emp01;

insert into emp01(empno, ename)
values (1111, 'SYG');

-- 인덱스 객체가 생성되기 전과 후 데이터 찾는 속도 비교
set timing on;

select distinct empno, ename from emp01
where ename = 'SYG';

-- 인덱스 객체 생성
create index idx_emp01_ename
on emp01 (ename);

desc user_ind_columns;

select INDEX_NAME, TABLE_NAME, COLUMN_NAME
from user_ind_columns
where table_name in ('EMP01');

-- 인덱스 삭제
drop index idx_emp01_ename;

데이터를 5만건 넣고 조회하는 속도를 비교해보았다.

 

 

🍀 데이터 베이스 권한

system 계정

-- 데이터 베이스 권한
-- 최고 권한 DBA (system 계정)

-- 계정 생성
-- DCL(Data Control Language)
-- grant : 사용자에게 권한 부여 
-- revoke : 사용자에게 권한 취소

-- 데이터 베이스의 권한을 부여하기 위해 새로운 개정 생성
create user user01 identified by 1234;

-- 권한
-- 시스템 권한
-- 객체 권한

-- 권한 부여 명령어

-- 세션 만들기 권한
grant create session
to user01;

-- 테이블 만들기 권한
grant create table
to user01;

-- 다른 계정의 객체를 사용하고 싶을 때 권한 위임
-- 객체에 따라 권한 목록이 다름

-- 권한 회수
revoke create table
from user01;

 

scott 계정에서 user01 계정으로 권한 부여, 회수

scott 계정

-- 객체 권한
grant select
on emp
to user01;

-- 권한 회수
revoke select
on emp
from user01;

 

user01 계정

create table emp(
empno number(4)
);

drop table emp;

-- 누구로부터 권한을 부여받았는지 명시해줘야 한다 (스키마 붙이기)
select * from scott.emp;

-- 삭제 권한은 없기 때문에 실행되지 않음
-- delete from scott.emp;

desc user_tab_privs_recd;

select * from user_tab_privs_recd;

 

 

role 권한

system 계정

-- role 권한
-- 오라클베이스에 만들어져 있다
-- connect
-- resouce
-- dba

create user user02 identified by 1234;

-- 만들어진 roll을 사용하여 모든 권한 부여
grant connect, resource
to user02;

 

user02 계정

create table test (
empno number(4)
);

테이블이 잘 만들어진다.

 

role 을 직접 만들어서 사용하기

system 계정

-- role 만들어서 사용
create role mrole;

grant create session, create table, create view
to mrole;

create user user03 identified b용y 1234;

grant mrole
to user03;

 

user03 계정

create table test (
empno number(4)
);

테이블이 잘 만들어진다

 

객체권한을 담는 role

system 계정

-- 객체권한을 담는 role
create role mrole2;

-- 권한 주기
grant mrole2
to user03;

revoke mrole2
from user03;

-- role 삭제
-- revoke는 role을 특정사용자로부터 권한 회수, drop은 role을 아예 삭제하는 것이다
drop role mrole2;

 

scott 계정

-- role에 권한 부여
grant select
on emp
to mrole2;

 

user03

create table test (
empno number(4)
);

select * from scott.emp;

 

 

🍀 확장된 SQL 구문

-- PL/SQL (확장된 sql 구문)
-- 변수, 반복문, 조건, 비교문
-- 실행문 마지막에 반드시 세미콜론을 붙인다.

[declare] 
변수
begin

변수의 초기화, 반목문, 조건문, sql구문, 출력함수()

[exception]

end;
/

 

 

변수의 초기화

-- 문장 출력하기
set serveroutput on;

begin
dbms_output.put_line('hello world');
end;
/

-- 변수, 상수 선언

declare
vempno number(4); -- 변수의 선언
vename varchar2(10);
vjob varchar2(10) := 'sales'; -- 선언 및 초기화

begin
vempno := 7788; -- 변수의 초기화
vename := 'HONG';

-- 출력함수
dbms_output.put_line(vempno || ' : ' || vename);
end;
/

-- pl/sql구문
-- select 구문 작성 시 반드시 into절과 where절을 함께 작성해야 한다.
-- where은 조건절이 온다.




declare
	  -- 스칼라 방식
	  -- 타입과 크기를 직접 명시하는 방식
    -- vempno number(4); 
    -- vename varchar2(10);
    
    -- 레퍼런스
     vempno emp.empno%type; -- number(4)
     vename emp.ename%type; -- varchar2(10)
     
begin
    select empno, ename into vempno, vename
    from emp
    where ename = 'SCOTT';
    
    dbms_output.put_line(vempno || ' : ' || vename);
end;
/

select empno,ename
from emp;

 

rowtype 타입으로 변수선언

declare
    -- rowtype 타입
    -- 테이블에 컬럼명을 변수로 사용하자
    remp emp%rowtype;
    
begin
    select * into remp
    from emp
    where ename = 'SCOTT';
    
    dbms_output.put_line(remp.empno || ' : ' || remp.ename);
    dbms_output.put_line(remp.job || ' : ' || remp.sal);
    dbms_output.put_line(remp.mgr || ' : ' || remp.hiredate);
    dbms_output.put_line(remp.comm || ' : ' || remp.deptno);
    
end;
/

-- 부서테이블 20번 부서정보를 rowtype를 적용하여 출력하세요


select * from dept;

declare
    rdept dept%rowtype;
    
begin
    select * into rdept
    from dept
    where deptno = 20;
    
    dbms_output.put_line(rdept.deptno || ' : ' || rdept.dname || ' : ' || rdept.loc);
  
end;
/

 

 

🍀 조건문

 

if 문

-- 조건문
-- 하나의 레코드만 조회되게 만들어야 한다

-- pl/sql 구분의 if문은 3가지
-- if문
-- if else 문
-- 다중 if문



declare
    vempno number(4);
    vename varchar2(20);
    vdeptno emp.deptno%type;
    vdname varchar2(10);
begin
    select empno, ename, deptno into vempno, vename, vdeptno
    from emp
    where empno = '7788';
    
    if(vdeptno = 10) then
    vdname := 'AAA';
    end if;
    
    if(vdeptno = 10) then
    vdname := 'BBB';
    end if;
    
    if(vdeptno = 10) then
    vdname := 'CCC';
    end if;
    
    if(vdeptno = 10) then
    vdname := 'DDD';
    end if;
    
    dbms_output.put_line(vempno || ' : ' || vename);
    dbms_output.put_line(vdeptno || ' : ' || vename);
end;
/
-- 사원의 연봉을 출력하는 프로그램

declare
    vemp emp%rowtype;
    annsal number(7,2);
    
begin
   select * into vemp
   from emp
   where ename = 'SCOTT';
   
   if (vemp.comm is null) then
   vemp.comm := 0;
   end if;
   
   annsal := vemp.sal * 12 + vemp.comm;
   
   dbms_output.put_line('사 번' || ' : ' || '이 름' || ' : ' || '연 봉');
   dbms_output.put_line(vemp.empno || ' : ' || vemp.ename || ' : ' || annsal);
end;
/

 

if else문, 다중 if문

-- if else 문

declare
    vemp emp%rowtype;
    annsal number(7,2);
    
begin
   select * into vemp
   from emp
   where ename = 'SCOTT';
   
   if(vemp.comm is null) then
   annsal := vemp.sal * 12;
   else 
   annsal := vemp.sal * 12 + vemp.comm;
   end if;
   
   dbms_output.put_line('사 번' || ' : ' || '이 름' || ' : ' || '연 봉');
   dbms_output.put_line(vemp.empno || ' : ' || vemp.ename || ' : ' || annsal);
end;
/



-- 다중 if문

declare
    vempno number(4);
    vename varchar2(20);
    vdeptno emp.deptno%type;
    vdname varchar2(10);
begin
    select empno, ename, deptno into vempno, vename, vdeptno
    from emp
    where empno = '7788';
    
    if(vdeptno = 10) then
    vdname := 'AAA';
    elsif(vdeptno = 20) then
    vdname := 'BBB';
    elsif(vdeptno = 30) then
    vdname := 'CCC';
    elsif(vdeptno = 40) then
    vdname := 'DDD';
    end if;
    
    dbms_output.put_line(vempno || ' : ' || vename);
    dbms_output.put_line(vdeptno || ' : ' || vename);
end;
/

+ Recent posts