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

[06] 게시판기초 : 일반목록, 글쓰기(+권한)

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재요청

 


공지사항 목록 조회

회원 비회원 모두 조회할 수 있다.


STEP1) Notice.java

  • 생성위치 : com.br.notice.model.vo
  • 공지사항 게시판의 vo 클래스를 만든다.
  • 공지사항 작성자를 담을 noticeWriter는 db에서는 number타입이지만(회원번호)
    화면에 보여지는건 회원번호가 아닌 아이디 혹은 이름이다.
    따라서 숫자와 문자열 둘다 담을 수 있는 String 타입으로 설정한다.

 

 

STEP2) menubar.jsp (수정)

  • Home 버튼 클릭시 메인페이지 가도록 설정하기
  • 공지사항 버튼을 클릭했을때 목록으로 이동하도록 서블릿 메핑값을 준다.
<a href="<%=contextPath%>">HOME</a>
<a href="<%=contextPath%>/list.no">공지사항</a>

 

 

STEP3) noticeListView.jsp

  • 생성위치 : webProject/src/main/webapp/views/notice
  • 공지사항 클릭시 뜨는 공지사항 목록 리스트를 설계한다.
  • 상단에 menubar를 include지시어로 삽입한다.

 

 

STEP4) NoticeListController.java

  • 생성위치 : com.br.notice.controller
    서블릿/매핑값 list.no
  • 페이지 포워딩하는 용도의 서블릿
    이때 DB로부터 조회된 공지사항에 대한 데이터가 필요
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // 1) 요청시 전달값 뽑기 >> 없으므로 생략
    // 2) 요청 처리 (select)
    ArrayList<Notice> list = new NoticeService().selectNoticeList();
		
    // 3) 응답뷰 지정하여 포워딩 => views/notice/noticeListView.jsp
    //    포워딩 시 응답뷰에 필요한 데이터는 request의 Attribute에 담으면 됨.
    //    DB에서 조회된 공지사항에 대한 데이터가 필요
    //    (조회 결과가 있든 없든 일단 데이터를 담아 페이지 이동)
    request.setAttribute("list", list);
    request.getRequestDispatcher("views/notice/noticeListView.jsp").forward(request, response);
}

 

 

STEP5) NoticeService.java

  • 생성위치 : com.br.notice.model.service
  • selectNoticeList() 작성
public ArrayList<Notice> selectNoticeList(){
    Connection conn = getConnection();
    ArrayList<Notice> list = new NoticeDao().selectNoticeList(conn);
    close(conn);
    return list;
}

 

 

STEP6) notice-mapper.xml

  • 게시글을 조회해오는 sql문 작성
  • 별칭을 지정하지 않으면 STATUS가 두개 컬럼에 있어서 ambiguausly 오류가 뜰것. 
  • 최신글이 위로 가도록하는 ORDER BY절 추가
<entry key="selectNoticeList">
        SELECT 
               NOTICE_NO
             , NOTICE_TITLE
             , USER_ID
             , COUNT
             , CREATE_DATE  
          FROM NOTICE N
          JOIN MEMBER ON (NOTICE_WRITER = USER_NO)
         WHERE N.STATUS = 'Y'
         ORDER
            BY NOTICE_NO DESC;	
<entry>

 

 

STEP) NoticeDao.java

  • 생성위치 : com.br.notice.model.daoselectNoticeList
  • 기본 생성자에 prop객체 생성하는 구문 추가
  • selectNoticeList(conn) 메소드 작성
public NoticeDao() {
    try {
        prop.loadFromXML(new FileInputStream(NoticeDao.class.getResource("/db/sql/notice-mapper.xml").getPath()));
        //그냥 load()가 아닌 loadFromXml()로 해야 오류없이 잘 읽어들여짐
    } catch (IOException e) {
        e.printStackTrace();
    }
}
    
