갈림길 이정표

[JSP] beans + dbcp[connection pooling] 본문

Programming Language/Servlet & JSP

[JSP] beans + dbcp[connection pooling]

이몽뇽 2020. 9. 2. 22:25

[beansDB2.jsp]

<%@page import="pack3.SangpumDTO"%>
<%@page import="java.util.ArrayList"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<jsp:useBean id="cdp" class="pack3.ConnDbPooling" scope="page"/>	<%--scope? --%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>beans + dbcp</title>
<script type="text/javascript">
function funcUp(){
	//alert("a");
	var code = prompt("수정할 코드 입력","");	//prompt: alert창에 값을 입력 할 수 있음
	//alert(code);
	if(code !== "" && code !== null){
		location.href="beansDB2_up.jsp?code=" + code;	//자바의 response.sendRedirect랑 비슷
	}
}

function funcDel(){
	//alert("b");
	var code = prompt("삭제할 코드 입력","");	//Java의 구식 방법으로 Javascript의 Dialog, 각 포털사이트 API제공 방식으로 세련되게 할 수 있음
	if(code !== "" && code !== null){
		if(confirm("정말 삭제할까요?") === true){
			location.href="beansDB2_del.jsp?code=" + code;
		}
	}
}
</script>
</head>
<body>
<h2>* 상품자료(beans + dbcp[connection pooling]사용) *</h2>
<!-- 아직 ModelⅠ 방식 -->
<a href="beansDB2_ins.html">상품 추가용</a>&nbsp;&nbsp;
<a href="javascript:funcUp()">상품 수정용</a>&nbsp;&nbsp;
<a href="javascript:funcDel()">상품 삭제용</a><br>
<table border='1'>
	<tr><td>코드</td><td>품명</td><td>수량</td><td>단가</td></tr>
	<%
	ArrayList<SangpumDTO> list = cdp.getDataAll();
	for(SangpumDTO s:list){
	%>
	<tr>
		<td><%=s.getCode() %></td>
		<td><%=s.getSang() %></td>
		<td><%=s.getSu() %></td>
		<td><%=s.getDan() %></td>
	</tr>
	<%
	}
	%>
</table>
</body>
</html>

▼ 기본 key별 데이터 getter, setter 그리고 DTO from DB

더보기
[SangpumBean.java]

package pack3;

public class SangpumBean {	//DB 입력 용도
	private String code, sang, su, dan;

	public String getCode() {
		return code;
	}

	public void setCode(String code) {
		this.code = code;
	}

	public String getSang() {
		return sang;
	}

	public void setSang(String sang) {
		this.sang = sang;
	}

	public String getSu() {
		return su;
	}

	public void setSu(String su) {
		this.su = su;
	}

	public String getDan() {
		return dan;
	}

	public void setDan(String dan) {
		this.dan = dan;
	}
}
[SangpumDTO.java]

package pack3;

public class SangpumDTO {	//용도:
	private String code, sang;
	private int su, dan;
	
	public String getCode() {
		return code;
	}
	public void setCode(String code) {
		this.code = code;
	}
	public String getSang() {
		return sang;
	}
	public void setSang(String sang) {
		this.sang = sang;
	}
	public int getSu() {
		return su;
	}
	public void setSu(int su) {
		this.su = su;
	}
	public int getDan() {
		return dan;
	}
	public void setDan(int dan) {
		this.dan = dan;
	}
}

▼ dbcp[connection pooling]

더보기

dbcp 기술을 이용하기 위해선 반드시 [content.xml] 파일이 미리 준비되어 있어야 한다.

WebContent > META-INF > [context.xml]

<?xml version="1.0" encoding="UTF-8"?>
<Context>
	<Resource name="jdbc_maria" auth="Container" type="javax.sql.DataSource"
		driverClassName="org.mariadb.jdbc.Driver" loginTimeout="10" maxWait="5000"
		username="root" password="369369" testOnBorrow="true"
		maxActive="500" maxIdle="100"
		url="jdbc:mysql://localhost:3306/test" />
</Context>

 준비가 다 되었다면 드라이버 로딩을 위해 이전 ConnDb class파일처럼 똑같이 java파일을 만들면 되는데 한 가지 차이점만 주의 하면 된다.

