Servlet JSP MVC Spring

[Servlet]커넥션풀을 이용한 회원 정보 CRUD(생성,조회,수정,삭제)

vhxpffltm 2020. 2. 23. 01:49

이전에 작업한 방법의 문제는 필요할 때마다 연동해서 작업하는 경우 연결에 시간이 많이 걸린다는 문제가 있다.

 

이를 위해 웹 어플리케이션이 실행됨과 함께 연동할 데이터베이스와의 연결을 미리 설정하여 필요에 따라 연결해 놓은 상태를 이용해 빠르게 DB와 연동하여 작업하는 방법이 있다. 이 방법을 '커넥션풀' 이라한다.

 

아래 그림을 보며 커넥션풀의 동작 과정을 보며 이해해보자.

 

 

구현을 위해서는 Java SE에서 제공하는 javax.sql.DataSource 클래스가 필요하다. 그리고 웹 어플리케이션 실행 시 Tomcat이 만들어 놓은 커넥션풀 객체제 접근할 때 JNDI를 사용할 것이다.

JNDI란 필요한 자원을 key/value 쌍으로 저장 후, 필요할 떄 키를 이용해 값을 얻는 방법이다.

Tomcat 컨테이너가 커넥션풀 객체를 생성하면 이 객체에 대한 JNDI key를 미리 설정하고 웹과 DB과 연동 작업을 할 때 이 JNDI key로 접근하여 작업한다.

 

DataSource 설정

 

아래 그림과 같이 설정한다.

Tomcat-jdbc...jar은 톰캣 폴더의 lib/ 의 경로에 존재한다. Program Files\Tomcat9.0\lib

그리고 톰캣의 context.xml을 아래와 같이 추가한다.

<Resource> 태그를 통해 톰캣 실행 시 연결할 데이터베이스를 설정할 수 있다.

usename과 password는 DB 설정할때의 이름과 비밀번호이다.

 

 

위의 사진에서 driverclassname, url, username, password 4가지가 데이터 베이스를 연결하는데 필요한 기본 설정값이며 이 속성을 이용해 DataSource에 접근한다.

 

회원 정보 조회하기 및 추가하기

 

조회는 이전시간에 했으니 이전에 사용한 코드를 사용하면 된다. 그 중, 조회에는 MemberDao.java 클래스를 수정하여 커넥션풀을 이용해 DB와 연동한다.

 

새로운 패키지를 생성하여 이전에 사용한 3개의 클래스를 복사하고 servlet 클래스의 매핑이름을 자유롭게 변경한다. 그리고 수정된 코드는 아래와 같다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package sec02.ex02;
 
 
 
public class MemberDAO {
    
    private Connection con;
    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");
            //JNDI에 접급하기 위한 기본 경로 지정, 톰캣 context.xml에 설정한 name값인 jdbc/oracle을 이용해
            //톰캣이 미리 연결한 DataSource를 받아온다.
        } 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("prepareStatememt: " + query);
            pstmt = con.prepareStatement(query);
            ResultSet rs = pstmt.executeQuery();
            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 vo = new MemberVO();
                vo.setId(id);
                vo.setPwd(pwd);
                vo.setName(name);
                vo.setEmail(email);
                vo.setJoinDate(joinDate); //각 컬럼 값을 다시 MemberVO객체의 속성에 설정
                list.add(vo); //설정된 MemberVO객체를 다시 ArrayList에 저장
            }
            rs.close();
            pstmt.close();
            con.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return list; //조회한 레코드의 개수만큼 MemberVo 객체를 저장한 ArrayList를 반환
    }
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

 

이제 변경한 이름으로 새로 접속하면 이전시간과 동일한 조회결과를 얻을 수 있다. 커넥션풀을 이용해 DB와 연동하여 조회하였다.

 

 

이번에는 회원을 등록하는 과정이다.

회원가입 Form이 필요하기에 새로운 html파일을 작성한다. html파일은 webcontent에 생성한다.

 