public ArrayList<Notice> selectNoticeList(Connection conn){
    //select문 = ResultSet(여러행)
    // ArrayList는 null로 초기화가 아닌 생성해두면 텅빈 리스트 생성
    ArrayList<Notice> list = new ArrayList<>();
    PreparedStatement pstmt = null;
    ResultSet rset = null;
    String sql = prop.getProperty("selectNoticeList") ;
    try {
        pstmt = conn.prepareStatement(sql);
        //완성된 sql문으로 바로 실행
        rset = pstmt.executeQuery();
        while(rset.next()){
            list.add(new Notice(rset.getInt("notice_no"),
                                .....
                                rset.getDate("create_date")));	
        }
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        close(rset);
        close(pstmt);
    }
    return list;
}

 

 

STEP) noticeListView.jsp (수정)

  • 데이터와 함께 포워딩을 받았으면, 최상단에에 전달받은 데이터를 뽑아놓는다.
  • if문으로 조회 결과가 없으면 게시글없음 문구를 출력하고, 조회결과가 있다면 for문으로 데이터 수 만큼 목록이 만들어 지도록 코드를 구성한다
 <%
    ArrayList<Notice> list = (ArrayList<Notice>)request.getAttribute("list");
 %>
 .....
<table>
    <tr>
        <th>글번호</th>
        <th width="400">글제목</th>
        <th width="100">작성자</th>
        <th>조회수</th>
        <th width="100">작성일</th>
    </tr>
<% if(list.isEmpty()) { %>
<!-- case1. 공지글이 없을 경우 -->
    <tr>
    <td colspan="5">존재하는 공지사항이 없습니다.</td>
    </tr>
<%} else { %>
<!-- case2. 공지글이 있을 경우-->
    <% for(Notice n : list) { %>
        <tr>
            <td><%= n.getNoticeNo() %></td>
            <td><%= n.getNoticeTitle() %></td>
            <td><%= n.getNoticeWriter() %></td>
            <td><%= n.getCount() %></td>
            <td><%= n.getCreateDate() %></td>
        </tr>
    <% } %>
<% } %>    
</table>

 

 


공지사항 조회하기

관리자일때만 글쓰기 버튼이 보이게 해서 권한을 부여한다.


 

 

STEP1) noticeListView.jsp (수정)

  • 로그인한 사용자가 관리자일 경우 보일 div 안에 글쓰기 버튼을 넣는다
  • session에 로그인한 회원정보인 loginUser 담겨있음(include된 menubar.jsp에 코드작성됨)
    >> 해당 객체의 id필드가 관리자 아이디인 admin과 일치하는지 검사한다.
    **이때, null검사 하지 않으면 오류가 뜸 (로그인 하지 않으면 loginUser는 null)
        &&연산자는 앞의 조건이 false이면 뒤의 조건은 실행하지 않기때문에 해당 원리로 검사
  • 버튼은 속성으로 href를 쓸 수 없어서 onclick= "location.href='요청할 url' " 구문을 사용해야한다.
    >> 번거로우므로 a태그를 쓰고 부트스트랩을 활용해서 버튼모양을 만든다.
<% if(loginUser != null && loginUser.getUserId().equals("admin")) { %>
    <a href="<%=contextPath%>/enrollForm.no" class="btn btn-secondary btn-sm">글작성</a>
<% } %>

 

 

STEP2) noticeEnrollForm.jsp

  • 생성위치 : webProject/src/main/webapp/views/notice
  • 게시글 작성하는 페이지를 구성한다.
  • 클릭시 뒤로가게 만들기 : onclick="history.back();"
  • 폼 제출 서블릿 : insert.no
<h2>공지사항 작성하기</h2>
<form action="<%=contextPath%>/insert.no" method="post" id="enroll-form">
제목 : <input type="text" name="title" required>
내용 : <textarea name="content" style="resize:none" id="" rows="10" required></textarea>

<button type="submit">등록하기</button>
<button type="reset">초기화</button>
<button type="button" onclick="history.back();">뒤로가기</button>
</form>

 

 

STEP3) NoticeEnrollFormController.java

  • 생성위치 : com.br.notice.controller
    서블릿/매핑값 enrollForm.no
  • 글쓰기 버튼을 눌렀을 때 글작성 페이지로 포워딩하는 용도
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // 응답페이지 views/notice/noticeEnrollForm.jsp 포워딩
    request.getRequestDispatcher("views/notice/noticeEnrollForm.jsp").forward(request, response);
}

 

 

