JSP/Servlet - 방명록!

방명록

방명록 기능을 mvc패턴으로 구축해보자.

image46

먼저 컨트롤러를 정의하고

다형성을 위한 CommandHandler객체와 이벤트를 찾지 못하였을 경우 처리해줄 NullHandler를 정의한다.

/* ControllerUsingURI.java */
public class ControllerUsingURI extends HttpServlet{
	private Map<String, CommandHandler> commandHandlerMap = new HashMap<>();
	
	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		process(request, response);
	}

	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		process(request, response);
	}

	@Override
	public void init() throws ServletException {
		String configFile = getInitParameter("configFile");
		Properties prop = new Properties();
		String configFilePrath = getServletContext().getRealPath(configFile);
		System.out.println(configFile);
		try(FileInputStream fis = new FileInputStream(configFilePrath))
		{
			prop.load(fis);
		} catch (IOException e) {
			throw new ServletException(e);
		}
		Iterator<Object> keyiter = prop.keySet().iterator();
		while (keyiter.hasNext()) {
			String command = (String) keyiter.next();
			String handlerClassName = prop.getProperty(command);
			try {
				Class<?> handlerClass = Class.forName(handlerClassName);
				CommandHandler handlerInstance = (CommandHandler) handlerClass.newInstance();
				commandHandlerMap.put(command, handlerInstance);
			}
			catch (ClassNotFoundException | InstantiationException | IllegalAccessException  e) {
				throw new ServletException(e);
			}
		}
	}

	private void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String command = request.getRequestURI();
		if (command.indexOf(request.getContextPath()) == 0) {
			command = command.substring(request.getContextPath().length());
		}
		System.out.println(command);
		CommandHandler handler = commandHandlerMap.get(command);
		if (handler == null) {
			handler = new NullHandler(); //404에러를 응답하는 핸들러 클래스
		}
		String viewPage = null;
		try {
			viewPage = handler.process(request, response);
			System.out.println("viewpage: " + viewPage);
		}
		catch (Exception e) {
			throw new ServletException(e);
		}
		if(viewPage != null) {
			String prefix = "/WEB-INF/view/message";
			viewPage = prefix + viewPage;
			RequestDispatcher dispatcher = request.getRequestDispatcher(viewPage);
			dispatcher.forward(request, response);
		}
	}
}
public interface CommandHandler {
	public String process(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
public class NullHandler implements CommandHandler {
	@Override
	public String process(HttpServletRequest request, HttpServletResponse response) throws Exception {
		response.sendError(HttpServletResponse.SC_NOT_FOUND);
		return null;
	}
}

commandHandler.properties파일의 내용은 아래와 같다.

/message/list.do=message.command.GetMessageListHandler
/message/write.do=message.command.WriteMessageHandler
/message/delete.do=message.command.DeleteMessageHandler
#somecmd=anySomeHandler

방명록 목록을 출력하는 헨들러,

병명록 쓰기를 처리하는 헨들러

방령록 삭제를 처리하는 헨들러를 작성하자.

이제 web.xml에서 DBCP 객체 생성하고 commandHandler.properties 파일 경로 설정은 생략하겠다.

참고: https://kouzie.github.io/jsp/JSP-DBCP,-세션/#dbcp-database-connection-pool
https://kouzie.github.io/jsp/JSP-게시판-어플리케이션/#컨트롤러-정의

방병록 DB

CREATE TABLE guestbook_message (
MESSAGE_ID  NUMBER        primary key,
GUEST_NAME  VARCHAR2(50)  NOT NULL,
PASSWORD    VARCHAR2(10)  NOT NULL,
MESSAGE     VARCHAR2(255) NOT NULL
);
CREATE SEQUENCE seq_guestbook_message ;

매우 간단한 DB이다. 로그인과정도 없고 그저 이름, 메세지, 비밀번호만 입력하면 된다.

message_id는 시퀀스로 자동 증가된다.

메세지 SQL문 - MessageDao

먼저 메세지를 넣기 위한 DTO객체와 SQL문이 정의되어 있는 DAO객체를 생성하자.

public class Message {

	private int message_id;
	private String guest_name;
	private String password;
	private String message;
	
	@Override
	public String toString() {
		return "Message [message_id=" + message_id + ", guest_name=" + guest_name + ", password=" + password
				+ ", message=" + message + "]";
	}

	...
	...(get, set메서드 )

	public boolean matchPassword(String pwd) {
		return password != null && password.equals(pwd);
	}
}

정석적인 DTO객체이다. 나중에 삭제를 위해 password가 맞는지 확인하기 위해 matchPassword()메서드를 추가로 정의하였다.

DAO객체에 다음 메서드가 정의되어있다.

insert(Connection conn, Message message)
select(Connection conn, int messageId)
delete(Connection conn, int messageId)

각각 게시글 하나를 삽입, 선택, 삭제하는 메서드이다.

public class MessageDao {
	private static MessageDao messageDao = new MessageDao();
	public static MessageDao getInstance() {
		return messageDao;
	}
	
	private MessageDao() {}
	
	public int insert(Connection conn, Message message) throws SQLException {
		PreparedStatement pstmt = null;
		try {
			pstmt = conn.prepareStatement(
					" insert into guestbook_message " + 
					" (message_id, guest_name, password, message) values "+
					" (seq_guestbook_message.nextval, ?, ?, ?) ");
			pstmt.setString(1, message.getGuest_name());
			pstmt.setString(2, message.getPassword());
			pstmt.setString(3, message.getMessage());
			int result =  pstmt.executeUpdate();
			return result;
		} finally {
			JdbcUtil.close(pstmt);
		}
	}

	public Message select(Connection conn, int messageId) throws SQLException {
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			pstmt = conn.prepareStatement(
					"select * from guestbook_message where message_id = ?");
			pstmt.setInt(1, messageId);
			rs = pstmt.executeQuery();
			if (rs.next()) {
				return makeMessageFromResultSet(rs);
			} else {
				return null;
			}
		} finally {
			JdbcUtil.close(rs);
			JdbcUtil.close(pstmt);
		}
	}

	public int selectCount(Connection conn) throws SQLException {
		Statement stmt = null;
		ResultSet rs = null;
		try {
			stmt = conn.createStatement();
			rs = stmt.executeQuery("select count(*) from guestbook_message");
			rs.next();
			return rs.getInt(1);
		} finally {
			JdbcUtil.close(rs);
			JdbcUtil.close(stmt);
		}
	}

	public List<Message> selectList(Connection conn, int firstRow, int endRow) 
			throws SQLException {
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			pstmt = conn.prepareStatement(
					"SELECT * FROM (" + 
						" SELECT ROWNUM no, sub.* from ( " + 
							" SELECT * FROM guestbook_message  " + 
							" ORDER BY message_id desc)sub )"+
					" WHERE no BETWEEN ? AND ?");
			pstmt.setInt(1, firstRow);
			pstmt.setInt(2, endRow);
			rs = pstmt.executeQuery();
			if (rs.next()) {
				List<Message> messageList = new ArrayList<Message>();
				do {
					messageList.add(makeMessageFromResultSet(rs));
				} while (rs.next());
				return messageList;
			} else {
				return Collections.emptyList();
			}
		} catch(Exception e) {
			e.printStackTrace();
		} finally {
			JdbcUtil.close(rs);
			JdbcUtil.close(pstmt);
		}
		return null;
	}

