본문 바로가기
JAVA_JSP

초보의 JSP 개발 다듬기

by old Developer 2020. 11. 16.

olDevStudy.zip
0.95MB

등록, 수정, 삭제, 조회의 기본적인 C.R.U.D를 구현은 완료되었다.

개별적으로 구현하다 보니 뭔가 나사 빠진 느낌이 드니깐 다듬어보자.


1. 목표

 

index.jsp에 목록을 구현하고 목록에서 데이터를 선택하면 상세 조회되도록 구성하자.

 

- index.jsp는 회원 목록 화면으로 수정한다.

- 목록에는 등록버튼으로 등록 화면으로 이동할 수 있도록 하자.

- 목록에서 데이터를 클릭하면 상세화면으로 이동하여 수정, 삭제할 수 있도록 하자.

- 등록 시 Insert SQL을 수정하여 등록자, 수정자 정보를 0이 아닌 등록자 정보를 넣게 하자.

- 상세화면은 수정, 삭제할 수 있도록 하자.

 

2. index.jsp 바꾸기

 

접근함과 동시에 목록을 뿌릴 수 있도록 하자.

 

소스코드 :

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.sql.Connection" %>
<%@ page import="java.sql.DriverManager" %>
<%@ page import="java.sql.SQLException" %>
<%@ page import="java.sql.Statement" %>
<%@ page import="java.sql.ResultSet" %>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>olDevStudy Hello World!</title>
</head>
<body>

<%
String paramMberId = request.getParameter("mberId");

if ("".equals(paramMberId) || paramMberId == null) {
	paramMberId = "";
}
%>

<form id="mberListFrm" name="mberListFrm" method="post">
	
	<div align="right" style="width: 90%">
		<input type="text" id="mberId" name="mberId" placeholder="아이디 입력" value="<%=paramMberId%>">
		<input type="button" onclick="fnPageChange('/index.jsp');" value="조회">
		<input type="button" onclick="fnPageChange('/userRegistView.jsp');" value="등록">
	</div>
	
	<br/>
	
	<table style="border:1px solid blue; width: 90%;">
		<tr>
			<td style="border-bottom:1px solid blue;">회원 일련번호</td>
			<td style="border-bottom:1px solid blue;">회원 아이디</td>
			<td style="border-bottom:1px solid blue;">회원 비밀번호</td>
			<td style="border-bottom:1px solid blue;">회원 이름</td>
			<td style="border-bottom:1px solid blue;">회원 휴대폰</td>
			<td style="border-bottom:1px solid blue;">비고</td>
			<td style="border-bottom:1px solid blue;">등록자</td>
			<td style="border-bottom:1px solid blue;">등록일시</td>
			<td style="border-bottom:1px solid blue;">수정자</td>
			<td style="border-bottom:1px solid blue;">수정일시</td>
		</tr>
<%

Connection dbConn = null;

try {
	
	Class.forName("org.mariadb.jdbc.Driver");
	
	dbConn = DriverManager.getConnection(
			"jdbc:mariadb://127.0.0.1:3306/oldev"
			, "olDev"
			, "olDev@1234"
			);
	
	Statement stmt = dbConn.createStatement();
	
	String sqlStr = "";
	
	sqlStr += "SELECT MBER_SN          								";
	sqlStr += "     , MBER_ID          								";
	sqlStr += "     , MBER_PWD         								";
	sqlStr += "     , MBER_NM          								";
	sqlStr += "     , IFNULL(MBER_MOBLPHON, '') AS MBER_MOBLPHON	";
	sqlStr += "     , IFNULL(RM, '') AS RM							";
	sqlStr += "     , REGIST_SN        								";
	sqlStr += "     , REGT_DTTM        								";
	sqlStr += "     , UPDT_SN          								";
	sqlStr += "     , UPDT_DTTM        								";
	sqlStr += "  FROM OD_MBER          								";
	
	if (!"".equals(paramMberId) && paramMberId != null) {
		sqlStr += "  WHERE MBER_ID = '"+paramMberId+"'				";
	}
	
	ResultSet resultSet = stmt.executeQuery(sqlStr);
	
	while(resultSet.next()) {
		String mberSn	= resultSet.getString("MBER_SN");
		String mberId	= resultSet.getString("MBER_ID");
		String mberPwd	= resultSet.getString("MBER_PWD");
		String mberNm	= resultSet.getString("MBER_NM");
		
		String moblPhon	= resultSet.getString("MBER_MOBLPHON");
		String rm		= resultSet.getString("RM");
		String regiSn	= resultSet.getString("REGIST_SN");
		String regiDt	= resultSet.getString("REGT_DTTM");
		String updtSn	= resultSet.getString("UPDT_SN");
		String updtDt	= resultSet.getString("UPDT_DTTM");
		
%>
		<tr style="background: lightgray;">	
			<td><%=mberSn%></td>
			<td><%=mberId%></td>
			<td><%=mberPwd%></td>
			<td><a href="#" onclick="fnUpdaetPage('<%=mberSn%>')"><%=mberNm%></a></td>
			<td><%=moblPhon%></td>
			<td><%=rm%></td>
			<td><%=regiSn%></td>
			<td><%=regiDt%></td>
			<td><%=updtSn%></td>
			<td><%=updtDt%></td>
		</tr>
<%
	}		
} catch (SQLException e) {
	e.printStackTrace();
}
%>
	</table>