Form.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원 가입창</title>
<script type="text/javascript">
function fn_sendMember(){
   var frmMember=document.frmMember;
   var id=frmMember.id.value;
   var pwd=frmMember.pwd.value;
   var name=frmMember.name.value;
   var email=frmMember.email.value;
   if(id.length==0 ||id==""){
      alert("아이디는 필수입니다.");
   }else if(pwd.length==0 ||pwd==""){
      alert("비밀번호는 필수입니다.");
   }
   else if(name.length==0 ||name==""){
      alert("이름은 필수입니다.");
   }else if(email.length==0 ||email==""){
      alert("이메일은 필수입니다.");
   }else{
      frmMember.method="post";
      frmMember.action="Member3";
      //전송 방법은 post이고 매핑이름은 Member3, 그리고 서블릿으로 전송한다.
   } 
}
</script>
</head>
<body>
  <form name="frmMember">
  <table>
       <th>회원 가입</th>
      <tr>
        <td>ID</td>
        <td><input type="text" name="id"></td>
      </tr>
      <tr>
        <td>Password</td>
        <td><input type="password" name="pwd"></td>
      </tr>
      <tr>
        <td>이름</td>
        <td><input type="text" name="name"></td>
      </tr>
        <tr>
        <td>이메일</td>
        <td><input type="text" name="email"></td>
      </tr>
      <!-- 위의 input태그는 서블릿으로 데이터를 전송한다. -->
  </table>
   <input type="button" value="가입하기" onclick="fn_sendMember()">
   <input type="reset" value="다시입력">
   <input  type="hidden" name="command" value="addMember" />    
   <!-- hidden 태그를 사용하여 서블릿에게 회원 등록임을 알림 -->
  </form>
 </body>
</html>
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

 

html파일을 작성하여 회원 가입 양식을 만들고 이것은 servlet에 전송하는 역할을 한다. 

이제 전송받은 servlet 클래스를 수정해야한다. 먼저 html이 'command' 를 전송했기에 이 값이 addMember이면 전송된 회원 정보를 받아온다. 회원 정보를 MemberVO 객체에 설정한 후 MemberDAO의 메서드로 전달해 SQL문을 이용하여 데이터를 DB에 추가한다.

 

MemberServlet.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
package sec02.ex02;
 
 
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
 
/**
 * Servlet implementation class MemberServlet
 */
@WebServlet("/Member3")
public class MemberServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doHandle(request, response);
    }
 
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doHandle(request, response);
    }
 
    private void doHandle(HttpServletRequest request,HttpServletResponse response)  throws ServletException, IOException {
      request.setCharacterEncoding("utf-8");
      response.setContentType("text/html;charset=utf-8");
      MemberDAO dao=new MemberDAO();
      PrintWriter out=response.getWriter();
      String command=request.getParameter("command");
      //command값을 받음
      if(command!= null && command.equals("addMember")){
          //회원 가입창에서 전송된 command가 addMember이면 전송값을 받음 -> Form.html을 확인
         String _id=request.getParameter("id");
         String _pwd=request.getParameter("pwd");
         String _name=request.getParameter("name");
         String _email=request.getParameter("email");
         MemberVO vo=new MemberVO();
         vo.setId(_id);
         vo.setPwd(_pwd);
         vo.setName(_name);
         vo.setEmail(_email);
         dao.addMember(vo);
         //회원 가입창에서 전송된 값들을 얻어 MemberVO객체제 저장한 후 SQL문을 이용해 전달
      }else if(command!= null && command.equals("delMember")) {
          String id = request.getParameter("id");
          dao.delMember(id);
      }
     List list=dao.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><td >삭제</td></tr>");
    
     for (int i=0; i<list.size();i++){
         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><td>"
                             +"<a href='/JSP_DB/member3?command=delMember&id="+id+"'>삭제 </a></td></tr>");
 
      }
      out.print("</table></body></html>");
     out.print("<a href='/JSP_DB/Form.html'>새 회원 등록하기</a");
     //클릭하면 다시 회원 가입창으로 이동
   }
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

 