	public int delete(Connection conn, int messageId) throws SQLException {
		PreparedStatement pstmt = null;
		try {
			pstmt = conn.prepareStatement(
					"delete from guestbook_message where message_id = ?");
			pstmt.setInt(1, messageId);
			return pstmt.executeUpdate();
		} finally {
			JdbcUtil.close(pstmt);
		}
	}

	private Message makeMessageFromResultSet(ResultSet rs) throws SQLException {
		Message message = new Message();
		message.setMessage_id(rs.getInt("message_id"));
		message.setGuest_name(rs.getString("guest_name"));
		message.setPassword(rs.getString("password"));
		message.setMessage(rs.getString("message"));
		return message;
	}
}

그리고 아래 2개 메서드가 더 있는데

selectList(Connection conn, int firstRow, int endRow)
selectCount(Connection conn)

게시글 목록을 출력하고 페이징 처리를 위해 게시글 수를 얻어오는 메서드이다.

DB관련 클래스와 DTO객체를 모두 만들었으니 방명록 목록조회, 추가, 삭제 이벤트를 순차적으로 처리해보자.

방명록 쓰기 이벤트 - WriteMessageHandler

글쓰기 <form>태그는 list.jsp에 있다.
리스트 출력은 나중에 설정하고 글쓰기 폼만 먼저 만들어보자.

