일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- Linux세팅
- Linux셋팅
- ObjectInputStream
- 스레드그룸
- include지시자
- sleep()메소드
- 표현 언어
- first-of-child
- 메모리스트림
- InputDialog
- include액션태그
- ID중복
- ThreadGroup()
- 동기화
- 상관서브쿼리
- Daemon()
- isinterrupted()
- StringWriter
- String char[] 형변환
- 리눅스셋팅
- StringReader
- MemoryStream
- interrupt()
- first-child
- 상관 서브 쿼리
- 리눅스세팅
- interrupted()
- include 지시자
- 아이디중복
- char[] String 형변환
- Today
- Total
다연이네
[days09] MVC패턴으로 방명록 만들기 본문
방명록 리스트 불러오기, 글 작성하기, 삭제하기, 수정하기
|
삭제 완료 후 리스트로 복귀 |
|
리스트에서 가장 우측의 [수정하기]를 클릭하면 |
수정 가능 |
[방명록 MVC패턴]
1. days09 폴더
ㄴ guestbook 폴더
ㄴ images 폴더
2. MV[C] 컨트롤러(서블릿)
days09. guestbook.controller.ControllerUsingURI
3. [M]VC 모델(로직 처리) ~~Handler
days09.guestbook.CommandHandler.java 인터페이스 String process()
.NullHandler.java 모델 (둘 다 지난번거 복사)
4. M[V]C JSP 페이지 (마지막에 만들자)
5-1. 테이블
1) 방명록 테이블 생성
create table guestbook_message
(
message_id number not null primary key
, guest_name varchar2(50) not null
, password varchar2(10) not null
, message clob not null
) ;
2) create sequence seq_guestbook_message;
5-2. DTO
days09.guestbook.model.Message.java
6-1. DAO
days09.guestbook.dao.MessageDao.java
6-2. DAO 클래스 안에서 Connection 객체에 접근하는 방법
1) DAO 클래스의 메소드 안에서 직접 Connection 객체 생성
insert() 방명록 쓰는 Connection con = ConnectionProvider.getConnection();
selectList() 방명록 가져오는 Connection con = ConnectionProvider.getConnection();
delete() 방명록 삭제하는 Connection con = ConnectionProvider.getConnection();
=> 매번 그 안에서 con 생성, 소멸
2) DAO 객체를 생성할 때 [생성자]로 Connection 객체를 주입받기 (DI)
3) DAO 클래스의 메소드의 파라미터로 Connection 객체를 주입받기(DI) (이번엔 이거 쓰겠다)
7. Service : 사용자의 요청 -> 처리하는 객체(DAO) == Model
days09.guestbook.service 패키지
1) GetMessageListService.java : 방명록 목록 반환 서비스 객체
8. DBCP (커넥션 풀) 사용
com.util.ConntectionProvider 안의 getConnection(){} 호출
9.
finally{
try{
rs.close(), pstmt.close(), con.close()
catch{
반복적으로 들어가져 있기 때문에 아예
rs, pstmt, con을 닫아주는 라이브러리를 생성해서 간단히 사용하도록 하자
com. util. JdbcUtil 클래스
10. web. xml
컨트롤러 서블릿 등록 days09.guestbook.controller.ControllerUsingURI
1. ex03.jsp
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="">
<style>
</style>
<script>
$(document).ready(function (){
});
</script>
</head>
<body>
<a href="/jspPro/days09/guestbook/list.do">방명록 목록</a>
</body>
</html>
2. 컨트롤러 days09.guestbook.controller.ControllerUsingURI
package days09.guestbook.controller;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import days09.guestbook.controller.CommandHandler;
public class ControllerUsingURI extends HttpServlet{
@Override
public void destroy() {
// 웹 컨테이너 안에서 생성된 서블릿이 제거될때 호출되는 메소드
}
private Map<String, CommandHandler> commandHandlerMap =
new HashMap<String, CommandHandler>();
@Override
public void init() throws ServletException {
String path = getInitParameter("path");
String configFilePath = getServletContext().getRealPath(path);
Properties prop = new Properties();
try(FileReader fr = new FileReader(configFilePath)) {
prop.load(fr); //자동으로 프로퍼티에 로딩
} catch (Exception e) {
throw new ServletException(e);
}
//prop -> commandHandlerMap 맵 채워넣는 작업
Iterator<Object> ir = prop.keySet().iterator();
while (ir.hasNext()) {
String url = (String) ir.next(); //요청한 url : "/hello.do" key값
String handlerClassFullName = prop.getProperty(url); // "days08.mvc.hello.HelloHandler"
try {
Class<?> handlerClass = Class.forName(handlerClassFullName); //물리적인 클래스 파일명을 인자로 넣어주면 해당하는 클래스를 반환
CommandHandler handlerInstance = (CommandHandler)handlerClass.newInstance();
this.commandHandlerMap.put(url, handlerInstance);
//요청이 들어오면 맵을 뒤져 어떤 요청인지 확인 가능하게 됐다
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
throw new ServletException(e);
}
}
}//init
@Override
protected void doGet(HttpServletRequest request
, HttpServletResponse response) throws ServletException, IOException {
String requestURI = request.getRequestURI();
//System.out.println(requestURI); // "/jspPro/hello.do"
String contextPath = request.getContextPath(); // "/jspPro"
if( requestURI.indexOf(contextPath)==0) { //요청 url이 그 contextPath로 시작하더라
int beginIndex = contextPath.length();
requestURI = requestURI.substring(beginIndex); //앞에 /jspPro 잘림 (endIndex 안주면 끝까지)
}
CommandHandler handler = this.commandHandlerMap.get(requestURI);
//일 시켜야 함
//M[View]C == JSP 페이지를 돌려줌
String viewPage = null;
try {
viewPage = handler.process(request, response);
} catch (Exception e) {
e.printStackTrace();
}
if(viewPage!=null) {
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPage);
dispatcher.forward(request, response);
}
}//doGet
@Override
protected void doPost(HttpServletRequest request
, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}//doPost
}//class
2 + web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>jspPro</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>guestListController</servlet-name>
<servlet-class>days09.guestbook.controller.ControllerUsingURI</servlet-class>
<init-param><!-- 경로가 바뀌어도 수정하기 쉽게 -->
<param-name>path</param-name>
<param-value>/days09/guestbook/commandHandler.properties</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>guestListController</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<filter> <!-- 이 필터를 거친 후 밑 필터를 거친다 (필터체인 이렇게 일어남) -->
<filter-name>EncodingFilter</filter-name>
<filter-class>com.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value> <!--나중에 이 값만 바꾸면 됨 -->
</init-param>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern> <!-- 모든 -->
</filter-mapping>
<resource-ref>
<description>Oracle Datasource example</description>
<res-ref-name>jdbc/myoracle</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</web-app>
2 + commandHandler.properties
# Request = Model
/days09/guestbook/list.do=days09.guestbook.command.GetMessageListHandler
/days09/guestbook/write.do=days09.guestbook.command.WriteMessageHandler
/days09/guestbook/deleteMessage.do=days09.guestbook.command.DeleteMessageHandler
/days09/guestbook/updateMessage.do=days09.guestbook.command.UpdateMessageHandler
3. 모델 - 리스트 출력 days09.guestbook.command.GetMessageListHandler
package days09.guestbook.command;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import days09.guestbook.controller.CommandHandler;
import days09.guestbook.service.GetMessageListService;
import days09.guestbook.service.MessageListView;
public class GetMessageListHandler implements CommandHandler { //days09 commandHandler (실수하면 안됨)
@Override
public String process(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println(">GetMessageListHandler.process() 호출..");
String pCurrentPage = request.getParameter("page");
int currentPage = 1;
if(pCurrentPage!=null) {
currentPage = Integer.parseInt(pCurrentPage);
}
//싱글톤
GetMessageListService messageListService
= GetMessageListService.getInstance();
MessageListView viewData = messageListService.getMessageList(currentPage);
request.setAttribute("viewData", viewData);
//원래는 2개 담았는데 전부 다를 하나에 담는 것이 이 클래스의 목적
return "/days09/guestbook/list.jsp";
}
}
3. 모델 - 글쓰기 days09.guestbook.command.WriteMessageHandler
package days09.guestbook.command;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import days09.guestbook.controller.CommandHandler;
import days09.guestbook.model.Message;
import days09.guestbook.service.WriteMessageService;
public class WriteMessageHandler implements CommandHandler {
@Override
public String process(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println(">write.do 요청 :WriteMessageHandler.process()호출됨.. ");
//결과물이 있다면 request에 담고
//redirect /forward 시키는 것이 주 목적
String guest_name = request.getParameter("guest_name");
String password = request.getParameter("password");
String message = request.getParameter("message");
//서비스 DTO
Message msg = new Message();
msg.setGuest_name(guest_name);
msg.setPassword(password);
msg.setMessage(message);
//dto.setMessage_id(message_id);
//message_id는 자동으로 시퀀스로 증가
//WriteMessageService 클래스 만들기 (만들고 와서 마지막에 여기와서 추가)
WriteMessageService messageService = WriteMessageService.getInstance();
messageService.write(msg);
//글을 쓰고 난 후 어디로 가야할까?
//list.do 요청을 해야 한다.
//주의) list.jsp주면 단순히 list.jsp만 뿌려질 것이다.(컨트롤러 안거치기 때문에 게시글 없음)
//그게 아니라 list.do 로 요청이 되어져야지 해당 요청에 의해 컨트롤러 응답받고 거쳐
//list.jsp 요청 못하도록 처리해야한다. WEB_INF > views 폴더 생성 이동
//list.do를 요청할건데 포워딩?리다이렉트?
//보여지긴 보여지는데 write.do(포워딩)가 있는게 낫겠냐 list.do(리다이렉트)가 있는게 낫겠냐?
// list.do가 낫겠다. => [리다이렉트] 하자
String location = "list.do";
response.sendRedirect(location);
return null;
//무조건 포워딩 할게 아니라 리다이렉트할 때도 있다는 것 기억, 클래스 타입으로 return하는 것
//리턴타입이 String이 아니라 객체여야함
}
}
3. 모델 - 글삭제 days09.guestbook.command.DeleteMessageHandler
package days09.guestbook.command;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import days09.guestbook.controller.CommandHandler;
import days09.guestbook.model.Message;
import days09.guestbook.service.DeleteMessageService;
//파라미터 deleteMessage.do?message_id=1&password=1234;
public class DeleteMessageHandler implements CommandHandler {
@Override
public String process(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println(">deleteMessage.do 요청 : DeleteMessageHandler.process() 호출..");
int messageId = Integer.parseInt(request.getParameter("messageId"));
String password = request.getParameter("password");
//누군가가 악의적으로 url 뒷부분 입력하면 삭제된다 => post로 가든
// 어딘가에 표시가 되어있지 않으면 아무 브라우저 보지도 않는 페이지 입력하면 삭제 일어남
//웹보안
//System.out.println(message_id+"/"+password);
//만들고오기
DeleteMessageService deleteMessageService = DeleteMessageService.getInstance();
deleteMessageService.delete(messageId, password);
response.sendRedirect("list.do?delete=success");
//delete.do 요청은 안보이고 list.do가 보여야하니 redirect
return null;
}
}
3. 모델 - 글수정 days09.guestbook.command.UpdateMessageHandler
package days09.guestbook.command;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import days09.guestbook.controller.CommandHandler;
import days09.guestbook.model.Message;
import days09.guestbook.service.GetMessageListService;
import days09.guestbook.service.UpdateMessageService;
public class UpdateMessageHandler implements CommandHandler {
@Override
public String process(HttpServletRequest request, HttpServletResponse response) throws Exception {
//수정할 수 있도록 입력받을 준비 해야하며, 입력버튼 누르면 db에 저장
//수정할 페이지로 넘겨줘야함 수정할 글번호의 내용을 담아서 페이지에 뿌려서 원래값은 보여지고
//원래값에서 수정받은 값을 저장
//GET
//POST 다르다
//GET - 수정 페이지 (a태그로 요청하면 입력폼을 뿌려줘야함 )
//POST - 수정 페이지에서 입력한 값들을 db에 update한 후 list.do로 이동
Message msg = new Message();
if(request.getMethod().equalsIgnoreCase("GET")) {
//updateMessage.do?messageId=2
//수정 페이지
System.out.println(">updateMessage.do 요청 : UpdateMessageHandler.process() GET 호출..");
int messageId = Integer.parseInt(request.getParameter("messageId"));
GetMessageListService messageService = GetMessageListService.getInstance();
Message message = messageService.getMessage(messageId); //클릭해서 메소드 만들기
//null이 넘어오면 존재하지 않는 글 => 목록으로 뿌려라 (일단 제외)
request.setAttribute("message", message);
//getMessage메소드 다 만든 후 update.jsp 파일 추가
return "/days09/guestbook/update.jsp";
}else if(request.getMethod().equalsIgnoreCase("POST")) {
// 수정 페이지에서 입력한 값들을 db에 update한 후 list.do로 이동
System.out.println(">updateMessage.do 요청 : UpdateMessageHandler.process() POST 호출..");
//int message_id = Integer.parseInt(request.getParameter("message_id"));
//disabled는 파라미터로 안넘어옴
//2째 방법 : update.jsp의 form action에 ?message_id= 달고가기
int message_id = Integer.parseInt(request.getParameter("h_id"));
String guest_name = request.getParameter("guest_name");
String password = request.getParameter("password");
String message = request.getParameter("message");
//서비스 DTO
msg.setMessage_id(message_id);
msg.setGuest_name(guest_name);
msg.setPassword(password);
msg.setMessage(message);
}//if
UpdateMessageService messageService = UpdateMessageService.getInstance();
messageService.update(msg);
String location = "list.do";
response.sendRedirect(location+"?update=success");
return null;
}
}
3 + 모델이 implement할 인터페이스
days09.guestbook.controller.CommandHandler
package days09.guestbook.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//로직을 처리할 모델(Model)객체가 공통적으로 구현할 인터페이스
public interface CommandHandler {
public String process( HttpServletRequest request
, HttpServletResponse response ) throws Exception ;
}
3 + Null을 처리할 모델
days09.guestbook.controller.NullHandler
package days09.guestbook.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class NullHandler implements CommandHandler{
@Override
public String process(HttpServletRequest request, HttpServletResponse response) throws Exception {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return null;
}
}
4. JSP (마지막에 생성)
5. DB 테이블, 시퀀스 생성
6. DTO days09.guestbook.model.Message
package days09.guestbook.model;
//방명록 DTO
public class Message {
//fileds
private int message_id;
private String guest_name;
private String password;
private String message;
//getter-setter
public int getMessage_id() {
return message_id;
}
public void setMessage_id(int message_id) {
this.message_id = message_id;
}
public String getGuest_name() {
return guest_name;
}
public void setGuest_name(String guest_name) {
this.guest_name = guest_name;
}
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;
}
//추가
public boolean hasPassword() {
return password != null && !password.isEmpty();
}
public boolean matchPassword(String pwd) {
return password != null && !password.equals(pwd);
}
}
7. DAO days09.guestbook.dao.MessageDao
package days09.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 com.util.ConnectionProvider;
import com.util.JdbcUtil;
import days09.guestbook.model.Message;
//싱글톤 (매번 dao만들 필요 없이 한번만 만들면 됨)
public class MessageDao {
private static MessageDao messageDao = new MessageDao();
private MessageDao() {} //생성자의 접근지정자가 private라 바로 객체 생성 못하게 막기
/* 2. 생성자를 통한 Connection 객체 주입 (전달)
- 트랜잭션 처리 가능
- 매번 서비스 클래스 -> DAO 객체 새로 생성한다는 단점 (지금은 싱글톤이기때문에 매번 생성하지 않아도 됨)
private Connection con = null;
private MessageDao(Connection con) {
this.con = con;
}
*/
public static MessageDao getInstance() {
return messageDao;
}//getInstance
/* 1. 일일히 생성~소멸
public int insert() {
Connection con = ConnectionProvider.getConnection();
}
public List<Message> selectList(){
Connection con = ConnectionProvider.getConnection();
}
*/
//3. 파라미터로 Connection 객체를 주입받기
//방명록 쓰기
public int insert(Connection con, Message message) throws SQLException{
PreparedStatement pstmt = null;
String sql = "insert into guestbook_message " +
" (message_id, guest_name, password, message) "+
" values (seq_guestbook_message.nextval, ?, ?, ? ) ";
try {
pstmt = con.prepareStatement(sql);
pstmt.setString(1, message.getGuest_name());
pstmt.setString(2, message.getPassword());
pstmt.setString(3, message.getMessage());
return pstmt.executeUpdate();
} finally { //예외는 throws를 통해 넘어갈거라 필요x
JdbcUtil.close(pstmt);
}
}
//총 방명록 게시글 수 반환하는 메소드
public int selectCount(Connection conn) throws SQLException { //예외 발생시 떠넘겨 => GetMessageListServiced 의 catch에 잡혀 예외메시지 출력
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 {
String sql = " select * ";
sql+= " from ( ";
sql+= " select rownum no, t.* ";
sql+= " from ( ";
sql+= " select * ";
sql+= " from guestbook_message ";
sql+= " order by message_id desc ";
sql+= " ) t ";
sql+= " ) b ";
sql+= " where b.no between ? and ? ";
//검색은 안되는 쿼리
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, firstRow );
pstmt.setInt(2, endRow );
rs = pstmt.executeQuery();
if (rs.next()) {
List<Message> messageList = new ArrayList<>();
do {
messageList.add(makeMessageFromResultSet(rs)); //do~while dto 채워넣기 함수로 만듦(반복때문)
} while (rs.next());
return messageList;
} else {
return Collections.emptyList(); //null 돌리는 것과 같음
}
} finally {
JdbcUtil.close(rs);
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;
}
public Message select(Connection con, int message_id) throws SQLException {
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
pstmt = con.prepareStatement(
"select * from guestbook_message "
+ " where message_id = ?");
pstmt.setInt(1, message_id);
rs = pstmt.executeQuery();
if (rs.next()) {
// makeMessageFromResultSet() 프로젝트 선언해서 사용.
return makeMessageFromResultSet(rs);
} else {
return null;
}
} finally {
JdbcUtil.close(rs);
JdbcUtil.close(pstmt);
}
}
public int delete(Connection con, int message_id) throws SQLException {
PreparedStatement pstmt = null;
try {
pstmt = con.prepareStatement(
"delete from guestbook_message "
+ " where message_id = ?");
pstmt.setInt(1, message_id);
return pstmt.executeUpdate();
} finally {
JdbcUtil.close(pstmt);
}
}
public int update(Connection con, Message message) throws SQLException {
String sql = "update guestbook_message "+
" set message=?, guest_name=? "+
" where message_id=? and password=? ";
PreparedStatement pstmt = null;
int rowCount = 0;
try {
pstmt = con.prepareStatement(sql);
pstmt.setString(1, message.getMessage());
pstmt.setString(2, message.getGuest_name());
pstmt.setInt(3, message.getMessage_id());
pstmt.setString(4, message.getPassword());
rowCount = pstmt.executeUpdate();
} finally {
JdbcUtil.close(pstmt);
// JdbcUtil.close(con); service에서 close하고있으니 여기서 필요x
}
return rowCount;
}
}//class
8. Service - 리스트 출력 서비스 days09.guestbook.service.GetMessageListService
package days09.guestbook.service;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Collections;
import java.util.List;
import javax.naming.NamingException;
import com.util.ConnectionProvider;
import com.util.JdbcUtil;
import days09.guestbook.dao.MessageDao;
import days09.guestbook.model.Message;
//싱글톤
public class GetMessageListService {
private GetMessageListService() {}
private static GetMessageListService instance = new GetMessageListService();
public static GetMessageListService getInstance() {
return instance;
}
//한 페이지에 방명록 출력 개수
private static final int MESSAGE_COUNT_PER_PAGE = 3;
//매개변수: 현재 페이지 pageNumber
//리턴타입: MessageListView
public MessageListView getMessageList(int pageNumber) {
Connection conn = null;
int currentPageNumber = pageNumber;
try {
// DBConn.getConnectionn();
conn = ConnectionProvider.getConnection();
// dao 객체 생성
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;
// dao.selectList() 해당 페이지의 방명록을 select
messageList =
messageDao.selectList(conn, firstRow, endRow);
} else {
currentPageNumber = 0;
messageList = Collections.emptyList(); //null주는거랑 똑같다
}
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);
}
}
public Message getMessage(int messageId) {
Connection con = null;
Message message = null;
try {
con = ConnectionProvider.getConnection();
MessageDao messageDao = MessageDao.getInstance();
message = messageDao.select(con, messageId);
}catch (Exception e) {
throw new ServiceException("메시지 구하기 실패: " + e.getMessage(), e);
} finally {
JdbcUtil.close(con);
}
return message;
}//
}//class
8 + days09.guestbook.service.MessageListView (리스트 출력시 필요)
package days09.guestbook.service;
import java.util.List;
import days09.guestbook.model.Message;
//days05.pageBlock + ArrayList<board> 모두를 담을 수 있는 클래스를 만들겠다
//list따로 pageBlock 따로 setAttribute 하지 않고 한번에 하도록
public class MessageListView {
//이 클래스를 왜 만드는지 ?
//누군가가 방명록 목록을 보겠다 요청 (ex02 링크태그 클릭)
//-> 모든 *.do 요청 -> 컨트롤러가 요청 받아 (web.xml에 컨트롤러 등록되어있는지 확인 필수)
//
private List<Message> messageList; //방명록 목록을 저장할 ArrayList
private int messageTotalCount; //총 방명록 글 수
private int pageTotalCount; //총 페이지 수
private int currentPageNumber; //현재 페이지 번호
private int messageCountPerPage; //한 페이지에 출력할 방명록 글 수
private int firstRow; //시작
private int endRow; //끝
//생성자
public MessageListView(
List<Message> messageList,
int messageTotalCount,
int currentPageNumber,
int messageCountPerPage,
int firstRow, int endRow) {
this.messageList = messageList;
this.messageTotalCount = messageTotalCount;
this.currentPageNumber = currentPageNumber;
this.messageCountPerPage = messageCountPerPage;
this.firstRow = firstRow;
this.endRow = endRow;
//총 페이지 수를 계산하는 메소드
calculatePageTotalCount();
}
// 총 페이지 수를 계산해서 반환하는 메소드
private void calculatePageTotalCount() {
if(messageTotalCount==0) {
pageTotalCount = 0;
}else {
pageTotalCount =(int) Math.ceil( (double)messageTotalCount/messageCountPerPage);
}
}
//getter만 만들기
public List<Message> getMessageList() {
return messageList;
}
public int getMessageTotalCount() {
return messageTotalCount;
}
public int getPageTotalCount() {
return pageTotalCount;
}
public int getCurrentPageNumber() {
return currentPageNumber;
}
public int getMessageCountPerPage() {
return messageCountPerPage;
}
public int getFirstRow() {
return firstRow;
}
public int getEndRow() {
return endRow;
}
//추가
public boolean isEmpty() {
return this.messageTotalCount==0;
}
}//class
8. Service - 글쓰기 서비스 days09.guestbook.service.GetMessageListService
package days09.guestbook.service;
import java.sql.Connection;
import com.util.ConnectionProvider;
import com.util.JdbcUtil;
import days09.guestbook.dao.MessageDao;
import days09.guestbook.model.Message;
//싱글톤
public class WriteMessageService {
private static WriteMessageService instance = new WriteMessageService();
public static WriteMessageService getInstance() {
return instance;
}
private WriteMessageService() {}
//위에 3개가 싱글톤
public int write(Message message) { //dto == message
Connection con = null;
int rowCount = 0; //영향받은 레코드 수
try {
con = ConnectionProvider.getConnection();
MessageDao dao = MessageDao.getInstance();
rowCount = dao.insert(con, message);
} catch (Exception e) {
throw new ServiceException(">메시지 등록 실패 : "+e.getMessage(), e);
}finally {
JdbcUtil.close(con);
}
return rowCount;
}
}
8. Service - 글 삭제서비스 days09.guestbook.service.GetMessageListService
package days09.guestbook.service;
import java.sql.Connection;
import com.util.ConnectionProvider;
import com.util.JdbcUtil;
import days09.guestbook.dao.MessageDao;
import days09.guestbook.model.Message;
//싱글톤
public class DeleteMessageService {
private static DeleteMessageService instance = new DeleteMessageService();
public static DeleteMessageService getInstance() {
return instance;
}
private DeleteMessageService() {}
//윗줄 싱글톤
//많은 데이터가 넘어온다면 Message message 매개변수로 주면 된다. (하나 담아서 dto로 넘겨주면 되니까)
public int delete(int message_id, String password) {
Connection con = null;
int rowCount = 0; //영향받은 레코드 수
try {
con = ConnectionProvider.getConnection();
MessageDao dao = MessageDao.getInstance();
//내가 삭제하러갔는데 관리자가 이미 삭제했을수도 있다 (게시글이 없을수도 있다)
// dao.select 만들기 - 마우스 올려
Message message = dao.select(con, message_id); //게시글 정보를 가져오는 메소드
if (message==null) {
throw new MessageNotFoundException("해당 메시지가 없습니다");
}
if(!message.matchPassword(password)){
throw new InvalidPasswordException("비밀번호가 일치하지 않습니다");
}
//dao.delete메소드 만들기 - 마우스 올려
rowCount = dao.delete(con, message_id);
}catch(InvalidPasswordException | MessageNotFoundException e) {
JdbcUtil.rollback(con);
throw e; //예외 재발생시켜 떠넘기기
}
catch (Exception e) {
throw new ServiceException(">메시지 삭제 실패 : "+e.getMessage(), e);
}finally {
JdbcUtil.close(con);
}
return rowCount;
}
}
8. Service - 글 수정 서비스 days09.guestbook.service.GetMessageListService
package days09.guestbook.service;
import java.sql.Connection;
import com.util.ConnectionProvider;
import com.util.JdbcUtil;
import days09.guestbook.dao.MessageDao;
import days09.guestbook.model.Message;
//싱글톤
public class UpdateMessageService {
private static UpdateMessageService instance = new UpdateMessageService();
public static UpdateMessageService getInstance() {
return instance;
}
private UpdateMessageService() {}
//싱글톤
public int update(Message message) {
Connection con = null;
int rowCount = 0;
try {
con = ConnectionProvider.getConnection();
MessageDao dao = MessageDao.getInstance();
//update클릭해서 만들기
rowCount = dao.update(con, message);
} catch (Exception e) {
throw new ServiceException("메시지 수정 실패 : "+e.getLocalizedMessage(), e);
}finally {
JdbcUtil.close(con);
}
return rowCount;
}
}
8 + 사용자 정의 예외 클래스 days09.guestbook.service 패키지 속
ServiceException
package days09.guestbook.service;
//사용자 정의 예외 클래스
public class ServiceException extends RuntimeException{
public ServiceException(String message) {
super(message);
}
public ServiceException(String message, Exception e) {
super(message, e);
}
}
MessageNotFoundException
package days09.guestbook.service;
//사용자 정의 예외 클래스
public class MessageNotFoundException extends ServiceException{
public MessageNotFoundException(String message) {
super(message);
}
}
InvalidPasswordException
package days09.guestbook.service;
//사용자 정의 예외 클래스
public class InvalidPasswordException extends ServiceException{
public InvalidPasswordException(String message) {
super(message);
}
}
9. list.jsp
<%@ page import="days09.guestbook.model.Message"%>
<%@ page import="days09.guestbook.service.MessageListView"%>
<%@ page import="days09.guestbook.service.GetMessageListService"%>
<%@ page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>방명록 메시지 목록</title>
<style>
/*
데이터는 있으나 list페이지가 원하는 결과가 안나온다면
컨트롤러를 열어 요청이 들어왔을때 요청을 체크해서 맵 안에서 체크해서 핸들러에 담긴 것 보고
핸들러로 가 프로세스 확인 -> viewData를 request.setAttribute를 담으니 이 것 확인
viewPage에 담겨 포워딩
viewData가 담겨짐 ->
결론 : MessageListView viewData 확인 -> 서비스의 겟메세지로 가서 메세지리스트 확인
-> 안넘어온다면 dao 잘 돌려주고 있는지 담아서 돌려주는지 확인
*/
body, * {
font-size: 12px;
}
input[type=text], textarea {
border: solid 1px gray;
}
.in {
/* color: green; */
}
a {
text-decoration: none;
}
a:hover {
color: black;
}
</style>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 모달창(삭제하기) -->
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script
src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script>
// window.onload = function (){}
$(function() {
// 방명록 열기 닫기 버튼을 클릭
$("#btnWrite").click(function (){
$("#write_box").slideToggle("slow"
, function (){ // 열기, 닫기 작업 된 후에 function() 호출
$("#btnWrite").val(
$("#btnWrite").val().indexOf("열기") != -1
?"방명록 쓰기 닫기":"방명록 쓰기 열기");
});
});
$('tr:even').css({
'background' : 'gray',
'color' : 'white'
});
$(':input').first().focus();
// 클래스명이 btnDelete 을 클릭할 때.....
$(".btnDelete").click(function(){
// 삭제 게시글의 실제 비밀번호를 js 변수
del_password = $(this).attr('alt'); // 비밀번호
del_messageId = $(this).attr('name'); // PK
// 모달창 띄우는 함수 : modal()
$("#myModal").modal({backdrop: "static"});
$("#myModal").on('shown.bs.modal', function () {
$('#password').focus();
});
});
$('#myModal > div').css({
"width":"400px"
,"top":'150px'
,"margin":'0 auto'
});
//
var del_messageId, del_password ;
$('#btnDeleteGo').click(function (){
// 삭제하기 위해 입력한 비밀번호 $('#password').val()
if( $('#password').val() != del_password){
alert(' 비밀번호 틀림!!!');
return;
}
//비밀번호가 맞으면
location.href=
"deleteMessage.do?messageId="+
del_messageId+"&password="+del_password;
});
// 수정하기
$('.btnEdit').click(function (){
//alert($(this).parents('tr').prev().css({"display":"none"}));
alert( $(this).parents('tr').prev().find(".m_message").html());
});
});
</script>
</head>
<body>
<div style="text-align: center">
<input type="button" id="btnWrite" value="방명록 쓰기 열기" />
</div>
<hr>
<!-- list.jsp write_box -->
<div id="write_box" style="display: none;">
<form action="/jspPro/days09/guestbook/write.do" method="post">
<div
style="text-align:center;border: solid 1px gray; width: 270px; margin: 0 auto; padding: 10px">
<h3>방명록<span class="glyphicon glyphicon-heart-empty"></span></h3>
이름 : <input type="text" name="guest_name" class="in"><br>
암호 : <input type="text" name="password" class="in"><br>
<!-- 위 name속성값들은 항상 dto의 필드명 (==db의 컬럼명)과 맞추기(가능하면) -->
메시지 :<br>
<textarea rows="3" style="width:75%" name="message" class="in"></textarea>
<br> <input type="submit" value="메시지 남기기">
</div>
</form>
</div>
<hr>
<div id="gm_box"
style="border: solid 1px gray; width: 270px; margin: 0 auto; padding: 10px">
<c:if test="${ empty viewData.messageList }">
등록된 메시지가 없습니다.
</c:if>
<c:if test="${ not viewData.isEmpty() }">
<table border="1" width="250px">
<c:forEach items="${ viewData.messageList }" var="message">
<tr>
<td>
<div style="position: relative;">
메시지ID : <span class="m_id">${message.message_id }</span> <br>
손님 이름 : <span class="m_name">${message.guest_name }</span>
<img src="./images/${message.guest_name }.gif" alt="" style="height:100%;position:absolute;right:0;top:0;" />
<br>
메시지 : <span class="m_message">${ message.message }</span><br>
</div>
</td>
</tr>
<tr>
<td align="center">
<!-- alt 속성에 실제 그 글의 비밀번호 숨겨... -->
<input type="button" class="btnDelete"
name="${ message.message_id }" value="[삭제하기]"
alt="${ message.password }">
<input type="button" class="btnEdit"
name="${ message.message_id }" value="[수정하기]"
alt="${ message.password }">
<a href="updateMessage.do?messageId=${ message.message_id }">
[수정하기]
</a>
</td>
</tr>
</c:forEach>
</table>
<%-- 현재페이지 : ${ viewData.currentPageNumber }<br> --%>
<div style="text-align: center">
<c:forEach var="pageNum" begin="1" end="${ viewData.pageTotalCount }">
<c:if test="${ pageNum eq viewData.currentPageNumber }">
<span style='color: red'>${ pageNum }</span>
</c:if>
<c:if test="${ not (pageNum eq viewData.currentPageNumber) }">
<a href="list.do?page=${ pageNum }">${ pageNum }</a>
</c:if>
</c:forEach>
</div>
</c:if>
</div>
<!-- Modal -->
<div class="modal fade" id="myModal" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">방명록 삭제</h4>
</div>
<form action="deleteMessage.do" method="post">
<div class="modal-body">
<%-- <input type="hidden" name="messageId" value='${ param.messageId }'> --%>
<input type="hidden" name="message_id" value='${ param.message_id }'>
메시지를 삭제하시려면 암호를 입력하세요 : <br>
암호 : <input type="password" id="password" name='password'><br>
</div>
<div class="modal-footer">
<!-- <input type="submit" class="btn btn-default" value="메시지 삭제하기" alt=""> -->
<input type="button" id="btnDeleteGo" class="btn btn-default" value="메시지 삭제하기" alt="" style="font-size:10px">
<input type="button" class="btn btn-default" data-dismiss="modal" value="닫기" style="font-size:10px">
</div>
</form>
</div>
</div>
</div>
<!-- list.jsp -->
<script>
var error = <%= request.getParameter("error") %>;
if( error != null && error == 0){
alert("비밀번호가 잘못되어서 수정 못했습니다. ");
}
</script>
</body>
</html>
9. update.jsp
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="">
<style>
</style>
<script>
$(document).ready(function (){
});
</script>
</head>
<body>
<form action="/jspPro/days09/guestbook/updateMessage.do" method="post">
<div
style="text-align: center; border: solid 1px gray; width: 270px; margin: 0 auto; padding: 10px">
<h3>
방명록 수정<span class="glyphicon glyphicon-heart-empty"></span>
</h3>
ID : <input type="text" name="message_id" value="${ message.message_id}"
disabled="disabled" class="in"><br> <!-- disabled 속성을 주면 데이터 못넘긴다 (submit될 때 제출 안함) -->
이름 : <input type="text" name="guest_name" value="${ message.guest_name }" class="in"><br>
암호 : <input type="text" name="password" class="in"><br>
메시지 :<br>
<textarea rows="3" style="width: 75%" name="message" class="in">${ message.message }</textarea>
<br> <input type="submit" value="메시지 수정하기">
</div>
<input type="hidden" name="h_id" value="${ message.message_id }" /><br>
<input type="hidden" name="h_guestName" value="${ message.guest_name }" /><br>
<!-- hidden 태그는 왜 남겼을까 ? 얘네 값까지 가지고 넘어가야 하니까
원래이름, 원래 id를 숨겨서 가져가는구나 생각 -->
</form>
</body>
</html>
'JSP' 카테고리의 다른 글
[days10] 이론 - 답글을 달 수 있는 게시판(==계층형 게시판==답변형 게시판) (1) | 2021.01.07 |
---|---|
[days10] 프로젝트 초기 환경설정과 MVC 다시 정리 (0) | 2021.01.07 |
[days09] ServletContextListener (0) | 2021.01.06 |
[days09] 필터 - 모든 파일에 setCharacterEncoding("UTF-8"); (0) | 2021.01.06 |
[days09] 필터(Filter) (0) | 2021.01.06 |