[Spring/SQL Developer]게시판에 필요한 테이블 작성 + 게시판시작

[Spring/SQL Developer]게시판에 필요한 테이블 작성 + 게시판시작

게시판 시작에 앞서 게시판에 사용할 테이블을 셋팅해주었다. 나는 수업이 다 지난 후에 따라하는 것이라 이 다음번에 추가했던 게시물 부모시퀀스번호에 대한 부분 쿼리도 함께 추가해 놓도록 하겠다.

--계층형 게시판 (댓글작성을 위해 필요) CREATE TABLE TBL_HIBOARD ( HIBBS_SEQ NUMBER(12) NOT NULL, USER_ID VARCHAR2(20) NOT NULL, HIBBS_GROUP NUMBER(12) NULL, --내가 댓글을 쓰면 그 댓글이 달린 글의 시퀀스번호 HIBBS_ORDER NUMBER(10) NULL, --댓글 순서 HIBBS_INDENT NUMBER(10) NULL, --댓글 들여쓰기 HIBBS_TITLE VARCHAR2(150) NULL, HIBBS_CONTENT CLOB NULL, HIBBS_READ_CNT NUMBER(10) NULL, REG_DATE DATE NULL ); --시퀀스 CREATE SEQUENCE SEQ_HIBOARD_SEQ INCREMENT BY 1 MAXVALUE 999999999999 MINVALUE 1 NOCACHE; COMMENT ON COLUMN TBL_HIBOARD.HIBBS_SEQ IS '게시물번호(시퀀스: SEQ_HIBOARD_SEQ)'; COMMENT ON COLUMN TBL_HIBOARD.USER_ID IS '사용자 아이디'; COMMENT ON COLUMN TBL_HIBOARD.HIBBS_GROUP IS '그룹번호'; COMMENT ON COLUMN TBL_HIBOARD.HIBBS_ORDER IS '그룹내순서'; COMMENT ON COLUMN TBL_HIBOARD.HIBBS_INDENT IS '들여쓰기'; COMMENT ON COLUMN TBL_HIBOARD.HIBBS_TITLE IS '게시물 제목'; COMMENT ON COLUMN TBL_HIBOARD.HIBBS_CONTENT IS '게시물 내용'; COMMENT ON COLUMN TBL_HIBOARD.HIBBS_READ_CNT IS '게시물 조회수'; COMMENT ON COLUMN TBL_HIBOARD.REG_DATE IS '게시물 등록일'; --유니크인덱스 생성 CREATE UNIQUE INDEX XPK_HIBOARD ON TBL_HIBOARD(HIBBS_SEQ ASC); --계층형게시판 첨부파일 (파일첨부를 위해 필요) CREATE TABLE TBL_HIBOARD_FILE ( HIBBS_SEQ NUMBER(12) NOT NULL, --하이보드테이블의 시퀀스번호. 생성X! 이미 생성된걸로 FILE_SEQ NUMBER(3) NOT NULL, --해당 게시글에 대한 파일 순서 FILE_ORG_NAME VARCHAR2(100) NULL, FILE_NAME VARCHAR2(50) NULL, FILE_EXT VARCHAR2(50) NULL, FILE_SIZE NUMBER(12) NULL, REG_DATE DATE NULL ); SELECT NVL(MAX(FILE_SEQ), 0)+1 FROM TBL_HIBOARD_FILE WHERE HIBBS_SEQ = 5; COMMENT ON COLUMN TBL_HIBOARD_FILE.HIBBS_SEQ IS '게시물번호(시퀀스: SEQ_HIBOARD.HIBBS_SEQ)'; COMMENT ON COLUMN TBL_HIBOARD_FILE.FILE_SEQ IS '파일번호(HIBBS_SEQ MAX+1)'; COMMENT ON COLUMN TBL_HIBOARD_FILE.FILE_ORG_NAME IS '원본 파일명'; COMMENT ON COLUMN TBL_HIBOARD_FILE.FILE_NAME IS '파일명'; COMMENT ON COLUMN TBL_HIBOARD_FILE.FILE_EXT IS '파일 확장자'; COMMENT ON COLUMN TBL_HIBOARD_FILE.FILE_SIZE IS '파일 크기'; COMMENT ON COLUMN TBL_HIBOARD_FILE.REG_DATE IS '등록일'; CREATE UNIQUE INDEX XPK_HIBOARD_FILE ON TBL_HIBOARD_FILE(HIBBS_SEQ ASC, FILE_SEQ ASC); --부모게시물에 대한것 ALTER TABLE TBL_HIBOARD ADD HIBBS_PARENT NUMBER(12) DEFAULT 0 NOT NULL; COMMENT ON COLUMN TBL_HIBOARD.HIBBS_PARENT IS '부모 게시물 번호';

첫날, 쿼리문을 작성할 껍데기인 HiBoardDao.xml를 아래처럼 만들어서 준비해뒀다가, 다음날 아래처럼 내용을 채웠다.

SELECT HIBBS_SEQ, USER_ID, USER_NAME, USER_EMAIL, HIBBS_GROUP, HIBBS_ORDER, HIBBS_INDENT, HIBBS_TITLE, HIBBS_CONTENT, HIBBS_READ_CNT, REG_DATE FROM (SELECT ROWNUM AS RNUM, HIBBS_SEQ, USER_ID, USER_NAME, USER_EMAIL, HIBBS_GROUP, HIBBS_ORDER, HIBBS_INDENT, HIBBS_TITLE, HIBBS_CONTENT, HIBBS_READ_CNT, REG_DATE FROM (SELECT A.HIBBS_SEQ AS HIBBS_SEQ, A.USER_ID AS USER_ID, NVL(B.USER_NAME, '') AS USER_NAME, NVL(B.USER_EMAIL, '') AS USER_EMAIL, NVL(A.HIBBS_GROUP, 0) AS HIBBS_GROUP, NVL(A.HIBBS_ORDER, 0) AS HIBBS_ORDER, NVL(A.HIBBS_INDENT, 0) AS HIBBS_INDENT, NVL(A.HIBBS_TITLE, '') AS HIBBS_TITLE, NVL(A.HIBBS_CONTENT, '') AS HIBBS_CONTENT, NVL(A.HIBBS_READ_CNT, 0) AS HIBBS_READ_CNT, NVL(TO_CHAR(A.REG_DATE, 'YYYY.MM.DD HH24:MI:SS'), '') AS REG_DATE FROM TBL_HIBOARD A, TBL_USER B WHERE A.USER_ID = B.USER_ID AND B.USER_NAME LIKE '%' || #{searchValue} || '%' AND A.HIBBS_TITLE LIKE '%' || #{searchValue} || '%' AND DBMS_LOB.INSTR(A.HIBBS_CONTENT, #{searchValue}) > 0 ORDER BY A.HIBBS_GROUP DESC, A.HIBBS_ORDER ASC)) WHERE RNUM >= #{startRow} AND RNUM <= #{endRow}

문법 자체가 어려워 보이는 단어가 많이 등장해서 오잉?하고 어려웠지만 이제는 제법 받아들여서 익숙해보인다. 에 대한것은 검색타입에 따라 1:작성자, 2:제목, 3:내용으로 정해뒀으므로 그에 따른 검색 내용을 나오게 하려는 것이다. Mybatis 에서는 if문을 대신 등을 사용하는데 이 choose가 if~else~ 같이 쓰이는 것이고, when이 으로 쓰여서 조건이 해당 될 시 실행 할 내용을 쓰면 된다.

또한 <,>는 우리가 태그처럼 쓰이기 때문에 <=등은 태그가 아니라 문법처럼 쓰인다는 것을 알려줘야 한다. 그렇게 떄문에 <,>,= 이런식으로 가장 안쪽의 [] 안에 내용을 써준다면, 이 문법 자체가 이 안에 있는 것이 문자다 라는것을 알려주는 것이 된다고 한다.

그리고 쿼리의 SELECT문에 있는 내용은 상단에 있는 와 반드시 매칭이 되어야 하기 때문에 꼭 확인해서 빼두지않도록 하자!

아래는 그 다음으로 내용을 쭉쭉 써내려갈건데, 게시물리스트가 끝난 후에는 게시물 총 수에 대한 내용을 채워준다.

아까의 리턴타입이 resultMap이라면 이번에는 resultType이다.

SELECT COUNT(A.HIBBS_SEQ) AS CNT FROM TBL_HIBOARD A, TBL_USER B WHERE A.USER_ID = B.USER_ID AND B.USER_NAME LIKE '%' || #{searchValue} || '%' AND A.HIBBS_TITLE LIKE '%' || #{searchValue} ||'%' AND DBMS_LOB.INSTR(A.HIBBS_CONTENT, #{searchValue}) > 0

SELECT문 안에 COUNT(A.HIBBS_SEQ) AS CNT에서 토탈카운트를 구하는데 A.HIBBS_SEQ로 해준 이유는

리스트를 가져오면 현재 테이블에 있는 정보를 전부 다 가져오게 된다. 이때에 메모리에 그만큼 로딩시키고 올리고 하는데 시간이 더 걸리게 된다. 하지만 A.HIBBS_SEQ로 하게되면 인덱스테이블을 서칭해서 인덱스 테이블에서 카운트만 조회해 오기 때문에 시간이 확실히 단축되게 된다! 그렇기때문에 이렇게 해주면 임의데이터를 가져오기보다는 현재 카운트를 먼저 한 후 인덱스 테이블을 거쳐서 카운트를 조회한 다음, 있을때만 리스트를 조회할 거야! 라고 하는 것이다. 또한, 우리가 페이징처리를 하려면 토탈카운트가 필요하기 때문에도 이것을 해준 것이다.

다음은 HiBoardDao.java도 틀만 만들어둔 첫날 상태에서 점점 내용을 채워간다.

HiBoardDao.xml과 짝꿍이 될 수 있도록 잘 맞춰주는 것을 항상 잊지 말아야 한다★

package com.icia.web.dao; import org.springframework.stereotype.Repository; @Repository("HiBoardDao") public interface HiBoardDao { //게시물 총 수 public long boardListCount(HiBoard hiBoard); //게시물 리스트 조회 public List boardList(HiBoard hiBoard); }

그리고 select문을 만들려면 Dao, xml, 데이터를 담아둘 객체(HiBoard.java)가 세트이므로 HiBoard.java도 만든다. HiBoard.java는 테이블과 구조가 똑같아야한다 ! getter, setter를 해야하므로. (HiBoard.java는 model폴더에 있다.)

package com.icia.web.model; import java.io.Serializable; public class HiBoard implements Serializable { private static final long serialVersionUID = 1L; //하이보드에 마우스 올리면 자동으로 뜸 첫번째꺼 private long hiBbsSeq; //게시물 번호 private String userId; //게시물 아이디 private long hiBbsGroup; //게시물 그룹번호 private int hiBbsOrder; //게시물 그룹 내 순서 private int hiBbsIndent; //게시물 들여쓰기 private String hiBbsTitle; //게시물 제목 private String hiBbsContent; //게시물 내용 private int hiBbsReadCnt; //게시물 조회수 private String regDate; //게시물 등록일 private String userName; //사용자 이름 private String userEmail; //사용자 이메일 private String searchType; //검색타입(1:이름, 2:제묵, 3:내용) private String searchValue; //검색값 private long startRow; //시작 rownum private long endRow; //끝rownum public HiBoard() { hiBbsSeq=0; userId=""; hiBbsGroup=0; hiBbsOrder=0; hiBbsIndent=0; hiBbsTitle=""; hiBbsContent=""; hiBbsReadCnt=0; regDate=""; userName=""; userEmail=""; searchType=""; searchValue=""; startRow=0; endRow=0; } //아래에는 getter, setter 해줄것! }

다음으로는 서비스를 구현하려고 한다. 서비스명은 HiBoardService.java로 한다.

package com.icia.web.service; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import com.icia.web.dao.HiBoardDao; @Service("HiBoardService") public class HiBoardService { private static Logger logger = LoggerFactory.getLogger(HiBoardService.class); //파일저장 디렉토리 @Value("#{env['upload.save.dir']}") private String UPLOAD_SAVE_DIR; @Autowired private HiBoardDao hiBoardDao; //총 게시물 수 public long boardListCount(HiBoard hiBoard) { long count = 0; try { count = hiBoardDao.boardListCount(hiBoard); } catch(Exception e) { logger.error("[HiBoardService] boardListCount Exception", e); } return count; } //게시물 리스트 public List boardList(HiBoard hiBoard) { List list = null; try { list = hiBoardDao.boardList(hiBoard); } catch(Exception e) { logger.error("[HiBoardService] boardList Exception", e); } return list; } }

이번에는 컨트롤러를 만들어 주려고 한다. 컨트롤러 폴더에 HiBoardController.java라는 이름으로 만들면 된다.

package com.icia.web.controller; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; @Controller("HiBoardController") public class HiBoardController { private static Logger logger= LoggerFactory.getLogger(HiBoardController.class); //쿠키명 @Value("#{env['auth.cookie.name']}") private String AUTH_COOKIE_NAME; //파일저장경로 @Value("#{env['upload.save.dir']}") private String UPLOAD_SAVE_DIR; @Autowired private HiBoardService hiBoardService; private static final int LIST_COUNT = 5; //한페이지의 게시물 수 private static final int PAGE_COUNT = 5; //페이징 수 @RequestMapping(value="/board/list") //포스트, 겟 방식이 없으면 디폴트로 겟방식으로 받는다 public String list(ModelMap model, HttpServletRequest request, HttpServletResponse response) { //조회항목(1:작성자, 2:제목, 3:내용) String searchType = HttpUtil.get(request, "searchType"); //조회값 String searchValue = HttpUtil.get(request, "searchValue"); //현재페이지 long curPage = HttpUtil.get(request, "curPage", (long)1); //없을 때는 0 처리 long totalCount=0; List list = null; //페이징객체 Paging paging = null; //조회 객체 HiBoard search = new HiBoard(); //매게변수로 받은 값이 정상적으로 넘어왔는지 체크 if(!StringUtil.isEmpty(searchType) && !StringUtil.isEmpty(searchValue)) { //두개 다 공백이 아니면 보드리스트의 메소드를 호출 할 거임, 거기 파라미터에 넘겨야한다. 서치타입, 밸류, startrow, endrow 도 넘겨야댐 search.setSearchType(searchType); search.setSearchValue(searchValue); } else { //공백일 때 //객체생성하고나서 초기값은 null로 ~! searchType=""; searchValue=""; } //카운트를 넘길 때 서치타입과, 밸류만 가져오면 됨. 그럼 토탈카운트 가능 totalCount = hiBoardService.boardListCount(search); //그러면 전체건수가 나오게찌 logger.debug("totalCount : " + totalCount); if(totalCount > 0) { //실제 리스트 값을 가져올거임+페이징처리도 추가 //일단 페이징을 위해 두개를 하드코딩으로 값을 넣어두기! 아직 페이징처리 전이니까. search.setStartRow(1); search.setEndRow(5); //초기값이 0으로 들어가있엉 list = hiBoardService.boardList(search); } model.addAttribute("list", list); model.addAttribute("searchType", searchType); model.addAttribute("searchValue", searchValue); model.addAttribute("curPage", curPage); model.addAttribute("paging", paging); return"/board/list"; } }

(Paging은 공통모듈로 교수님께 받아서 파일을 넣어놓아야 한다!)

그리고 보여지는 화면을 위해 /board/list.jsp 파일을 만들어준다.

아래에는 그 중 바디부분만 보여주도록 하겠다. 스크립트는 다음에 채울 예정이므로.

<%@ include file="/WEB-INF/views/include/navigation.jsp" %> 게시판 조회 항목 selected>작성자 selected>제목 selected>내용 조회 번호 제목 작성자 날짜 조회수 ${hiBoard.hiBbsSeq} ${hiBoard.regDate} 이전블럭 ${i} ${i} 다음블럭 글쓰기

위 내용의 ${searchType eq '1'}에서 eq는 같다는 의미이다. (equal,=) 그리고 그 아래 나오는 ${i ne curPage}의 ne는 다르다는 뜻이다. tbody의 내용은 리스트에 데이터가 존재할때만 보여줄 것이기 때문에 로 tbody를 묶어준다. c:if를 잘 닫아주지 않으면 오류가 나게 되므로 닫는것도 꼭꼭 잘 챙겨줄것!

마지막으로 내용이 잘 나오는지 확인해주기 위해 sql developer에서 게시물을 하나 추가해보려고 한다.

INSERT INTO TBL_HIBOARD ( HIBBS_SEQ, USER_ID, HIBBS_GROUP, HIBBS_ORDER, HIBBS_INDENT, HIBBS_TITLE, HIBBS_CONTENT, HIBBS_READ_CNT, REG_DATE ) VALUES ( SEQ_HIBOARD_SEQ.NEXTVAL, 'test', SEQ_HIBOARD_SEQ.CURRVAL, 0, 0, 'test tesT', 'test ttttttt', 0, SYSDATE ); COMMIT;

1행을 추가 한 후에는 반드시 coomit을 해줘야만 한다 !! 이 커밋을 하지 않아 아무 이상이 없는데도 행이 뜨지 않아 한참을 헤맨 기억이 난다. 그러니 커밋을 반드시 꼭꼭 해줄것! (하지만 커밋을 너무 자주하면 또 안된다고 하니 주의 ,,)

from http://bbizzang.tistory.com/28 by ccl(A) rewrite - 2021-12-19 17:27:36