순서대로 일반 Connection DB파일과 DB Connection Pooling파일의 차이를 살펴보자.

public ConnDbBean() {
	try {
		Class.forName("org.mariadb.jdbc.Driver");
	} catch (Exception e) {
    	System.out.println("ConnDbBean err: " + e);
	}
}
private DataSource ds;
	
public ConnDbPooling() {
	try {
		Context context = new InitialContext();
		ds = (DataSource)context.lookup("java:comp/env/jdbc_maria");
	} catch (Exception e) {
		System.out.println("ConnDbPoolinf err: " + e);
	}
}

이렇게 DataSource class의 객체 멤버(ds)를 선언 했다면 아까 준비해 두었던 Context 클래스의 새로운 객체(context)를 선언할 수 있고, context는 내장 함수로써 lookup을 사용하여 mariaDB를 사용 할 수 있게 된다.

단, context.lookup은 Object 타입이기 때문에 [Casting]이 필요하다.

 

(※ A factory for connections to the physical data source that this DataSource object represents. An alternative to the DriverManager facility, a DataSource object is the preferred means of getting a connection. An object that implements the DataSource interface will typically be registered with a naming service based on the Java™ Naming and Directory (JNDI) API)


 

[ConnDbPooling.java]

package pack3;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;

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


public class ConnDbPooling {	//Business logic 담당
	private Connection conn;
	private PreparedStatement pstmt;
	private ResultSet rs;
	private DataSource ds;	//META-INF > context.xml을 만들어서 가능한 것
	
	public ConnDbPooling() {
		try {
			Context context = new InitialContext();	//JNDI
			ds = (DataSource)context.lookup("java:comp/env/jdbc_maria");
			//context.xml <Resource> tag의 name과 일치해야 함 (context.lookup은 Object타입이기 때문에 [Casting] 필요)
		} catch (Exception e) {
			System.out.println("ConnDbPoolinf err: " + e);
		}
	}
	
	public ArrayList<SangpumDTO> getDataAll(){
		ArrayList<SangpumDTO> list = new ArrayList<SangpumDTO>();
		try {
			// DB연결
			String sql = "SELECT * FROM sangdata";
			conn = ds.getConnection();	//dbcp(Connection 객체가 여러개 있을 때 사용)
			//conn = DriverManager.getConnection("jdbc:mysql://localhost/test", "root", "369369"); 이렇게 안해도 됨
			//보안 강화, 짧은 코딩
			pstmt = conn.prepareStatement(sql);
			rs = pstmt.executeQuery();
			
			while(rs.next()) {
				SangpumDTO dto = new SangpumDTO(); 
				dto.setCode(rs.getString("code"));
				dto.setSang(rs.getString("sang"));
				dto.setSu(rs.getInt("su"));
				dto.setDan(rs.getInt("dan"));
				list.add(dto);
			}
			//System.out.println("list : " + list.size());	//연결 되면 찍힐 것
		} catch (Exception e) {
			System.out.println("getDataAll err: " + e);
		} finally {
			try {
				if (rs != null)
					rs.close();
				if (pstmt != null)
					pstmt.close();
				if (conn != null)
					conn.close();
			} catch (Exception e2) {
		
			}
		}
		return list;
	}
	
