일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 스레드그룸
- 메모리스트림
- isinterrupted()
- 표현 언어
- StringReader
- interrupted()
- 상관서브쿼리
- StringWriter
- interrupt()
- ThreadGroup()
- InputDialog
- Linux셋팅
- 리눅스세팅
- 리눅스셋팅
- first-child
- String char[] 형변환
- ObjectInputStream
- 상관 서브 쿼리
- include 지시자
- char[] String 형변환
- 아이디중복
- Linux세팅
- include액션태그
- include지시자
- Daemon()
- MemoryStream
- 동기화
- first-of-child
- ID중복
- sleep()메소드
- Today
- Total
다연이네
[days10] 코드 - 답글을 달 수 있는 게시판(==계층형 게시판==답변형 게시판) 본문
그냥 list.jsp, update.jsp, write.jsp를 실행시켜 파일을 실행시킬 수 없도록 폴더를 분산시켰다.
WebContent > days10 > ex01.jsp(a태그로 .do로 연결)
WebContent > WEB-INF > views > days10 > replyboard >
.jsp파일들과 .properties파일
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>ReplyboardController</servlet-name>
<servlet-class>days10.replyboard.controller.ControllerUsingURI</servlet-class>
<init-param>
<param-name>path</param-name>
<param-value>/WEB-INF/views/days10/replyboard/commandHandler.properties</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ReplyboardController</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>
commandHandler.properties
# Request = Model
/days10/replyboard/list.do=days10.replyboard.command.ListHandler
/days10/replyboard/write.do=days10.replyboard.command.WriteHandler
/days10/replyboard/view.do=days10.replyboard.command.ContentHandler
/days10/replyboard/delete.do=days10.replyboard.command.DeleteHandler
/days10/replyboard/edit.do=days10.replyboard.command.UpdateHandler
DTO - days10.replyboard.model.ReplyBoardDTO
package days10.replyboard.model;
import java.util.Date;
import days10.replyboard.service.GetListService;
public class ReplyBoardDTO {
//fields
private int num;
private String writer;
private String email;
private String subject; //제목
private String pass; //비밀번호
private int readcount; //조회수
private Date regdate; //등록일
private String content;
private String ip;
private int ref; //***그룹
private int step; //***그룹 내 순번
private int depth; //***깊이
//새로운 게시글일 경우 new 이미지 붙히기 위한 필드 추가 (db와 관련 없이)
private boolean newImg;
//getter-setter
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getWriter() {
return writer;
}
public void setWriter(String writer) {
this.writer = writer;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getPass() {
return pass;
}
public void setPass(String pass) {
this.pass = pass;
}
public int getReadcount() {
return readcount;
}
public void setReadcount(int readcount) {
this.readcount = readcount;
}
public Date getRegdate() {
return regdate;
}
public void setRegdate(Date regdate) {
this.regdate = regdate;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public int getRef() {
return ref;
}
public void setRef(int ref) {
this.ref = ref;
}
public int getStep() {
return step;
}
public void setStep(int step) {
this.step = step;
}
public int getDepth() {
return depth;
}
public void setDepth(int depth) {
this.depth = depth;
}
public boolean isNewImg() {
return newImg;
}
public void setNewImg(boolean newImg) {
this.newImg = newImg;
}
public boolean hasPassword() {
return pass!= null && !pass.isEmpty();
}
public boolean matchPassword(String pwd) {
return pass != null && pass.equals(pwd);
}
}
컨트롤러
days10.replyboard.controller.ControllerUsingURI
(
String prefix = "/WEB-INF/views/";
String suffix = ".jsp";
viewPage = String.format("%s%s%s", prefix ,viewPage, suffix);
수정
)
package days10.replyboard.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 days10.replyboard.command.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); //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) {
//Spring Framework - ViewResolver 객체가 자동으로 해준다
String prefix = "/WEB-INF/views/";
String suffix = ".jsp";
viewPage = String.format("%s%s%s", prefix ,viewPage, suffix);
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
모델(핸들러) + 서비스 + 뷰
인터페이스 - days10.replyboard.command.CommandHandler
package days10.replyboard.command;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//로직을 처리할 모델(Model)객체가 공통적으로 구현할 인터페이스
public interface CommandHandler {
public String process( HttpServletRequest request
, HttpServletResponse response ) throws Exception ;
}
널 처리 - dffdays10.replyboard.command.NullHandler
package days10.replyboard.command;
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;
}
}
리스트
핸들러 - days10.replyboard.command.ListHandler (글목록)
package days10.replyboard.command;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import days10.replyboard.model.ReplyBoardDTO;
import days10.replyboard.service.ListService;
public class ListHandler implements CommandHandler{
@Override
public String process(HttpServletRequest request, HttpServletResponse response) throws Exception {
//서비스 클래스 호출 -> DAO 호출
//결과물을 request.setAttribute()에 위에서 처리한 결과물 저장
//return값은 view로 사용할 JSP 페이지 경로
//리다이렉트(가로채기)하면 리턴문 안만나서 포워딩 안일어남
//아까 만들었고 단위테스트도 끝냈음
ListService service = ListService.getInstance();
List<ReplyBoardDTO> list = service.select();
request.setAttribute("list", list);
request.setAttribute("pageBlock", "[1] 2 3 4 5 6 7 8 9 10 >"); //페이징처리는 안했지만 저번에 블록으로 페이징 처리된 객체를 넘겼듯이
//페이징 처리했고, 1번페이지 보는중이라고 결과물 가정
//return "/WEB-INF/views/days10/replyboard/list.jsp"; /WEB-INF/views/매번쓰지 말자 컨트롤러 가서 viewPage 수정
return "days10/replyboard/list";
}
}
서비스 - days10.replyboard.service.ListService (글목록)
package days10.replyboard.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.DBConn;
import com.util.JdbcUtil;
import days09.guestbook.dao.MessageDao;
import days09.guestbook.model.Message;
import days09.guestbook.service.MessageListView;
import days09.guestbook.service.ServiceException;
import days10.replyboard.dao.ReplyBoardDAO;
import days10.replyboard.model.ReplyBoardDTO;
//싱글톤
public class ListService {
private ListService() {}
private static ListService instance = new ListService();
public static ListService getInstance() {
return instance;
}
public List<ReplyBoardDTO> select(){
Connection con = null;
try {
con = ConnectionProvider.getConnection();
// con = DBConn.getConnection(); //단위테스트 할땐 이걸로
ReplyBoardDAO dao = ReplyBoardDAO.getInstance();
List<ReplyBoardDTO> list = null;
list = dao.selectList(con);
return list;
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
JdbcUtil.close(con);
}
}//select
}//class
뷰- WEB-INF > views > days10 > replyboard > list.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>
a {
text-decoration: none;
color: black;
}
table, tr, td {
border:solid 1px gray;
border-radius: 3px;
padding: 5px;
font-size: 12px;
}
/*
tr.data:nth-last-child(odd) {
background: gray;
}
tr.data:nth-last-child(even) {
background: #EFEFEF;
}
*/
tr.data:hover {
background: #EFEFEF;
}
select , input{
vertical-align:middle;
}
</style>
<script>
$(function (){
$('#searchBtn').click(function (){
// jquery 사용하는 선택자 :first
// attr() 속성을 설정하거나 가져오는 함수
$('form:first').attr('action','list.do');
$('form:first').attr('method','get');
$('form:first').submit();
});
});
</script>
</head>
<body>
<h3 style="text-align: center;">계층형 게시판</h3>
<table style="width:700px;margin:50px auto" border="1" >
<tr>
<td align="right" colspan="6">
<a href="write.do">글쓰기</a>
<!-- <a href="/jspPro/days10/replyboard/write.do">글쓰기</a> -->
</td>
</tr>
<tr style="background:gray;color:white;font-weight:bold">
<td width="50" align="center">번호</td>
<td width="280" align="center">제 목</td>
<td width="100" align="center">작성자</td>
<td width="120" align="center">작성일</td>
<td width="50" align="center">조회</td>
<td width="100" align="center">IP</td>
</tr>
<tbody>
<!-- request.setAtttribute("list", ??); -->
<c:if test="${ empty list }">
<tr class="data">
<td align="center" colspan="6">
<h3>작성된 게시글이 없습니다.</h3>
</td>
</tr>
</c:if>
<c:if test="${ not empty list }">
<c:forEach items="${ list }" var="dto">
<tr class="data">
<td align="center">${ dto.num }</td>
<td>
<c:if test="${ dto.depth gt 0 }">
<img width="${ dto.depth*10 }px"/>
<img src="/jspPro/days10/replyboard/images/arr.gif" alt="" />
</c:if>
<a href="view.do?num=${ dto.num }&page=${ param.page }&searchCondition=${ param.searchCondition }&searchWord=${ param.searchWord }">${ dto.subject }</a>
<c:if test="${ dto.newImg }">
<img src="/jspPro/days10/replyboard/images/ico-new.gif" alt="" />
</c:if>
</td>
<td>
<c:if test="${ dto.writer eq 'kenik' }">
<img src="/jspPro/days10/replyboard/images/star.gif" alt="" />
</c:if>
<a href="mailto:${ dto.email }">${ dto.writer }</a>
</td>
<td>${ dto.regdate }</td>
<td>${ dto.readcount }</td>
<td>${ dto.ip }</td>
</tr>
</c:forEach>
<tr>
<td align="center" colspan="6">
<!-- request.setAttribute("pageBlock", "[1] 2 3 4 5 6 7 8 9 10 >"); -->
${ pageBlock }
</td>
</tr>
</c:if>
</tbody>
<form>
<tr>
<td colspan="6" align="center" style="padding:3px;">
<select id="searchCondition" name="searchCondition"
style="font-size: 15px;">
<option value="subject" ${ param.searchCondition eq "subject" ? "selected" : "" }>제목</option>
""
<option value="writer" ${ param.searchCondition eq "writer" ? "selected" : "" }>작성자</option>
<option value="subject+content">제목+내용</option>
</select>
<input type="text" name="searchWord" value='${ param.searchWord }'>
<input type="button" style="height:22px;width:50px"
value="검색" id="searchBtn">
</td>
</tr>
</form>
</table>
</body>
</html>
글쓰기
핸들러- days10.replyboard.command.WriteHandler (글작성)
package days10.replyboard.command;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import days10.replyboard.model.ReplyBoardDTO;
import days10.replyboard.service.WriteService;
public class WriteHandler implements CommandHandler{
@Override
public String process(HttpServletRequest request, HttpServletResponse response) throws Exception {
//새글 write.do 파라미터 없음
//답글 write.do?부모글 정보(num=3&ref=3&step=0&depth=0)
//GET 입력페이지(write.jsp) 포워딩
//POST 입력값 db 저장 (Service -> DAO.insert() -> list.do 요청 리다이렉트
if(request.getMethod().equalsIgnoreCase("GET")) {
//저장할 값 없이 포워딩
return "/days10/replyboard/write";
}else if(request.getMethod().equalsIgnoreCase("POST")){
ReplyBoardDTO dto = new ReplyBoardDTO();
dto.setWriter(request.getParameter("writer"));
dto.setEmail(request.getParameter("email"));
dto.setSubject(request.getParameter("subject"));
dto.setContent(request.getParameter("content"));
dto.setPass(request.getParameter("pass"));
dto.setIp(request.getRemoteAddr());
String pNum = request.getParameter("num");//num만 넘어오는지 체크할게요
if(pNum==null) { //파라미터 안넘어오면 새글
//새글 이라도 0 0 넘어간다
dto.setStep(0);
dto.setDepth(0);
}else {//그렇지 않으면 답글
//답글
int pRef = Integer.parseInt(request.getParameter("ref"));
int pStep = Integer.parseInt(request.getParameter("step"));
int pDepth = Integer.parseInt(request.getParameter("depth"));
dto.setRef(pRef);
dto.setStep(pStep+1);
dto.setDepth(pDepth+1);
}
//WriteService 작성하러가기
//작성 완료 된 후 다시 와서 호출
WriteService service = WriteService.getInstance();
int rowCount = service.write(dto);
if(rowCount==1) {
String location = "list.do";
response.sendRedirect(location);
}
}else {
//response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
}
return null;
}
}
서비스 - days10.replyboard.service.WriteService (글작성)
package days10.replyboard.service;
import java.sql.Connection;
import com.util.ConnectionProvider;
import com.util.JdbcUtil;
import days10.replyboard.dao.ReplyBoardDAO;
import days10.replyboard.model.ReplyBoardDTO;
//싱글톤
public class WriteService {
private WriteService() {}
private static WriteService instance = new WriteService();
public static WriteService getInstance() {
return instance;
}
public int write(ReplyBoardDTO dto){
Connection con = null;
int rowCount = 0;
try {
con = ConnectionProvider.getConnection();
con.setAutoCommit(false);
ReplyBoardDAO dao = ReplyBoardDAO.getInstance();
rowCount = dao.insert(con, dto);
con.commit();
} catch (Exception e) {
JdbcUtil.rollback(con); //서비스 안에서 insert 여러개면(트랜잭션 처리라면) 롤백시키고 오자고(지금은 1개니까 없어도 됨)
throw new RuntimeException(e);
} finally {
JdbcUtil.close(con);
}
return rowCount;
}//select
}//class
뷰- WEB-INF > views > days10 > replyboard > write.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>
a{
text-decoration: none;
color:black;
}
table, tr, td {
border-radius: 3px;
}
</style>
<script>
$(document).ready(function (){
});
</script>
</head>
<body>
<!-- action = "http://localhost/jspPro/days10/replyboard/write.do" -->
<form method="post">
<table width="600px" style="margin:50px auto" border="1">
<tr>
<td colspan="2" align="right">
<a href="list.do">글목록</a>
</td>
</tr>
<tr>
<td width="70" align="center">작성자</td>
<td width="330">
<input type="text" name="writer" size="12" >
</td>
</tr>
<tr>
<td width="70" align="center">이메일</td>
<td width="330">
<input type="text" name="email" size="30" >
</td>
</tr>
<tr>
<td width="70" align="center">제목</td>
<td width="330">
<input type="text" name="subject" size="50"
value='<c:if test="${ not empty param.ref }">[답글]</c:if>' >
<!-- 부모글이 있고 부모 그룹번호가 1번이라면 부모의 step이 넘어오도록
같은 페이지지만 [답글] 이라는 텍스트가 제목에 붙어있도록
==부모글의 정보가 안넘어오면 새글, 넘어오면 답글 -->
</td>
</tr>
<tr>
<td width="70" align="center">내용</td>
<td width="330">
<textarea rows="13" cols="50" name="content"></textarea>
</td>
</tr>
<tr>
<td width="70" align="center">비밀번호</td>
<td width="330">
<input type="password" name="pass" size="10" >
</td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="글쓰기">
<input type="reset" value="다시작성">
<input type="button" value="글목록"
onclick="location.href='list.do'">
</td>
</tr>
</table>
<%-- 왜적었냐? 댓글을 작성할 때의 글쓰기 페이지라면 부모글의 글번호, 그룹, 스텝, 딥스 (정보를) 파라미터로 달고 올 거니까
그 놈을 저장하겠다는, submit할때 같이 가지고 갈 것이라는 의미, 일단 주석처리
<input type="hidden" name="p_num" value="${ param.num }">
<input type="hidden" name="p_ref" value="${ param.ref }">
<input type="hidden" name="p_step" value="${ param.step }">
<input type="hidden" name="p_depth" value="${ param.depth }">
--%>
</form>
</body>
</html>
콘텐츠(내용)
핸들러 - days10.replyboard.command.ContentHandler (내용)
package days10.replyboard.command;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import days10.replyboard.model.ReplyBoardDTO;
import days10.replyboard.service.ContentService;
import days10.replyboard.service.ListService;
public class ContentHandler implements CommandHandler{
@Override
public String process(HttpServletRequest request, HttpServletResponse response) throws Exception {
//List핸들러 복붙
//?view.do?num=3&page=&searchCondition=&searchWord
//보고자하는 글번호
int num = Integer.parseInt(request.getParameter("num"));
ContentService service = ContentService.getInstance();
ReplyBoardDTO dto = service.selectOne(num);
request.setAttribute("dto", dto);
return "/days10/replyboard/content";
}
}
서비스 - days10.replyboard.service.ContentService (내용)
package days10.replyboard.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.DBConn;
import com.util.JdbcUtil;
import days09.guestbook.dao.MessageDao;
import days09.guestbook.model.Message;
import days09.guestbook.service.MessageListView;
import days09.guestbook.service.ServiceException;
import days10.replyboard.dao.ReplyBoardDAO;
import days10.replyboard.model.ReplyBoardDTO;
//ListService 복붙
//싱글톤
public class ContentService {
private ContentService() {}
private static ContentService instance = new ContentService();
public static ContentService getInstance() {
return instance;
}
//MVC 패턴에서 트랜잭션 처리 (면접관: 트랜잭션 질문시 이럴떄 써봤다고 하기)
public ReplyBoardDTO selectOne(int num){ //가져올 글번호를 매개변수로
Connection con = null;
ReplyBoardDTO dto = null;
try {
con = ConnectionProvider.getConnection();
ReplyBoardDAO dao = ReplyBoardDAO.getInstance();
con.setAutoCommit(false); //자동 커밋 막기
//게시글 내용 가져올 때
//1. 해당 게시글 조회수 1증가
dao.updateReadCount(con, num); //클릭해서 두개 함수 만들기
//2. 해당 게시글 정보 가져오기
dto = dao.selectOne(con, num);
con.commit(); //위 1.2. 둘다 잘 되면 커밋
} catch (Exception e) {
JdbcUtil.rollback(con); //1.2. 하나라도 잘못되면 롤백
throw new RuntimeException(e);
} finally {
JdbcUtil.close(con);
}
return dto;
}//select
}//class
뷰- WEB-INF > views > days10 > replyboard > content.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">
<link rel="stylesheet"
href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script
src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<style>
a {
text-decoration: none;
color: black;
}
table {
border-spacing: 1px;
border-collapse: separate;
}
table, tr, td {
border-radius: 3px;
padding: 3px;
}
</style>
<script>
$(document).ready(function (){
$("#btnModalDelete").click(function (){
$("#myModal").modal("show");
});
// Delete.jsp 복사 붙이기 ㅋㅋ
$("#btnDelete").click(function (){
// alert("test");
if( confirm("정말 삭제합니까? ")){
// delete.do?num=1&cp&sc&sw
$("#form1").submit();
}
});
});
</script>
</head>
<body>
<table width="600" style="margin: 50px auto" border="1">
<tr>
<td colspan="2" align="right">글보기</td>
</tr>
<tr>
<td width="70" align="center">글번호</td>
<td width="330">${ dto.num }</td>
</tr>
<tr>
<td width="70" align="center">조회수</td>
<td width="330">${ dto.readcount }</td>
</tr>
<tr>
<td width="70" align="center">작성자</td>
<td width="330">${ dto.writer }</td>
</tr>
<tr>
<td width="70" align="center">글제목</td>
<td width="330">${ dto.subject }</td>
</tr>
<tr>
<td width="70" align="center">글내용</td>
<td width="330">
<div style="width: 100%; height: 200px; overflo: scroll;">${ dto.content }
</div>
</td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="button" value="글수정"
onclick="location.href='edit.do?num=${ dto.num }&page=${ param.page}&searchCondition=${ param.searchCondition }&searchWord=${ param.searchWord }'">
<a href="delete.do?num=${ dto.num }">글삭제</a>
<%--
<input type="button" value="글삭제"
onclick="location.href='Delete.do?num=${ vo.num }¤tPage=${currentPage}'">
--%>
<!--[핵심] 답글 버튼 클릭하면 write.do?부모num, 부모 그룹ref, 부모step, 부모=depth를 달고 간다는 것 중요 -->
<input type="button" value="답글"
onclick="location.href='write.do?num=${ dto.num }&ref=${dto.ref }&step=${ dto.step }&depth=${ dto.depth }'">
<input type="button" value="글목록"
onclick="location.href='list.do?page=${ param.page}&searchCondition=${ param.searchCondition }&searchWord=${ param.searchWord }'">
</td>
</tr>
<tr>
<td colspan="2" align="center">
<!-- days03/Ex01.jsp -->
<input type="button" id="btnModalDelete"
value="모달창으로 글 삭제">
</td>
</tr>
</table>
<!-- 삭제 - 모달창 -->
<div class="modal fade" id="myModal" role="dialog">
<div class="modal-dialog" style="width: 350px">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">게시물 삭제</h4>
</div>
<div class="modal-body">
<!-- Delete.jsp 복사 붙이기. -->
<div style="text-align: center">
<form id="form1" action="delete.do" method="post">
<table width="300px" border="1" align="center">
<tr>
<td>비밀 번호 입력하세요?</td>
</tr>
<tr>
<td><input type="password" name="pass">
<input type="hidden" name="num" value="${ param.num }"></td>
</tr>
<tr>
<td><input type="button" id="btnDelete" value="글삭제">
<a href="list.do?page=${param.page }">글목록</a></td>
</tr>
</table>
</form>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</body>
</html>
삭제
핸들러 - days10.replyboard.command.DeleteHandler (삭제)
package days10.replyboard.command;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import days10.replyboard.service.DeleteService;
public class DeleteHandler implements CommandHandler {
@Override
public String process(HttpServletRequest request, HttpServletResponse response) throws Exception {
//delete.do?num=${ dto.num }
int num = Integer.parseInt(request.getParameter("num"));
String pass = request.getParameter("pass");
DeleteService service = DeleteService.getInstance();
service.delete(num, pass);
response.sendRedirect("list.do?delete=success");
return null;
}
}
서비스 - days10.replyboard.service.DeleteService (삭제)
package days10.replyboard.service;
import java.sql.Connection;
import java.sql.SQLException;
import javax.naming.NamingException;
import com.util.ConnectionProvider;
import com.util.JdbcUtil;
import days09.guestbook.service.InvalidPasswordException;
import days09.guestbook.service.MessageNotFoundException;
import days09.guestbook.service.ServiceException;
import days10.replyboard.dao.ReplyBoardDAO;
import days10.replyboard.model.ReplyBoardDTO;
public class DeleteService {
private DeleteService() {}
private static DeleteService instance = new DeleteService();
public static DeleteService getInstance() {
return instance;
}
//싱글톤
public int delete(int num, String pass) {
Connection con = null;
int rowCount = 0;
try {
con = ConnectionProvider.getConnection();
ReplyBoardDAO dao = ReplyBoardDAO.getInstance();
ReplyBoardDTO dto = dao.select(con, num);
if(dto==null) {
throw new MessageNotFoundException("게시글 없음");
}
if(!dto.matchPassword(pass)) {
throw new InvalidPasswordException("비밀번호 오류");
}
rowCount = dao.delete(con, num);
} catch (NamingException | SQLException e) {
JdbcUtil.rollback(con);
throw new ServiceException(">메시지 삭제 실패"+e, e);
}finally {
JdbcUtil.close(con);
}
return rowCount;
}
}
뷰- WEB-INF > views > days10 > replyboard > .jsp (글삭제)는 뷰가 없네요 ~ ^^
업데이트
핸들러 - days10.replyboard.command.UpdateHandler (업데이트)
package days10.replyboard.command;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import days10.replyboard.model.ReplyBoardDTO;
import days10.replyboard.service.GetListService;
import days10.replyboard.service.UpdateService;
public class UpdateHandler implements CommandHandler {
@Override
public String process(HttpServletRequest request, HttpServletResponse response) throws Exception {
//수정하기 버튼 누르면 수정 폼으로 이동
ReplyBoardDTO boardDTO = new ReplyBoardDTO();
if(request.getMethod().equalsIgnoreCase("GET")) {
int num = Integer.parseInt(request.getParameter("num"));
//서비스 만들기
GetListService listService = GetListService.getInstance();
ReplyBoardDTO dto = listService.getdto(num);
request.setAttribute("dto", dto);
return "/days10/replyboard/update";
}else if(request.getMethod().equalsIgnoreCase("POST")) {
//이메일, 제목, 내용 ,비번
String writer = request.getParameter("p_writer");
String email = request.getParameter("email");
String subject = request.getParameter("subject");
String pass = request.getParameter("pass");
String content = request.getParameter("content");
int num = Integer.parseInt( request.getParameter("p_num"));
//int ref = Integer.parseInt(request.getParameter("p_ref"));
//int step = Integer.parseInt(request.getParameter("p_step"));
//int depth = Integer.parseInt(request.getParameter("p_depth"));
boardDTO.setWriter(writer);
boardDTO.setEmail(email);
boardDTO.setSubject(subject);
boardDTO.setPass(pass);
boardDTO.setNum(num);
boardDTO.setContent(content);
//boardDTO.setRef(ref);
//boardDTO.setStep(step);
//boardDTO.setDepth(depth);
}
UpdateService updateService = UpdateService.getInstance();
updateService.update(boardDTO);
String location = "list.do";
response.sendRedirect(location);
return null;
}
}
서비스1 - days10.replyboard.service.GetListService (리스트 얻어오기 -업데이트 위해)
package days10.replyboard.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.service.ServiceException;
import days10.replyboard.dao.ReplyBoardDAO;
import days10.replyboard.model.ReplyBoardDTO;
public class GetListService {
private GetListService() {}
private static GetListService instance = new GetListService();
public static GetListService getInstance() {
return instance;
}
public ReplyBoardDTO getdto(int num) {
Connection con = null;
ReplyBoardDTO dto = new ReplyBoardDTO();
try {
con = ConnectionProvider.getConnection();
ReplyBoardDAO dao = ReplyBoardDAO.getInstance();
dto = dao.selectOne(con,num);
} catch (NamingException | SQLException e) {
throw new RuntimeException(e);
} finally {
JdbcUtil.close(con);
}
return dto;
}
}
서비스2 - days10.replyboard.service.UpdateService (업데이트)
package days10.replyboard.service;
import java.sql.Connection;
import java.sql.SQLException;
import javax.naming.NamingException;
import com.util.ConnectionProvider;
import com.util.JdbcUtil;
import days09.guestbook.service.ServiceException;
import days10.replyboard.dao.ReplyBoardDAO;
import days10.replyboard.model.ReplyBoardDTO;
public class UpdateService {
//싱글톤
private static UpdateService instance = new UpdateService();
public static UpdateService getInstance() {
return instance;
}
private UpdateService() {}
public int update(ReplyBoardDTO dto) {
Connection con = null;
int rowCount =0;
try {
con = ConnectionProvider.getConnection();
ReplyBoardDAO dao = ReplyBoardDAO.getInstance();
rowCount = dao.update(con, dto);
} catch (Exception e) {
throw new ServiceException("메시지 수정 실패 : "+e.getLocalizedMessage(), e);
}finally {
JdbcUtil.close(con);
}
return rowCount;
}
}
뷰- WEB-INF > views > days10 > replyboard > list.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>
a{
text-decoration: none;
color:black;
}
table, tr, td {
border-radius: 3px;
}
</style>
<script>
$(document).ready(function (){
});
</script>
</head>
<body>
<!-- action = "http://localhost/jspPro/days10/replyboard/edit.do" -->
<form method="post">
<table width="600px" style="margin:50px auto" border="1">
<tr>
<td colspan="2" align="right">
<a href="list.do">글목록</a>
</td>
</tr>
<tr>
<td width="70" align="center">작성자</td>
<td width="330">
<input type="text" name="writer" size="12" value="${dto.writer }" disabled >
</td>
</tr>
<tr>
<td width="70" align="center">이메일</td>
<td width="330">
<input type="text" name="email" size="30" value="${dto.email }" >
</td>
</tr>
<tr>
<td width="70" align="center">제목</td>
<td width="330">
<input type="text" name="subject" size="50"
value="${dto.subject }" >
</td>
</tr>
<tr>
<td width="70" align="center">내용</td>
<td width="330">
<textarea rows="13" cols="50" name="content" value="${dto.content }">${dto.content }</textarea>
</td>
</tr>
<tr>
<td width="70" align="center">비밀번호</td>
<td width="330">
<input type="password" name="pass" size="10" >
</td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="글쓰기">
<input type="reset" value="다시작성">
<input type="button" value="글목록"
onclick="location.href='list.do'">
</td>
</tr>
</table>
<input type="hidden" name="p_writer" value="${ param.writer }">
<%-- 왜적었냐? 댓글을 작성할 때의 글쓰기 페이지라면 부모글의 글번호, 그룹, 스텝, 딥스 (정보를) 파라미터로 달고 올 거니까
그 놈을 저장하겠다는, submit할때 같이 가지고 갈 것이라는 의미, 일단 주석처리 --%>
<input type="hidden" name="p_num" value="${ param.num }">
<input type="hidden" name="p_ref" value="${ param.ref }">
<input type="hidden" name="p_step" value="${ param.step }">
<input type="hidden" name="p_depth" value="${ param.depth }">
</form>
</body>
</html>
DAO - days10.replyboard.dao.ReplyBoardDAO
package days10.replyboard.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import com.util.JdbcUtil;
import days10.replyboard.model.ReplyBoardDTO;
//싱글톤
public class ReplyBoardDAO {
private static ReplyBoardDAO dao = null;
private ReplyBoardDAO() {}
public static ReplyBoardDAO getInstance() {
if(dao==null) {
dao=new ReplyBoardDAO();
}
return dao;
}
//싱글톤
//게시글 목록 메소드
//페이징 처리 제외
//단위 테스트 (test패키지 만들어서 other -> 테스트 추가) (서블릿, 서비스 만들기도 전에)
public List<ReplyBoardDTO> selectList(Connection con) throws SQLException{ //페이징 처리 안하니 컨넥션 객체만 받기
String sql =
" select rownum rnum, num,writer,email,subject,pass, regdate,readcount,ref,step,depth,content,ip "
+ ", case when ( sysdate - regdate ) < 0.041667 then 'true' else 'false' end new "
+ " from replyboard " //case 구문 : 글쓴지 1시간 미만 true/false
+" order by ref desc, step asc"; //***!! 정렬 중요
ArrayList<ReplyBoardDTO> list = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
pstmt = con.prepareStatement(sql);
rs = pstmt.executeQuery();
if(rs.next()) { //최소한 레코드가 하나라도 있으면
list= new ArrayList<ReplyBoardDTO>();
ReplyBoardDTO dto = null;
do {
dto = new ReplyBoardDTO();
dto.setNum(rs.getInt("num"));
dto.setWriter(rs.getString("writer"));
dto.setEmail(rs.getString("email"));
dto.setSubject(rs.getString("subject"));
//dto.setPass(rs.getString("pass"));
dto.setReadcount(rs.getInt("readcount"));
dto.setRegdate(rs.getDate("regdate"));
dto.setIp(rs.getString("ip"));
dto.setRef(rs.getInt("ref")); //엄밀히 따지면 필요x
dto.setStep(rs.getInt("step")); //얘도 (쿼리 자체에도 필요 없음)
dto.setDepth(rs.getInt("depth"));
dto.setNewImg(new Boolean(rs.getString("new")));
list.add(dto);
}while(rs.next());
}
}finally {
JdbcUtil.close(pstmt);
JdbcUtil.close(rs);
}
return list;
}//selectList
//글쓰기 return값은 영향받은 레코드 개수
public int insert(Connection con, ReplyBoardDTO dto) throws SQLException {
PreparedStatement pstmt = null;
int rowCount = 0 ;
if (dto.getRef()==0) { //새글일때 - 부모글 정보를 확인 - dto보면 step이 0 (0이아니라면 답글) 물론 depth, ref를 가지고도 알아올 수 있다.
//step 또는 ref 또는 depth가 0이냐 물어보면 됨
//새글 SQL num==ref
String sql = "insert into replyboard ( "
+" num, writer, email, subject, pass"
+ ", ref, step, depth, content, ip )"
+ " values "
+" ( seq_replyboard.nextval, ?,?,?,? "
+ " , seq_replyboard.currval, ?,?,?,? )";
try {
pstmt = con.prepareStatement(sql);
pstmt.setString(1, dto.getWriter());
pstmt.setString(2, dto.getEmail());
pstmt.setString(3, dto.getSubject());
pstmt.setString(4, dto.getPass());
pstmt.setInt(5, dto.getStep()); //새글일때 STEP 0
pstmt.setInt(6, dto.getDepth()); //새글일때 DEPTH 0
pstmt.setString(7, dto.getContent());
pstmt.setString(8, dto.getIp());
rowCount = pstmt.executeUpdate();
}finally {
JdbcUtil.close(pstmt);
}
} else { //답글일때
//1. 같은 그룹 내에서 부모 step보다 큰 것들은 step을 1씩 증가 (update)
String sql = "update replyboard "
+" set step = step+1 "
+"where ref=? and step> ? ";
//dto에서 부모 step보다 1증가한 값을 보냈으니 -1
try {
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, dto.getRef()); //그룹은 똑같으니 뺄 필요 없음
pstmt.setInt(2, dto.getStep()-1); //
rowCount = pstmt.executeUpdate();
//2. 새로운 게시글 추가
sql = "insert into replyboard ( "
+" num, writer, email, subject, pass"
+ ", ref, step, depth, content, ip )"
+ " values "
+" ( seq_replyboard.nextval, ?,?,?,? "
+ " ,?, ?,?,?,? )"; //group은 부모꺼 따라감
pstmt = con.prepareStatement(sql);
pstmt.setString(1, dto.getWriter());
pstmt.setString(2, dto.getEmail());
pstmt.setString(3, dto.getSubject());
pstmt.setString(4, dto.getPass());
pstmt.setInt(5, dto.getRef()); //부모그룹과 동일하게
pstmt.setInt(6, dto.getStep()); //부모+1
pstmt.setInt(7, dto.getDepth()); //부모+1 이미 넘어오니 그냥 넘겨주기
pstmt.setString(8, dto.getContent());
pstmt.setString(9, dto.getIp());
rowCount = pstmt.executeUpdate();
}finally {
JdbcUtil.close(pstmt);
}
}
return rowCount;
}
public int updateReadCount(Connection con, int num) throws SQLException { //조회수 증가
String sql = "update replyboard "
+" set readcount = readcount +1 "
+" where num = ?";
PreparedStatement pstmt = null;
int rowCount = 0;
try {
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, num);
rowCount = pstmt.executeUpdate();
} finally {
JdbcUtil.close(pstmt);
}
return rowCount;
}
public ReplyBoardDTO selectOne(Connection con, int num) throws SQLException {
String sql = "select * from replyboard "
+" where num = ?";
PreparedStatement pstmt = null;
ResultSet rs = null;
ReplyBoardDTO dto = null;
try {
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, num);
rs = pstmt.executeQuery();
if(rs.next()) {
dto = new ReplyBoardDTO();
dto.setNum( rs.getInt("num") );
dto.setWriter( rs.getString("writer"));
dto.setEmail( rs.getString("email"));
dto.setSubject( rs.getString("subject"));
dto.setReadcount( rs.getInt("readcount"));
dto.setRegdate(rs.getDate("regdate"));
dto.setIp( rs.getString("ip"));
dto.setStep( rs.getInt("step"));
dto.setDepth(rs.getInt("depth"));
dto.setRef(rs.getInt("ref"));
dto.setPass(rs.getString("pass"));
dto.setContent(rs.getString("content"));
}
} finally {
JdbcUtil.close(pstmt);
JdbcUtil.close(rs);
}
return dto;
}
public ReplyBoardDTO select(Connection con, int num) throws SQLException{
PreparedStatement pstmt = null;
ResultSet rs = null;
ReplyBoardDTO dto = new ReplyBoardDTO();
try {
pstmt = con.prepareStatement("select * from replyboard "
+" where num=? ");
pstmt.setInt(1, num);
rs = pstmt.executeQuery();
if(rs.next()) {
dto = new ReplyBoardDTO();
dto.setNum( rs.getInt("num") );
dto.setWriter( rs.getString("writer"));
dto.setEmail( rs.getString("email"));
dto.setSubject( rs.getString("subject"));
dto.setReadcount( rs.getInt("readcount"));
dto.setRegdate(rs.getDate("regdate"));
dto.setIp( rs.getString("ip"));
dto.setStep( rs.getInt("step"));
dto.setDepth(rs.getInt("depth"));
dto.setRef(rs.getInt("ref"));
dto.setPass(rs.getString("pass"));
dto.setContent(rs.getString("content"));
return dto;
}else {
return null;
}
} finally {
JdbcUtil.close(rs);
JdbcUtil.close(pstmt);
}
}
public int delete(Connection con, int num) throws SQLException {
PreparedStatement pstmt = null;
try {
pstmt = con.prepareStatement(
"delete from replyboard "
+" where num=? ");
pstmt.setInt(1, num);
return pstmt.executeUpdate();
}finally {
JdbcUtil.close(pstmt);
}
}
public int update(Connection con, ReplyBoardDTO dto) throws SQLException {
String sql = "update replyboard " +
" set email=?, subject=?, content=?" +
" where num=? and pass=? ";
PreparedStatement pstmt = null;
int rowCount = 0;
try {
pstmt = con.prepareStatement(sql);
pstmt.setString(1, dto.getEmail());
pstmt.setString(2, dto.getSubject());
pstmt.setString(3, dto.getContent());
pstmt.setInt(4, dto.getNum());
pstmt.setString(5, dto.getPass());
rowCount = pstmt.executeUpdate();
}finally {
JdbcUtil.close(pstmt);
}
return rowCount;
}
}//class
'JSP' 카테고리의 다른 글
[days12] 파일을 업로드, 수정, 삭제하는 게시판 (0) | 2021.01.12 |
---|---|
[days11] 파일 업로드 (0) | 2021.01.11 |
[days10] 이론 - 답글을 달 수 있는 게시판(==계층형 게시판==답변형 게시판) (1) | 2021.01.07 |
[days10] 프로젝트 초기 환경설정과 MVC 다시 정리 (0) | 2021.01.07 |
[days09] MVC패턴으로 방명록 만들기 (0) | 2021.01.06 |