본문 바로가기
다양한 기술들/레거시 Web 실습

[07] 게시판기초 : 상세조회, 수정, 삭제

by 예스p 2023. 1. 9.

게시판 상세기능

목록을 클릭했을 때 상세조회 페이지로 넘어가는 기능과

수정 및 삭제 기능을 구현해보자


 

<< 이전포스팅에서 완료된 요청     |    이번포스팅에서 구현할 요청 >>

기능 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>

 

 

 

 

 

 

 

 

 

 

 

 

 

댓글