Back-end/JSP

Servlet 비즈니스 로직 처리

메델 2023. 1. 24. 14:57

7장 Servlet 비즈니스 로직 처리 

 

(1) Servlet 비즈니스 로직 처리 방법

 

서블릿 비즈니스 처리 작업 

 

: Servlet이 Client로부터 요청을 받으면 그 요청에 대해 작업을 수행하는 것을 말한다. 웹 프로그램에서 대부분의 비즈니스 처리 작업은 DB 연동 작업이지만 다른 서버와 연동하여 데이터를 얻은 작업도 수행할 수 있다.

 

ex)

웹 사이트 회원 등록 요청 처리 작업

웹 사이트 로그인 요청 처리 작업

쇼핑몰 상품 주문 처리 작업

 

Servlet의 비즈니스  처리 과정

  • 클라이언트로부터 요청을 받음
  • 데이터베이스 연동과 같은 비즈니스 로직 처리
  • 처리 결과를 클라이언트에게 돌려줌 

 

(2) Servlet의 데이터베이스 연동

 

: Client로부터 요청을 받으면 Servlet은 SQL문을 사용해 데이터베이스 접근하여 작업 .

DAO/VO 클래스 사용

서블릿의 데이터베이스 연동 과정

 

Servlet으로 회원 정보 테이블의 회원 정보 조회

 

  1. 웹 브라우저가 Servlet에 회원 정보 요청
  2. MemberServlet은 요청은 받은 후 MemerDAO 객체 생성하여 listMembers() 메서드 호출
  3. listMembers()에서 다시  connDB() 메서드를 호출하여 DB와 연결한 후 SQL문을 실행해 회원 정보 조회
  4. 조회된 회원 정보를 MemberVO 속성에 설정한 후 다시 ArrayList에 저장
  5. ArrayList를 다시 메서드를 호출한 MemberServlet으로 반환한 후 ArrayList의 MemberVO를 차례로 가져와 회원 정보를 HTML 태그의 문자열로 만든다.
  6. 만들어진 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에서 제공하는 메서드를 호출하여 연동

응용 프로그램에서 ConnectionPool 객체를 이용해 DB연동

 

속성 설명
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