</form>
</body>
<script type="text/javascript">

function fnPageChange(pageUrl) {

	var frm = document.getElementById("mberListFrm");
	frm.action = pageUrl;
	frm.submit();
}

function fnUpdaetPage(mberSn) {
	
	// 히든 input을 동적으로 생성해보자.
	var mberSnInput = document.createElement("input");
	
	mberSnInput.setAttribute("type", "hidden");
	mberSnInput.setAttribute("name", "mberSn");
	mberSnInput.setAttribute("value", mberSn);

	var frm = document.getElementById("mberListFrm");
	
	// 찾은 폼에 붙여주자.
	frm.appendChild(mberSnInput);	
	frm.action = "/userUpdateView.jsp";
	frm.submit();
	
}
</script>
</html>

 

index.jsp 화면이 뭔가 좀 많아졌다. 일단 요 녀석을 복사 붙여 넣기 하고 실행해보자. (목록인데 데이터가 없으면 초라해서 2건의 데이터를 추가하였다.)

 

소스코드를 실행하면 index.jsp가 이렇게 바뀌었다.

 

소스를 실행한 김에 test든 test2든 아이디를 입력하고 조회해보자.

 

아이디를 넣고 조회하면 해당 아이디만 조회된다.

 

이제 아이디를 지우고 다시 조회해보자.

 

아이디를 지우고 조회하면 처음 접속한 화면처럼 조회된다.

 

실행은 한번 해봤으니 소스코드를 살펴보면

 

String paramMberId = request.getParameter("mberId"); 내용은 음? 이게 왜? 첫 화면인데 받아져? 당연히 처음 접속은 값이 비었다.

그래서 if if ("". equals(paramMberId) || paramMberId == null) {...} 처리를 해준 것이고 그 값을 <input type="text" id="mberId"... value="<%=paramMberId%>"> 태그에 세팅해주는데 이는 아이디를 입력받고 해당 아이디의 정보만 조회하려는 처리다.

 

<form> 태그의 method 속성은 post로 변경하였다. get방식은 localhost:8080/index.jsp? mberId=test와 같이 값이 노출되므로 사용자의 아이디를 감추도록 post로 변경. <form> 내용이 많이 늘어나 보이지만 사실 뭐 기존에 만들어둔 거 재활용하고 DB 테이블 칼럼을 추가로 적어준 게 전부다.

 

<table> 태그의 첫 <tr>은 제목으로 사용할 테니 SQL 수행 전에 작성했고 실제 데이터 부분은 기존대로 SQL 수행 후 ResultSet 반복문 안에 위치해있다.

 

SQL은 늘 사용하던 Select SQL에 request.getParameter가 있으면 조건으로 설정하고 없으면 제외될 수 있도록 분기 처리되었고 추가된 칼럼을 작성, 조회된 내용을 뿌리게 되는데 사용자 이름 칼럼을 <a> 태그로 감싸서 요고 클릭된다! 하는 느낌을 주었고 userUpdateView.jsp로 이동할 수 있도록 함수와 인자로 mberSn을 추가해줬다.

 

등록 버튼의 이벤트는 기존과 동일한 fnPageChange 함수를 사용했는데 update는 fnUpdatePage 함수를 추가하고 인자로 mberSn을 받도록 처리되었다. 이 함수에는 동적으로 input 태그를 추가하도록 작성되었는데 굳이 이렇게 하지 않고 각 tr 영역에 hidden이 들어가도록 처리해도 된다. 이렇게도 쓰는구나 정도로 이해하면 되겠다.

 

이것저것 덕지덕지 붙였겠다 등록부터 조금 손을 봐보자.

 

3. 등록 바꾸기(userRegist.jsp)

 

