게시판 상세기능
목록을 클릭했을 때 상세조회 페이지로 넘어가는 기능과
수정 및 삭제 기능을 구현해보자
![]() |
<< 이전포스팅에서 완료된 요청 | 이번포스팅에서 구현할 요청 >>
| 기능 | url요청 | 요청시 전달값 | 응답페이지 또는 url재요청 | |
| /web | index.jsp | |||
| 로그인요청 | /login.me | userId=?&userPwd=? | 실패시 | views/common/errorPage.jsp |
| 성공시 | /web url재요청=> index.jsp | |||
| 로그아웃요청 | /logout.me | /web url재요청=> index.jsp | ||
| 회원가입페이지 | /enrollForm.me | views/member/memberEnrollForm.jsp | ||
| 회원가입요청 | /insert.me | userId=? ... 등 | 실패시 | views/common/errorPage.jsp |
| 성공시 | /web url재요청 => index.jsp | |||
| 마이페이지요청 | /myPage.me | 로그인전 | /web url재요청 => index.jsp | |
| 로그인후 | views.member/myPage.jsp | |||
| 정보변경요청 |
/update.me |
userId=? ... 등 | 실패시 | view/common/errorPage.jsp |
| 성공시 | /myPage.me url재요청 | |||
| 비번변경요청 | /updatePwd.me | 성공/실패 | /myPage.me url재요청 | |
| 탈퇴요청 |
/delete.me |
실패시 | /myPage.me url재요청 | |
| 성공시 | /web url재요청 | |||
| 공지사항 목록 | /list.no | views/notice/noticeListView.jsp | ||
| 공지사항글쓰기 | /enrollForm.no | views/noticeEnrollForm.jsp | ||
| 공지사항등록 | /insert.no | title=?&content=? | 실패시 | views/common/errorPage.jsp |
| 성공시 | /list.no url재요청 | |||
| 공지 - 상세페이지 | /detail.no | no=? (수기기재) | 실패시 | views/common/errorPage.jsp |
| 성공시 | views/notice/noticeDetailView.jsp | |||
| 공지 - 수정페이지 | /updateForm.no | no=? | views/notice/noticeUpdateForm.jsp | |
| 공지 - 수정요청 | /update.no | no=?&title=?&content=? | 실패시 | views/common/errorPage.jsp |
| 성공시 | /detail.no?no=XX url재요청 |
공지사항 상세조회
목록에서 글을 클릭시 쿼리스트링을 활용하여
상세페이지로 넘어가보자
STEP1) notice-mapper.xml(수정)
- 상세조회 요청시에는 2가지 쿼리문을 수행해야 한다
>> 1. 조회수 증가 (update문)
>> 2. 상세조회 (select문)
>> 조회수가 증가한 상황(유효한 글임이 검증된 상황)에서 상세조회를 한다 - 프라이머리키(NOTICE_NO)는 화면에 노출되지 않는 상황이더라도 조회를 함께하는것이 좋다.
>> 수정, 삭제등에 활용되기 때문 - 유효하지 않은 글번호 혹은 삭제된 글번호가 넘어오는 경우
>> 업데이트되지 않도록 status조건추가
<entry key="increseCount">
UPDATE NOTICE
SET COUNT = COUNT + 1
WHERE NOTICE_NO = ?
AND STATUS='Y'
</entry>
<entry key="selectNotice">
SELECT
NOTICE_NO
, NOTICE_TITLE
, NOTICE_CONTENT
, USER_ID
, CREATE_DATE
FROM NOTICE
JOIN MEMBER ON (NOTICE_WRITER=USER_NO)
WHERE NOTICE_NO = ?
</entry>
STEP2) noticeListView.jsp(수정)
- 목록에 마우스를 올렸을때 클릭가능하다는 느낌주기
.list-area>tbody>tr:hover {
background-color: gray;
cursor:pointer;
}
- 쿼리스트링으로 서블릿에 데이터 넘기기
>> 클릭이벤트가 발생한 tr요소들 중에 첫번째 td요소의 텍스트값 (글번호)가 함께 넘어가야한다.
>> 쿼리스트링 방법 사용 : [ 요청할 url?키=밸류&키=밸류... ]
>> location.href="<%=contextPath%>/detail.no?no="+num;
>> 해당 방법은 get방식이 된다.
<script>
$(function(){
$(".list-area>tbody>tr").click(function(){
//클릭된 요소의 첫번째 자식으로 있는 글번호 num에 담기
const num = $(this).children().eq(0).text();
//get방식(쿼리스트링)으로 글번호를 넘기자.
location.href="<%=contextPath%>/detail.no?no="+num;
})
})
</script>
STEP3) NoticeDetailController.java
- 생성위치 : com.br.notice.controller
서블릿 / 매핑값 detail.no - 목록에서 게시글을 선택했을때 해당 게시글의 상세페이지를 돌려주는 서블릿.
- 쿼리스트링으로 넘겨받은 경우에도 값은 request의 parameter에 담겨있다.
- 쿼리스트링으로 받은 경우 유효하지 않는 글번호가 넘어올 수 있다
(사용자가 url을 건들인경우, 삭제된 글번호가 넘어오는 등)
>>조회수 증가 sql문에서 유효성 검사를 1번만 하고, 조회수가 증가 update 후 공지사항 조회를 하자
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int noticeNo = Integer.parseInt(request.getParameter("no"));
// 1) 조회수 증가
int result = new NoticeService().increseCount(noticeNo);
if(result>0) {
// 성공 == 조회가능한 공지사항이 맞다. => 응답페이지(views/notice/noticeDetail.View.jsp)
// 2) 공지사항 상세조회 (select)
Notice n = new NoticeService().selectNotice(noticeNo);
//포워딩될때 데이터 담기
request.setAttribute("notice", n);
request.getRequestDispatcher("views/notice/noticeDetailView.jsp").forward(request, response);
}else {
// 실패 == 조회 불가능한 공지사항. => 에러페이지
}
}
STEP4) NoticeService.java(수정)
- 조회수 증가 increseCount(noticeNo) 메소드 생성
- 게시글 조회 selectNotice(noticeNo) 메소드 생성
public int increseCount(int noticeNo) {
Connection conn = getConnection();
int result = new NoticeDao().increseCount(conn, noticeNo);
if(result>0) {
commit(conn);
}else {
rollback(conn);
}
close(conn);
return result;
}
public Notice selectNotice(int noticeNo) {
Connection conn = getConnection();
Notice n = new NoticeDao().selectNotice(conn, noticeNo);
// 조회만 했기때문에 트랜젝션 처리 필요없다.
close(conn);
return n;
}
STEP5) NoticeDao.java(수정)
- 조회수 증가 increseCount(conn, noticeNo) 메소드 생성
- 게시글 조회 selectNotice(conn, noticeNo) 메소드 생성
public int increseCount(Connection conn, int noticeNo) {
int result = 0;
PreparedStatement pstmt = null;
String sql = prop.getProperty("increseCount");
try {
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, noticeNo);
result = pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(pstmt);
}
return result;
}
public Notice selectNotice(Connection conn, int noticeNo) {
Notice n = null;
PreparedStatement pstmt = null;
ResultSet rset = null;
String sql = prop.getProperty("selectNotice");
try {
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, noticeNo);
rset = pstmt.executeQuery();
if(rset.next()) {
n = new Notice(rset.getInt("notice_no"),
rset.getString("notice_title"),
.....
rset.getDate("create_date"));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(rset);
close(pstmt);
}
return n;
}
STEP6) noticeDetailView.jsp
- 생성위치 : webProject/src/main/webapp/views/notice
- 게시글 클릭시 나타나는 상세조회 페이지 설계
- 만약 관리자가 보고있다면 수정과 삭제버튼 노출
>>로그인한 상태이고(null오류 방지 위해 앞에서 조건검사) && 로그인한 사용자와 작성자가 동일한 경우 노출 - 상단에 필요한 데이터들을 뽑아놓는다.
<%
Notice n = (Notice)request.getAttribute("notice");
//db로부터 조회한 글번호, 제목, 내용, 작성자, 작성일이 담겨있다.
%>
.....
<h2>공지사항 상세보기</h2>
제목 : <%=n.getNoticeTitle()%></td>
작성자 : <%=n.getNoticeWriter()%></td>
작성일 : <%=n.getCreateDate()%>
내용 : <%=n.getNoticeContent()%>
<a href="<%=contextPath%>/list.no">목록가기</a>
<% if(loginUser != null && loginUser.getUserId().equals(n.getNoticeWriter())) { %>
<!-- 현재 로그인한 사용자가 해당 글을 쓴 본인일 경우 -->
<a href="" class="btn btn-warning btn-sm">수정하기</a>
<a href="" class="btn btn-danger btn-sm">삭제하기</a>
<% } %>
.....
게시글 수정하기
수정하기 버튼을 누르면 수정하는 페이지로 넘어간다
![]() |
STEP1) noticeDetailView.jsp (수정)
- '상세조회 페이지'에서 수정하기버튼 클릭시 수정하고자 하는 글 번호도 함께 넘겨야한다.
>> 상단에 가져와놓은 Notice n 객체에 번호가 담겨있다!
>> 쿼리스트링으로 넘긴다.
<a href="<%=contextPath%>/updateForm.no?no=<%=n.getNoticeNo()%>">수정하기</a>
STEP2) NoticeUpdateFormController.java
- 생성위치 : com.br.notice.controller
서블릿 / 매핑값 updateForm.no - noticeNo를 통해 게시글을 조회해서 수정페이지로 포워딩한다.
(기존에 만들어두었던 selectNotice() 메소드 재사용)
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int noticeNo = Integer.parseInt(request.getParameter("no"));
Notice n = new NoticeService().selectNotice(noticeNo);
request.setAttribute("n", n);
request.getRequestDispatcher("views/notice/noticeUpdateForm.jsp").forward(request, response);
}
STEP3) noticeUpdateForm.jsp
- 생성위치 : webProject/src/main/webapp/views/notice
- 수정하기 버튼 클릭시 나타날 수정페이지
- noticeEnrollForm.jsp와 거진 비슷하니 복붙후 일부수정
**수정 체크사항**
1. 제목의 input태그에 value속성을 주어 기존값을 입력한다.
2. 내용의 textarea태그의 content부에 기존값을 입력한다. - 포워딩시 전달받은 객체를 상단에 저장해놓은 후 기존값을 불러오는데 활용한다.
<%@ page import="com.br.notice.model.vo.Notice" %>
<% Notice n = (Notice)request.getAttribute("n"); %>
.....
<input type="text" name="title" required value="<%=n.getNoticeTitle()%>">
.....
<textarea name="content" style="resize:none" id="" rows="10" required><%=n.getNoticeContent()%></textarea>
.....
- form 태그의 action값을 update.no로 준다.
- 제목, 내용 뿐만 아니라 글번호도 넘어가게끔 input hidden으로 설정
<form action="<%=contextPath%>/update.no" method="post" id="update-form">
<input type="hidden" name="no" value="<%=n.getNoticeNo()%>">
STEP4) NoticeUpdateController.java
- 생성위치 : com.br.notice.controller
서블릿 / 매핑값 update.no - post 방식 요청이므로 인코딩을 해야한다.
- 수정 성공시 상세페이지를, 수정 실패시 에러페이지를 띄운다.
- 쿼리스트링으로 데이터를 넘겨받았던 서블릿의 매핑값을 쓸 경우,
똑같이 같은 데이터를 넘겨주어야 한다!
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
int noticeNo = Integer.parseInt(request.getParameter("no"));
String noticeTitle = request.getParameter("title");
String noticeContent = request.getParameter("content");
Notice n = new Notice();
n.setNoticeNo(noticeNo);
n.setNoticeTitle(noticeTitle);
n.setNoticeContent(noticeContent);
int result = new NoticeService().updateNotice(n);
if(result>0) {
//성공 => 응답페이지(views/notice/noticeDetailView.jsp)
// + alert
request.getSession().setAttribute("alertMsg", "성공적으로 공지사항 수정되었습니다");
//기존에 url이 있으므로 포워딩이 아닌 재요청 방식
//**주의 : 해당 url은 넘겨야하는 데이터가 있다. **
response.sendRedirect(request.getContextPath()+"/detail.no?no="+noticeNo);
}else {
//실패 => 에러페이지
}
}
STEP) NoticeService.java(수정)
- 게시글 수정을 처리하는 updateNotice(n) 메소드 생성
public int updateNotice(Notice n) {
Connection conn = getConnection();
int result = new NoticeDao().updateNotice(conn, n);
if(result>0) {
commit(conn);
}else {
rollback(conn);
}
close(conn);
return result;
}
STEP) notice-mapper.xml(수정)
- 게시글데이터를 수정하는 sql문 작성
<entry key="updateNotice">
UPDATE NOTICE
SET NOTICE_TITLE = ?
, NOTICE_CONTENT = ?
WHERE NOTICE_NO = ?
</entry>
STEP) NoticeDao.java(수정)
- 게시글 수정을 처리하는 updateNotice(conn, n) 메소드 생성
public int updateNotice(Connection conn, Notice n) {
int result = 0;
PreparedStatement pstmt = null;
String sql = prop.getProperty("updateNotice");
try {
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, n.getNoticeTitle());
pstmt.setString(2, n.getNoticeContent());
pstmt.setInt(3, n.getNoticeNo());
result = pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}finally {
close(pstmt);
}
return result;
}
게시글 삭제
STEP1) noticeDetailView.jsp (수정)
- 삭제하기버튼 클릭시 바로 요청할 서블릿의 매핑값을 입력한다.
- 쿼리스트링으로 글번호를 담아서 넘긴다.
<a href="<%=contextPath%>/delete.no?no=<%=n.getNoticeNo()%>">삭제하기</a>
STEP2) NoticeDeleteController.java
- 생성위치 : com.br.notice.controller
서블릿 / 매핑값 delete.no - 삭제를 진행한 후 성공시 게시글 목록으로 url 재요청 한다.
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int noticeNo = Integer.parseInt(request.getParameter("no"));
int result = new NoticeService().deleteNotice(noticeNo);
if(result>0) {
request.getSession().setAttribute("alertMsg", "성공적으로 삭제되었습니다");
response.sendRedirect(request.getContextPath()+"/list.no");
}else {
//실패시 에러문구 보이는 에러페이지
request.setAttribute("errorMsg", "공지사항 삭제 실패");
request.getRequestDispatcher("views/common/errorPage.jsp").forward(request, response);
}
}
STEP3) NoticeService.java(수정)
- deleteNotice(noticeNo) 메소드 생성
public int deleteNotice (int noticeNo) {
Connection conn = getConnection();
int result = new NoticeDao().deleteNotice(conn, noticeNo);
if(result>0) {
commit(conn);
}else {
rollback(conn);
}
close(conn);
return result;
}
STEP4) NoticeDao.java(수정)
- deleteNotice(conn, noticeNo) 메소드 생성
public int deleteNotice(Connection conn, int noticeNo) {
int result = 0;
PreparedStatement pstmt = null;
String sql = prop.getProperty("deleteNotice");
try {
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, noticeNo);
result = pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}finally {
close(pstmt);
}
return result;
}
STEP5) notice-mapper.xml(수정)
- 삭제더라도 DELETE가 아닌 UPDATE로 진행한다.
<entry key="deleteNotice">
UPDATE NOTICE
SET STATUS = 'N'
WHERE NOTICE_NO=?
</entry>

'다양한 기술들 > 레거시 Web 실습' 카테고리의 다른 글
| [09] 게시판심화1 : 글쓰기(+파일첨부) (0) | 2023.01.11 |
|---|---|
| [08] 게시판심화1 : 페이징처리 (1) | 2023.01.11 |
| [06] 게시판기초 : 일반목록, 글쓰기(+권한) (0) | 2023.01.09 |
| [05] 모달을 사용한 비밀번호변경 (0) | 2023.01.06 |
| [04] 회원정보변경 (0) | 2023.01.06 |


댓글