7장 Servlet 비즈니스 로직 처리
(1) Servlet 비즈니스 로직 처리 방법
서블릿 비즈니스 처리 작업
: Servlet이 Client로부터 요청을 받으면 그 요청에 대해 작업을 수행하는 것을 말한다. 웹 프로그램에서 대부분의 비즈니스 처리 작업은 DB 연동 작업이지만 다른 서버와 연동하여 데이터를 얻은 작업도 수행할 수 있다.
ex)
웹 사이트 회원 등록 요청 처리 작업
웹 사이트 로그인 요청 처리 작업
쇼핑몰 상품 주문 처리 작업
- 클라이언트로부터 요청을 받음
- 데이터베이스 연동과 같은 비즈니스 로직 처리
- 처리 결과를 클라이언트에게 돌려줌
(2) Servlet의 데이터베이스 연동
: Client로부터 요청을 받으면 Servlet은 SQL문을 사용해 데이터베이스 접근하여 작업 .
DAO/VO 클래스 사용
Servlet으로 회원 정보 테이블의 회원 정보 조회
- 웹 브라우저가 Servlet에 회원 정보 요청
- MemberServlet은 요청은 받은 후 MemerDAO 객체 생성하여 listMembers() 메서드 호출
- listMembers()에서 다시 connDB() 메서드를 호출하여 DB와 연결한 후 SQL문을 실행해 회원 정보 조회
- 조회된 회원 정보를 MemberVO 속성에 설정한 후 다시 ArrayList에 저장
- ArrayList를 다시 메서드를 호출한 MemberServlet으로 반환한 후 ArrayList의 MemberVO를 차례로 가져와 회원 정보를 HTML 태그의 문자열로 만든다.
- 만들어진 HTML 태그를 웹 브라우저로 전송해서 회원정보 출력
(1) 회원 정보를 저장하는 테이블 생성
CREATE TABLE t_member(
id varchar2(10) PRIMARY KEY,
pwd varchar2(10),
name varchar2(50),
email varchar2(50),
joinDate DATE DEFAULT sysdate
);
INSERT INTO T_MEMBER values(
'hong', '1212', '홍길동', 'hong@gmail.com', sysdate
);
INSERT INTO T_MEMBER values(
'lee', '1212', '이순신', 'lee@test.com', sysdate
);
INSERT INTO T_MEMBER values(
'kim', '1212', '김유신', 'kim@naver.com', sysdate
);
SELECT * FROM T_MEMBER;
(2) 회원 조회와 관련된 자바 클래스 파일 MemberDAO, MemberServlet, MemberVO 클래스 생성
MemberDAO.java
package sec04.ex01;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class MemberDAO {
private static final String driver = "oracle.jdbc.driver.OracleDriver";
private static final String url = "jdbc:oracle:thin:@localhost:1521:XE";
private static final String user = "c##scott";
private static final String pwd = "tiger";
private Connection con;
private Statement stmt;
public List<MemberVO> listMembers() {
List<MemberVO> list = new ArrayList<MemberVO>();
try {
connDB(); // 네 가지 정보로 데이터 베이스를 연결
String query = "select * from t_member";
System.out.println(query);
ResultSet rs = stmt.executeQuery(query); // ResultSet : SQL 결과
while (rs.next()) {
//조회한 레코드의 각 컬럼 값을 받아옴
String id = rs.getString("id");
String pwd = rs.getString("pwd");
String name = rs.getString("name");
String email = rs.getString("email");
Date joinDate = rs.getDate("joinDate");
// 각 컬럼 값을 다시 MemberVO 객체의 속성에 설정
MemberVO vo = new MemberVO();
vo.setId(id);
vo.setPwd(pwd);
vo.setName(name);
vo.setEmail(email);
vo.setJoinDate(joinDate);
list.add(vo);
}
rs.close();
stmt.close();
con.close();
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
private void connDB() {
try {
Class.forName(driver);
System.out.println("Oracle 드라이버 로딩 성공");
con = DriverManager.getConnection(url, user, pwd);
stmt = con.createStatement();
System.out.println("Connection 생성 성공");
} catch (Exception e) {
e.printStackTrace();
}
}
}
MemberServlet.java
package sec04.ex01;
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 java.io.IOException;
import java.io.PrintWriter;
import java.sql.Date;
import java.util.List;
@WebServlet("/member")
public class MemberServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
response.setContentType("text/html; charset=utf-8");
PrintWriter out = response.getWriter();
MemberDAO dao = new MemberDAO(); //sql문으로 조회할 memberdao 객체 생성
List<MemberVO> list = dao.listMembers(); //listMembers() 메서드로 회원 정보 제공
out.print("<html><body>");
out.print("<table border=1><tr align='center' bgcolor='lightgreen'>");
out.print("<td>아이디</td><td>비밀번호</td><td>이름</td><td>이메일</td><td>가입일</td></tr>");
for (int i=0; i<list.size();i++){
//조회한 회원정보를 for문과 <tr>태그를 이용해 리스트 출력
MemberVO memberVO=(MemberVO) list.get(i);
String id=memberVO.getId();
String pwd = memberVO.getPwd();
String name=memberVO.getName();
String email=memberVO.getEmail();
Date joinDate = memberVO.getJoinDate();
out.print("<tr><td>"+id+"</td><td>"+
pwd+"</td><td>"+
name+"</td><td>"+
email+"</td><td>"+
joinDate+"</td></tr>");
}
out.print("</table></body></html>");
}
}
MemberVO.java
package sec04.ex01;
import java.sql.Date;
public class MemberVO {
private String id;
private String pwd;
private String name;
private String email;
private Date joinDate;
public MemberVO() {
System.out.println("MemberVO 생성자 호출");
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Date getJoinDate() {
return joinDate;
}
public void setJoinDate(Date joinDate) {
this.joinDate = joinDate;
}
}
(3) PreparedStatement 인터페이스
회원 정보를 조회하기 위해 MemberDAO에서 Statement 인터페이스를 이용하여 DB와 연동하는 방법은 연동할 때마다 DBMS에서 다시 SQL문을 컴파일해야 하므로 속도가 느림
→ PreparedStatement 인터페이스를 사용하면 SQL문을 미리 컴파일해서 사용하므로 Statement 인터페이스보다 빠르게 데이터 베이스 작업 수행 가능
- DB와 연동할 때, 빠른 반복 처리가 필요할때 사용
- PreparedStatement 인터페이스는 Statement 인터페이스를 상속하므로 지금까지 사용한 메서드 그대로 사용
- Statement 인터페이스가 DBMS에 전달하는 SQL문은 단순한 문자열이므로 DBMS은 이 문자열을 DMBS가 이해할 수 있도록 컴파일하고 실행 하지만 PreparedStatement 인터페이스는 컴파일된 SQL문을 DBMS에 전달하여 성능향상
- PreparedStatement 인터페이스에서 실행하려는 SQL문에 '?'를 넣을 수 있음 → ?의 값만 바꿔 손쉽게 설정 가능, Statement 보다 SQL문 작성하기 간단
MemberDAO.java
package sec04.ex02;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class MemberDAO {
private static final String driver = "oracle.jdbc.driver.OracleDriver";
private static final String url = "jdbc:oracle:thin:@localhost:1521:XE";
private static final String user = "^^";
private static final String pwd = "^^";
private Connection con;
// private Statement stmt;
private PreparedStatement pstmt;
public List<MemberVO> listMembers() {
List<MemberVO> list = new ArrayList<MemberVO>();
try {
connDB(); // 네 가지 정보로 데이터 베이스를 연결
String query = "select * from t_member";
System.out.println("preparedStatement"+query);
pstmt = con.prepareStatement(query);
ResultSet rs = pstmt.executeQuery();
// ResultSet rs = stmt.executeQuery(query); // ResultSet : SQL 결과
while (rs.next()) {
//조회한 레코드의 각 컬럼 값을 받아옴
String id = rs.getString("id");
String pwd = rs.getString("pwd");
String name = rs.getString("name");
String email = rs.getString("email");
Date joinDate = rs.getDate("joinDate");
// 각 컬럼 값을 다시 MemberVO 객체의 속성에 설정
MemberVO vo = new MemberVO();
vo.setId(id);
vo.setPwd(pwd);
vo.setName(name);
vo.setEmail(email);
vo.setJoinDate(joinDate);
list.add(vo);
}
rs.close();
//stmt.close();
pstmt.close();
con.close();
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
private void connDB() {
try {
Class.forName(driver);
System.out.println("Oracle 드라이버 로딩 성공");
con = DriverManager.getConnection(url, user, pwd);
// stmt = con.createStatement();
System.out.println("Connection 생성 성공");
} catch (Exception e) {
e.printStackTrace();
}
}
}
MemberServlet.java
package sec04.ex02;
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 java.io.IOException;
import java.io.PrintWriter;
import java.sql.Date;
import java.util.List;
@WebServlet("/member")
public class MemberServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
response.setContentType("text/html; charset=utf-8");
PrintWriter out = response.getWriter();
MemberDAO dao = new MemberDAO(); //sql문으로 조회할 memberdao 객체 생성
List<MemberVO> list = dao.listMembers(); //listMembers() 메서드로 회원 정보 제공
out.print("<html><body>");
out.print("<table border=1><tr align='center' bgcolor='lightgreen'>");
out.print("<td>아이디</td><td>비밀번호</td><td>이름</td><td>이메일</td><td>가입일</td></tr>");
for (int i=0; i<list.size();i++){
//조회한 회원정보를 for문과 <tr>태그를 이용해 리스트 출력
MemberVO memberVO=(MemberVO) list.get(i);
String id=memberVO.getId();
String pwd = memberVO.getPwd();
String name=memberVO.getName();
String email=memberVO.getEmail();
Date joinDate = memberVO.getJoinDate();
out.print("<tr><td>"+id+"</td><td>"+
pwd+"</td><td>"+
name+"</td><td>"+
email+"</td><td>"+
joinDate+"</td></tr>");
}
out.print("</table></body></html>");
}
}
MemberVO.java
package sec04.ex02;
import java.sql.Date;
public class MemberVO {
private String id;
private String pwd;
private String name;
private String email;
private Date joinDate;
public MemberVO() {
System.out.println("MemberVO 생성자 호출");
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Date getJoinDate() {
return joinDate;
}
public void setJoinDate(Date joinDate) {
this.joinDate = joinDate;
}
}
(4) DataSource 이용해 DB 연동
위에서 다루었던 Statement 인터페이스, PreparedStatement 인터페이스로 DB 연동 과정은 웹 애플리케이션이 필요할 때마다 DB에 연결하는 방식
→ 애플리케이션에서 DB에 연결하는 과정에서 시간이 많이 걸림
→ ConnectionPool 등장
ConnectionPool이란?
- 미리 DB와 연결시킨 상태를 유지하는 기술
- 애플리케이션 실행 시 미리 ConnectionPool 객체를 생성한 후 DB와 연결
- 애플리케이션은 DB연동 작업 발생시 이 ConnectionPool 객체를 이용하여 작업
- ConnectionPool 동작 과정
: 톰캣 컨테이너는 자체적으로 ConnectionPool 기능 제공, 톰캣 실행시 톰캣은 설정 파일에 설정된 DB 정보를 이용해 미리 DB와 연결하여 ConnectionPool 객체를 생성한 후 애플리케이션이 DB와 연동할 일이 생기면 ConnectionPool 객체의 메서드를 호출해 빠르게 연동하여 작업
1. 톰캣 컨테이너를 실행한 후 응용 프로그램을 실행
2. 톰캣 컨테이너를 실행시 ConnectionPool 객체 생성
3. 생성된 커넥션 객체는 DBMS와 연결
4. 데이터베이스와 연동 작업이 필요할 경우 응용프로그램은 ConnectionPool에서 제공하는 메서드를 호출하여 연동
속성 | 설명 |
name | DataSource에 대한 JNDI 이름 |
auth | 인증 주체 |
driverClassName | 연결할 데이터베이스 종류에 따른 드라이버 클래스 이름 |
factory | 연결할 데이터에비읏 종류에 따른 ConnectionPool 생성 클래스 이름 |
maxActive | 동시에 최대로 DB에 연결할 수 있는 Connection 수 |
maxIdle | 동시에 idle 상태로 대기할 수 있는 최대 수 |
maxIdle | 새로운 연결이 생길 때까지 기다릴 수 있는 최대 시간 |
maxWait | 새로운 연결이 생길 때까지 기다릴 수 있는 최대 시간 |
user | 데이터베이스 접속 ID |
password | 데이터베이스 접속 비밀번호 |
type | 데이터베이스 종류별 DataSource |
url | 접속할 데이터베이스 주소와 포트 번호 및 SID |
JNDI란?
- JNDI(Java Naming and Directory Interface)란 필요한 자원을 key/value 쌍으로 저장한 후 필요할 떄 키를 이용해 값을 얻는 방법
- 미리 접근할 자원에 키를 지정한 후 애플리케이션이 실행 중일때 이 키를 이용해 자원에 접근해서 작업을 하는 것
- 웹 애플리케이션에서 ConnectionPool 객체를 구현할 떄는 Java SE에서 제공하는 javax.sql.DataSource 클래스를 이용 → 웹 애플리케이션 실행시 톰캣이 만들어 놓은 ConnectionPool 객체에 접근할 때 JNDI 이용
- 톰캣 컨테이너가 ConnectionPool 객체를 생성하면 이 객체에 대한 JNDI 이름(Key)를 미리 설정 → 웹 애플리케이션에서 DB와 연동 작업을 할 때 JNDI 이름(Key)으로 접근
ex)
- 웹 브라우저에서 name/value 쌍으로 전송한 후 Servlet에서 getParameter(name)로 값을 가져올 때
- HashMap이나 HashTable에 key/value으로 저장한 후 key를 이용해 값을 가져올 때
- 웹 브라우저에서 도메인 네임으로 DNS 서버에 요청할 경우 도메인 네임에 대한 IP 주소를 가져올 때
context.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/">
<Resource
name="jdbc/oracle"
auth="Container"
type="javax.sql.DataSource"
driverClassName="oracle.jdbc.driver.OracleDriver"
url="jdbc:oracle:thin:@localhost:1521:XE"
username="^^"
password="^^"
maxActive="50"
maxWait="-1" />
</Context>
수정된 MemberDAO.java
생성자에서 톰캣 실행 시 톰캣에서 미리 생성한 DataSource를 name 값인 jdbc/oracle을 이용해 미리 받아옴
서블릿에서 listMembers() 메서드를 호출하면 getConnection()메서드를 호출하여 DataSource에 접근한 후 데이터베이스와 연동 작업을 수행
package sec02.ex01;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class MemberDAO {
// private static final String driver = "oracle.jdbc.driver.OracleDriver";
// private static final String url = "jdbc:oracle:thin:@localhost:1521:XE";
// private static final String user = "c##scott";
// private static final String pwd = "tiger";
private Connection con;
// private Statement stmt;
private PreparedStatement pstmt;
private DataSource dataFactory;
public MemberDAO(){
try{
Context ctx = new InitialContext();
Context envContext = (Context) ctx.lookup("java:/comp/env");
dataFactory = (DataSource) envContext.lookup("jdbc/oracle");
}catch (Exception e){
e.printStackTrace();
}
}
public List<MemberVO> listMembers() {
List<MemberVO> list = new ArrayList<MemberVO>();
try {
// connDB(); // 네 가지 정보로 데이터 베이스를 연결
con = dataFactory.getConnection();
String query = "select * from t_member";
System.out.println("preparedStatement"+query);
pstmt = con.prepareStatement(query);
ResultSet rs = pstmt.executeQuery();
// ResultSet rs = stmt.executeQuery(query); // ResultSet : SQL 결과
while (rs.next()) {
//조회한 레코드의 각 컬럼 값을 받아옴
String id = rs.getString("id");
String pwd = rs.getString("pwd");
String name = rs.getString("name");
String email = rs.getString("email");
Date joinDate = rs.getDate("joinDate");
// 각 컬럼 값을 다시 MemberVO 객체의 속성에 설정
MemberVO vo = new MemberVO();
vo.setId(id);
vo.setPwd(pwd);
vo.setName(name);
vo.setEmail(email);
vo.setJoinDate(joinDate);
list.add(vo);
}
rs.close();
//stmt.close();
pstmt.close();
con.close();
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
// private void connDB() {
// try {
// Class.forName(driver);
// System.out.println("Oracle 드라이버 로딩 성공");
// con = DriverManager.getConnection(url, user, pwd);
// // stmt = con.createStatement();
// System.out.println("Connection 생성 성공");
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
}
(참고: 자바 웹을 다루는 기술)
'Back-end > JSP' 카테고리의 다른 글
Servlet 기초 (0) | 2023.01.21 |
---|---|
Servlet 이란? (0) | 2023.01.20 |
웹 애플리케이션 (0) | 2023.01.19 |
프로그램의 발전 과정, 웹 프로그래밍과 JSP (0) | 2023.01.19 |