일전에 등록 시 REGITS_SN과 UPDT_SN값을 0으로 처리했는데 0으로 처리했던 이유가 insert 하는 당장에 auto_increment의 새 값을 사용해야는데 이걸 어찌 받아옴? oracle 같은 경우야 sequence.NEXT_VAL()을 먼저 조회해서 insert 할 때 넣어주면 되는데 auto.. 님은 insert가 수행되어야 되더라는... 게 문제... 하... 즉 미리 새로 생길 고윳값을 당겨 올 수가 없더라.. 그래서 MariaDB에서 LAST_INSRET_ID 함수 제공해주는데 이 함수가 누가 했는지는 모르겠지만 마지막으로 insert가 수행된 auto_increment 된 값을 전달해주는데 이걸 받아서 사용하려 하면 현재 auto_increment 값의 -1 값이 나온다 즉 현재 값은 LAST_INSERT_ID의 +1 인 것이다. 그럼 이거 +1 해서 쓰면 안 되나? 싶겠지만 동접자가 여럿이면 어쩔? A, B라는 사용자가 동시 접속했다고 치자 LAST... ID를 갖고 왔는데 둘 다 같지 않겠는가? A도 B도 직전 값이 9라면 둘 다 9를 조회하게 되는데 +1 하면? 둘 다 10이잖은가? 그럼 중복 나는데? 그래서 LAST_INSERT_ID로 처리하면 중복될 우려가 있다.  (대충 이렇게 중복 날 수가 있다더라 정도만 이해하자 Transaction은.. 차차..)

 

뭐 어쨌든 사설이 길었는데 등록 화면은 굳이 고칠 게 없어 보인다. 테이블이 변경된 것도 아니고.. 그래서 SQL이 작성되어 있는 userRegist.jsp를 수정하다.

 

소스코드 :

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.sql.Connection" %>
<%@ page import="java.sql.DriverManager" %>
<%@ page import="java.sql.SQLException" %>
<%@ page import="java.sql.Statement" %>
<%@ page import="java.sql.ResultSet" %>

<%

Connection dbConn = null;

try {
	
	String mberId		= request.getParameter("mberId");
	String mberPwd		= request.getParameter("mberPwd");
	String mberNm		= request.getParameter("mberNm");
	String mberMoblphon	= request.getParameter("mberMoblphon");
	String rm			= request.getParameter("rm");
	
	Class.forName("org.mariadb.jdbc.Driver");
	
	dbConn = DriverManager.getConnection(
			"jdbc:mariadb://127.0.0.1:3306/oldev"
			, "olDev"
			, "olDev@1234"
			);
	
	Statement stmt = dbConn.createStatement();
	
	String sqlStr = "";
	
	sqlStr += "INSERT INTO OD_MBER                  ";
	sqlStr += "(                                    ";
	sqlStr += "  MBER_ID                            ";
	sqlStr += ", MBER_PWD                           ";
	sqlStr += ", MBER_NM                            ";
	sqlStr += ", MBER_MOBLPHON                      ";
	sqlStr += ", RM                                 ";
	sqlStr += ", REGIST_SN                          ";
	sqlStr += ", REGT_DTTM                          ";
	sqlStr += ", UPDT_SN                            ";
	sqlStr += ", UPDT_DTTM                          ";
	sqlStr += ")                                    ";
	sqlStr += "VALUES                               ";
	sqlStr += "(                                    ";
	sqlStr += "  '"+mberId+"'                       ";
	sqlStr += ", '"+mberPwd+"'                      ";
	sqlStr += ", '"+mberNm+"'                       ";
	sqlStr += ", NULLIF('"+mberMoblphon+"', '')     ";
	sqlStr += ", NULLIF('"+rm+"', '')           	";
	sqlStr += ", '0'                                ";
	sqlStr += ", DATE_FORMAT(NOW(), '%Y%m%d%H%i%s') ";
	sqlStr += ", '0'                                ";
	sqlStr += ", DATE_FORMAT(NOW(), '%Y%m%d%H%i%s') ";
	sqlStr += ")                                    ";

	
	int resultNum = stmt.executeUpdate(sqlStr, 1);
	ResultSet resultSet = stmt.getGeneratedKeys();
	
	String genKey = null;
	
	if (resultNum > 0) {
		while(resultSet.next()) {
			genKey = resultSet.getString(1);
		}
	}
	
	if (!"".equals(genKey) && genKey != null) {
		
		String sqlStr2 = "";
		
		sqlStr2 += "UPDATE OD_MBER             			";
		sqlStr2 += "   SET REGIST_SN  = '"+genKey+"'	";
		sqlStr2 += "     , UPDT_SN    = '"+genKey+"'	";
		sqlStr2 += " WHERE MBER_SN    = '"+genKey+"'	";
		
		resultNum += stmt.executeUpdate(sqlStr2);
		
	}
	
	if (resultNum < 1) {
%>
	<script type="text/javascript">
		alert("등록에 실패했어요!");
		location.href="/";
	</script>
<%
	} else {
%>
	<script type="text/javascript">
		alert("등록이 완료되었습니다.");
		location.href="/";
	</script>
<%
	}
	
} catch (SQLException e) {
	e.printStackTrace();
}
%>

