1 / 36

JSP BBS (Bulletin Board System)

JSP BBS (Bulletin Board System). Internet Computing Laboratory @ KUT Youn-Hee Han. Design. 게시물에 할당해야 할 값 일렬 번호 ( 테이블 필드명 : THEME_MESSAGE_ID) 게시물마다 고유의 값을 가지면 글이 추가될 때 마다 1 씩 증가 그룹 번호 (GROUP_ID) 연관된 게시물들이 공유하는 번호 주 게시물 및 그 게시물의 모든 답글은 같은 그룹 번호를 가짐 부모 번호 (PARENT_ID) 주 게시물은 항상 0 을 지님

dagan
Download Presentation

JSP BBS (Bulletin Board System)

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. JSP BBS (Bulletin Board System) Internet Computing Laboratory @ KUT Youn-Hee Han

  2. Design • 게시물에 할당해야 할 값 • 일렬 번호 (테이블 필드명: THEME_MESSAGE_ID) • 게시물마다 고유의 값을 가지면 글이 추가될 때 마다 1씩 증가 • 그룹 번호 (GROUP_ID) • 연관된 게시물들이 공유하는 번호 • 주 게시물 및 그 게시물의 모든 답글은 같은 그룹 번호를 가짐 • 부모 번호 (PARENT_ID) • 주 게시물은 항상 0을 지님 • 답변 게시물은 해당 주 게시물의 일렬 번호를 부모 번호로 가짐 • 출력 순서 (ORDER_NO) • 주 게시물은 항상 0을 지님 • 같은 그룹 내의 답변 게시물 들에 대한 출력 순서를 저장 • 단계값 (LEVEL) • 주 게시물은 항상 1을 지님 • 얼마나 중첩이 된 답변 게시물인지를 나타냄 Web Programming

  3. Design 게시물에 할당해야 할 값 Primary Key 입력 순서 1 2 입력 순서 1 3 2 Web Programming

  4. Design 게시물에 할당해야 할 값 입력 순서 1 4 3 2 입력 순서 1 3 5 4 2 Web Programming

  5. Design 게시물에 할당해야 할 값 입력 순서 1 3 5 6 4 2 입력 순서 1 3 5 6 7 4 2 Web Programming

  6. DB Schema for BBS • 데이터베이스 Table 목록 • THEME_MESSAGE(, NOTICE_MESSAGE, STUDY_MESSAGE…) • THEME_CONTENT(, NOTICE_CONTENT, STUDY_CONTENT…) Web Programming

  7. DB Schema for BBS • 데이터베이스 Table 목록 • ID_SEQUENCE • 인덱스 • THEME_MESSAGE_INDEX Web Programming

  8. 컴파일러준비 • sjc.bat • 다음과 같이 재정비 할 필요 • 기본 위치는 java 설치 디렉토리의 bin 디렉토리 밑 • 하지만, \2006777888\WEB-INF\src 밑에 두고 써도 상관없음 • 그러나, 시스템 전체에 sjc.bat는 하나만 존재해야 함! set CLASSPATH= set CLASSPATH=%CLASSPATH%;D:\jakarta-tomcat-5.0.19\webapps\2006777888\WEB-INF\classes;D:\jakarta-tomcat-5.0.19\common\lib\servlet-api.jar javac -d D:\jakarta-tomcat-5.0.19\webapps\2006777888\WEB-INF\classes %1 Web Programming

  9. DB 준비 • 데이터베이스 준비 • MySQL 4.0.18 설치 • 압축 해제 디렉토리: d:\install_mysql • 설치 디렉토리: d:\mysql • d:\mysql\bin\winmysqladmin.exe 을실행한다. • User ID는 root로 PASSWD는 적절하게 넣어준다. • 도스창에서 mysqladmin -p create theme • d:\mysql\bin\ 에서수행 • 패스워드는 아무것도 넣지 말고 엔터 누름 • theme.sql 다운받기 • d:\mysql\bin\ 에 다운받는다. • 도스창에서 mysql -p theme < theme.sql • d:\mysql\bin\ 에서수행 • 패스워드는 아무것도 넣지 말고 엔터 누름 패스워드는디폴트로 없이 수행 Web Programming

  10. WEB Application 준비 • kut.ime.jdbcdriver.DBCPInit 서블릿 클래스 • DBCPInit.java 다운로드 • 다운로드 디렉토리: \2006777888\WEB-INF\src • 패키지명 유의 • 컴파일 Web Programming

  11. Connection Pool 및 JDBC 드라이버 로드 • Connection Pool 설정 • pool.jocl 다운로드: /2006777888/WEB-INF/classes 밑에 저장 • 교재 474 페이지 참고 • JDBC Driver 사용을 위한 web.xml 수정 • 교재 475 페이지 참고 • web.xml 내에 다음을 추가 … <servlet> <servlet-name>DBCPInit</servlet-name> <servlet-class>kut.ime.jdbcdriver.DBCPInit</servlet-class> <load-on-startup>1</load-on-startup> <init-param> <param-name>jdbcdriver</param-name> <param-value>com.mysql.jdbc.Driver</param-value> </init-param> </servlet> … Web Programming

  12. Connection Pool 및 JDBC 드라이버 로드 • DB 이용을 위한 라이브러리 다운로드 • 다운로드 위치: /2006777888/WEB-INF/lib • 다운로드할 파일 • classes12.jar • commons-collections-3.1.jar • commons-dbcp-1.2.1.jar • commons-pool-1.2.jar • mysql-connector-java-3.0.14-production-bin.jar • Tomcat 재시작 • DB 테스트 2006777888/bbs/test.jsp <%@ page import="java.sql.*"%> <% Connection conn = DriverManager.getConnection("jdbc:apache:commons:dbcp:/"+"pool"); ResultSet rs = conn.createStatement().executeQuery("show tables;"); while(rs.next()) { out.println(rs.getString(1) + "<BR>"); } %> pool.jocl Web Programming

  13. 보조 클래스 • kut.ime.util.DBUtil 클래스 2006777888/WEB-INF/src/DBUtil.java package kut.ime.util; import java.sql.DriverManager; import java.sql.Connection; import java.sql.SQLException; public class DBUtil { public static Connection getConnection(String poolName) throws SQLException { return DriverManager.getConnection( "jdbc:apache:commons:dbcp:/"+poolName); } } 이후모든 .java 소스는 다운 받아서 sjc 로컴파일 필요

  14. 보조 클래스 • kut.ime.bbs.Sequencer 클래스 (교재 p.476) • 다음의 1개 메소드 제공 • public synchronized static int nextID(Connection conn, String tableName) • ID_SEQUENCE 테이블에 저장된 게시물들의 가장 큰 일련 번호인 MESSAGE_ID 필드 값을 얻어와 하나 증가된 값을 리턴해줌 • 사용법 • intid = Sequencer.nextId(conn, “THEME_MESSAGE”); • kut.ime.bbs.Theme 클래스 (교재 p.477~479) • 자바빈 클래스 • THEME_MESSAGE 테이블과 THEME_CONTENT 테이블의 내용을 모두 포함 • 용도 • 새로운 게시물을 입력할 때 • 게시물을 얻어올 때 • 게시물을 업데이트 할 때 • kut.ime.bbs.ThemeManagerException 클래스 (교재 p.480) • 본 JSP BBS 관련 작업 처리 중 발생하는 예외를다른 예외들과 구별하기 위하여 필요함

  15. 주클래스: ThemeManager • ThemeManager 클래스 • JSP BBS의 대부분의 기능을 수행하는 클래스 • 메소드 목록 • publicstatic ThemeManager getInstance(); • ThemeManager의 인스턴스를 얻어옴 • public void insert(Theme theme) throws ThemeManagerException; • 게시판에 새로운 글을 삽입할 때 사용 • public int count(List whereCond, Map valueMap) throws ThemeManagerException; • 특정 조건에 만족하는 게시물의 총 개수를 구함 • public List selectList(List whereCond, Map valueMap, int startRow, int endRow) throws ThemeManagerException; • 특정 조건에 만족하는 게시물을 목록을 가져 올때 사용 • public int select(int id) throws ThemeManagerException; • 하나의게시물을 읽어 올 때 사용 • public int update(Theme theme) throws ThemeManagerException; • 게시물 하나를 업데이트 할 때 사용 • public int delete(int id) throws ThemeManagerException; • 게시물 하나를 삭제 할 때 사용

  16. 클래스 배치 현재까지 클래스 컴파일 결과 모습

  17. 이미지 업로드&핸들링을 대비한 사전 준비 작업 • 폴더 생성 • 업로드 이미지 임시 저장소 • D:\jakarta-tomcat-5.0.19\webapps\2006777888\bbs\temp • 업로드 이미지 저장소 • D:\jakarta-tomcat-5.0.19\webapps\2006777888\bbs\image • ImageUtil 클래스 배치 • FileUploadRequestWrapper 클래스 배치

  18. 이미지 업로드&핸들링을 대비한 사전 준비 작업 • 라이브러리 재확인 • TOMCAT 재시작!!!

  19. 화면 출력용 JSP 구성 • BBS.zip 다운로드 • 다운로드 위치: 2006777888/bbs/ • write.jsp 에서 2006777888을 자신의 폴더 이름으로 변경 • 화면 레이아웃과 모듈화 • 교재 494 페이지 참조 2006777888/bbs/template/template.jsp 2006777888/bbs/module/top.jsp 2006777888/bbs/list_view.jsp 2006777888/bbs/writeForm_view.jsp 2006777888/bbs/read_view.jsp 2006777888/bbs/updateForm_view.jsp 2006777888/bbs/deleteForm_view.jsp 2006777888/bbs/module/bottom.jsp

  20. 화면 출력용 JSP 구성 • JSP 구성 및 연결도 (아래파일들은 2006777888/bbs 아래에 위치함) • 게시물 목록 출력 • 새 게시물 입력 /module/top.jsp list.jsp /template/template.jsp list_view.jsp /module/bottom.jsp /module/top.jsp writeForm.jsp /template/template.jsp writeForm_view.jsp /module/bottom.jsp form action javascript  location.href = “list.jsp” write.jsp

  21. 화면 출력용 JSP 구성 • JSP 구성 및 연결도 • 게시물 읽기 • 게시물 수정 /module/top.jsp read.jsp /template/template.jsp read_view.jsp /module/bottom.jsp /module/top.jsp updateForm.jsp /template/template.jsp updateForm_view.jsp /module/bottom.jsp form action javascript  document.move.action = "list.jsp"; document.move.submit(); list.jsp update.jsp

  22. 화면 출력용 JSP 구성 • JSP 구성 및 연결도 • 게시물 삭제 /module/top.jsp deleteForm.jsp /template/template.jsp deleteForm_view.jsp /module/bottom.jsp form action javascript  location.href = “list.jsp” list.jsp delete.jsp

  23. BBS 수행 모습 • 수행 모습 • 데이터 베이스 모습

  24. 게시물 목록 출력 코드 • 게시물 목록 출력 코드설명 (검색조건 없을 경우) • 관련 코드 리스트 • 코드 리스트 18.18, 18.8, 18.9 • 출력할페이지 번호 설정 • currentPage 변수 설정 • searchCond, searchKey 는 null 이라고 가정 • 따라서, whereCond, whereValue, searchCondName, searchCondTitle 모두 null • 글의 전체 개수를 얻어옴 • intcount = manager.count(whereCond, whereValue); • 수행되는 Query 문 • select count(*) from THEME_MESSAGE • 전체 페이지 개수와 읽어 올 시작행, 끝행을 구한다. • totalPageCount, startRow, endRow 설정

  25. 게시물 목록 출력 코드 • 게시물 목록 출력 코드설명 (검색조건 없을 경우) – 계속 • 글 목록을 읽어 옴 • Listlist = manager.selectList(whereCond, whereValue, startRow-1, endRow-1); • 수행되는 Query 문 • select * from THEME_MESSAGE order by GROUP_ID desc, ORDER_NO asc limit ?, ? • Java 코딩에서 Query 구성 법 • EL과 JSTL을 이용해서 글 목록 출력 • 글목록 및 하나의 게시글 보기에 대한 링크 생성 • 자바 스크립트와 form을 활용 • 페이지 이동 링크 출력 ([이전], [1], [2], …., [다음]) • 검색 폼 출력 StringBuffer query = new StringBuffer(200); query.append(“select * from THEME_MESSAGE “); query.append(“order by GROUP_ID desc, ORDER_NO asc limit ?, ?”); Connection conn = DBUtil.getConnection(POOLNAME); PreparedStatement pstmtMessage = conn.prepareStatement(query.toString()); pstmtMessage.setInt(valueMap.size() + 1, startRow); pstmtMessage.setInt(valueMap.size() + 2, endRow- startRow + 1); ResultSet rsMessage = pstmtMessage.executeQuery(); 리스트 18.10

  26. 게시물 목록 출력 코드 value: title • 게시물 목록 출력 코드설명 (검색조건 있을 경우) • 관련 변수 선언 • 검색조건 구성 value: name name: search_cond name: search_key String[] searchCond = request.getParameterValues("search_cond"); String searchKey = request.getParameter("search_key"); boolean searchCondName = false; boolean searchCondTitle = false; List whereCond = new java.util.ArrayList(); Map whereValue = new java.util.HashMap(); 리스트 18.8 for (int i = 0 ; i < searchCond.length ; i++) { if (searchCond[i].equals("name")) { whereCond.add("NAME = ?"); whereValue.put(new Integer(1), searchKey); searchCondName = true; } else if (searchCond[i].equals("title")) { whereCond.add("TITLE LIKE '%"+searchKey+"%'"); searchCondTitle = true; } } 리스트 18.8 whereCond 구성 예 ( List) : < “NAME=?”, “TITLE LIKE ‘%공지%’ ”> whereValue 구성 예 ( Map) : < (new Integer(1), ”한연희”), >

  27. 게시물 목록 출력 코드 • 게시물 목록 출력 코드설명 (검색조건 있을 경우) – 계속 • 글의 전체 개수를 얻어옴 • intcount = manager.count(whereCond, whereValue); • 수행되는 Query 문 • select count(*) from THEME_MESSAGE whereNAME=한연희 • select count(*) from THEME_MESSAGE whereNAME=한연희 or title like ‘%공지%’ • Java 코딩에서 Query 구성 법 StringBuffer query = new StringBuffer(200); query.append("select count(*) from THEME_MESSAGE "); if (whereCond != null && whereCond.size() > 0) { query.append("where "); for (int i = 0 ; i < whereCond.size() ; i++) { query.append(whereCond.get(i)); if (i < whereCond.size() -1 ) { query.append(" or "); } } } pstmt = conn.prepareStatement(query.toString()); Iterator keyIter = valueMap.keySet().iterator(); Integer key = (Integer)keyIter.next(); Object obj = valueMap.get(key); pstmt.setString(key.intValue(), (String)obj); 리스트 18.9

  28. 게시물 목록 출력 코드 • 게시물 목록 출력 코드설명 (검색조건 있을 경우) – 계속 • 글 목록을 읽어 옴 • Listlist = manager.selectList(whereCond, whereValue, startRow-1, endRow-1); • 수행되는 Query 문 • select * from THEME_MESSAGE whereNAME=한연희 or title like ‘%공지%’ order by GROUP_ID desc, ORDER_NO asc limit ?, ? • Java 코딩에서 Query 구성 법 • 글전체 개수를 구하는 코드에서 Query 구성법과 비슷 • 검색 조건 없을 때의 Query 구성법과 병합하여 최종 Query를구성!!! • 새 게시물 입력 링크 • 관련 코드 <td colspan="4" align="right"><a href="writeForm.jsp">[이미지등록]</a></td>

  29. 게시물 목록 출력 코드 • 파라미터 값 갖는 링크 구성 • 링크 구성 시 활용하는 폼 • 게시물 링크 리스트 18.8 <form name="move" method="post"> <input type="hidden" name="id" value=""> <input type="hidden" name="page" value="${currentPage}"> <c:if test="<%= searchCondTitle %>"> <input type="hidden" name="search_cond" value="title"> </c:if> <c:if test="<%= searchCondName %>"> <input type="hidden" name="search_cond" value="name"> </c:if> <c:if test="${! empty param.search_key}"> <input type="hidden" name="search_key" value="${param.search_key}"> </c:if> </form> <a href="javascript:goView(${theme.id})">${theme.title}</a> . . <scriptlanguage=“JavaScript”> function goView(id) { document.move.action = "read.jsp"; document.move.id.value = id; document.move.submit(); } </script> 리스트 18.8

  30. 게시물 목록 출력 코드 • 파라미터 값 갖는 링크 구성 • 페이지번호 링크 <c:set var="count" value="<%= Integer.toString(count) %>" /> <c:set var="PAGE_SIZE" value="<%= Integer.toString(PAGE_SIZE) %>" /> <c:set var="currentPage" value="<%= Integer.toString(currentPage) %>" /> <c:if test="${count > 0}"> <c:set var="pageCount" value="${count / PAGE_SIZE + (count % PAGE_SIZE == 0 ? 0 : 1)}" /> <c:set var="startPage" value="${currentPage - (currentPage % 10) + 1}" /> <c:set var="endPage" value="${startPage + 10}" /> <c:if test="${endPage > pageCount}"> <c:set var="endPage" value="${pageCount}" /> </c:if> <c:if test="${startPage > 10}"> <a href="javascript:goPage(${startPage - 10})">[이전]</a> </c:if> <c:forEach var="pageNo" begin="${startPage}" end="${endPage}"> <c:if test="${currentPage == pageNo}"><b></c:if> <a href="javascript:goPage(${pageNo})">[${pageNo}]</a> <c:if test="${currentPage == pageNo}"></b></c:if> </c:forEach> <c:if test="${endPage < pageCount}"> <a href="javascript:goPage(${startPage + 10})">[다음]</a> </c:if> </c:if> 리스트 18.8 <scriptlanguage=“JavaScript”> function goPage(pageNo) { document.move.action = "list.jsp"; document.move.page.value = pageNo; document.move.submit(); } </script>

  31. 게시물 보기 코드 • 게시물 보기 코드 설명 • 게시물 읽어 오기 • 사용하는 SQL Query 문 • select * from THEME_MESSAGE where THEME_MESSAGE_ID = ? • select CONTENT from THEME_CONTENT where THEME_MESSAGE_ID = ? • Theme 자바빈 구성 String themeId = request.getParameter("id"); ThemeManager manager = ThemeManager.getInstance(); Theme theme = manager.select(Integer.parseInt(themeId)); 리스트 18.23 Theme theme = new Theme(); theme.setId(rsMessage.getInt("THEME_MESSAGE_ID")); theme.setGroupId(rsMessage.getInt("GROUP_ID")); . . theme.setContent(buffer.toString()); . . return theme;

  32. 게시물 보기 코드 • 게시물 보기 코드 설명 • 링크 구성 시 활용하는 폼 <form name="move" method="post"> <input type="hidden" name="id" value=“${theme.id}"> <input type="hidden" name=“parentId" value=“${theme.id}"> <input type="hidden" name=“groupId" value=“${theme.groupId}"> <input type="hidden" name="page" value="${param.page}"> <c:forEach var="searchCond" items="${paramValues.search_cond}"> <c:if test="${searchCond == 'title'}"> <input type="hidden" name="search_cond" value="title"> </c:if> <c:if test="${searchCond == 'name'}"> <input type="hidden" name="search_cond" value="name"> </c:if> </c:forEach> <c:if test="${! empty param.search_key}"> <input type="hidden" name="search_key" value="${param.search_key}"> </c:if> </form> 리스트 18.23

  33. 게시물 보기 코드 • 게시물 보기 코드 설명 • 다양한링크구성 <tr> <td colspan="2"> <a href="javascript:goReply()">[답변]</a> <a href="javascript:goModify()">[수정]</a> <a href="javascript:goDelete()">[삭제]</a> <a href="javascript:goList()">[목록]</a> </td> </tr> <script language="JavaScript"> function goReply() { document.move.action = "writeForm.jsp"; document.move.submit(); } function goModify() { document.move.action = "updateForm.jsp"; document.move.submit(); } function goDelete() { document.move.action = "deleteForm.jsp"; document.move.submit(); } function goList() { document.move.action = "list.jsp"; document.move.submit(); } function viewLarge(imgUrl) { } </script> 리스트 18.23

  34. 게시물 입력 코드 • 게시물 입력 코드 설명 • writeForm_view.jsp  write.jsp • 답변글일 경우 parentId 및 부모글의 제목 읽음 • 부모글은 theme 변수에 저장 • 폼 입력시 hidden 필드 구성 • 폼 입력 내용에 대한 validation <input type="hidden" name="level" value="${theme.level + 1}"> <c:if test="${! empty param.groupId}"> <input type="hidden" name="groupId" value="${param.groupId}"> </c:if> <c:if test="${! empty param.parentId}"> <input type="hidden" name="parentId" value="${param.parentId}"> </c:if> 리스트 18.20 <form action="write.jsp" method="post" enctype="multipart/form-data" onSubmit="return validate(this)"> 리스트 18.20

  35. 게시물 입력 코드 • 게시물 입력 코드 설명 • writeForm_view.jsp이 전달해준 입력 폼 내용을 write.jsp에서 받기 • 업로드 이미지 저장 및 썸네일 이미지 저장 • theme 빈 내용 추가 및 DB 저장 <jsp:useBean id="theme" class="kut.ime.bbs.Theme"> <jsp:setProperty name="theme" property="*" /> </jsp:useBean> 리스트 18.21 theme.setRegister(new Timestamp(System.currentTimeMillis())); theme.setImage(image); ThemeManager manager = ThemeManager.getInstance(); manager.insert(theme); 리스트 18.21

  36. 게시물 입력 코드 • 게시물 입력 코드 설명 • 답변글이 아닌 경우 제일 큰 그룹번호를 구하는 SQL Query • select max(GROUP_ID) from THEME_MESSAGE • 답변글인 경우 같은 부모를 지닌 답글 중 제일 큰 순서 번호를 구하는 SQL Query • select max(ORDER_NO) from THEME_MESSAGE where PARENT_ID = [theme.getParentId()] or THEME_MESSAGE_ID = [theme.getParentId()] • 답변글을저장할 경우 새롭게 저장될 순서 번호에 맞추어 기존글들의 순서 번호 갱신하는 SQL Query • update THEME_MESSAGE set ORDER_NO = ORDER_NO + 1 where GROUP_ID = [theme.getGroupId()] and ORDER_NO >= [theme.getOrderNo()] • 새로운글의 일련 번호를 구함 • 새로운글을 삽입하는 SQL Query • insert into THEME_MESSAGE values (?,?,?,?,?,?,?,?,?,?,?)"); • insert into THEME_CONTENT values (?,?) theme.setId(Sequencer.nextId(conn, "THEME_MESSAGE")); 리스트 18.8

More Related