오늘은 웹 프로젝트를 생성하고 SQL을 활용해서 DB 연결을 해보겠습니다!
■ JDBC(JAVA DataBase Connectivity)
JDBC는 자바 언어로 DB 프로그래밍을 하기 위한 라이브러리입니다.
JDBC 라이브러리는 관계형 데이터베이스에 접근하고 SQL 쿼리문을 실행하는 방법을 제공합니다. 예를 들면 회원 관리 시스템을 만들기 위해서 DB 테이블에 레코드를 추가/ 수정/ 삭제해야 하는데, 그러기 위해서 SQL 쿼리문을 자바 프로그램 내에서 이용해야 합니다, 이러한 방법을 제공하는 게 JDBC입니다.
※ JDBC 프로그래밍의 문제점
-> JDBC와 DBMS와의 연동작업은 Connection이라는 객체를 생성하면서 이루어집니다.
이 연동 작업은 클라이언트로부터의 요청이 있을 때마다 매번 이루어져야 한다는 점에서 문제가 발생합니다.
이러한 일련의 과정들은 시간과 비용적인 측면에서 비효율을 낳습니다.
그럼 JDBC는 어디서 가져오는가?
바로 DBMS를 설치한 경로에 있습니다. (없으신 분들은 검색해서 다운로드 받으시면 됩니다.)
C:\oraclexe\app\oracle\product\11.2.0\server\jdbc\lib
글쓴이는 이전에 오라클을 설치했기 때문에 오라클의 JDBC가 있습니다.
JDBC는 사용하는 방법이 3가지 있습니다.
- JDK설치디렉터리\jre\lib\ext\에 복사하는 방법.
- 톰캣 설치디렉터리\common\lib 폴더에 복사하는 방법.
- 이클립스 프로젝트의 Webcontent\WEB-INF\lib 폴더에 복사하는 방법.
대부분 이클립스 프로젝트의 폴더에 복사하는 방법을 사용합니다. 이 포스팅 또한 동일한 방식으로 진행합니다.
■ JDBC 연결
먼저 JAVA에 DB를 연결하려면 SQL, 오라클 DB 등이 설치되어있어야 합니다.
각 회사마다 Driver가 다르기 때문에 자신이 설치한 DB에 맞는 Driver를 사용해야 합니다.
연결 방식은 간단합니다.
File – New – Dynamic Web Project - jsp01이라는 웹프로젝트 생성 (주의: web.xml 체크)
/jsp01/src/main/webapp/WEB-INF/lib/ojdbc6.jar (오라클 드라이버 복사)
위 방식과 동일하게 진행했다면 테스트를 진행해 봅시다.
테스트 코드는 다음과 같습니다.
<예제 1>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%@ page import="java.sql.*" %>
<%
Connection conn=null;
try{
//DB연결 문자열
//jdbc:oracle:thin:@호스트:포트:sid
String jdbcUrl="jdbc:oracle:thin:@localhost:1521:xe";
String dbId="java"; //오라클 접속 아이디
String dbPass="java1234"; // 비밀번호
//jdbc driver 로딩
Class.forName("oracle.jdbc.driver.OracleDriver");
// getConnection(연결문자열,아이디,비번) DB에 접속
conn=DriverManager.getConnection(jdbcUrl, dbId, dbPass);
out.println("오라클에 접속되었습니다.");
}catch(Exception e){
out.println("오라클 접속 에러...");
e.printStackTrace();
}
%>
</body>
</html>
저처럼 try절의 출력 내용이 동일하다면 성공입니다.
그럼 다음으로 context.xml에 설정값을 넣어줘야 하는데, 실행 전에 DBCP에 대해서 알아봅시다.
■ DBCP(DataBase Connection Pool)
클라이언트와 서버 사이드인 웹 애플리케이션에서, 사용자의 요청에 따라 Connection이 생성된다면, 수많은 사용자가 요청을 했을 때 서버에 과부하가 걸리게 됩니다.
DBCP는 이러한 상황을 예방하기 위해 미리 일정 개수의 Connection을 만들어 Pool에 저장을 하고, 사용자의 요청이 발생하면 Connection을 제공하고 사용자와의 연결이 종료된다면 Pool에 다시 반환하여 보관하는 것을 의미합니다.
즉, 정리하자면 다음과 같습니다.
- 여러 개의 DB Connection을 하나의 Pool에 모아놓고 관리합니다.
- DB 커넥션 객체를 여러 개 생성한 뒤 Pool에 담아놓고 필요할 때 불러와서 사용합니다.
- 사용이 끝난 커넥션 객체는 다른 작업에서 다시 사용할 수 있도록 Pool에 반환합니다.
- 만약, 빌려줄 수 있는 Connection이 없다면 Connnection 객체가 반환할 때까지 클라이언트는 대기 상태로 전환합니다.
그럼 DB연결, 생성과 반환을 원활하게 하기 위해 context.xml에서 DBCP를 설정해 봅시다.
글쓴이는 톰캣에 파일이 있습니다. 혹시 못 찾는 분들을 위해 경로를 남겨드리겠습니다.
/Servers/Tomcat v9.0 Server at localhost-config/context.xml
<DBCP 설정>
<!-- dbcp(DataBase Connection Pool) 설정함으로 초기 DB연결생성과 반환을
원활하게하기 위함 -->
<Resource name="oraDB" => 자바코드에서 참조하는 이름
driverClassName="oracle.jdbc.driver.OracleDriver" =>JDBC 드라이버
maxTotal="50" => DB커넥션의 갯수
maxIdle="10" => 커넥션 풀에서 유지될수 있는 idle 상태 커넥션의 최대
개수. (기본값 : 8)
maxWaitMillis="-1" => 여분의 커넥션이 생길때 까지 기다리는 시간
type="javax.sql.DataSource"
url="jdbc:oracle:thin:@localhost:1521:xe"
username="java" =>DB 접속 계정
password="java1234" />
</Context>
- driverClassName : DB작업을 위해 로딩할 JDBC 드라이버 파일에 드라이버 인터페이스를 상속하는 파일명을 전체 이름으로 지정. Class.forName()의 인자값으로 들어가는 내용입니다.
- url : 접속할 DB 서버의 URL
- username : DB 서버의 계정
- password : 해당 계정의 비밀번호
- name : 현재 리소스를 등록할 이름
- type : 리소스의 타입. Connection Pool을 사용할 수 있도록 해주는 객체인 javax.sql.DataSource 타입으로 지정합니다.
- maxTotal : DB커넥션의 개수
- maxIdle : 커넥션 풀에서 유지될 수 있는 idle 상태 커넥션의 최대 개수. (기본값 : 8)
- maxWaitMillis : 여분의 커넥션이 생길 때까지 기다리는 시간
준비는 끝났습니다.
이제 DB를 연결해 봅시다. 저는 JAVA에 config 패키지를 만든 후 패키지 안에서 DB 클래스를 만들었습니다.
그럼 DB 클래스를 만들면 경로는 다음과 동일해야죠?
/jsp01/src/main/java/config/DB.java
DB 클래스 코드는 아래를 참고해 봅시다.
< DB >
package config;
import java.sql.Connection;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;
public class DB {
public static Connection getConn(){
//context.xml에 설정된 dbcp에서 커넥션을 가져옴
DataSource ds=null; //javax.sql
Connection conn=null;
try {
//context.xml을 분석하는 객체
Context ctx=new InitialContext(); //javax.naming
//context.xml의 Resource 태그 검색, name="oraDB"와 매칭
ds=(DataSource)ctx.lookup("java:comp/env/oraDB");
conn=ds.getConnection();//커넥션 할당받음
} catch (Exception e) {
e.printStackTrace();
}
return conn;//커넥션 리턴
}
}
그럼 제대로 연동이 됐는지 예제 코드를 통해서 알아봅시다.
준비물은 이클립스, SQL이고, 예제 코드로는 메모장 프로그램을 만들 겁니다.
예제로는 MVC 패턴으로 진행이 되는데, MVC(Model-View-Controller) 모델은 4 개의 계층으로 구성이 됩니다.
다음 포스팅으로 좀 더 세부적인 내용으로 찾아뵙겠습니다. 패턴은 다음 사진을 참고해 봅시다.
그럼 MVC 패턴으로 메모장 프로그램을 만드는데, 처리 순서는 다음과 같습니다.
그럼 예제 코드를 통해서 알아봅시다.
먼저 SQL 테이블을 생성합니다.
<SQL_Table_code>
create table memo(
idx number not null primary key, --글번호
writer varchar2(50) not null, --이름
memo varchar2(4000) not null, --내용
post_date date default sysdate --날짜
);
테이블 생성을 했다면 insert문을 활용해서 테스트 테이블의 데이터를 추가합니다.
<SQL memo_table_insert_code >
insert into memo (idx, writer, memo) values(1,'kim','메모');
insert into memo (idx, writer, memo) values(2,'김철수','메모');
insert into memo (idx, writer, memo) values(3,'park','메모');
데이터 추가를 완료했다면 확인해 봅시다.
위 사진처럼 테이블 생성이 완료되면 이제 JAVA로 넘어오는데, 연습 예제로는 @(어노테이션)을 활용하지 않고, 고전 방식으로 진행해보려 합니다.
그럼 어떻게 해야 할까?
바로 web.xml에 콘텍스트를 지정해 줍니다.
이전 포스팅에서 저희는 서블릿에 대해서 알아봤습니다. 이번 예제 코드로 활용해 봅시다.
web.xml은 지금 진행하고 있는 프로젝트의 WEB-INF 폴더 안에 있습니다.
그럼 서블릿을 지정합니다.
< Servlet_code >
<!-- 웹프로젝트 이름(컨텍스트) -->
<display-name>jsp01</display-name>
<servlet>
<servlet-name>memo</servlet-name>
<servlet-class>memo.MemoServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>memo</servlet-name>
<url-pattern>/memo_servlet/*</url-pattern>
</servlet-mapping>
설정을 맞췄다면 JAVA 코드로 호출을 해야 합니다.
이전 포스팅에서 알아봤던 호출 방법 두 가지인 doGet(), doPost 방식을 설정합니다.
< JAVA_MemoServlet >
package memo;
import java.io.IOException;
import java.util.List;
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("/MemoServlet") //어노테이션 주석처리
public class MemoServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("memo servlet...");
// dao 생성
MemoDAO dao = new MemoDAO();
//메모 목록을 받아옴
List<MemoDTO> items = dao.listMemo();
// 웹영역에 저장
request.setAttribute("list", items); // key, value
//페이지 이동(포워딩)
RequestDispatcher rd = request.getRequestDispatcher("/memo/memo_list.jsp");
rd.forward(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
서블릿 처리까지 완료되면 JSP 파일을 만들어줍니다.
이번 코드로는 ajax 방식을 활용해 보겠습니다.
< JSP_memo.jsp >
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>memo</title>
<script src="../include/jquery-3.6.3.min.js"></script>
<script type="text/javascript">
$(function() {
$.ajax({
type : "get", /*get방식은 생략가능 */
url : "/jsp01/memo_servlet/memo_list.do", /* 요청 url */
success : function(result) { //콜백함수
$("#div1").html(result); //결과값을 div에 출력
}
})
});
</script>
</head>
<body>
<h2>한줄메모장</h2>
<!-- 메모를 출력시킬 영역 -->
<div id="div1"></div>
</body>
</html>
ajax에서 요청 url : memo_list.jsp를 만들어야 하는데, 그전에 SQL Table로 만들었던 데이터를 가져와야 하기 때문에 이번에는 MVC 패턴에서 필요한 DTO, DAO 클래스 파일을 생성합니다.
여기서 잠깐 알고 넘어갑시다.
- DTO : 데이터베이스 레코드의 데이터를 매핑하기 위한 데이터 객체입니다.
- DAO : DATA에 접근하기 위한 객체이며, 데이터베이스 접근을 하기 위한 로직과 비즈니스 로직을 분리하기 위해 사용합니다.
먼저 DTO 클래스를 만드는데, SQL 테이블을 생성할 때 테이블 데이터 조건 값을 NUMBER, BARCHAR2 등으로 숫자 타입, 스트링 타입으로 설정했습니다.
JAVA에서도 동일합니다 숫자 타입은 int , 스트링 타입은 String으로 설정해 줍니다. 변수 네임은 동일하게 설정하는 게 좋습니다.
DTO 클래스에서는 getter/setter , ToString를 활성화합니다.
(JSP 파트를 공부하는 단계라면 JAVA 공부할 때 기억이 가물가물 할 수 있습니다. JAVA는 계속 공부하셔야 합니다.)
< JAVA_MemoDTO >
package memo;
public class MemoDTO {
private int idx;
private String writer;
private String memo;
private String memo_date;// 날짜는 계산할 필요가 없으면 String 타입써도 됨,
//getter,setter, toString
public int getIdx() {
return idx;
}
public void setIdx(int idx) {
this.idx = idx;
}
public String getWriter() {
return writer;
}
public void setWriter(String writer) {
this.writer = writer;
}
public String getMemo() {
return memo;
}
public void setMemo(String memo) {
this.memo = memo;
}
public String getMemo_date() {
return memo_date;
}
public void setMemo_date(String memo_date) {
this.memo_date = memo_date;
}
@Override
public String toString() {
return "MemoDTO [idx=" + idx + ", writer=" + writer + ", memo=" + memo + ", memo_date=" + memo_date + "]";
}
}
자 그럼 이제 DATA에 접근하기 위해 DAO를 생성합니다.
< JAVA_MemoDAO >
package memo;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import config.DB;
public class MemoDAO {
public List<MemoDTO> listMemo(){
List<MemoDTO> items = new ArrayList<>();
Connection conn=null; //DB연결 객체
PreparedStatement pstmt=null; //sql처리 객체
ResultSet rs =null; //**중요 : select문의 결과행 처리 객체
try {
conn = DB.getConn(); //DB 접속
String sql ="select * from memo order by idx desc";
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery(); //sql문 실행
while(rs.next()) {
MemoDTO dto = new MemoDTO();
dto.setIdx(rs.getInt("idx"));
dto.setWriter(rs.getString("writer"));
dto.setMemo(rs.getString("memo"));
dto.setMemo_date(rs.getString("post_date"));
items.add(dto);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if(rs != null) rs.close();
} catch (Exception e2) {
e2.printStackTrace();
}
try {
if(pstmt != null) pstmt.close();
} catch (Exception e2) {
e2.printStackTrace();
}
try {
if(conn != null) conn.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
return items;
}
}
데이터에 접근할 때는 항상 예외 처리를 해줘야 하기 때문에 Try~catch문을 사용합니다.
값은 배열처리로 가져오는데, 여기서 꼭 알고 넘어가야 하는 부분이 있습니다.
위 코드를 보면 DB연결 -> SQL 처리 -> Select문의 결과행 처리 순서로 진행했습니다.
항상 코드들은 열었다면 닫아야 합니다.
DAO는 닫을 때 역순으로 닫습니다.
그렇다면 순서는 Select문의 결과행 처리 순서 -> SQL 처리 -> DB 순입니다.
DAO는 데이터에 접근하는 클래스라서 꼭 알고 넘어가셔야 합니다. ( 중요합니다! )
자 그럼 모든 준비는 끝났습니다. 배열에 담아둔 값을 이제 불러와야겠죠?
처음에 ajax url 설정을 했던 memo_list.jsp 파일을 만들어 줍니다.
< JSP_memo.jsp >
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.util.List" %> <!-- 페이지 import -->
<%@ page import="memo.MemoDTO" %> <!-- 페이지 import -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="../include/jquery-3.6.3.min.js"></script>
</head>
<body>
<%
List<MemoDTO> items=(List<MemoDTO>)request.getAttribute("list"); // Object
%>
<table border="1">
<tr>
<th>번호</th>
<th>이름</th>
<th>메모</th>
<th>날짜</th>
</tr>
<% for(MemoDTO dto : items) { %>
<tr>
<td><%= dto.getIdx() %> </td>
<td><%= dto.getWriter() %> </td>
<td><%= dto.getMemo() %> </td>
<td><%= dto.getMemo_date() %> </td>
</tr>
<% } %>
</table>
</body>
</html>
위 코드를 확인해 보면 page import 두 개가 보입니다.
먼저 우리는 데이터를 배열에 담아뒀습니다. JSP에서 배열을 활용하려면 import 처리를 해줘야 합니다.
그리고 값을 가져오기 위해 DTO를 가져와야 합니다. ( 경로는 확실하게 적어줘야 합니다. )
여기서 중요한 부분은 MemoServlet에서 웹 영역에 저장하기 위해 request.setAttribute로 key~value 값을 설정했습니다.
request.setAttribute로 전달된 값은 request.getAttribute로 받습니다.
이게 무슨 의미일까요??
그건 바로.
들어오는 데이터 타입은 Object 타입이기 때문에 받는 타입으로는 반드시 형변환처리를 해줘야 합니다.
만약에 result라는 변수가 있는데 int 타입이라면?
ex ) result = (int) request.getAttribute("result");
이렇게 서로 같은 타입으로 만들어주어야 합니다.
그렇기 때문에 위 코드에서 스크립틀릿을 보면
List<MemoDTO> items=(List<MemoDTO>)request.getAttribute("list");
이런 식으로 동일한 타입으로 형변환을 해야 합니다.
자 그럼 이제 제대로 데이터를 가져왔는지 출력해 봅시다.
출력 파일은 ajax를 활용한 memo.jsp에서 시작합니다.
글쓴이처럼 테이블이 제대로 나온다면 성공입니다.
마치며
오늘은 DB 연동 및 간단한 MVC 패턴에 대해서 알아봤습니다.
처음 접하시는 분들은 다소 어렵고 코딩량도 많아져서 이해가 안 될 수 있습니다.
그럴 땐 하나씩 천천히 알아가면 좋습니다.
물론 직접 코딩을 해봐야겠죠.
그럼 다음 포스팅에서 뵙겠습니다.
'[ View ] > JSP' 카테고리의 다른 글
[ JSP ] 에러 처리 (0) | 2023.03.06 |
---|---|
[ JSP ] 액션 태그 (0) | 2023.03.05 |
[ JSP ] model 종류 및 내장 객체 응용 (0) | 2023.03.04 |
[ JSP ] 내장 객체 (2) | 2023.03.03 |
[ JSP ] 웹 프로그래밍(JSP)의 개요 및 구성 요소 (0) | 2023.03.01 |