	public boolean insertData(SangpumBean bean) {
		boolean b = false;
		String sql = "";
		try {
			//새상품 코드 구하기 (마지막 최대 코드 구하기 +1)
			sql="SELECT MAX(code) as max FROM sangdata";
			conn = ds.getConnection();
			pstmt = conn.prepareStatement(sql);
			rs = pstmt.executeQuery();
			int maxCode = 0;	//데이터가 아예 없을 경우를 대비
			if(rs.next()) {
				maxCode = rs.getInt("max");	//max라는 별명의 column값을 읽어옴
			}
			maxCode += 1;		//데이터가 아예 없어도 1부터 시작
			
			//상품 입력
			pstmt.close();	//여러번 사용해야 될 경우 한번 닫고 사용하는 걸 권고
			sql =  "INSERT INTO sangdata VALUES(?,?,?,?)";
			pstmt = conn.prepareStatement(sql);
			pstmt.setInt(1,	maxCode);
			pstmt.setString(2, bean.getSang());	//client에서 입력한 자료 호출 (argument가 SangpumBean class의 객체이기 때문)
			pstmt.setString(3, bean.getSu());
			pstmt.setString(4, bean.getDan());
			int re = pstmt.executeUpdate();		//re의 의미? 바뀐 데이터 자료수
			/*
			System.out.println(bean.getSang());
			System.out.println(bean.getSu());
			System.out.println(bean.getDan());*/
			
			
			if(re == 1) b = true;
		} catch (Exception e) {
			System.out.println("insertData err: " + e);
		} finally {
			try {
				if (rs != null)
					rs.close();
				if (pstmt != null)
					pstmt.close();
				if (conn != null)
					conn.close();
			} catch (Exception e2) {
		
			}
		}
		
		return b;
	}
	
	public SangpumDTO updateDataRead(String code) {
		SangpumDTO dto = null;
		String sql = "";
		try {
			sql = "SELECT * FROM sangdata WHERE code=?";
			conn =ds.getConnection();
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, code);
			rs = pstmt.executeQuery();
			
			if(rs.next()) {	//자료가 하나라는 것을 알때!
				dto = new SangpumDTO();
				dto.setCode(rs.getString(1));
				dto.setSang(rs.getString(2));
				dto.setSu(rs.getInt(3));	//SangpumDTO su, dan은 int 타입임
				dto.setDan(rs.getInt(4));
			}
			
		} catch (Exception e) {
			System.out.println("updataDataRead err: " + e);
		}finally {
			try {
				if (rs != null)
					rs.close();
				if (pstmt != null)
					pstmt.close();
				if (conn != null)
					conn.close();
			} catch (Exception e2) {
		
			}
		}
		return dto;	//dto=null이면 수정 못하게
	}
	
	public boolean updateData(SangpumBean bean) {
		boolean b = false;
		try {
			conn = ds.getConnection();
			String sql = "UPDATE sangdata SET sang=?, su=?, dan=? WHERE code=?";
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, bean.getSang());
			pstmt.setString(2, bean.getSu());
			pstmt.setString(3, bean.getDan());
			pstmt.setString(4, bean.getCode());
			if(pstmt.executeUpdate() > 0) b = true;	//0보다 크면 뭔가가 바뀌었다는 말 | 값을 받아오는 게 아니라서 rs 안해도 됨
		} catch (Exception e) {
			System.out.println("updataData err: " + e);
		}finally {
			try {
				if (pstmt != null)
					pstmt.close();
				if (conn != null)
					conn.close();
			} catch (Exception e2) {
		
			}
		}
		
		return b;
	}
	
	public boolean deleteData(String code) {
		boolean b = false;
		
		try {
			conn = ds.getConnection();
			String sql = "DELETE FROM sangdata WHERE code=?";
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, code);
			if(pstmt.executeUpdate() > 0) b = true;	//0보다 크면 뭔가가 바뀌었다는 말 | 값을 받아오는 게 아니라서 rs 안해도 됨
		} catch (Exception e) {
			System.out.println("deleteData err: " + e);
		}finally {
			try {
				if (pstmt != null)
					pstmt.close();
				if (conn != null)
					conn.close();
			} catch (Exception e2) {
		
			}
		}
		return b;
	}
	
	//
}