<!-- list.jsp -->
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html>
<head>
	<title>방명록 메시지 목록</title>
</head>
<body>
<form action="/jspPro/message/write.do" method="post">
	이름: <input type="text" name="guest_name"> <br>
	암호: <input type="password" name="password"> <br>
	메시지: <textarea name="message" cols="30" rows="3"></textarea> <br>
	<input type="submit" value="메시지 남기기" />
</form>
<hr>
</body>
</html>

image58

action 속성에 의해 /jspPro/message/write.do url을 post방식으로 요청한다.

properties파일에 설정해놓은 대로 컨트롤러는 WriteMessageHandlerprocess()메서드를 호출한다.

public class WriteMessageHandler implements CommandHandler{
	private static final String FORM_VIEW = "/view/list.jsp";
	WriteMessageService writeService = WriteMessageService.getInstance();
	@Override
	public String process(HttpServletRequest request, HttpServletResponse response) throws Exception {
		if (request.getMethod().equalsIgnoreCase("GET")) {
			return processForm(request, response);
		}
		else if (request.getMethod().equalsIgnoreCase("POST")) {
			return processSubmit(request, response);
		}
		else {
			response.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
			return null;
		}
	}
	private String processForm(HttpServletRequest request, HttpServletResponse response) {
		return FORM_VIEW;
	}
	private String processSubmit(HttpServletRequest request, HttpServletResponse response) {
		System.out.println("WriteMessageHandler processSubmit");
		Message message = new Message();
		message.setGuest_name(request.getParameter("guest_name"));
		message.setPassword(request.getParameter("password"));
		message.setMessage(request.getParameter("message"));
		System.out.println("message: " + message.toString());
		
		writeService.write(message);
		return "/view/writeMessage.jsp";
	}
}

메세지 리스트와 글쓰기 폼이 한곳에 있어 write.do를 GET방식으로 호출할 일은 없겠지만 일단 list.jsp로 이동하도록 설정하였다 .

게시판 때와 마찬가지로 processSubmit()메서드가 호출되면
서비스 객체의 글쓰기 메서드를 호출하게 된고 서비스 객체는 dao의 INSERT쿼리가 들어있는 메서드를 호출한다.

이번엔 서비스 객체를 인스턴스 생성자로 생성하지 않고 싱글톤 방식을 사용하였다.

WriteMessageService writeService = WriteMessageService.getInstance();

어쨋건 생성된 WriteMessageServicewrite()메서드를 사용해 전달받은 메세지(방명록)을 DB에 INSERT한다.

방명록 쓰기 이벤트 - WriteMessageService

public class WriteMessageService {
	private static WriteMessageService instance = new WriteMessageService();

	public static WriteMessageService getInstance() {
		return instance;
	}

	private WriteMessageService() {
	}

	public void write(Message message) {
		System.out.println(	message.toString());
		Connection conn = null;
		try {
			conn = ConnectionProvider.getConnection();
			MessageDao messageDao = MessageDao.getInstance();
			messageDao.insert(conn, message);
		} catch (SQLException | NamingException e) {
			throw new ServiceException("메시지 등록 실패: " + e.getMessage(), e);
		} finally {
			JdbcUtil.close(conn);
		}
	}
}

생성자를 private 접근지정자를 통해 사용하지 못하도록 설정하고 정적필드로 프로그램 시작과 동시에 자가자신을 생성해 놓는다.

getInstance()메서드가 호출되면 생성해 놓은 정적필드(자기를 가리키는 인스턴스)를 반환한다.

정적필드로 프로그램 시작과 동시에 메모리에 올리면 메모리 관리상 비효율적인 면이 있지만 아래처럼 if문을 거칠 필요 없어 편리하다.

...
private WriteMessageService instance;
public static WriteMessageService getInstance() {
	if(this.instance == null)
		instance = new WriteMessageService();
	return instance;	
}

write()메서드는 dao객체의 insert(conn, message)메서드를 호출하여 DB에 데이터를 집어넣는다.

참고: 입력과정에서 예외가 발생되면 자신을 호출한 WriteMessageHandler에 예외를 thorw하도록 하였지만 WriteMessageHandler 에선 따로 예외처리를 하지 않았다.

지금 보니 MessageDao클래스도 싱글톤 방식으로 설계되었다.

방명록 보기 이벤트 - GetMessageListHandler

게시글 목록 조회 url /message/list.do가 요청되면 방명록 목록을 읽어 list.jsp로 포워딩 시킨다.