그리고 MemberDAO 클래스에 아래 내용을 추가한다. 이전의 코드에서 아래 내용만 추가한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public void addMember(MemberVO memberVO) {
        try {
            con = dataFactory.getConnection(); //DataSource를 이용해 데이터 베이스와 연결
            String id = memberVO.getId();
            String pwd = memberVO.getPwd();
            String name = memberVO.getName();
            String email = memberVO.getEmail();
            //테이블에 저장할 회원 정보를 받음
            
            String query = "insert into t_member";
            query += " (id,pwd,name,email)";
            query += " values(?,?,?,?)";
            //insert문을 문자열로 만듬
            
            System.out.println("prepareStatememt: " + query);
            pstmt = con.prepareStatement(query);
            
            pstmt.setString(1, id);
            pstmt.setString(2, pwd);
            pstmt.setString(3, name);
            pstmt.setString(4, email);
            //insert문의 각 ?에 순서대로 회원정보를 세팅
            pstmt.executeUpdate(); //회원 정보를 테이블에 추가
            pstmt.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        /*PrepareStatement에서 insert문은 회원 정보를 사용하기 위해 ?를 사용 이것은
         * id, pwd, name, age 순으로 대응하며 대응값을 저장하기 위해 setter()메서드 사용
         * insert,delete,update문은 executeUpdate() 메서드를 호출함 */
    }
public void delMember(String id) {
 
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

 

결과는 아래와 같다. Form.html을 통해 회원 정보를 입력하고 가입하기를 클릭하면 회원 정보가 추가됨을 볼 수 있다.

 

 

 

회원 정보 삭제하기

 

회원 정보를 추가했으면 이제 그 정보를 삭제해보자

우리는 이제 MemberServlet 클래스와 DAO클래스를 수정해야 함을 알 수있다. 그 클래스들을 수정할 것이다. 그런데 이미 위의 sevlet클래스 코드 에는 삭제하는 코드도 지금 같이 포함되어 있다. (50, 66번 라인)

 

else if(command!= null && command.equals("delMember")) {

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

          dao.delMember(id);

      }

....

out.print("<tr><td>"+id+"</td><td>"

                             +pwd+"</td><td>"

                             +name+"</td><td>"

                             +email+"</td><td>"

                             +joinDate+"</td><td>"

                             +"<a href='/pro07/member3?command=delMember&id="+id+"'>삭제 </a></td></tr>");

 

위 코드들이 포함되어 있기 때문에 위 결과에 '삭제' 문구를 확인할 수 있을 것이다. 그래서 servlet코드에는 수정할 내용이 없다. 위 코드를 설명하면 command값이 delmember인 경우 ID를 가져와 SQL문으로 전달하여 삭제를 진행한다.

 

이제 DAO클래스를 수정해보자. 위의 DAO클래스 코드를 보면 delMember()가 비워져있다. 여기를 수정해서 DB의 내용을 삭제해보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void delMember(String id) {
        try {
            Connection con = dataFactory.getConnection();
            String query = "delete from t_member" + "where id = ?";
            //delete문을 문자열로 만듬
            System.out.println("prepareStatement: "+query);
            pstmt = con.prepareStatement(query);
            pstmt.setString(1, id);//첫번째 '?'에 전달된 ID를 인자로 넣음
            pstmt.execute(); // delete문을 실행하여 해당 ID의 정보 삭제
            pstmt.close();
        }catch(Exception e) {
            e.printStackTrace();
        }
    }
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

 

 

이제 /Member3의 DB테이블에 '삭제'버튼을 누르면 해당 ID가 삭제되는것을 볼 수 있다.

 

 

URL이 <a>태그의 내용으로 바뀌면서 내용이 삭제되고 남은 DB테이블을 확인할 수 있다.

 

Refernce

자바 웹을 다루는 기술<길벗>