소스코드를 복사해서 붙여 넣고 실행해보자.

 

test4 번을 등록해보자.

 

test4를 입력하고 저장을 클릭하자. 완료되었다는 메시지를 확인하면 index.jsp로 화면으로 이동된다.

 

이전 데이터와 다르게 회원 일련번호가 등록자, 수정자 칼럼에 입력된다.

회원 일련번호가 16이나 되는데 작업하면서 만들고 지우고.. 만들고 지우고 하다 보니깐... 초기화하고 싶으면 GG님께 Auto_increment 초기화라고... 문의하자.

 

목록과 마찬가지로 실행은 시켜봤으니 소스코드를 살펴보자

 

이전에 만들어둔 Insert SQL을 그대로 사용하면서 statement 객체의 오버 로드된 executeUpdate method의 인자로 executeUpdate(sqlStr, 1) 숫자 1을 추가해주었다.

오버 로드된 method 원문을 보면 execute(sql, autoGeneratedKeys)인데 자동 생성되는 key가 몇 번째 인자인지 column position을 넣을 수 있게 되어있다. index가 아니라 position이다. 즉 MBER_SN의 칼럼 위치는 첫 번째이므로 1번이다. (index처럼 0번 아니다.)

column position을 추가하고 결과를 받을 때 getGeneratedKeys() 메서드를 이용해서 받게 되는데 이 메서드는 ResultSet을 결과로 Return 하게 되고 Auton_incremet 된 column인 MBER_SN의 position값으로 getString(1) 할 수 있다.

결국 앞서 이야기한 MariaDB의 LAST_INSERT_ID 함수를 쓰는 것과 같은 원리인데 insert는 이미 수행했으므로 Auto_increment의 증가된 값을 반환받을 수 있다. (요고 XXBatis Framework에서 많이 본 useGeneratedKeys 똑같은데?)

 

결국 Insert 시점에는 바로 넣어줄 수 없기 때문에 받아온 Key값을 다시 한번 Update 해주었다.

 

뭐 문제가 있을지도 모르지만 어쨌든 Insert 됐으니깐 이제 Update를 손대 보자.

 

4. 수정 바꾸기(userUpdateView.jsp)

 

index.jsp 변경할 때 회원 이름에 <a> 태그로 뭔가 클릭해도 될 것처럼 표현하였는데 고놈을 mberSn값으로 처리되도록 적용해두었으니 mberId로 조회했던 수정 화면을 PK 칼럼인 mberSn으로 변경만 하고 테스트해보자.

 

목록에서 회원 이름을 클릭하고 상세화면으로 들어가 보자.

 

홍길동을 클릭해보자.

 

홍길동을 클릭해보자 조회가 잘된다. 

상세정보를 접근하고 다시 목록으로도 가야 하지 않겠는가? 그래서 목록으로 버튼도 추가해두었다.

 

비밀번호를 333으로 수정해보자.

 

딱히 손댄것이 없으니.. 잘된다 ㅎ

 

손댄 것이 없으니 수정이 안 되는 게 오히려 이상할 것 같다.

아무거나 클릭하고 목록으로 클릭하면 잘 오겠지... 뭐 쨌든 소스코드를 보자

 

소스코드 : 

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.sql.Connection" %>
<%@ page import="java.sql.DriverManager" %>
<%@ page import="java.sql.SQLException" %>

<%@ page import="java.sql.Statement" %>
<%@ page import="java.sql.ResultSet" %>

<body>
<%

Connection dbConn = null;

String mberSn	= "";
String mberId	= "";
String mberPwd	= "";
String mberNm	= "";
String rm		= "";

try {
	
		String paramMberSn = request.getParameter("mberSn");
		
		Class.forName("org.mariadb.jdbc.Driver");
		
		dbConn = DriverManager.getConnection(
				"jdbc:mariadb://127.0.0.1:3306/oldev"
				, "olDev"
				, "olDev@1234"
				);
		
		Statement stmt = dbConn.createStatement();
		
		String sqlStr = "";
		
		sqlStr += "SELECT MBER_SN          		";
		sqlStr += "     , MBER_ID          		";
		sqlStr += "     , MBER_PWD         		";
		sqlStr += "     , MBER_NM          		";
		sqlStr += "     , MBER_MOBLPHON			";
		sqlStr += "     , IFNULL(RM, '') AS RM	";
		sqlStr += "     , REGIST_SN        		";
		sqlStr += "     , REGT_DTTM        		";
		sqlStr += "     , UPDT_SN          		";
		sqlStr += "     , UPDT_DTTM        		";
		sqlStr += "  FROM OD_MBER          		";
		sqlStr += " WHERE MBER_SN = '"+paramMberSn+"'";
		
		ResultSet resultSet = stmt.executeQuery(sqlStr);
		
		while(resultSet.next()) {
			mberSn	= resultSet.getString("MBER_SN");
			mberId	= resultSet.getString("MBER_ID");
			mberPwd	= resultSet.getString("MBER_PWD");
			mberNm	= resultSet.getString("MBER_NM");
			rm		= resultSet.getString("rm");
		}
		
	} catch (SQLException e) {
		e.printStackTrace();
	}
%>
<form id="updateOrDeleteFrm">
	<table style="border:1px solid blue;">
		<tr>
			<td style="border:1px solid blue;">회원 일련번호</td>
			<td style="border:1px solid blue;">회원 아이디</td>
			<td style="border:1px solid blue;">회원 비밀번호</td>
			<td style="border:1px solid blue;">회원 이름</td>
			<td style="border:1px solid blue;">비고</td>
		</tr>
		<tr>
			<td style="border:1px solid blue;"><input type="hidden" id="mberSn" name="mberSn" value="<%=mberSn%>"><%=mberSn%></td>
			<td style="border:1px solid blue;"><%=mberId%></td>
			<td style="border:1px solid red;"><input type="text" id="mberPwd" name="mberPwd" value="<%=mberPwd%>"></td>
			<td style="border:1px solid red;"><input type="text" id="mberNm" name="mberNm" value="<%=mberNm%>"></td>
			<td style="border:1px solid red;"><input type="text" id="rm" name="rm" value="<%=rm%>"></td>
		</tr>
		<tr>
			<td colspan="5">
				<div align="right">
					<input type="button" onclick="fnUserUpdate('/userUpdate.jsp');" value="수정">
					<input type="button" onclick="fnUserDelete('/userDelete.jsp');" value="삭제">
					<input type="button" onclick="fnUserUpdate('/');" value="목록으로">
				</div>
			</td>
		</tr>
	</table>
</form>

<script type="text/javascript">
	
function fnUserUpdate(pageUrl) {
	var frm = document.getElementById("updateOrDeleteFrm");
	frm.action = pageUrl;
	frm.submit();
}

function fnUserDelete(pageUrl) {
	var frm = document.getElementById("updateOrDeleteFrm");
	frm.action = pageUrl;
	frm.submit();
}

</script>
</body>

 

수정은 userUpdateView.jsp에서 상세를 조회하고 userUpdate.jsp는 SQL만 수행하므로 화면을 고쳐야 했다.

손댄 거라곤 mberSn으로 조회하고 목록으로 버튼을 추가한 게 전부다... 

 

삭제는 상세화면에서 기능으로 만들어졌고 손댄 게 전혀 없다. 잘 지워지겠지...

 

그래도 기왕 다듬기 하는 거 test 3의 상세에서 삭제를 해보자.

 

test3 데이터가 삭제됐다.

 

삭제도 잘된다.  이렇게 목표는 완료! ㅎㅎ


JAVA WEB 개발 시작부터 지금까지 생략된 내용이 너무나 많다. Scope 개념은 언급도 안 했고 DBConnection은 close 하지도 않았으며 Transaction은 단어 하나 잠깐 넣었다. 그래서 누군가 본다면 엥? 이걸 그냥 넘어가네? 하는 말을 할 수도 있겠지만 간단하게 JSP로 개발 맛이나 한번 보자고 만들어 본 것일 뿐 그 이상도 이하도 아니다.

 

JSP로 개발 맛보는 건 이 정도 하고 앞으로는 Servlet으로 바꿔가며 하나씩 제대로 짚어봐야겠다.

 

* 현재까지의 프로젝트를 통으로 올려두었다.

댓글