public class GetMessageListHandler implements CommandHandler{
	private static final String FORM_VIEW = "/list.jsp";

	@Override
	public String process(HttpServletRequest request, HttpServletResponse response) throws Exception {
		String pageNumberStr = request.getParameter("page");
		int pageNumber = 1;
		if (pageNumberStr != null) {
			pageNumber = Integer.parseInt(pageNumberStr);
		}
		GetMessageListService messageListService = 
				GetMessageListService.getInstance();
		MessageListView viewData = 
				messageListService.getMessageList(pageNumber);
		request.setAttribute("viewData", viewData);
		return FORM_VIEW;
	}
}

읽는 요청밖에 없으니 GetMessageListHandlerprocess()메서드에선 get, post방식으로 따로 나뉘지 않는다.

방명록 리스트를 가져오는 DTO개체인 MessageListView와 리스트를 어떻게 읽어오는지 GetMessageListServicegetMessageList()메서드를 확인해보자.

그리고 request.getParameter()메서드를 통해 page란 파라미터를 전달받는데 이는 후에 페이지 블록 처리를 위해 현재 보려고 하는 페이지 넘버를 전달받는다.

방명록 보기 이벤트 - MessageListView

게시글 페이징 처리를 하기 위해선 여러가지 정보가 필요하다.

우선 사용자 혹은 개발자가 정하는 정보는 아래 2가지

  1. 페이지당 표시할 메세지 개수
  2. 보려고 하는 페이지 넘버

그리고 서버에서 위 2가지 정보를 가지고 아래 내용들을 얻어내야 한다.

  1. 전체 메세지 개수
  2. 페이지 개수(전체메세지 수 / 페이지당 표시할 메세지 수)
  3. 출력 시작 메시지 넘버
  4. 출력 마침 메시지 너버

전체 메세지 개수와 페이지 개수는 DB에서 COUNT집계함수를 사용해 얻을 수 있다.

출력시작 메시지 넘버는 (현제 페이지 - 1) * 페이지당 표시할 메세지 개수 + 1
출력마침 메시지 넘버는 출력시작 메시지 넘버 + 페이지당 표시할 메세지 개수 - 1

굳이 DB연결과정 없이 구할 수 있다.

public class MessageListView {
	
	private int messageCountPerPage;
	private int currentPageNumber;

	private int messageTotalCount;
	private int pageTotalCount;
	private int firstRow;
	private int endRow;
	private List<Message> messageList;

	public MessageListView(List<Message> messageList, int messageTotalCount, 
			int currentPageNumber, int messageCountPerPage, 
			int startRow, int endRow) {
		this.messageList = messageList;
		this.messageTotalCount = messageTotalCount;
		this.currentPageNumber = currentPageNumber;
		this.messageCountPerPage = messageCountPerPage;
		this.firstRow = startRow;
		this.endRow = endRow;
		calculatePageTotalCount();
	}

	...
	...(get, set메서드)

	private void calculatePageTotalCount() {
		if (messageTotalCount == 0) {
			pageTotalCount = 0;
		}
		else {
			pageTotalCount = messageTotalCount / messageCountPerPage;
			if (messageTotalCount % messageCountPerPage > 0) {
				pageTotalCount++;
			}
		}
	}

	public boolean isEmpty() {
		return messageTotalCount == 0;
	}
}

MessageListView를 완성하기 위해선 위의 6가지 정보 + List<Message> messageList만 채우면 된다!

방명록 보기 이벤트 - GetMessageListService

MessageListView를 만들기 위해 위의 여러 정보를 얻는 과정이 MessageListViewgetMessageList()메서드에 모두 있다.

우선 현재 페이지 넘버 currentPageNumber는 사용자로부터 넘겨받는 정보이고 페이지당 표시할 메세지 개수는 MESSAGE_COUNT_PER_PAGE = 4로 정해두었다.

그리고 messageDao.selectCount(conn)를 통해 전체 페이지 개수를 얻어오고 firstRowendRow 계산후 messageDao.selectList(conn, firstRow, endRow)를 통해 List<Message> messageList를 얻어온다.

마지막으로 페이지 개수는 MessageListView생성자 호출시 calculatePageTotalCount()메서드가 계산하여 pageTotalCount에 대입한다.

public class GetMessageListService {
	private static GetMessageListService instance = new GetMessageListService();

	public static GetMessageListService getInstance() {
		return instance;
	}