[beansDB2_ins.html]

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>beanDB2_ins(상품추가용)</title> <!-- 추가를 내부적으로 하는 용도 -->
<script src="http://code.jquery.com/jquery-latest.js"></script>	<!-- jQuery 사용가능 환경 만들기 (type X, src O) -->
<!-- src=주소 | type=xml,text/javascript 등.. -->
<script type="text/javascript">
$(document).ready(function(){	//$표시=jQuery에서 요소 선택 시 선언
	$("#btnIns").click(function(){
		//alert("a");
		if($("#sang").val() === ""){
			alert("상품명 입력");
			return;
		}
		//...(나머지 입력자료 유효검사 생략 ex.focus, 정규표현식,...)
		$("#frm").submit();
	});
	$("#btnList").bind("click",listFunc);
});	
function listFunc(){
	//alert("b");
	location.href="beansDB2.jsp"	//= history.back();
}
</script>
</head>
<body>
*상품 추가*<br>
<form action="beansDB2_ins.jsp" method="post" id="frm">
품명: <input type="text" name="sang" id="sang"><br>		<!-- name을 DTO 변수와 일치시켜야  jsp액션 태그 자동화 사용가능 -->
수량: <input type="text" name="su" id="su"><br>
단가: <input type="text" name="dan" id="dan"><br>
<br>
<input type="button" value="자료 추가" id="btnIns">
<input type="reset" value="입력 취소">
<input type="button" value="목록 보기" id="btnList">
</form>
</body>
</html>
[beansDB2_ins.jsp]

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%--business logic 임. client가 볼수 없음 --%>
<%
request.setCharacterEncoding("utf-8");
%>
<jsp:useBean id="bean" class="pack3.SangpumBean"/>
<jsp:setProperty property="*" name="bean"/> <%--알아서 들어감--%>
<%--두줄에 의해서 DB 입력 됨--%>


<jsp:useBean id="cdp" class="pack3.ConnDbPooling"/>
<%
boolean b = cdp.insertData(bean);
if(b)
	response.sendRedirect("beansDB2.jsp");
else
	response.sendRedirect("beansDB2_fail.html");
	

%>

[beansDB2_up.jsp]

<%@page import="pack3.SangpumDTO"%>
<%@ 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>

<%
request.setCharacterEncoding("utf-8");
String code = request.getParameter("code");
%>

<jsp:useBean id="cdp" class="pack3.ConnDbPooling"/>

<%
SangpumDTO dto = cdp.updateDataRead(code);
if(dto == null){
%>
	<script>
	alert("등록된 상품 코드가 아닙니다.\n수정불가");
	location.href="beansDB2.jsp";
	</script>
<%
	return;
}
%>
<%--여기 부터 자바 <body> tag --%>
** 상품 수정 **<br>
<form action="beansDB2_upok.jsp" method="post">
코드: <%=dto.getCode() %><input type="hidden" name="code" value="<%=dto.getCode() %>"><br>
상품명: <input type="text" name="sang" value="<%=dto.getSang() %>"><br>	<%-- 이름 맞춰줘야 jsp액션 태그 자동화 사용 가능 --%>
상품명: <input type="text" name="su" value="<%=dto.getSu() %>"><br>
상품명: <input type="text" name="dan" value="<%=dto.getDan() %>"><br>
<br>
<input type="submit" value="자료 수정">
<input type="button" value="목록 보기" onclick="javascript:location.href='beansDB2.jsp'">
</form>

</body>
</html>
[beansDB2_upok.jsp]

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

<%
request.setCharacterEncoding("utf-8");	//한글 넘어온다
%>
<jsp:useBean id="bean" class="pack3.SangpumBean"/>
<jsp:setProperty property="*" name="bean"/>	<%--다 넘어와라--%>
<jsp:useBean id="cdp" class="pack3.ConnDbPooling"/>
<%
if(cdp.updateData(bean)){	//boolean type은 그냥 if 조건으로 쓸 수 있음 
	response.sendRedirect("beansDB2.jsp");	//수정 후 목록 보기
}else{
	response.sendRedirect("beansDB2_fail.html");
}
%>

[beansDB2_del.jsp]

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
request.setCharacterEncoding("utf-8");
String code = request.getParameter("code");
%>
<jsp:useBean id="cdp" class="pack3.ConnDbPooling"/>

<%
if(cdp.deleteData(code)){	//boolean type은 그냥 if 조건으로 쓸 수 있음 
	response.sendRedirect("beansDB2.jsp");	//삭제 후 목록 보기
}else{
	response.sendRedirect("beansDB2_fail.html");
}
%>

[beansDB2_fail.html]

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<b style="font-size: 30px; color: red;">작업실패!!!</b>
<br>
<a href="beansDB2.jsp">목록 으로 돌아가기</a>
</body>
</html>
Comments