[JSP16_DAODTO : 자바빈을 활용한 DAO, DTO 개발 기술을 사용하여 게시판 만들기] MVC Model1
1. 기존에 만든 게시글의 문제점
1) 프로그래밍(비지니스 로직) 부분과 웹 구조(프론트엔트) 부분이 섞여 있다.
2) DB커넥션’을 만드는 과정들이 매 페이지 요청 마다 계속 동일하게 반복된다.
3) 규모가 커지면 분업 제작하기도 힘들고 유지관리도 어렵다.
[이러한 문제점을 해결하기 위해] 프로그래밍과 웹 구조를 분리
자바빈을 활용한 DAO, DTO 개발 기술 사용하기!
2. DB, SQL 관련 상수 정의 클래스
: DB접속 정보, 쿼리문, 테이블명, 컬럼명 등은 별도로 관리하는 것이 좋다
** common > D 클래스
package common;
/*
* DB 접속 정보, 쿼리문, 테이블명, 컬럼명 등은
* 별도로 관리하든지
* XML, 초기화 파라미터 등에서 관리하는 것이 좋다.
*/
public class D {
// Connection 에 필요한 값 세팅
public static final String DRIVER = "oracle.jdbc.driver.OracleDriver";
public static final String URL = "jdbc:oracle:thin:@localhost:1521:XE";
public static final String USERID = "scott0316";
public static final String USERPW = "tiger0316";
// 쿼리문
public static final String SQL_WRITE_SELECT
= "SELECT * FROM test_write ORDER BY wr_uid DESC";
public static final String SQL_WRITE_INSERT = "INSERT INTO test_write "
+ "(wr_uid, wr_subject, wr_content, wr_name) "
+ "VALUES(test_write_seq.nextval, ?, ?, ?)";
public static final String SQL_WRITE_INC_VIEWCNT
= "UPDATE test_write SET wr_viewcnt = wr_viewcnt + 1 WHERE wr_uid = ?";
public static final String SQL_WRITE_SELECT_BY_UID
= "SELECT * FROM test_write WHERE wr_uid = ?";
public static final String SQL_WRITE_UPDATE
= "UPDATE test_write SET wr_subject = ?, wr_content = ? WHERE wr_uid = ?";
public static final String SQL_WRITE_DELETE_BY_UID
= "DELETE FROM test_write WHERE wr_uid = ?";
}
3. 클래스 필드명 = DB 필드명 = form의 name명
4. DTO(Data Transfer Object) : 기본생성자, 매개변수 생성자, getter/setter, toString() 오버라이딩
: 데이터가 포함된 객체를 다른 시스템으로 전달하는 역할을 하는 객체,
DB에 있는 레코드를 객체화한 클래스 혹은 VO(Volume Object)라고 말한다.
(그러나 VO는 read only immutable 속성을 가짐) ,
기본생성자, 매개변수 생성자, getter/setter 작성, toString() 오버라이딩 : 있으면 디버깅시 편리.
** com.lec.beans > WriteDTO 클래스
package com.lec.beans;
// DTO(Date Transfer Object)
// 데이터를 담아 나르기 위한 객체
// 게시글 DTO, 회원 DTO, ... 필요한 데이터 객체들 만큼 정의
// Bean 객체
public class WriteDTO {
private int uid; //wr_uid
private String subject; // wr_subject
private String content; // wr_content
private String name; // wr_name
private int viewCnt; // wr_viewcnt
private String regDate; // wr_regdate
// 다음시..
// 다음 3가지 네이밍은 일치시켜주는 것이 좋다.
// 클래스 필드명 = DB 필드명 = form의 name명
// 기본생성자, 매개변수생성자, getter/setter
public WriteDTO() {
super();
System.out.println("WriteDTO() 객체 생성");
}
public WriteDTO(int uid, String subject, String content, String name, int viewCnt) {
super();
this.uid = uid;
this.subject = subject;
this.content = content;
this.name = name;
this.viewCnt = viewCnt;
System.out.println("WriteDTO(uid, subject, content, name, viewCnt) 객체 생성");
}
// getter / setter
public int getUid() {
System.out.println("getUid 호출");
return uid;
}
public void setUid(int uid) {
System.out.println("setUID("+ uid +") 호출");
this.uid = uid;
}
public String getSubject() {
System.out.println("getSubject() 호출");
return subject;
}
public void setSubject(String subject) {
System.out.println("setSubject("+ subject +") 호출");
this.subject = subject;
}
public String getContent() {
System.out.println("getContent() 호출");
return content;
}
public void setContent(String content) {
System.out.println("setContent("+ content +") 호출");
this.content = content;
}
public String getName() {
System.out.println("getName() 호출");
return name;
}
public void setName(String name) {
System.out.println("setName("+ name +") 호출");
this.name = name;
}
public int getViewCnt() {
System.out.println("getViewCnt() 호출");
return viewCnt;
}
public void setViewCnt(int viewCnt) {
System.out.println("setViewCnt("+ viewCnt +") 호출");
this.viewCnt = viewCnt;
}
public String getRegDate() {
System.out.println("getResDate() 호출");
return regDate;
}
public void setRegDate(String regDate) {
System.out.println("setRegDate("+ regDate +") 호출");
this.regDate = regDate;
}
// 테스트, 개발용으로 toString() 오버라이딩 하면 좋다
@Override
public String toString() {
return "WriteDTO]" + uid + " : " + subject + " : "
+ content + " : " + name + " : "
+ viewCnt + " : " + regDate;
}
} // end DTO
5. DAO(Data Access Object)
: DB 데이터 접근을 목적으로 하는 객체
** DAO 객체
: 웹어플리케이션에서 필요한 데이터 동작과 트랜잭션들에 관한 메소드들을 정의해서 사용하면 된다,
프로그래밍 영역과 웹 영역이 구분될 수 있는 기반,
다루는 데이터의 종류에 따라 DAO는 여러 개 정의하여 사용 가능
** com.lec.beans > WriteDAO 클래스
package com.lec.beans;
import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Time;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import common.D;
// 비지니스 로직 : 데이터 동작, 트랜잭션들
// DAO : Data Access Object
// DB에 접속하여 트랜잭션을 수행하는 객체
// 다루는 데이터 소스의 종류에 따라 DAO는 여러 개 정의 사용 가능
public class WriteDAO {
// JDBC 관련 기본 객체변수
Connection conn = null;
Statement stmt = null;
PreparedStatement pstmt = null;
ResultSet rs = null; // SELECT 결과, executeQuery()
// DAO 객체가 생성될때 Connection도 생성된다
public WriteDAO() {
try {
Class.forName(D.DRIVER);
conn = DriverManager.getConnection(D.URL, D.USERID, D.USERPW);
System.out.println("WriteDAO 생성, 데이터 베이스 연결!");
} catch(Exception e) {
e.printStackTrace(); // 콘솔창에서 에러 메시지 확인 가능
}
} // end 기본 생성자
// DB 자원 반납 메소드
public void close() throws SQLException {
if(rs != null) {rs.close();}
if(pstmt != null) {pstmt.close();}
if(stmt != null) {stmt.close();}
if(conn != null) {conn.close();}
} // end close()
// 새 글 작성 <-- DTO
public int insert(WriteDTO dto) throws SQLException {
String subject = dto.getSubject();
String content = dto.getContent();
String name = dto.getName();
int cnt = this.insert(subject, content, name);
return cnt;
}
// 새 글 작성 <-- 제목, 내용, 작성자
public int insert(String subject, String content, String name) throws SQLException {
int cnt = 0;
try {
pstmt = conn.prepareStatement(D.SQL_WRITE_INSERT);
pstmt.setString(1, subject);
pstmt.setString(2, content);
pstmt.setString(3, name);
cnt = pstmt.executeUpdate();
} finally {
close();
}
return cnt;
}
// ResultSet --> DTO 배열로 리턴
public WriteDTO [] createArray(ResultSet rs) throws SQLException {
WriteDTO [] arr = null; // DTO 배열
ArrayList<WriteDTO> list = new ArrayList<WriteDTO>();
while(rs.next()) {
int uid = rs.getInt("wr_uid");
String subject = rs.getString("wr_subject");
String name = rs.getString("wr_name");
String content = rs.getString("wr_content");
int viewCnt = rs.getInt("wr_viewcnt");
Date d = rs.getDate("wr_regdate");
Time t = rs.getTime("wr_regdate");
String regDate = "";
if(d != null){
regDate = new SimpleDateFormat("yyyy-MM-dd").format(d) + " "
+ new SimpleDateFormat("hh:mm:ss").format(t);
}
WriteDTO dto = new WriteDTO(uid, subject, content, name, viewCnt);
dto.setRegDate(regDate);
list.add(dto);
} // end while
int size = list.size();
if(size == 0) return null;
arr = new WriteDTO[size];
list.toArray(arr); // List -> 배열
return arr;
}
// 전체 SELECT
public WriteDTO [] select() throws SQLException {
WriteDTO [] arr = null;
try {
pstmt = conn.prepareStatement(D.SQL_WRITE_SELECT);
rs = pstmt.executeQuery();
arr = createArray(rs);
} finally {
close();
}
return arr;
} // end select()
// 특정 uid 의 글 내용 읽기, 조회수 증가
// viewCnt 도 1 증가 해야 하고, 글 읽어와야 한다 --> 트랜잭션 처리
public WriteDTO [] readByUid(int uid) throws SQLException{
int cnt = 0;
WriteDTO [] arr = null;
try {
// 트랜잭션 처리
// Auto-commit 비활성화
conn.setAutoCommit(false);
// 쿼리들 수행
pstmt = conn.prepareStatement(D.SQL_WRITE_INC_VIEWCNT);
pstmt.setInt(1, uid);
cnt = pstmt.executeUpdate();
pstmt.close();
pstmt = conn.prepareStatement(D.SQL_WRITE_SELECT_BY_UID);
pstmt.setInt(1, uid);
rs = pstmt.executeQuery();
arr = createArray(rs);
conn.commit();
} catch(SQLException e) {
conn.rollback();
throw e;
} finally {
close();
}
return arr;
} // end readByUid()
// 특정 uid의 글만 SELECT(조회수 증가 없음)
public WriteDTO [] selectByUid(int uid) throws SQLException {
WriteDTO [] arr = null;
try {
pstmt = conn.prepareStatement(D.SQL_WRITE_SELECT_BY_UID);
pstmt.setInt(1, uid);
rs = pstmt.executeQuery();
arr = createArray(rs);
} finally {
close();
}
return arr;
}
// 특정 uid 의 글 수정 (제목, 내용)
public int update(int uid, String subject, String content) throws SQLException {
int cnt = 0;
try {
pstmt = conn.prepareStatement(D.SQL_WRITE_UPDATE);
pstmt.setString(1, subject);
pstmt.setString(2, content);
pstmt.setInt(3, uid);
cnt = pstmt.executeUpdate();
} finally {
close();
}
return cnt;
} // end update()
// 특정 uid 글 삭제하기
public int deleteByUid(int uid) throws SQLException {
int cnt = 0;
try {
pstmt = conn.prepareStatement(D.SQL_WRITE_DELETE_BY_UID);
pstmt.setInt(1, uid);
cnt = pstmt.executeUpdate();
} finally {
close();
}
return cnt;
} // end deleteByUid()
} // end DAO
6. db_test는 이제 필요 없기 때문에 삭제 가능,
list.jsp, view.jsp, write.jsp, writeOk.jsp, update.jsp, updateOk.jsp, deleteOk.jsp를 알맞게 수정하면 됨
** write.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>글작성</title>
</head>
<script>
function chkSubmit() { // 폼 검증
frm = document.forms["frm"];
var name = frm["name"].value.trim();
var subject = frm["subject"].value.trim();
// 프론트 엔드에서 폼 유효성 체크, 검증하기
if(name == "") {
alert('작성자 란은 반드시 입력해야 합니다.');
frm["name"].focus();
return false;
}
if(subject == "") {
alert('제목은 반드시 작성해야 합니다.');
frm["subject"].focus();
return false;
}
return true;
}
</script>
<body>
<h2>글작성</h2>
<%-- 글 내용이 많을수 있기 때문에 POST 방식 사용 --%>
<form name="frm" action="writeOk.jsp" method="post" onsubmit="return chkSubmit()">
작성자:
<input type="text" name="name"/><br>
제목:
<input type="text" name="subject"/><br>
내용:<br>
<textarea name="content"></textarea>
<br><br>
<input type="submit" value="등록"/>
</form>
<br>
<button type="button" onclick="location.href='list.jsp'">목록으로</button>
</body>
</html>
** writeOk.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!-- DAO bean 객체 생성 -->
<jsp:useBean id="dao" class="com.lec.beans.WriteDAO"/>
<%--
<%
// post 방식은 한글 인코딩이 반드시 필요!(누락되지 않도록 조심하기!!)
request.setCharacterEncoding("utf-8");
// 입력한 값 받아오기
String name = request.getParameter("name");
String subject = request.getParameter("subject");
String content = request.getParameter("content");
// 백엔드에서 폼 유효성 체크, 검증하기
// name, subject 는 비어 있으면 안된다(not null)
// null 이거나 빈 문자열이면 이전 화면으로 돌아가기
if(name == null || subject == null ||
name.trim().equals("") || subject.trim().equals("")) {
%>
<script>
alert('작성자 이름, 글 제목은 필수입니다!');
history.back(); // history.go(-1)
</script>
<%
return; // ★ [매우 매우 중요!] 더이상 JSP 프로세싱 하지 않도록 종료 ★
}
%>
--%>
<%
request.setCharacterEncoding("utf-8"); // 한글 인코딩 꼭
%>
<jsp:useBean id="dto" class="com.lec.beans.WriteDTO"/>
<jsp:setProperty property="*" name="dto"/>
<%
// DAO 사용한 트랜젝션
//int cnt = dao.insert(subject, content, name);
int cnt = dao.insert(dto);
%>
<% if(cnt == 0) { %>
<script>
alert('등록 실패!!');
history.back(); // 브라우저가 직전에 직전 페이지(입력중 페이지로)
</script>
<% } else { %>
<script>
alert('등록 성공, 리스트를 출력합니다!');
location.href = "list.jsp";
</script>
<% } %>
** list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="com.lec.beans.*" %>
<jsp:useBean id="dao" class="com.lec.beans.WriteDAO"/> <%-- DAO bean 생성 --%>
<% // dao 사용한 트랜잭션
WriteDTO[] arr = dao.select();
%>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>글 목록</title>
<style>
table {width: 100%;}
table, th, td {
border: 1px solid black;
border-collapse: collapse;
}
</style>
</head>
<body>
<hr>
<h2>리스트</h2>
<table>
<tr>
<th>UID</th>
<th>제목</th>
<th>작성자</th>
<th>조회수</th>
<th>등록일</th>
</tr>
<%
if(arr != null){
for(int i = 0; i < arr.length; i++){
%>
<tr>
<td><%= arr[i].getUid() %></td>
<td><a href="view.jsp?uid=<%= arr[i].getUid()%>"><%= arr[i].getSubject() %></a></td>
<td><%= arr[i].getName() %></td>
<td><%= arr[i].getViewCnt() %></td>
<td><%= arr[i].getRegDate() %></td>
</tr>
<%
} // end for
} // end if
%>
</table>
<br>
<button onclick="location.href='write.jsp'">신규등록</button>
</body>
</html>
** view.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="com.lec.beans.*" %>
<jsp:useBean id="dao" class="com.lec.beans.WriteDAO"/>
<%
// parameter 받아 오기
int uid = Integer.parseInt(request.getParameter("uid"));
// * 이 단계에서 parameter 검증 필요하나 생략.
%>
<% // dao 사용한 트랜젝션
WriteDTO[] arr = dao.readByUid(uid);
%>
<%
if(arr == null || arr.length == 0) {
%>
<script>
alert("해당 정보가 삭제되거나 없습니다");
history.back();
</script>
<%
return; // 더이상 JSP 프로세싱 하지 않고 종료
} // end if
%>
<%
String name = arr[0].getName();
String subject = arr[0].getSubject();
String content = arr[0].getContent();
String regDate = arr[0].getRegDate();
int viewCnt = arr[0].getViewCnt();
%>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>읽기 <%= subject %></title> <!-- title에 글제목 넣기 -->
</head>
<script>
// script 는 위치 구애를 받지 않는다
function chkDelete(uid) {
// 삭제 여부, 다시 확인하고 진행하기
var r = confirm('삭제하시겠습니까?');
if(r) {
location.href = 'deleteOk.jsp?uid=' + uid;
}
}
</script>
<body>
<body>
<h2>읽기 <%= subject %></h2>
<br>
UID : <%= uid %><br>
작성자 : <%= name %><br>
제목 : <%= subject %><br>
등록일 : <%= regDate %><br>
조회수 : <%= viewCnt %><br>
내용: <br>
<hr>
<div>
<%= content %>
</div>
<hr>
<br>
<button onclick="location.href='update.jsp?uid=<%= uid%>'">수정하기</button>
<button onclick="location.href = 'list.jsp'">목록보기</button>
<button onclick="chkDelete(<%= uid %>)">삭제하기</button>
<button onclick="location.href = 'write.jsp'">신규등록</button>
</body>
</html>
** update.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="com.lec.beans.*" %>
<jsp:useBean id="dao" class="com.lec.beans.WriteDAO"/> <%-- DAO bean 생성 --%>
<% // parameter 받아오기
int uid = Integer.parseInt(request.getParameter("uid"));
// * 이 단계에서 parameter 검증이 필요하나 생략
%>
<% // dao 사용한 트랜젝션
WriteDTO[] arr = dao.selectByUid(uid);
%>
<%
if(arr == null || arr.length == 0) {
%>
<script>
alert("해당 정보가 삭제되거나 없습니다");
history.back();
</script>
<%
return; // 더이상 JSP 프로세싱 하지 않고 종료
} // end if
%>
<%
String name = arr[0].getName();
String subject = arr[0].getSubject();
String content = arr[0].getContent();
int viewCnt = arr[0].getViewCnt();
%>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>수정 <%= subject %></title>
</head>
<script>
function chkSubmit(){
frm = document.forms['frm'];
var subject = frm['subject'].value.trim();
if(subject == ""){
alert("제목은 반드시 작성해야 합니다");
frm['subject'].focus();
return false;
}
return true;
}
</script>
<body>
<h2>수정</h2>
<form name="frm" action="updateOk.jsp" method="post" onsubmit="return chkSubmit()">
<input type="hidden" name="uid" value="<%= uid %>"/>
작성자 : <%= name %><br> <%-- 작성자 이름 변경 불가 --%>
제목 :
<input type="text" name="subject" value="<%= subject %>"/><br>
내용: <br>
<textarea name="content"><%= content %></textarea>
<br>
<input type="submit" value="수정"/>
</form>
<button onclick="history.back()">이전으로</button>
<button onclick="location.href='list.jsp'">목록보기</button>
</body>
</html>
** updateOk.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<jsp:useBean id="dao" class="com.lec.beans.WriteDAO"/>
<%
// parameter 받아오기
request.setCharacterEncoding("utf-8"); // 한글 인코딩 반드시!
int uid = Integer.parseInt(request.getParameter("uid"));
String subject = request.getParameter("subject");
String content = request.getParameter("content");
// * 이 단계에서 parameter 검증 필요하나 생략.
%>
<% // DAO 사용한 트랜잭션
int cnt = dao.update(uid, subject, content);
%>
<% if(cnt == 0) { %>
<script>
alert('수정 실패');
history.back();
</script>
<% } else { %>
<script>
alert('수정 성공');
location.href = "view.jsp?uid=<%= uid %>";
</script>
<% } %>
** deleteOk.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<jsp:useBean id="dao" class="com.lec.beans.WriteDAO"/> <%-- DAO bean 생성 --%>
<%
// parameter 받아오기
int uid = Integer.parseInt(request.getParameter("uid"));
// * 이 단계에서 parameter 검증 필요하나 생략
%>
<% // DAO 사용한 트랜잭션
int cnt = dao.deleteByUid(uid);
%>
<% if(cnt == 0) { %>
<script>
alert('삭제 실패');
history.back();
</script>
<% } else { %>
<script>
alert('삭제 성공');
location.href = "list.jsp"; <%-- 삭제후에는 list 로 가자 --%>
</script>
<% } %>
[JSP17_ConnectionPool, 커넥션 풀(Connection Pool, CP)]
1. 기존에 만든 게시판은 매 페이지마다 Connection이 발생한다!
: 이런 경우 다수의 클라이언트에서 동시 요청(request)이 들어오면
과도한 Connection 생성으로 인해 서버에 큰 무리를 주며 심하면 웹 서버 다운도 발생할 수 있다.
2. 커넥션 풀(Connection Pool)
: WAS에서 Connection들을 미리 만들어서 관리,
별도의 프로세스로 데이터베이스 Connection 관리(DBCP),
일정수준 이상의 Connection 유지하기 때문에 최적의 성능 보장,
사용하지 않는 Connection 자동관리,
최대접속에 대한 제한 기능
[DBCP API] 데이터베이스와 연결된 커넥션들을 미리 만들어서 풀(pool) 속에 저장해 두고 있다가,
필요할 때에 커넥션을 가져다 쓰고 다시 풀에 반환하는 기능 수행하는 프로그래밍 인터페이스
3. 커넥션 풀을 사용하기 위한 톰캣 컨테이너 설정
: servers > Tomcat v9.0 Server at localhost-config > web
<Context docBase="JSP17_ConnectionPool"
path="/JSP17_ConnectionPool" reloadable="true"
source="org.eclipse.jst.jee.server:JSP17_ConnectionPool"
useNaming="true">
<Resource
description="DB Connection"
auth="Container"
driverClassName="oracle.jdbc.driver.OracleDriver"
name="jdbc/testDB"
type="javax.sql.DataSource"
username="scott0316"
password="tiger0316"
url="jdbc:oracle:thin:@localhost:1521:XE"
maxIdle="5"
maxTotal="50"
maxWaitMillis="5000"
/>
</Context>
4. JNDI 리소스 사용 설정
: WebContent > lib > web.xml
<resource-ref>
<description>DB Connection Pool</description>
<res-ref-name>jdbc/testDB</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
5. 기존 게시판 파일 중 WriteDAO만 수정하면 됨
package com.lec.beans;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Time;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import common.D;
// 비지니스 로직 : 데이터 동작, 트랜잭션들
// DAO : Data Access Object
// DB에 접속하여 트랜잭션을 수행하는 객체
// 다루는 데이터 소스의 종류에 따라 DAO는 여러 개 정의 사용 가능
public class WriteDAO {
// JDBC 관련 기본 객체변수
Connection conn = null;
Statement stmt = null;
PreparedStatement pstmt = null;
ResultSet rs = null; // SELECT 결과, executeQuery()
// DAO 객체가 생성될때 Connection 도 생성된다.
public WriteDAO() {} // 생성자 (더이상 Connection 생성 안한다!)
// Connection Pool 리소스
public static Connection getConnection() throws SQLException, NamingException {
Context initContext = new InitialContext();
Context envContext = (Context)initContext.lookup("java:/comp/env");
DataSource ds = (DataSource)envContext.lookup("jdbc/testDB");
return ds.getConnection();
}
// DB 자원 반납 메소드
public void close() throws SQLException {
if(rs != null) {rs.close();}
if(pstmt != null) {pstmt.close();}
if(stmt != null) {stmt.close();}
if(conn != null) {conn.close();}
} // end close()
// 새 글 작성 <-- DTO
public int insert(WriteDTO dto) throws SQLException, NamingException {
String subject = dto.getSubject();
String content = dto.getContent();
String name = dto.getName();
int cnt = this.insert(subject, content, name);
return cnt;
}
// 새 글 작성 <-- 제목, 내용, 작성자
public int insert(String subject, String content, String name) throws SQLException, NamingException {
int cnt = 0;
try {
conn = getConnection(); // Connection Pool 사용
pstmt = conn.prepareStatement(D.SQL_WRITE_INSERT);
pstmt.setString(1, subject);
pstmt.setString(2, content);
pstmt.setString(3, name);
cnt = pstmt.executeUpdate();
} finally {
close();
}
return cnt;
}
// ResultSet --> DTO 배열로 리턴
public WriteDTO [] createArray(ResultSet rs) throws SQLException {
WriteDTO [] arr = null; // DTO 배열
ArrayList<WriteDTO> list = new ArrayList<WriteDTO>();
while(rs.next()) {
int uid = rs.getInt("wr_uid");
String subject = rs.getString("wr_subject");
String name = rs.getString("wr_name");
String content = rs.getString("wr_content");
int viewCnt = rs.getInt("wr_viewcnt");
Date d = rs.getDate("wr_regdate");
Time t = rs.getTime("wr_regdate");
String regDate = "";
if(d != null){
regDate = new SimpleDateFormat("yyyy-MM-dd").format(d) + " "
+ new SimpleDateFormat("hh:mm:ss").format(t);
}
WriteDTO dto = new WriteDTO(uid, subject, content, name, viewCnt);
dto.setRegDate(regDate);
list.add(dto);
} // end while
int size = list.size();
if(size == 0) return null;
arr = new WriteDTO[size];
list.toArray(arr); // List -> 배열
return arr;
}
// 전체 SELECT
public WriteDTO [] select() throws SQLException, NamingException {
WriteDTO [] arr = null;
try {
conn = getConnection(); // Connection Pool 사용
pstmt = conn.prepareStatement(D.SQL_WRITE_SELECT);
rs = pstmt.executeQuery();
arr = createArray(rs);
} finally {
close();
}
return arr;
} // end select()
// 특정 uid 의 글 내용 읽기, 조회수 증가
// viewCnt 도 1 증가 해야 하고, 글 읽어와야 한다 --> 트랜잭션 처리
public WriteDTO [] readByUid(int uid) throws SQLException, NamingException{
int cnt = 0;
WriteDTO [] arr = null;
try {
conn = getConnection(); // Connection Pool 사용
// 트랜잭션 처리
// Auto-commit 비활성화
conn.setAutoCommit(false);
// 쿼리들 수행
pstmt = conn.prepareStatement(D.SQL_WRITE_INC_VIEWCNT);
pstmt.setInt(1, uid);
cnt = pstmt.executeUpdate();
pstmt.close();
pstmt = conn.prepareStatement(D.SQL_WRITE_SELECT_BY_UID);
pstmt.setInt(1, uid);
rs = pstmt.executeQuery();
arr = createArray(rs);
conn.commit();
} catch(SQLException e) {
conn.rollback();
throw e;
} finally {
close();
}
return arr;
} // end readByUid()
// 특정 uid의 글만 SELECT(조회수 증가 없음)
public WriteDTO [] selectByUid(int uid) throws SQLException, NamingException {
WriteDTO [] arr = null;
try {
conn = getConnection(); // Connection Pool 사용
pstmt = conn.prepareStatement(D.SQL_WRITE_SELECT_BY_UID);
pstmt.setInt(1, uid);
rs = pstmt.executeQuery();
arr = createArray(rs);
} finally {
close();
}
return arr;
}
// 특정 uid 의 글 수정 (제목, 내용)
public int update(int uid, String subject, String content) throws SQLException, NamingException {
int cnt = 0;
try {
conn = getConnection(); // Connection Pool 사용
pstmt = conn.prepareStatement(D.SQL_WRITE_UPDATE);
pstmt.setString(1, subject);
pstmt.setString(2, content);
pstmt.setInt(3, uid);
cnt = pstmt.executeUpdate();
} finally {
close();
}
return cnt;
} // end update()
// 특정 uid 글 삭제하기
public int deleteByUid(int uid) throws SQLException, NamingException {
int cnt = 0;
try {
conn = getConnection(); // Connection Pool 사용
pstmt = conn.prepareStatement(D.SQL_WRITE_DELETE_BY_UID);
pstmt.setInt(1, uid);
cnt = pstmt.executeUpdate();
} finally {
close();
}
return cnt;
} // end deleteByUid()
} // end DAO
[JSP18_MVC : MVC Model2]
1. MVC 모델 : 추후 유지부수에 유리
: Model, View, Controller를 뜻하는 용어로 개발 형태이다.
Model - 데이터베이스와의 관계를 담당,
클라이언트의 요청에서 필요한 자료를 데이터베이스로부터 추출하거나, 수정하여 Controller로 전달,
View - 사용자한테 보여지는 UI 화면,
주로 .jsp파일로 작성하며, Controller에서 어떤 View 컴폰넌트를 보여줄지 결정
Controller - 클라이언트의 요청을 받고, 적절한 Model에 지시를 내리며,
Model에서 전달된 데이터를 적절한 View에 전달한다.
2. MVC Model1은 View(출력)와 Controller(로직)가 같이 있는 형태,
MVC Model2는 Model, View, Controller가 모두 모듈화 되어 있는 형태
3. MVC Model2의 장점
1) 출력을 위한 뷰 코드와 로직 처리를 위한 자바 코드를 분리하기 때문에
JSP가 MVC Model1에 비해 코드가 복잡하지 않다.
2) 뷰, 로직처리에 대한 분업이 용이하다.
3) 기능에 따라 분리되어있기 때문에 유지보수가 용이하다.
4. MVC Model2의 단점
1) 구조가 복잡하여 습득이 어렵고 작업량이 많다.
2) JAVA에 대한 깊은 이해가 필요하다.
5. MVC Mode2 컴포넌트 설계
[로직 실행] (DTO)
클라이언트 --요청--> (FrontController) --로직실행 지시--> [여러 개의 Command -- (DTA --> DB)]
(FrontController --응답--> 여러 개의 화면 UI)
6. 대형프로젝트의 경우 DAO, DTO도 별개의 패키지로 관리하는게 좋으나 예제에서는 같은 패키지에서 만듦.
** com.lec.beans > DTO
package com.lec.beans;
// DTO(Date Transfer Object)
// 데이터를 담아 나르기 위한 객체
// 게시글 DTO, 회원 DTO, ... 필요한 데이터 객체들 만큼 정의
// Bean 객체
public class WriteDTO {
private int uid; //wr_uid
private String subject; // wr_subject
private String content; // wr_content
private String name; // wr_name
private int viewCnt; // wr_viewcnt
private String regDate; // wr_regdate
// 개발시..
// 다음 3가지 네이밍은 일치시켜주는 것이 좋다.
// 클래스 필드명 = DB 필드명 = form의 name명
// 기본생성자, 매개변수생성자, getter/setter
public WriteDTO() {
super();
System.out.println("WriteDTO() 객체 생성");
}
public WriteDTO(int uid, String subject, String content, String name, int viewCnt) {
super();
this.uid = uid;
this.subject = subject;
this.content = content;
this.name = name;
this.viewCnt = viewCnt;
System.out.println("WriteDTO(uid, subject, content, name, viewCnt) 객체 생성");
}
// getter / setter
public int getUid() {
System.out.println("getUid 호출");
return uid;
}
public void setUid(int uid) {
System.out.println("setUID("+ uid +") 호출");
this.uid = uid;
}
public String getSubject() {
System.out.println("getSubject() 호출");
return subject;
}
public void setSubject(String subject) {
System.out.println("setSubject("+ subject +") 호출");
this.subject = subject;
}
public String getContent() {
System.out.println("getContent() 호출");
return content;
}
public void setContent(String content) {
System.out.println("setContent("+ content +") 호출");
this.content = content;
}
public String getName() {
System.out.println("getName() 호출");
return name;
}
public void setName(String name) {
System.out.println("setName("+ name +") 호출");
this.name = name;
}
public int getViewCnt() {
System.out.println("getViewCnt() 호출");
return viewCnt;
}
public void setViewCnt(int viewCnt) {
System.out.println("setViewCnt("+ viewCnt +") 호출");
this.viewCnt = viewCnt;
}
public String getRegDate() {
System.out.println("getResDate() 호출");
return regDate;
}
public void setRegDate(String regDate) {
System.out.println("setRegDate("+ regDate +") 호출");
this.regDate = regDate;
}
// 테스트, 개발용으로 toString() 오버라이딩 하면 좋다
@Override
public String toString() {
return "WriteDTO]" + uid + " : " + subject + " : "
+ content + " : " + name + " : "
+ viewCnt + " : " + regDate;
}
} // end DTO
** com.lec.beans > DAO
package com.lec.beans;
import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Time;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import common.D;
// 비지니스 로직 : 데이터 동작, 트랜잭션들
// DAO : Data Access Object
// DB에 접속하여 트랜잭션을 수행하는 객체
// 다루는 데이터 소스의 종류에 따라 DAO는 여러 개 정의 사용 가능
public class WriteDAO {
// JDBC 관련 기본 객체변수
Connection conn = null;
Statement stmt = null;
PreparedStatement pstmt = null;
ResultSet rs = null; // SELECT 결과, executeQuery()
// DAO 객체가 생성될때 Connection도 생성된다
public WriteDAO() {
try {
Class.forName(D.DRIVER);
conn = DriverManager.getConnection(D.URL, D.USERID, D.USERPW);
System.out.println("WriteDAO 생성, 데이터 베이스 연결!");
} catch(Exception e) {
e.printStackTrace(); // 콘솔창에서 에러 메시지 확인 가능
}
} // end 기본 생성자
// DB 자원 반납 메소드
public void close() throws SQLException {
if(rs != null) {rs.close();}
if(pstmt != null) {pstmt.close();}
if(stmt != null) {stmt.close();}
if(conn != null) {conn.close();}
} // end close()
// 새 글 작성 <-- DTO
public int insert(WriteDTO dto) throws SQLException {
String subject = dto.getSubject();
String content = dto.getContent();
String name = dto.getName();
int cnt = this.insert(subject, content, name);
return cnt;
}
// 새 글 작성 <-- 제목, 내용, 작성자
public int insert(String subject, String content, String name) throws SQLException {
int cnt = 0;
try {
pstmt = conn.prepareStatement(D.SQL_WRITE_INSERT);
pstmt.setString(1, subject);
pstmt.setString(2, content);
pstmt.setString(3, name);
cnt = pstmt.executeUpdate();
} finally {
close();
}
return cnt;
}
// ResultSet --> DTO 배열로 리턴
public WriteDTO [] createArray(ResultSet rs) throws SQLException {
WriteDTO [] arr = null; // DTO 배열
ArrayList<WriteDTO> list = new ArrayList<WriteDTO>();
while(rs.next()) {
int uid = rs.getInt("wr_uid");
String subject = rs.getString("wr_subject");
String name = rs.getString("wr_name");
String content = rs.getString("wr_content");
int viewCnt = rs.getInt("wr_viewcnt");
Date d = rs.getDate("wr_regdate");
Time t = rs.getTime("wr_regdate");
String regDate = "";
if(d != null){
regDate = new SimpleDateFormat("yyyy-MM-dd").format(d) + " "
+ new SimpleDateFormat("hh:mm:ss").format(t);
}
WriteDTO dto = new WriteDTO(uid, subject, content, name, viewCnt);
dto.setRegDate(regDate);
list.add(dto);
} // end while
int size = list.size();
if(size == 0) return null;
arr = new WriteDTO[size];
list.toArray(arr); // List -> 배열
return arr;
}
// 전체 SELECT
public WriteDTO [] select() throws SQLException {
WriteDTO [] arr = null;
try {
pstmt = conn.prepareStatement(D.SQL_WRITE_SELECT);
rs = pstmt.executeQuery();
arr = createArray(rs);
} finally {
close();
}
return arr;
} // end select()
// 특정 uid 의 글 내용 읽기, 조회수 증가
// viewCnt 도 1 증가 해야 하고, 글 읽어와야 한다 --> 트랜잭션 처리
public WriteDTO [] readByUid(int uid) throws SQLException{
int cnt = 0;
WriteDTO [] arr = null;
try {
// 트랜잭션 처리
// Auto-commit 비활성화
conn.setAutoCommit(false);
// 쿼리들 수행
pstmt = conn.prepareStatement(D.SQL_WRITE_INC_VIEWCNT);
pstmt.setInt(1, uid);
cnt = pstmt.executeUpdate();
pstmt.close();
pstmt = conn.prepareStatement(D.SQL_WRITE_SELECT_BY_UID);
pstmt.setInt(1, uid);
rs = pstmt.executeQuery();
arr = createArray(rs);
conn.commit();
} catch(SQLException e) {
conn.rollback();
throw e;
} finally {
close();
}
return arr;
} // end readByUid()
// 특정 uid의 글만 SELECT(조회수 증가 없음)
public WriteDTO [] selectByUid(int uid) throws SQLException {
WriteDTO [] arr = null;
try {
pstmt = conn.prepareStatement(D.SQL_WRITE_SELECT_BY_UID);
pstmt.setInt(1, uid);
rs = pstmt.executeQuery();
arr = createArray(rs);
} finally {
close();
}
return arr;
}
// 특정 uid 의 글 수정 (제목, 내용)
public int update(int uid, String subject, String content) throws SQLException {
int cnt = 0;
try {
pstmt = conn.prepareStatement(D.SQL_WRITE_UPDATE);
pstmt.setString(1, subject);
pstmt.setString(2, content);
pstmt.setInt(3, uid);
cnt = pstmt.executeUpdate();
} finally {
close();
}
return cnt;
} // end update()
// 특정 uid 글 삭제하기
public int deleteByUid(int uid) throws SQLException {
int cnt = 0;
try {
pstmt = conn.prepareStatement(D.SQL_WRITE_DELETE_BY_UID);
pstmt.setInt(1, uid);
cnt = pstmt.executeUpdate();
} finally {
close();
}
return cnt;
} // end deleteByUid()
} // end DAO
7. MVC Model2의 커맨드 객체
** com.command.write > Command 인터페이스
package com.command.write;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface Command {
void execute(HttpServletRequest request, HttpServletResponse response);
}
<<Command 인터페이스를 이용하여 Write, List, View, Upeate, UpdateOk, Delete Command 만들기>>
** WriteCommend implements Command
package com.command.write;
import java.sql.SQLException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.lec.beans.WriteDAO;
public class WriteCommand implements Command {
@Override
public void execute(HttpServletRequest request, HttpServletResponse response) {
int cnt = 0;
WriteDAO dao = new WriteDAO();
// 매개변수 받아오기
String name = request.getParameter("name");
String subject = request.getParameter("subject");
String content = request.getParameter("content");
if(name != null && subject != null
&& name.trim().length() > 0 && subject.trim().length() > 0) {
try {
cnt = dao.insert(subject, content, name);
} catch(SQLException e) {
e.printStackTrace();
}
} // end if
request.setAttribute("result", cnt);
} // end execute()
} // end Command
** ListCommand implements Command
package com.command.write;
import java.sql.SQLException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.lec.beans.WriteDAO;
import com.lec.beans.WriteDTO;
public class ListCommand implements Command {
@Override
public void execute(HttpServletRequest request, HttpServletResponse response) {
WriteDAO dao = new WriteDAO(); // DAO 객체 생성
WriteDTO[] arr = null;
try {
// 트랜젝션 수행
arr = dao.select();
// "list"란 name으로 request에 arr 값 전달
// 즉, request에 담아서 컨트롤러에 전달되는 셈!
request.setAttribute("list", arr);
} catch(SQLException e) {
// 만약에 CP 사용한다면
// 여기서 NamingException도 처리해줘야 함
e.printStackTrace();
}
}
}
** ViewCommand implements Command
package com.command.write;
import java.sql.SQLException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.lec.beans.WriteDAO;
import com.lec.beans.WriteDTO;
public class ViewCommand implements Command {
@Override
public void execute(HttpServletRequest request, HttpServletResponse response) {
WriteDAO dao = new WriteDAO(); // DAO 객체 생성
WriteDTO[] arr = null;
// uid 값 받아 오기
int uid = Integer.parseInt(request.getParameter("uid"));
try {
// 트랜잭션 수행
arr = dao.selectByUid(uid);
// "view"란 name으로 request에 arr 값 전달
// 즉, request에 담아서 컨트롤러에 전달되는 셈!
request.setAttribute("view", arr);
} catch(SQLException e) {
// 만약 ConnectionPool을 사용한다면
// 여기서 NamingException도 catch 해야 한다.
e.printStackTrace();
}
}
}
** UpdateCommand implements Command
: 수정하기 위해서는 저장되어 있는 자료를 불러와야 함!
package com.command.write;
import java.sql.SQLException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.lec.beans.WriteDAO;
import com.lec.beans.WriteDTO;
public class UpdateCommand implements Command {
@Override
public void execute(HttpServletRequest request, HttpServletResponse response) {
WriteDAO dao = new WriteDAO(); // DAO 객체 생성
WriteDTO[] arr = null;
// 매개변수 받아오기
int uid = Integer.parseInt(request.getParameter("uid"));
try {
// 트랜잭션 수행
// 수정하기 위해서는 자료를 불러와야 함..!!
arr = dao.selectByUid(uid); // 읽기 only
// "update"란 name으로 request에 arr 값 전달
// 즉, request에 담아서 컨트롤러에 전달되는 셈!
request.setAttribute("update", arr);
} catch(SQLException e) {
// 만약 ConnectionPool을 사용한다면
// 여기서 NamingException도 catch 해야 한다
e.printStackTrace();
}
}
}
** UpdateOkCommand implements Command
: 사용자가 입력한 값으로 새롭게 저장한 후 view 화면으로 돌아가기,
view 화면으로 돌아갈때 uid 값도 같이 넘겨주기
package com.command.write;
import java.sql.SQLException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.lec.beans.WriteDAO;
import com.lec.beans.WriteDTO;
public class UpdateOkCommand implements Command {
@Override
public void execute(HttpServletRequest request, HttpServletResponse response) {
int cnt = 0;
WriteDAO dao = new WriteDAO(); // DAO 객체 생성
// 입력한 값을 받아오기
int uid = Integer.parseInt(request.getParameter("uid"));
String subject = request.getParameter("subject");
String content = request.getParameter("content");
try {
// 트랜잭션 수행
// 사용자가 입력한 값으로 변경
cnt = dao.update(uid, subject, content);
request.setAttribute("updateOk", cnt);
} catch(SQLException e) {
e.printStackTrace();
} finally {
// 무조건 아이디 값은 넘겨줘야함,
// 이 아이디 값을 매개변수로 받고 view 화면으로 갈 것이기 때문에
request.setAttribute("updateOkUID", uid);
}
} // end execute()
}
** DeleteOkCommand implements Command
package com.command.write;
import java.sql.SQLException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.lec.beans.WriteDAO;
public class DeleteOkCommand implements Command {
@Override
public void execute(HttpServletRequest request, HttpServletResponse response) {
int cnt = 0;
WriteDAO dao = new WriteDAO(); // DAO 객체 생성
// 매개변수 받아오기
int uid = Integer.parseInt(request.getParameter("uid"));
try {
// 트랜잭션 수행
cnt = dao.deleteByUid(uid);
} catch(SQLException e) {
e.printStackTrace();
}
// "update"란 name으로 request에 arr 값 전달
// 즉, request에 담아서 컨트롤러에 전달되는 셈!
request.setAttribute("deleteOk", cnt);
}
}
8. MVC Model2의 컨트롤러 객체
** com.docontroller > WriteController 서블릿
: URL 매핑 *.do로 설정,
URL에 ~~.do로 입력되면 이 서블릿이 요청(확장자 패턴이라고도 함)
package com.controller;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
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 com.command.write.Command;
import com.command.write.DeleteOkCommand;
import com.command.write.ListCommand;
import com.command.write.ViewCommand;
import com.command.write.WriteCommand;
import com.command.write.UpdateCommand;
import com.command.write.UpdateOkCommand;
@WebServlet("*.do")
public class WriteController extends HttpServlet {
private static final long serialVersionUID = 1L;
public WriteController() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
actionDo(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
actionDo(request, response);
}
protected void actionDo(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("actionDo() 호출");
request.setCharacterEncoding("UTF-8");
// 컨트롤러는 다음 두개를 선택해야 한다.
String viewPage = null; // 어떠한 뷰? --> 페이지
Command command = null; // 어떠한 커맨드? --> 어떠한 로직 수행.
// URL로부터 URI, ContextPath, Command 분리
String uri = request.getRequestURI();
String conPath = request.getContextPath();
String com = uri.substring(conPath.length());
// 테스트 출력
System.out.println("uri: " + uri);
System.out.println("conPath: " + conPath);
System.out.println("com: " + com);
// 컨트롤러는 커멘드에 따라, 로직을 수행하고
// 결과를 내보낼 view를 결정한다.
switch(com) {
case "/list.do":
command = new ListCommand();
command.execute(request, response);
viewPage = "list.jsp";
break;
case "/write.do":
viewPage = "write.jsp";
break;
case "/writeOk.do":
command = new WriteCommand();
command.execute(request, response);
viewPage = "writeOk.jsp";
break;
case "/view.do":
command = new ViewCommand();
command.execute(request, response);
viewPage = "view.jsp";
break;
case "/update.do":
command = new UpdateCommand();
command.execute(request, response);
viewPage = "update.jsp";
break;
case "/updateOk.do":
command = new UpdateOkCommand();
command.execute(request, response);
viewPage = "updateOk.jsp";
break;
case "/deleteOk.do":
command = new DeleteOkCommand();
command.execute(request, response);
viewPage = "deleteOk.jsp";
break;
} // end switch
// request를 위에서 결정한 view에 forward 해줌.
if(viewPage != null) {
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPage);
dispatcher.forward(request, response);
}
}
}
9. write, writeOk, list, view, update, updateOk, deleteOk
** write.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>글작성</title>
</head>
<script>
function chkSubmit() { // 폼 검증
frm = document.forms["frm"];
var name = frm["name"].value.trim();
var subject = frm["subject"].value.trim();
// 프론트 엔드에서 폼 유효성 체크, 검증하기
if(name == "") {
alert('작성자 란은 반드시 입력해야 합니다.');
frm["name"].focus();
return false;
}
if(subject == "") {
alert('제목은 반드시 작성해야 합니다.');
frm["subject"].focus();
return false;
}
return true;
}
</script>
<body>
<h2>글작성</h2>
<%-- 글 내용이 많을수 있기 때문에 POST 방식 사용 --%>
<form name="frm" action="writeOk.do" method="post" onsubmit="return chkSubmit()">
작성자:
<input type="text" name="name"/><br>
제목:
<input type="text" name="subject"/><br>
내용:<br>
<textarea name="content"></textarea>
<br><br>
<input type="submit" value="등록"/>
</form>
<br>
<button type="button" onclick="location.href='list.do'">목록으로</button>
</body>
</html>
** writeOk.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<% // Controller로부터 결과 데이터 받음
int cnt = (Integer)request.getAttribute("result");
%>
<% if(cnt == 0) { %>
<script>
alert('등록 실패!!');
history.back(); // 브라우저가 직전에 직전 페이지(입력중 페이지로)
</script>
<% } else { %>
<script>
alert('등록 성공, 리스트를 출력합니다!');
location.href = "list.do";
</script>
<% } %>
** list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="com.lec.beans.*" %>
<% // Controller로부터 결과 데이터 받음.
WriteDTO[] arr = (WriteDTO[])request.getAttribute("list");
%>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>글 목록</title>
<style>
table {width: 100%;}
table, th, td {
border: 1px solid black;
border-collapse: collapse;
}
</style>
</head>
<body>
<hr>
<h2>리스트</h2>
<table>
<tr>
<th>UID</th>
<th>제목</th>
<th>작성자</th>
<th>조회수</th>
<th>등록일</th>
</tr>
<%
if(arr != null){
for(int i = 0; i < arr.length; i++){
%>
<tr>
<td><%= arr[i].getUid() %></td>
<td><a href="view.do?uid=<%= arr[i].getUid()%>"><%= arr[i].getSubject() %></a></td>
<td><%= arr[i].getName() %></td>
<td><%= arr[i].getViewCnt() %></td>
<td><%= arr[i].getRegDate() %></td>
</tr>
<%
} // end for
} // end if
%>
</table>
<br>
<button onclick="location.href='write.do'">신규등록</button>
</body>
</html>
** view.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="com.lec.beans.*" %>
<% //Controller로부터 결과 데이터 받음
WriteDTO[] arr = (WriteDTO[])request.getAttribute("view");
%>
<%
if(arr == null || arr.length == 0) {
%>
<script>
alert("해당 정보가 삭제되거나 없습니다" + uid);
history.back();
</script>
<%
return; // 더이상 JSP 프로세싱 하지 않고 종료
} // end if
%>
<%
int uid = arr[0].getUid();
String name = arr[0].getName();
String subject = arr[0].getSubject();
String content = arr[0].getContent();
String regDate = arr[0].getRegDate();
int viewCnt = arr[0].getViewCnt();
%>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>읽기 <%= subject %></title> <!-- title에 글제목 넣기 -->
</head>
<script>
// script 는 위치 구애를 받지 않는다
function chkDelete(uid) {
// 삭제 여부, 다시 확인하고 진행하기
var r = confirm('삭제하시겠습니까?');
if(r) {
location.href = 'deleteOk.do?uid=' + uid;
}
}
</script>
<body>
<body>
<h2>읽기 <%= subject %></h2>
<br>
UID : <%= uid %><br>
작성자 : <%= name %><br>
제목 : <%= subject %><br>
등록일 : <%= regDate %><br>
조회수 : <%= viewCnt %><br>
내용: <br>
<hr>
<div>
<%= content %>
</div>
<hr>
<br>
<button onclick="location.href='update.do?uid=<%= uid %>'">수정하기</button>
<button onclick="location.href = 'list.do'">목록보기</button>
<button onclick="chkDelete(<%= uid %>)">삭제하기</button>
<button onclick="location.href = 'write.do'">신규등록</button>
</body>
</html>
** update.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="com.lec.beans.*" %>
<% // dao 사용한 트랜젝션
WriteDTO[] arr = (WriteDTO[])request.getAttribute("update");
%>
<%
if(arr == null || arr.length == 0) {
%>
<script>
alert("해당 정보가 삭제되거나 없습니다");
history.back();
</script>
<%
return; // 더이상 JSP 프로세싱 하지 않고 종료
} // end if
%>
<%
int uid = arr[0].getUid();
String name = arr[0].getName();
String subject = arr[0].getSubject();
String content = arr[0].getContent();
int viewCnt = arr[0].getViewCnt();
%>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>수정 <%= subject %></title>
</head>
<script>
function chkSubmit(){
frm = document.forms['frm'];
var subject = frm['subject'].value.trim();
if(subject == ""){
alert("제목은 반드시 작성해야 합니다");
frm['subject'].focus();
return false;
}
return true;
}
</script>
<body>
<h2>수정</h2>
<form name="frm" action="updateOk.do" method="post" onsubmit="return chkSubmit()">
<input type="hidden" name="uid" value="<%= uid %>"/>
작성자 : <%= name %><br> <%-- 작성자 이름 변경 불가 --%>
제목 :
<input type="text" name="subject" value="<%= subject %>"/><br>
내용: <br>
<textarea name="content"><%= content %></textarea>
<br>
<input type="submit" value="수정"/>
</form>
<button onclick="history.back()">이전으로</button>
<button onclick="location.href='list.do'">목록보기</button>
</body>
</html>
** updateOk.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<% // Controller로부터 결과 데이터 받음
// parameter 받아오기
int cnt = (Integer)request.getAttribute("updateOk");
int uid = (Integer)request.getAttribute("updateOkUID");
%>
<% if(cnt == 0) { %>
<script>
alert('수정 실패');
history.back();
</script>
<% } else { %>
<script>
alert('수정 성공');
location.href = "view.do?uid=<%=uid%>";
</script>
<% } %>
** deleteOk.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
// Controller로부터 결과 데이터 받음
int cnt = (Integer)request.getAttribute("deleteOk");
%>
<% if(cnt == 0) { %>
<script>
alert('삭제 실패');
history.back();
</script>
<% } else { %>
<script>
alert('삭제 성공');
location.href = "list.do"; <%-- 삭제후에는 list 로 가자 --%>
</script>
<% } %>
10. request.setAttribute(name, value), request.getAttribute(name)
: request.setAttribute(name, value), request.getAttribute(name)는 어떠한 Object 타입도 보내고 받을 수 있다.
getAttribute(name)의 리턴타입은 Object이니 필요한 타입으로 형변환 필요
'웹_프론트_백엔드 > JAVA프레임윅기반_풀스택' 카테고리의 다른 글
2020.05.26 (0) | 2020.05.26 |
---|---|
2020.05.25 (0) | 2020.05.25 |
2020.05.21 (0) | 2020.05.21 |
2020.05.20 (0) | 2020.05.20 |
2020.05.19 (0) | 2020.05.19 |