	private GetMessageListService() {
	}

	private static final int MESSAGE_COUNT_PER_PAGE = 4;

	public MessageListView getMessageList(int pageNumber) {
		Connection conn = null;
		int currentPageNumber = pageNumber;
		try {
			conn = ConnectionProvider.getConnection();
			MessageDao messageDao = MessageDao.getInstance();

			int messageTotalCount = messageDao.selectCount(conn);

			List<Message> messageList = null;
			int firstRow = 0;
			int endRow = 0;
			if (messageTotalCount > 0) {
				firstRow = (pageNumber - 1) * MESSAGE_COUNT_PER_PAGE + 1 ;
				endRow = firstRow + MESSAGE_COUNT_PER_PAGE - 1;
				System.out.println("firstRow : " +firstRow);
				System.out.println("endRow : " +endRow);
				messageList = messageDao.selectList(conn, firstRow, endRow);
			} else {
				currentPageNumber = 0;
				messageList = Collections.emptyList();
			}
			return new MessageListView(messageList,
					messageTotalCount, currentPageNumber,
					MESSAGE_COUNT_PER_PAGE, firstRow, endRow);
		} catch (SQLException | NamingException e) {
			throw new ServiceException("목록 구하기 실패: " + e.getMessage(), e);
		} finally {
			JdbcUtil.close(conn);
		}
	}
}

직접만든 ServiceException 예외객체를 throw하긴 하지만

public class ServiceException extends RuntimeException {

	public ServiceException(String string, Exception e) {
	}
}

GetMessageListHandler에서 따로 예외처리 작업은 하지 않았다.

방명록 보기 이벤트 - list.jsp

마지막으로 입력받은 방명록을 보여줄 View역할을 하는 list.jspMessageListView를 출력하는 작업을 해보자.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="message.service.MessageListView"%>
<%@ page import="message.model.Message"%>
<%@ page import="message.service.GetMessageListService"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
	<title>방명록 메시지 목록</title>
</head>
<body>

<form action="/jspPro/message/write.do" method="post">
이름: <input type="text" name="guest_name"> <br>
암호: <input type="password" name="password"> <br>
메시지: <textarea name="message" cols="30" rows="3"></textarea> <br>
<input type="submit" value="메시지 남기기" />
</form>
<hr>
<c:if test="${viewData.isEmpty()}">
등록된 메시지가 없습니다.
</c:if>

<c:if test="${!viewData.isEmpty()}">
<table border="1">
	<c:forEach var="message" items="${viewData.messageList}">
		<tr>
			<td>
			메시지 번호: ${message.message_id} <br/>
			손님 이름: ${message.guest_name} <br/>
			메시지: ${message.message} <br/>
			<a href="/jspPro/message/delete.do?messageId=${message.message_id}">[삭제하기]</a>
			</td>
		</tr>
	</c:forEach>
</table>

<c:forEach var="pageNum" begin="1" end="${viewData.pageTotalCount}">
	<a href="/jspPro/message/list.do?page=${pageNum}">[${pageNum}]</a> 
</c:forEach>

</c:if>
</body>
</html>

image46

방명록 삭제 이벤트 - DeleteMessageHandler

위의 list.jsp[삭제하기] a태그를 누르면 아래 url을 요청한다.
message/delete.do?messageId=${message.message_id}
(고유 ID인 message_id를 통해 삭제요청을 함)

삭제의 경우 get방식, post방식에 따라 포워딩 시키는 jsp페이지가 달라진다.

만약 get방식이라면 비밀번호 입력페이지인 /view/comfirmDeletion.jsp로 바로 포워딩 시킨다.

<!-- comfirmDeletion.jsp -->
<%@ page contentType="text/html; charset=utf-8" %>
<html>
<head>
    <title>방명록 메시지 삭제 확인</title>
</head>
<body>

<form action="/jspPro/message/delete.do" method="post">
<input type="hidden" name="messageId" value="${param.messageId}">
메시지를 삭제하시려면 암호를 입력하세요:<br>
암호: <input type="password" name="password"> <br>
<input type="submit" value="메시지 삭제하기">
</form>
</body>
</html>

아주 간단한 페이지, 암호를 입력하고 /message/delete.do url에 post방식으로 요청한다.

<input type="hidden" name="messageId" value="${param.messageId}">을 통해 메세지 ID를 유지시킨다.

