실행 순서
JSP -> service -> dao -> db
JSP <- service <- dao <- db
jquery 다운로드
https://jquery.com/ 접속
download 클릭
upcompressed 클릭 -> 내용 복사
js폴더에 파일 만들고, 복사한 내용 붙여넣기
---> 이제 script src에 해당 위치 적어서 사용 가능!
<방명록 게시판 만드는 순서>
1.GuestbookMessage 객체 생성
2.Dao 객체 생성
3.Service 객체 생성 및 예외처리
4.jsp파일로 View 작성
package dto;
//자바빈 클래스
public class GuestbookMessage {
private int messageId;
private String guestName;
private String password;
private String message;
//기본생성자(Constructor)
public GuestbookMessage() {
super();
// TODO Auto-generated constructor stub
}
//생성자
public GuestbookMessage(int messageId, String guestName, String password, String message) {
super();
this.messageId = messageId;
this.guestName = guestName;
this.password = password;
this.message = message;
}
public int getMessageId() {
return messageId;
}
public void setMessageId(int messageId) {
this.messageId = messageId;
}
public String getGuestName() {
return guestName;
}
public void setGuestName(String guestName) {
this.guestName = guestName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
@Override
public String toString() {
return "GuestbookMessage [messageId=" + messageId + ", guestName=" + guestName + ", password=" + password
+ ", message=" + message + "]";
}
}
package guestbook.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import dto.GuestbookMessage;
import jdbc.JdbcUtil;
//Data Access Object
public class MessageDao {
//싱글톤 패턴
private static MessageDao instance = new MessageDao();
public static MessageDao getInstance() {
return instance;
}
private MessageDao() {}
/**guestbook_message 테이블로 insert
* insert, update, delete 기본 return type은 int
* params : 커넥션 객체, 무엇을 입력할 것인지!(대상)
*/
public int insert(Connection conn, GuestbookMessage message) {
//선언
PreparedStatement pstmt = null;
int result = 0;
try {
pstmt = conn.prepareStatement(
"INSERT INTO GUESTBOOK_MESSAGE(MESSAGE_ID,GUEST_NAME,PASSWORD,MESSAGE)" +
" VALUES(" +
" (SELECT NVL(MAX(MESSAGE_ID),0)+1 FROM GUESTBOOK_MESSAGE)" +
" ,?,?,?" +
")"
);
pstmt.setString(1, message.getGuestName());
pstmt.setString(2, message.getPassword());
pstmt.setString(3, message.getMessage());
return pstmt.executeUpdate();
}catch(SQLException ex){
ex.printStackTrace();
return 0;
}finally {
//주의! 커넥션 객체는 비즈니스로직에서 닫음(Service)
JdbcUtil.close(pstmt);
}
}//end insert
//list.jsp의 메시지 목록
public List<GuestbookMessage> selectList(Connection conn) throws SQLException {
Statement stmt = null;
ResultSet rs = null;
try {
//SELECT구문..
String query = "SELECT MESSAGE_ID" +
" , GUEST_NAME" +
" , PASSWORD" +
" , MESSAGE " +
" FROM GUESTBOOK_MESSAGE" +
" ORDER BY MESSAGE_ID DESC";
stmt = conn.createStatement();
rs = stmt.executeQuery(query);
//커서가 다음행으로 바라봤을 때 데이터가 있다면 실행
if(rs.next()) {
List<GuestbookMessage> messageList = new ArrayList<GuestbookMessage>();
do {
GuestbookMessage vo = new GuestbookMessage();
vo.setMessageId(rs.getInt("MESSAGE_ID"));
vo.setGuestName(rs.getString("GUEST_NAME"));
vo.setPassword(rs.getString("PASSWORD"));
vo.setMessage(rs.getString("MESSAGE"));
//message_id는 자료형이 int이므로 getInt()로 받는다
messageList.add(vo);
}while(rs.next());
return messageList;
}else { //select 결과 없을 때
return Collections.emptyList();
}//end if
}finally {
JdbcUtil.close(rs);
JdbcUtil.close(stmt);
}
}
//메시지 수정(커넥션, 무엇을)
public int update(Connection conn, GuestbookMessage message) {
PreparedStatement pstmt = null;
try {
pstmt = conn.prepareStatement("UPDATE GUESTBOOK_MESSAGE" +
" SET GUEST_NAME = ?, MESSAGE = ?" +
" WHERE MESSAGE_ID = ? AND PASSWORD = ?");
pstmt.setString(1, message.getGuestName());
pstmt.setString(2, message.getMessage());
pstmt.setInt(3, message.getMessageId());
pstmt.setString(4, message.getPassword());
return pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
return 0;
}finally {
JdbcUtil.close(pstmt);
//커넥션 객체는 서비스단에서 close해준다.
}//end try
}
//삭제 : conn은 db연결, message는 삭제할 대상 지정
public int delete(Connection conn, GuestbookMessage message) {
PreparedStatement pstmt = null;
try {
pstmt = conn.prepareStatement("DELETE FROM GUESTBOOK_MESSAGE" +
" WHERE MESSAGE_ID = ?");
pstmt.setInt(1, message.getMessageId());
return pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
return 0;
}finally {
JdbcUtil.close(pstmt);
}
}
}
package guestbook.service;
import java.sql.Connection;
import java.sql.SQLException;
import dto.GuestbookMessage;
import guestbook.dao.MessageDao;
import jdbc.ConnectionProvider;
import jdbc.JdbcUtil;
//***Service.java => 비즈니스(기능) 로직
public class WriteMessageService {
//싱글톤 패턴 적용
private static WriteMessageService instance = new WriteMessageService();
public static WriteMessageService getInstance() {
return instance;
}
private WriteMessageService() {}
//방명록 insert
public void write(GuestbookMessage message) {
//커넥션 객체를 선언(DBCP에서 가져온 커넥션)
Connection conn = null;
try {
//DBCP 커넥션 객체를 생성
conn = ConnectionProvider.getConnection();
//guestbook_message테이블로 insert => Data Access Object 영역
MessageDao messageDao = MessageDao.getInstance();
int result = messageDao.insert(conn, message);
}catch(SQLException ex) {
throw new ServiceException("메시지 등록 실패 : " + ex.getMessage(), ex);
}finally {
JdbcUtil.close(conn);
}
}
}
package guestbook.service;
public class ServiceException extends RuntimeException {
//생성자
public ServiceException(String message, Exception cause) {
super(message, cause);
}
//생성자
public ServiceException(String message) {
super(message);
}
}
package guestbook.service;
import java.sql.Connection;
import java.sql.SQLException;
import dto.GuestbookMessage;
import guestbook.dao.MessageDao;
import jdbc.ConnectionProvider;
import jdbc.JdbcUtil;
public class UpdateMessageService {
//싱글톤 패턴
private static UpdateMessageService instance = new UpdateMessageService();
public static UpdateMessageService getInstance() {
return instance;
}
private UpdateMessageService() {}
//메시지를 update하는 비즈니스 로직
public int update(GuestbookMessage message) {
Connection conn = null;
int result = 0;
try {
conn = ConnectionProvider.getConnection();
//DAO 객체 생성
MessageDao messageDao = MessageDao.getInstance();
result = messageDao.update(conn, message);
}catch(SQLException ex) {
throw new ServiceException("메시지 수정 실패 : " + ex.getMessage(), ex);
}finally {
JdbcUtil.close(conn);
}
return result;
}
}
package guestbook.service;
import java.sql.Connection;
import java.sql.SQLException;
import dto.GuestbookMessage;
import guestbook.dao.MessageDao;
import jdbc.ConnectionProvider;
import jdbc.JdbcUtil;
public class DeleteMessageService {
//new를 사용하면 요청할 때마다 객체가 생성되어 과부하가 되므로 싱글톤을 사용한다.
private static DeleteMessageService instance = new DeleteMessageService();
public static DeleteMessageService getInstance() {
return instance;
}
private DeleteMessageService() {}
//데이터 삭제
public int delete(GuestbookMessage message) {
Connection conn = null;
try {
conn = ConnectionProvider.getConnection();
MessageDao messageDao = MessageDao.getInstance();
int result = messageDao.delete(conn, message);
return result;
} catch (SQLException ex) {
//삭제 시 문제가 발생되면 롤백 처리
//DC(control)L : commit, rollback(마지막 커밋 시점으로 돌아감)
// -> 트랜잭션이 종료가 되는 동시에 새로운 트랜잭션이 시작
// -> 트랜잭션? DB를 변경하기 위해 수행되어야 할 논리적 단위(여러개의 sql로 구성)
JdbcUtil.rollback(conn);
throw new ServiceException("삭제 실패", ex);
}finally {
JdbcUtil.close(conn);
}
}
}
package guestbook.service;
public class ServiceException extends RuntimeException {
//생성자
public ServiceException(String message, Exception cause) {
super(message, cause);
}
//생성자
public ServiceException(String message) {
super(message);
}
}
<%@page import="guestbook.service.GetMessageListService"%>
<%@ page import="dto.GuestbookMessage"%>
<%@ page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
//list.jsp에서 사용할
//메시지 목록(List<GuestbookMessage>)을 가져와주는 서비스 로직
GetMessageListService messageListService = GetMessageListService.getInstance();
List<GuestbookMessage> list = messageListService.getMessageList();
%>
<c:set var="list" value="<%=list%>" />
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="/js/jquery-3.6.0.js"></script>
<title>방명록 메시지 목록</title>
<script type="text/javascript">
$(function(){
// alert("왔다!");
});
//fn_updt(기본키, 작성자 , 메시지)
function fn_updt(vara, varb, varc){
//alert(vara);
//기본키 데이터를 vara 매개변수로 받아서 frmUpdate 폼의 기본키 데이터로 사용
$("#messageId").val(vara);
//작성자 매개변수를 frmUpdate 폼의 이름 데이터로 사용
$("#guestName").val(varb);
//메시지 매개변수를 frmUpdate 폼의 내용 데이터로 사용
$("#message").val(varc);
$("#frmWrite").css("display","none");
$("#frmUpdate").css("display","block");
}
</script>
</head>
<body>
<form id="frmWrite" method="post" action="writeMessage.jsp" style="display:block;">
이름 : <input type="text" name="guestName"/><br>
비밀번호 : <input type="password" name="password"/><br>
내용 : <textarea rows="3" cols="30" name="message"></textarea><br>
<input type="submit" value="메시지 남기기" />
</form>
<form id="frmUpdate" method="post" action="updateMessage.jsp" style="display:none;">
<input type="hidden" name="messageId" id="messageId" />
이름 : <input type="text" name="guestName" id="guestName"/><br>
비밀번호 : <input type="password" name="password"/><br>
내용 : <textarea rows="3" cols="30" name="message" id="message"></textarea><br>
<input type="submit" value="확인" />
<input type="button" value="취소" onclick="javascript:location.href='list.jsp';"/>
</form>
<hr>
<!--
[수정]
1. 클릭 시 상단의 폼에 정보가 입력되고(비밀번호 제외)
"메시지 남기기" 버튼이 hidden, "확인" 및 "취소" 버튼이 block
2. "확인" 클릭 시 해당 정보가 업데이트가 되는데, 이때 비밀번호가 일치해야 함
3. "취소" 클릭 시 현재 페이지의 목록으로 되돌아감
"메시지 남기기" 버튼이 block, "확인" 및 "취소" 버튼이 hidden
-->
<c:if test="${param.result eq 1}">
<div style="color:red;">변경 성공했습니다.</div>
</c:if>
<c:if test="${param.result < 1}">
<div style="color:red;">비밀번호를 확인해주세요.</div>
</c:if>
<table border="1">
<c:forEach var="message" items="${list}">
<tr>
<td>
메시지 번호 : <span>${message.messageId}</span><br>
손 님 이 름 : <span>${message.guestName}</span><br>
메 시 지 : <span>${message.message}</span><br>
<a href="#" id="updt" onclick="fn_updt('${message.messageId}','${message.guestName}','${message.message}')">[수정]</a>
<a href="deleteMessage.jsp?messageId=${message.messageId}">[삭제]</a>
</td>
</tr>
</c:forEach>
</table>
</body>
</html>
<%@page import="guestbook.service.WriteMessageService"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
request.setCharacterEncoding("UTF-8");
%>
<!DOCTYPE html>
<html>
<head>
<title>방명록 메시지 남김</title>
</head>
<body>
<jsp:useBean id="guestbookMessage" class="dto.GuestbookMessage">
<jsp:setProperty name="guestbookMessage" property="*" />
<!-- request로 넘어온 모든 데이터를 guestbookMessage 이름으로 매핑한다-->
</jsp:useBean>
${guestbookMessage.messageId}<br>
${guestbookMessage.guestName}<br>
${guestbookMessage.password}<br>
${guestbookMessage.message}<br>
<%
//싱글톤 패턴
WriteMessageService writeMessageService = WriteMessageService.getInstance();
writeMessageService.write(guestbookMessage);
%>
방명록에 메시지를 남겼습니다.
<a href="list.jsp">[목록보기]</a>
</body>
</html>
<%@page import="dto.GuestbookMessage"%>
<%@page import="guestbook.service.UpdateMessageService"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
request.setCharacterEncoding("UTF-8");
String messageId = request.getParameter("messageId");
String guestName = request.getParameter("guestName");
String password = request.getParameter("password");
String message = request.getParameter("message");
out.print("messageId : " + messageId + "<br>");
out.print("guestName : " + guestName + "<br>");
out.print("password : " + password + "<br>");
out.print("message : " + message + "<br>");
//getter 안쓰는 대신 생성자 파라미터에 이렇게 넣는다!
GuestbookMessage guestbookmessage = new GuestbookMessage(Integer.parseInt(messageId), guestName, password, message);
//여기서 사용할 UpdateMessageService의 객체를 생성
UpdateMessageService service = UpdateMessageService.getInstance();
int result = service.update(guestbookmessage);
if(result>0){ //변경 성공
out.print("<script type='text/javascript'>location.href='list.jsp?result=1'</script>");
}else{ //변경 실패
out.print("<script type='text/javascript'>location.href='list.jsp?result=0'</script>");
}
%>
<%@page import="guestbook.service.ServiceException"%>
<%@page import="dto.GuestbookMessage"%>
<%@page import="guestbook.service.DeleteMessageService"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
request.setCharacterEncoding("UTF-8");
//list.jsp에서 보낸 파라미터 받기 -> request.getParameter로 받으면 무조건 String형
String messageId = request.getParameter("messageId");
GuestbookMessage message = new GuestbookMessage();
//int messageId 멤버변수(String messageId)로 형변환
message.setMessageId(Integer.parseInt(messageId));
//삭제 성공 여부(성공으로 세팅)
boolean result = true;
//삭제된 건수
int cnt = 0;
try{
DeleteMessageService service = DeleteMessageService.getInstance();
cnt = service.delete(message);
}catch(ServiceException ex){ //서비스에서 throw new ServiceException으로 던진거 받기
//실패 처리
result = false;
}
%>
<!DOCTYPE html>
<html>
<head>
<title>방명록 메시지 삭제</title>
</head>
<body>
<%
if(result){ //result : true일 때
if(cnt>0){ //삭제가 잘 된 경우
out.print("메시지를 삭제하였습니다.");
}else{ //기본키에 해당되는 데이터가 없을 경우
out.print("해당 데이터가 없습니다.");
}
}else{ //result : false
out.print("삭제가 되지 않았습니다.");
}
%>
<br>
<a href="list.jsp">[목록 보기]</a>
</body>
</html>
JSP - Service - Dao - Oracle
l l l l
view Model
사용자 비즈니스 로직
영역
Controller는 View의 요청과 Model의 응답을 처리한다
Spring -> Spring Boot(스프링을 더 쉽게 이용하기 위한 도구)
프레임워크 : 디자인패턴(view, model) + 라이브러리(jar)
카멜 표기 변환
create or replace FUNCTION FN_GETCAMEL(COLUMN_NAME IN VARCHAR2)
RETURN VARCHAR2
IS
RSLT VARCHAR2(30);
BEGIN
--카멜표기로 변환(SITE_NUM -> siteNum)
SELECT LOWER(SUBSTR(REPLACE(INITCAP(COLUMN_NAME),'_'),1,1))
|| SUBSTR(REPLACE(INITCAP(COLUMN_NAME),'_'),2) INTO RSLT
FROM DUAL;
--리턴
RETURN RSLT;
END;
/
--구글 카멜변환(https://heavenly-appear.tistory.com/270)
SELECT COLUMN_NAME
, DATA_TYPE
, CASE WHEN DATA_TYPE='NUMBER' THEN 'private int ' || FN_GETCAMEL(COLUMN_NAME) || ';'
WHEN DATA_TYPE IN('VARCHAR2','CHAR') THEN 'private String ' || FN_GETCAMEL(COLUMN_NAME) || ';'
WHEN DATA_TYPE='DATE' THEN 'private Date ' || FN_GETCAMEL(COLUMN_NAME) || ';'
ELSE 'private String ' || FN_GETCAMEL(COLUMN_NAME) || ';'
END AS CAMEL_CASE
, '' RESULTMAP
FROM ALL_TAB_COLUMNS
WHERE TABLE_NAME = 'CUS';