STEP4) notice-mapper.xml(수정)

  • 게시글을 삽입하는 sql문을 작성해보면 로그인한 회원의 번호가 필요하다는것을 알 수 있다.
    INSERT 
           INTO NOTICE
        (
           NOTICE_NO
         , NOTICE_TITLE
         , NOTICE_CONTENT
         , NOTICE_WRITER		  
        )
           VALUES
        (
           SEQ_NNO.NEXTVAL
         , ?
         , ?
         , ?	
        )

 

 

STEP5) NoticeInsertController.java

  • 생성위치 : com.br.notice.controller
    서블릿/매핑값 insert.no
  • 사용자가 작성한 게시글을 넘겨받아 db에 삽입하는 요청처리를 하는 서블릿
  • post방식이고 한글이 넘어올 수 있으므로 인코딩 해야한다
  • 로그인한 회원 정보를 얻어내는 방법
    1. input type="hidden"으로 애초에 요청시 숨겨서 전달하는 방법
    2. session에 담겨있는 회원객체로부터 데이터 뽑기 (서블릿에서도 세션에 접근가능하다!)
    >> getAttribute() 사용시 오브젝트타입 반환이므로 강제 형변환 후 getter 메소드 사용한다.
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    request.setCharacterEncoding("UTF-8");
    String noticeTitle = request.getParameter("title");
    String noticeContent = request.getParameter("content");
	//로그인한 회원 번호 알아내기
    HttpSession session = request.getSession();
    int userNo = ((Member)session.getAttribute("loginUser")).getUserNo();
		
    Notice n = new Notice();
    n.setNoticeTitle(noticeTitle);
    n.setNoticeContent(noticeContent);
    //noticeWriter는 vo작성 당시 숫자가 아닌 문자열로 담기로 설계해놨었다.
    //숫자>문자 변환 메소드 String.valueOf() 사용
    n.setNoticeWriter(String.valueOf(userNo));
		
    int result = new NoticeService().insertNotice(n);
    if(result>0) {
        // 성공 => 공지사항 목록페이지 띄우기(noticeListView.jsp)
        // alert로 "성공적으로 공지사항 등록되었습니다."
        session.setAttribute("alertMsg", "공지사항 등록에 성공했습니다");
        //이미 등록해둔 url이 있으므로 포워딩 할 필요가 없이 url재요청을 한다.
        response.sendRedirect(request.getContextPath() + "/list.no");
    }else {
        // 실패 =>  에러페이지(errorPage.jsp)
        // 에러문구 "공지사항 등록 실패"
        request.setAttribute("errorMsg", "공지사항 등록에 실패했습니다.");
        //포워딩을 한다.
        request.getRequestDispatcher("/views/common/errorPage.jsp").forward(request,response);
    }
}

 

 

STEP6) NoticeService.java (수정)

  • insertNotice(n) 메소드 생성
public int insertNotice(Notice n) {
    Connection conn = getConnection();
    int result = new NoticeDao().insertNotice(conn, n);
    if(result>0) {
        commit(conn);
    }else {
        rollback(conn);
    }
    close(conn);
    return result;
}

 

 

STEP7) NoticeDao.java (수정)

  • insertNotice(conn, n) 메소드 생성
public int insertNotice(Connection conn, Notice n) {
    int result = 0;
    PreparedStatement pstmt = null;
    String sql = prop.getProperty("insertNotice");
    try {
        pstmt = conn.prepareStatement(sql);
        pstmt.setString(1, n.getNoticeTitle());
        pstmt.setString(2, n.getNoticeContent());
        //문자열로 담았으니 숫자로 파싱해준다.
        //pstmt.setInt(3, Integer.parseInt(n.getNoticeWriter()));
        //사실 파싱 안해줘도 됨. 오라클은 자동형변환해줌
        pstmt.setString(3, n.getNoticeWriter());
        result = pstmt.executeUpdate();
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        close(pstmt);
    }		
    return result;
}

 

 

 

 

 

 

댓글