위 사황에서 submit하게 된다면 messageIdpassword가 서버에 post된다.

public class DeleteMessageHandler implements CommandHandler{
	private static final String FORM_VIEW = "/view/comfirmDeletion.jsp";
	@Override
	public String process(HttpServletRequest request, HttpServletResponse response) throws Exception {
		if (request.getMethod().equalsIgnoreCase("GET")) {
			System.out.println("LoginHandler preocess GET");
			return processForm(request, response);
		}
		else if (request.getMethod().equalsIgnoreCase("POST")) {
			System.out.println("LoginHandler preocess POST");
			return processSubmit(request, response);
		}
		else {
			response.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
			return null;
		}
	}
	private String processForm(HttpServletRequest request, HttpServletResponse response) {
		return FORM_VIEW;
	}
	private String processSubmit(HttpServletRequest request, HttpServletResponse response) {
		int messageId = Integer.parseInt(request.getParameter("messageId"));
		String password = request.getParameter("password");
		boolean invalidPassowrd = false;
		try {
			DeleteMessageService deleteService = 
					DeleteMessageService.getInstance();
			deleteService.deleteMessage(messageId, password);
		} catch(InvalidPassowrdException ex) {
			invalidPassowrd = true;
		} catch (Exception e) {
			e.printStackTrace();
		}
		request.setAttribute("invalidPassowrd", invalidPassowrd);
		return "/view/deleteMessage.jsp";
	}
}

DeleteMessageHandler는 post방식일 경우 DeleteMessageServicedeleteMessage(messageId, password)메서드를 호출하고
삭제 완료/실패를 알리는 /view/deleteMessage.jsp로 포워딩 시킨다.

<!-- deleteMessage.jsp -->
<%@ page contentType="text/html; charset=utf-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
	<title>방명록 메시지 삭제함</title>
</head>
<body>
<c:if test="${ invalidPassowrd != true }">
	메시지를 삭제하였습니다.
</c:if>
<c:if test="${ invalidPassowrd == true }">
	입력한 암호가 올바르지 않습니다. 암호를 확인해주세요.
</c:if>
<br/>
<a href="/jspPro/message/list.do">[목록 보기]</a>
</body>
</html>

메세지 비밀번호가 일치하지 않으면 request.setAttribute()메서드를 통해 invalidPassowrdtrue값을 담아 전달하는데 위의 deleteMessage.jsp에서도 invalidPassowrd를 확인하고 오류메세지를 출력한다.

방명록 삭제 이벤트 - DeleteMessageService

DeleteMessageService에선 메세지를 삭제시킬 메세지를 검새하기 위해 SQL문 messageDao.select(conn, messageId)를 호출하고
메세지가 없거나 입력받은 password가 다르다면 예외를 발생시킨다.

public class DeleteMessageService {

	private static DeleteMessageService instance = new DeleteMessageService();

	public static DeleteMessageService getInstance() {
		return instance;
	}

	private DeleteMessageService() {
	}

	public void deleteMessage(int messageId, String password) throws Exception {
		Connection conn = null;
		try {
			conn = ConnectionProvider.getConnection();
			conn.setAutoCommit(false);

			MessageDao messageDao = MessageDao.getInstance();
			Message message = messageDao.select(conn, messageId);
			if (message == null) {
				throw new MessageNotFoundException("메시지 없음");
			}
			if (!message.matchPassword(password)) {
				throw new InvalidPassowrdException("bad password");
			}
			messageDao.delete(conn, messageId);

			conn.commit();
		} catch (SQLException ex) {
			JdbcUtil.rollback(conn);
			throw new ServiceException("삭제 실패:" + ex.getMessage(), ex);
		} catch (InvalidPassowrdException | MessageNotFoundException | NamingException ex) {
			JdbcUtil.rollback(conn);
			throw ex;
		} finally {
			JdbcUtil.close(conn);
		}
	}
}

InvalidPassowrdException예외가 발생하면 rollback시키고 DeleteMessageHandler에 예외를 throw한다. InvalidPassowrdException는 예외처리를 해두었지만 MessageNotFoundException예외는 따로 예외처리를 하지 않았다.

따로 패스워드 불일치, 메세지 없음 예외가 발생하지 않는다면 messageDao.delete(conn, messageId)를 호출하고 실제 메세지를 삭제한다.

image57

https://github.com/Kouzie/Kouzie.github.io/tree/master/_posts/JSP/message

카테고리:

업데이트: