회원제 게시판 프로그램 중 게시판(Board) 만들기!
-- 게시글 목록 조회 + 댓글 개수(상관 서브쿼리 + 스칼라 서브쿼리)
-- BOARD 테이블 : BOARD_NO, BOARD_TITLE, BOARD_CONTENT, CREATE_DATE, READ_COUNT, MEMBER_NO
SELECT BOARD_NO, BOARD_TITLE, CREATE_DATE, READ_COUNT, MEMBER_NM,
(SELECT COUNT(*) FROM REPLY R
WHERE R.BOARD_NO = B.BOARD_NO) REPLY_COUNT
FROM BOARD B
JOIN MEMBER USING(MEMBER_NO)
ORDER BY BOARD_NO DESC;
-- 게시글 번호가 크다 == 최신 글이다
-- 댓글 개수 조회(특정 게시글만)
SELECT COUNT(*) FROM REPLY
WHERE BOARD_NO = 1;
-- BOARD 테이블 샘플 데이터
INSERT INTO BOARD
VALUES(SEQ_BOARD_NO.NEXTVAL, '샘플 게시글 1', '샘플1 내용입니다.', DEFAULT, DEFAULT, 1);
INSERT INTO BOARD
VALUES(SEQ_BOARD_NO.NEXTVAL, '샘플 게시글 2', '샘플2 내용입니다.', DEFAULT, DEFAULT, 1);
INSERT INTO BOARD
VALUES(SEQ_BOARD_NO.NEXTVAL, '샘플 게시글 3', '샘플3 내용입니다.', DEFAULT, DEFAULT, 1);
COMMIT;
-- 댓글 샘플 데이터 삽입
-- REPLY_NO, REPLY_CONTENT, CREATE_DATE, MEMBER_NO, BOARD_NO
INSERT INTO REPLY
VALUES(SEQ_REPLY_NO.NEXTVAL, '샘플1의 댓글1', DEFAULT, 1, 1);
INSERT INTO REPLY
VALUES(SEQ_REPLY_NO.NEXTVAL, '샘플1의 댓글2', DEFAULT, 1, 1);
INSERT INTO REPLY
VALUES(SEQ_REPLY_NO.NEXTVAL, '샘플1의 댓글3', DEFAULT, 1, 1);
COMMIT;
-- 특정 게시글 상세 조회
SELECT B.*, MEMBER_NM
FROM BOARD B
JOIN MEMBER M ON(B.MEMBER_NO = M.MEMBER_NO)
WHERE BOARD_NO = 1;
-- 특정 게시글의 댓글 목록 조회
SELECT R.*, MEMBER_NM
FROM REPLY R
JOIN MEMBER M ON(R.MEMBER_NO = M.MEMBER_NO)
WHERE BOARD_NO = 1
-- ORDER BY REPLY_NO DESC; -- 최근 댓글이 상단
ORDER BY REPLY_NO; -- 최근 댓글이 하단
-- 댓글 목록에서 최근 작성한 글은 제일 위? 제일 아래?
-- SNS 카페, 커뮤니티
-- 게시글 수 증가
-- 이전 조회수 +1 을 조회수 컬럼에 대입
UPDATE BOARD SET
READ_COUNT = READ_COUNT + 1
WHERE BOARD_NO = ?;
-- 게시글 삭제
DELETE FROM BOARD WHERE BOARD_NO = 1;
-- ORA-02292: 무결성 제약조건(ASH_MEMBER.SYS_C007898)이 위배되었습니다- 자식 레코드가 발견되었습니다
SELECT * FROM BOARD WHERE BOARD_NO = 1; -- BOARD 테이블 1번 게시글
SELECT * FROM REPLY WHERE BOARD_NO = 1; -- REPLY 테이블에서 BOARD 테이블 1번 게시글을 참조하는 댓글
--> 기본적으로 삭제 불가
--> 삭제 옵션을 추가하면 가능
--> ON DELETE SET NULL(자식 컬럼 NULL) / ON DELETE CASCADE(참조하던 자식 행도 삭제)
-- 제약조건은 ALTER(변경) 없음 -> 삭제 후 다시 추가
-- 기존 REPLY 테이블에 FK 제약조건 삭제
ALTER TABLE REPLY DROP CONSTRAINT SYS_C007898;
-- 삭제 옵션이 추가된 FK를 다시 추가
ALTER TABLE REPLY
ADD FOREIGN KEY(BOARD_NO)
REFERENCES BOARD
ON DELETE CASCADE;
-- Table REPLY이(가) 변경되었습니다.
-- 다시 1번 게시글 삭제 시도
DELETE FROM BOARD WHERE BOARD_NO = 1;
SELECT * FROM BOARD WHERE BOARD_NO = 1;
SELECT * FROM REPLY WHERE BOARD_NO = 1;
ROLLBACK;
-- 게시글 수정
UPDATE BOARD SET
BOARD_TITLE = ?,
BOARD_CONTENT = ?
WHERE BOARD_NO = ?;
-- 댓글 작성
INSERT INTO REPLY
VALUES(SEQ_REPLY_NO.NEXTVAL, ?, DEFAULT, ?, ?);
-- 댓글 삭제
DELETE FROM REPLY
WHERE REPLY_NO = ?;
-- 댓글 수정
UPDATE REPLY SET
REPLY_CONTENT = ?
WHERE REPLY_NO = ?;
-- 게시글 작성
INSERT INTO BOARD
VALUES(SEQ_BOARD_NO.NEXTVAL, ?, ?, DEFAULT, DEFAULT, ?);
-- 게시글 검색
SELECT BOARD_NO, BOARD_TITLE, CREATE_DATE, READ_COUNT, MEMBER_NM,
(SELECT COUNT(*) FROM REPLY R
WHERE R.BOARD_NO = B.BOARD_NO) REPLY_COUNT
FROM BOARD B
JOIN MEMBER USING(MEMBER_NO)
-- WHERE BOARD_TITLE LIKE '%' || ? || '%'; -- 제목 검색
-- WHERE BOARD_CONTENT LIKE '%' || ? || '%'; -- 내용 검색
-- WHERE BOARD_TITLE LIKE '%' || ? || '%'
-- OR BOARD_CONTENT LIKE '%' || ? || '%'; -- 제목 + 내용
WHERE MEMBER_NM LIKE '%' || ? || '%' -- 작성자 검색
ORDER BY BOARD_NO DESC;
package edu.kh.jdbc.run;
import edu.kh.jdbc.main.view.MainView;
public class ProjectRun {
public static void main(String[] args) {
MainView view = new MainView();
view.displayMenu();
}
}
package edu.kh.jdbc.main.view;
import java.util.InputMismatchException;
import java.util.Scanner;
import edu.kh.jdbc.board.view.BoardView;
import edu.kh.jdbc.member.model.vo.Member;
import edu.kh.jdbc.member.view.MemberView;
public class MainView { // 메인 메뉴(메뉴 선택용/입력 화면)
private Scanner sc = new Scanner(System.in);
// 로그인한 회원의 정보가 저장된 객체를 참조할 변수
private Member loginMember = null;
// 회원 관련 기능 화면을 모아둔 객체를 참조할 변수
private MemberView memberView = new MemberView();
// 게시판 관련 기능 화면을 모아둔 객체를 참조할 변수
private BoardView boardView = new BoardView();
// alt + shift + j : 메소드/클래스 설명용 주석 생성
/**
* 메인 메뉴 출력 메소드
*/
public void displayMenu() {
int menuNum = -1; // 메뉴 선택 값 저장 변수
// 초기 값을 -1로 지정하여, 반복문 첫 바퀴에서 오류 발생 시 종료되는 것을 방지
do {
try {
if(loginMember == null) { // 로그인이 되어 있지 않은 경우
System.out.println("\n************* 회원제 게시판 프로그램 *************\n");
System.out.println("1. 로그인");
System.out.println("2. 회원 가입");
System.out.println("0. 프로그램 종료");
System.out.print("메뉴를 선택해 주세요 >> ");
menuNum = sc.nextInt(); // InputMismatchException
sc.nextLine(); // 입력 버퍼 개행문자 제거
System.out.println(); // 개행
switch(menuNum) {
case 1 : loginMember = memberView.login(); break;
case 2 : memberView.signUp(); break;
case 0 : System.out.println("----- 프로그램 종료 -----"); break;
default : System.out.println("메뉴에 작성된 번호를 입력해 주세요.");
}
} else { // 로그인이 되어 있는 경우
System.out.println("\n************** 회원 메뉴 **************\n");
// - 로그인한 회원 정보 조회
// - 회원 목록 조회
// - 회원 정보 수정(이름, 성별)
// - 비밀번호 변경
// - 회원 탈퇴
System.out.println("1. 내 정보 조회");
System.out.println("2. 가입된 회원 목록 조회");
System.out.println("3. 내 정보 수정(이름, 성별)");
System.out.println("4. 비밀번호 변경");
System.out.println("5. 회원 탈퇴");
System.out.println("6. * 게시판 메뉴 화면 *");
System.out.println("9. 로그아웃");
System.out.print("메뉴를 선택해 주세요 >> ");
menuNum =sc.nextInt();
sc.nextLine();
switch(menuNum) {
case 1 : memberView.myInfo(loginMember); break;
case 2 : memberView.selectAll(); break;
case 3 : memberView.updateMyInfo(loginMember); break;
case 4 : memberView.updatePw(loginMember); break;
case 5 :
int result = memberView.secession(loginMember);
if(result > 0) loginMember = null; // 로그아웃
break;
case 6 : boardView.boardMenu(loginMember); break;
case 9 : loginMember = null; break;
default : System.out.println("메뉴에 작성된 번호를 입력해 주세요.");
}
}
} catch(InputMismatchException e) {
System.out.println("\n입력 형식이 올바르지 않습니다. 다시 시도해 주세요.");
sc.nextLine(); // 입력 버퍼에 남은 잘못된 문자열 제거
}
} while(menuNum != 0);
}
}
package edu.kh.jdbc.board.view;
import java.util.ArrayList;
import java.util.InputMismatchException;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.ExecutionException;
import edu.kh.jdbc.board.model.service.BoardService;
import edu.kh.jdbc.board.model.vo.Board;
import edu.kh.jdbc.board.model.vo.Reply;
import edu.kh.jdbc.member.model.vo.Member;
// 게시판 메뉴 전용 화면
public class BoardView {
private Scanner sc = new Scanner(System.in);
private BoardService service = new BoardService();
/** 게시판 전용 메뉴 화면
* @param loginMember (로그인한 회원 정보)
*/
public void boardMenu(Member loginMember) {
int menuNum = -1;
do {
try {
System.out.println("\n********** 게시판 메뉴 **********\n");
System.out.println("1. 게시글 목록 조회");
System.out.println("2. 게시글 상세 조회(게시글 번호 입력)");
// 게시글 작성자와 로그인한 회원이 같을 때
// 게시글 수정(UPDATE), 게시글 삭제(DELETE)
System.out.println("3. 게시글 작성(INSERT)");
System.out.println("4. 게시글 검색(제목/내용/제목+내용/작성자)");
System.out.println("0. 회원 메뉴로 돌아가기");
System.out.print("메뉴를 선택해 주세요 >> ");
menuNum = sc.nextInt();
sc.nextLine(); // 개행 문자 제거
System.out.println(); // 줄바꿈
switch(menuNum) {
case 1 : selectAll(); break;
case 2 : selectOne(loginMember); break;
// 상세 조회 시 게시글 수정/삭제(게시글 작성 == 로그인한 회원 비교)
// 댓글(누가 작성? / 작성자가 수정, 삭제 확인)
// -> loginMember를 매개변수로 전달
case 3 : insertBoard(loginMember.getMemberNo()); break;
case 4 : searchBoard(); break;
case 0 : System.out.println("회원 메뉴로 돌아갑니다 .."); break;
default : System.out.println("메뉴에 작성된 번호를 입력해 주세요."); break;
}
} catch(InputMismatchException e) {
System.out.println("\n입력 형식이 올바르지 않습니다. 다시 시도해 주세요.");
sc.nextLine(); // 입력 버퍼에 남은 잘못된 문자열 제거
}
} while(menuNum != 0);
}
/**
* 게시글 검색
*/
private void searchBoard() {
System.out.println("\n[게시글 검색]\n");
int menuNum = -1;
do {
try {
System.out.println("--- 검색 조건을 선택해 주세요 ---");
System.out.println("1. 제목");
System.out.println("2. 내용");
System.out.println("3. 제목 + 내용");
System.out.println("4. 작성자");
System.out.println("0. 돌아가기");
System.out.println("선택 >> ");
menuNum = sc.nextInt();
sc.nextLine();
switch(menuNum) {
case 0 : System.out.println("\n게시판 메뉴로 돌아갑니다...\n"); break;
case 1 : case 2 : case 3 : case 4 :
// 검색어 입력 -> Service 호출
System.out.print("검색어 : ");
String keyword = sc.nextLine();
List<Board> boardList = service.searchBoard(menuNum, keyword);
if(boardList.isEmpty()) { // 검색 결과가 비어 있다 == 검색 결과 없음
System.out.println("\n검색 결과가 없습니다.\n");
} else {
System.out.println("------------------------------------------------------------------------");
System.out.printf("%3s %13s%12s %7s%3s %7s%2s %s\n",
"글번호", "제목", "", "작성자", "", "작성일", "" , "조회수");
System.out.println("------------------------------------------------------------------------");
// 향상된 for문
for(Board b : boardList) {
System.out.printf("%3d %20s [%d] %10s %s %3d\n",
b.getBoardNo(), b.getBoardTitle(), b.getReplyCount(),
b.getMemberName(), b.getCreateDate().toString(), b.getReadCount());
}
}
break;
default : System.out.println("\n메뉴에 작성된 번호를 입력해 주세요.\n");
}
} catch(InputMismatchException e) {
System.out.println("\n입력 형식이 올바르지 않습니다. 다시 시도해 주세요.");
sc.nextLine(); // 입력 버퍼에 남은 잘못된 문자열 제거
} catch(Exception e) {
System.out.println("<\n게시글 검색 중 예외 발생>\n");
e.printStackTrace();
break; // 검색 반복문 종료
}
} while(menuNum != 0);
}
/** 게시글 작성
* @param memberNo
*/
private void insertBoard(int memberNo) {
System.out.println("\n[게시글 작성]\n");
System.out.print("게시글 제목 : ");
String boardTitle = sc.nextLine();
System.out.println("\n게시글 내용 (종료 시 @exit 입력)\n");
String boardContent = inputContent();
Board board = new Board();
board.setBoardTitle(boardTitle);
board.setBoardContent(boardContent);
board.setMemberNo(memberNo);
try {
int result = service.insertBoard(board);
if(result > 0) {
System.out.println("\n게시글이 등록되었습니다.\n");
} else {
System.out.println("\n게시글 작성 실패\n");
}
} catch (Exception e) {
System.out.println("\n<게시글 작성 중 예외 발생>\n");
e.printStackTrace();
}
}
/**
* 게시글 목록 조회
*/
private void selectAll() {
System.out.println("[게시글 목록 조회]");
try {
// 게시글 목록 조회 Service 호출 후 결과 반환 받기
List<Board> boardList = service.selectAll();
if(boardList.isEmpty()) { // 조회 결과가 없는 경우
System.out.println("\n[조회된 게시글이 없습니다.]\n");
}else {
System.out.println("------------------------------------------------------------------------");
System.out.printf("%3s %13s%12s %7s%3s %7s%2s %s\n",
"글번호", "제목", "", "작성자", "", "작성일", "" , "조회수");
System.out.println("------------------------------------------------------------------------");
// 향상된 for문
for(Board b : boardList) {
System.out.printf("%3d %20s [%d] %10s %s %3d\n",
b.getBoardNo(), b.getBoardTitle(), b.getReplyCount(),
b.getMemberName(), b.getCreateDate().toString(), b.getReadCount());
}
}
} catch(Exception e) {
System.out.println("\n<게시글 목록 조회 중 예외 발생>\n");
e.printStackTrace();
} finally {
}
}
/** 게시글 상세 조회
* @param loginMember
*/
private void selectOne(Member loginMember) {
System.out.println("[게시글 상세 조회]");
System.out.print("조회할 게시글 번호 입력 : ");
int boardNo = sc.nextInt();
sc.nextLine();
// 게시글 상세 조회 Service를 호출 후 결과 반환(게시글 1개의 정보 == Board)
try {
Board board = service.selectOne(boardNo);
if(board != null) { // 조회된 게시글이 있을 경우
// 상세 조회 출력
System.out.println("\n------------------------------------------------------------");
System.out.printf("번호 : %d | 제목 : %s\n", board.getBoardNo(), board.getBoardTitle());
System.out.println("------------------------------------------------------------");
System.out.printf("작성자 : %s\n"
+ "작성일 : %s\n"
+ "조회수 : %d\n",
board.getMemberName(), board.getCreateDate(), board.getReadCount());
System.out.println("------------------------------------------------------------");
System.out.printf("\n%s\n\n", board.getBoardContent());
System.out.println("------------------------------------------------------------");
// 댓글 목록 조회
System.out.println("\n[댓글]");
for( Reply r : board.getReplyList() ) {
System.out.printf("<%d> | %s | %s\n",
r.getReplyNo(), r.getMemberName(), r.getCreateDate());
System.out.println(r.getReplyContent());
System.out.println(".............................................................\n");
}
// -------------------------------------------
// 상세 조회용 메뉴 출력
System.out.println("===== 상세 조회 메뉴 =====");
System.out.println("1. 댓글 삽입"); // 어떤 회원이든 가능
// 댓글 번호 입력 받아
// 댓글을 작성한 회원 번호 == 로그인한 회원 번호
// -> 수정/삭제
System.out.println("2. 댓글 수정");
System.out.println("3. 댓글 삭제");
// 댓글 번호 입력 -> 댓글이 있는지 확인 -> 해당 댓글이 로그인한 회원 것이 맞는지 검사
// 상세 조회된 게시글의 회원 번호 == 로그인한 회원 번호
// -> 게시글 수정/삭제
if(board.getMemberNo() == loginMember.getMemberNo()) {
System.out.println("4. 게시글 수정");
System.out.println("5. 게시글 삭제");
}
System.out.println("0. 게시판 메뉴로 돌아가기");
System.out.print("메뉴 선택 >> ");
int menuNum = sc.nextInt();
sc.nextLine();
switch(menuNum) {
case 0 : System.out.println("\n게시판 메뉴로 돌아갑니다...\n"); break;
case 1 : insertReply(loginMember, boardNo); break;
case 2 : case 3 :
String tmp = menuNum == 2 ? "\n[댓글 수정]\n" : "\n[댓글 삭제]\n"; // 삼항 연산자
System.out.println(tmp);
System.out.print("댓글 번호 입력 : ");
int replyNo = sc.nextInt();
sc.nextLine();
// 입력 받은 댓글 번호가 댓글 목록에 있는지 확인
Reply reply = null; // 확인된 댓글을 참조할 변수
for(Reply r : board.getReplyList()) { // 반복 접근
if(r.getReplyNo() == replyNo) { // 입력 받은 번호와 일치하는 댓글이 있다면
reply = r;
break;
}
}
if(reply == null) { // 같은 댓글 번호가 목록에 없는 경우
System.out.println("\n해당 댓글이 존재하지 않습니다.\n");
} else { // 같은 댓글 번호가 목록에 있을 경우
// 해당 댓글의 회원 번호(작성자)와
// 로그인한 회원의 번호가 같은지 확인
// -> 같을 경우 로그인한 사람의 댓글이다!
if(reply.getMemberNo() == loginMember.getMemberNo()) {
if(menuNum == 2) updateReply(replyNo); // 댓글 수정
else deleteReply(replyNo); // 댓글 삭제
} else {
System.out.println("\n현재 로그인한 회원의 댓글이 아닙니다.\n");
}
}
break;
case 4 : case 5 :
// 게시글 작성자 번호 == 로그인 회원 번호
if(board.getMemberNo() == loginMember.getMemberNo()) {
// 4번 게시글 수정
if(menuNum == 4) {
updateBoard(boardNo); // 수정용 메소드
} else { // 5번 게시글 삭제
deleteBoard(boardNo); // 삭제용 메소드
}
} else {
System.out.println("메뉴에 표시된 번호만 입력해 주세요.");
}
break;
default : System.out.println("메뉴에 표시된 번호만 입력해 주세요.");
}
} else { // board == null -> 조회된 게시글이 없을 경우
System.out.println("\n존재하지 않는 게시글 번호입니다.\n");
}
}catch(Exception e) {
System.out.println("\n<게시글 상세 조회 중 예외 발생>\n");
e.printStackTrace();
}
}
/** 댓글 수정
* @param replyNo
*/
private void updateReply(int replyNo) {
System.out.println("수정할 내용 입력(종료 시 @exit 입력)");
String input = inputContent();
// Reply 객체 생성해서 댓글 번호, 내용 저장
Reply reply = new Reply();
reply.setReplyNo(replyNo);
reply.setReplyContent(input);
try {
int result = service.updateReply(reply);
if(result > 0) {
System.out.println(replyNo + "번 댓글이 수정되었습니다.\n");
} else {
System.out.println("\n댓글 수정 실패\n");
}
} catch (Exception e) {
System.out.println("\n<댓글 수정 중 예외 발생>\n");
e.printStackTrace();
}
}
/** 댓글 삭제
* @param replyNo
*/
private void deleteReply(int replyNo) {
char ch = ' ';
while(true) {
System.out.print("정말로 삭제하시겠습니까?(Y/N) : ");
ch = sc.next().toUpperCase().charAt(0);
if(ch == 'Y' || ch == 'N') {
break;
} else {
System.out.println("Y 또는 N을 입력해 주세요.\n");
}
}
if(ch =='Y') {
// 보안 문자 생성
String cap = capcha();
System.out.print("다음 보안 문자를 입력해 주세요 >> " + cap);
System.out.print("\n보안 문자 입력 : ");
String input = sc.next();
if(input.equals(cap)) {
try {
int result = service.deleteReply(replyNo);
if(result > 0) {
System.out.println(replyNo + "번 댓글이 삭제되었습니다.");
} else {
System.out.println("삭제 실패");
}
} catch(Exception e) {
System.out.println("\n<댓글 삭제 중 예외 발생>\n");
e.printStackTrace();
}
} else {
System.out.println("\n보안 문자가 일치하지 않습니다. (삭제 취소)\n");
}
} else {
System.out.println("\n삭제를 취소했습니다.\n");
}
}
/** 게시글 수정
* @param boardNo
*/
private void updateBoard(int boardNo) {
System.out.println("\n[게시글 수정]\n");
System.out.print("수정할 제목 : ");
String boardTitle = sc.nextLine();
System.out.println("\n수정할 내용( 종료 시 @exit 입력 )\n");
String boardContent = inputContent(); // 내용 입력 메소드 호출 후 결과 반환 받기
// 게시글 번호 / 수정한 제목 + 내용을 한 번에 저장할 Board 객체 생성
Board board = new Board();
board.setBoardNo(boardNo);
board.setBoardTitle(boardTitle);
board.setBoardContent(boardContent);
try {
int result = service.updateBoard(board);
if(result > 0) {
System.out.println(boardNo + "번 게시글이 수정되었습니다.\n");
} else {
System.out.println("수정 실패");
}
} catch(Exception e) {
System.out.println("\n<게시글 수정 중 예외 발생>\n");
e.printStackTrace();
}
}
/* String(객체)
* - 불변성(immutable) <-> 가변성(mutable)
*
* -> 한 번 생성된 String 객체에 저장된 문자열은 변하지 않는다.
*
* ex) String str = "abc"; // Heap 영역에 String 객체가 생성되고
* // 생성된 객체에 "abc" 문자열 저장
*
*
* str = "123"; // Heap 영역에 새로운 String 객체가 생성되고
* // 생성된 객체에 "123" 문자열 저장 후
* // 객체 주소를 str에 대입
*
* ex) String str = "abc";
*
* str += "123"; // "123"이 저장된 String 객체 생성 후
* // "abc"와 "123"이 합쳐진 String 객체가 추가로 별도 생성
* // 그 후 "abc123" 객체의 주소를 str에 저장
*
* ** String의 문제점 **
*
* - String에 저장된 값을 바꾸거나 누적하려고 할 때마다
* String 객체가 무분별하게 생성됨 --> 메모리 낭비(메모리 누수)
*
* ** 해결 방법 **
* - StringBuffer / StringBuilder (가변성)
* 클래스를 자바에서 제공함
*
* (StringBuffer / StringBuilder는 사용 방법은 똑같음)
* -> 차이점은 동기/비동기 차이밖에 없음
*
*
* */
/** 댓글 작성
* @param loginMember
* @param boardNo
*/
private void insertReply(Member loginMember, int boardNo) {
System.out.println("[댓글 작성]");
System.out.println("댓글 내용 입력(종료 시 @exit 입력)\n");
String replyContent = inputContent();
// 회원 번호, 게시글 번호, 댓글 내용 -> 하나의 Reply 객체에 저장
Reply reply = new Reply();
reply.setMemberNo(loginMember.getMemberNo());
reply.setBoardNo(boardNo);
reply.setReplyContent(replyContent);
try {
// 댓글 삽입(INSERT) Service 호출 후 결과 반환
int result = service.insertReply(reply);
if(result > 0) {
System.out.println("\n댓글이 작성되었습니다.\n");
} else {
System.out.println("댓글 삽입 실패");
}
} catch(Exception e) {
System.out.println("\n<댓글 작성 중 예외 발생>\n");
e.printStackTrace();
}
}
/** 게시글/댓글 내용 입력 메소드
* @return content
*/
private String inputContent() {
// String content = "";
StringBuffer content = new StringBuffer();
String input = null;
while(true) { // @exit가 입력될 때까지 무한히 문자열을 입력받아
// 하나의 변수에 누적 == 게시글 내용
input = sc.nextLine();
if(input.equals("@exit")) { // @exit가 입력된 경우
break;
} else {
// content += input + "\n"; // 줄 바꾸며 누적
content.append(input);
content.append("\n");
// StringBuffer에 저장된 문자열의 제일 뒤에 input을 추가(누적)
// append : (제일 뒤에) 덧붙이다, 추가하다, 첨부하다
// -> 하나의 StringBuffer 객체에 문자열이 계속 누적됨 == (가변)
// (추가적인 String 객체 생성이 없다)
}
}
return content.toString(); // StringBuffer에 오버라이딩된 toString()
// -> 저장된 문자열을 String 형태로 반환
}
/** 게시글 삭제
* @param boardNo
*/
private void deleteBoard(int boardNo) {
// "정말 삭제하시겠습니까?(Y/N) -- 제대로 입력될 때까지 무한 반복"
// -> "Y" 입력 시
// -> 보안 문자 생성
// -> 보안 문자가 일치하는 경우에 삭제 진행
System.out.println("\n[게시글 삭제]\n");
char ch = ' '; // Y/N 저장
while(true) {
System.out.print("정말 삭제하시겠습니까?(Y/N) : ");
ch = sc.next().toUpperCase().charAt(0);
if(ch == 'Y' || ch == 'N') { // Y 또는 N인 경우 추가 입력 X(반복 종료)
break;
} else {
System.out.println("Y 또는 N을 입력해 주세요.\n");
}
}
if(ch == 'Y') { // 삭제를 하려고 하는 경우
// 보안 문자 생성
String cap = capcha();
System.out.print("다음 보안 문자를 입력해 주세요 >> " + cap);
System.out.print("\n보안 문자 입력 : ");
String input = sc.next();
if(input.equals(cap)) { // 입력받은 문자열과 보안 문자가 같을 때
// 삭제 Service 호출
try {
int result = service.deleteBoard(boardNo);
if(result > 0) {
System.out.println(boardNo + "번 게시글이 삭제되었습니다.\n");
} else {
System.out.println("삭제 실패");
}
} catch (Exception e) {
System.out.println("\n<게시글 삭제 중 예외 발생>\n");
e.printStackTrace();
}
} else {
// 취소
System.out.println("\n보안 문자가 일치하지 않습니다. (삭제 취소)\n");
}
} else { // 삭제 취소
System.out.println("\n삭제를 취소했습니다.\n");
}
}
/** 보안 문자 생성 메소드(랜덤 영어 소문자 5개)
* @return cap
*/
private String capcha() {
String cap = "";
for(int i=0; i<5; i++) {
cap += (char)(Math.random() * 26 + 'a');
// int 형변환 : 97 ~ 122
// char 형변환 : 'a' ~ 'z'
}
return cap;
}
}
package edu.kh.jdbc.board.model.service;
// import static : static 필드/메소드 호출 시 클래스명 생략
import static edu.kh.jdbc.common.JDBCTemplate.*;
// * 기호 : 모두, 전부(ALL)
import java.sql.Connection;
import java.util.List;
import edu.kh.jdbc.board.model.dao.BoardDAO;
import edu.kh.jdbc.board.model.vo.Board;
import edu.kh.jdbc.board.model.vo.Reply;
public class BoardService {
private BoardDAO dao = new BoardDAO();
/** 게시글 목록 조회 Service
* @return boardList
* @throws Exception
*/
public List<Board> selectAll() throws Exception {
// 1) Connection 생성
Connection conn = getConnection();
// 2) DAO 메소드(SELECT) 호출 후 결과 반환 받기
List<Board> boardList = dao.selectAll(conn);
// 3) Connection 반환
close(conn);
// 4) DAO 수행 결과 View에 반환
return boardList;
}
/** 게시글 상세 조회
* @param boardNo
* @return
* @throws Exception
*/
public Board selectOne(int boardNo) throws Exception {
// 1) Connection 생성
Connection conn = getConnection();
// 2) 특정 게시글 상세 조회 DAO 메소드(SELECT) 호출 후 결과 반환
Board board = dao.selectOne(conn, boardNo);
if(board != null) { // 2)번 게시글 상세 조회 내용이 있을 경우에만
// 3-1) 특정 게시글의 댓글 목록 조회 DAO 메소드(SELECT) 호출 후 결과 반환 받기
List<Reply> replyList = dao.selectReplyList(conn, boardNo);
// Board 객체의 replyList 필드에 조회한 댓글 목록을 대입(세팅)
board.setReplyList(replyList);
// 3-2) 게시글 조회수 증가 DAO 메소드(UPDATE) 호출 후 결과(성공한 행의 개수) 반환 받기
int result = dao.increaseReadCount(conn, boardNo);
// increase : 증가하다
// 트랜잭션 처리 + 조회수 동기화
if(result > 0) {
commit(conn);
// DB -> READ_COUNT 업데이트
// -> 업데이트 전에 게시글 정보를 조회했음
// -> 조회된 게시글 조회수가 DB보다 조회수 1 낮음
// -> 조회된 게시글의 조회수를 +1 시켜서 DB와 동기화
board.setReadCount(board.getReadCount() + 1);
} else {
rollback(conn);
}
}
// 4) Connection 반환
close(conn);
// 5) DAO 수행 결과 View로 반환
return board; // 게시글 상세 조회 + 댓글 목록
}
/** 게시글 삭제 Service
* @param boardNo
* @return result
* @throws Exception
*/
public int deleteBoard(int boardNo) throws Exception {
// 1) Connection 생성
Connection conn = getConnection();
// 2) DAO 수행 후 결과 반환 받기
int result = dao.deleteBoard(conn, boardNo);
// 3) DAO 수행 결과에 따라 트랜잭션 처리
if(result > 0) commit(conn);
else rollback(conn);
// 4) 사용한 Connection 객체 반환
close(conn);
// 5) DAO 수행 결과 View로 반환
return result;
}
/** 게시글 수정 Service
* @param board
* @return result
* @throws Exception
*/
public int updateBoard(Board board) throws Exception {
Connection conn = getConnection();
int result = dao.updateBoard(conn, board);
if(result > 0) commit(conn);
else rollback(conn);
close(conn);
return result;
}
/** 댓글 작성 Service
* @param reply
* @return result
* @throws Exception
*/
public int insertReply(Reply reply) throws Exception {
// 커넥션 생성
Connection conn = getConnection();
// DAO 수행
int result = dao.insertReply(conn, reply);
// 트랜잭션 처리
if(result > 0) commit(conn);
else rollback(conn);
// 커넥션 반환
close(conn);
return result;
}
/** 댓글 수정 Service
* @param reply
* @return result
* @throws Exception
*/
public int updateReply(Reply reply) throws Exception {
Connection conn = getConnection();
int result = dao.updateReply(conn, reply);
if(result > 0) commit(conn);
else rollback(conn);
close(conn);
return result;
}
/** 댓글 삭제 Service
* @param reply
* @return result
* @throws Exception
*/
public int deleteReply(int replyNo) throws Exception {
Connection conn = getConnection();
int result = dao.deleteReply(conn, replyNo);
if(result > 0) commit(conn);
else rollback(conn);
close(conn);
return result;
}
/** 게시글 작성 Service
* @param board
* @return result
* @throws Exception
*/
public int insertBoard(Board board) throws Exception {
Connection conn = getConnection();
int result = dao.insertBoard(conn, board);
if(result > 0) commit(conn);
else rollback(conn);
close(conn);
return result;
}
/** 게시글 검색 Service
* @param menuNum
* @param keyword
* @return boardList
* @throws Exception
*/
public List<Board> searchBoard(int menuNum, String keyword) throws Exception {
Connection conn = getConnection();
List<Board> boardList = dao.searchBoard(conn, menuNum, keyword);
close(conn);
return boardList;
}
}
package edu.kh.jdbc.board.model.dao;
import static edu.kh.jdbc.common.JDBCTemplate.*;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import edu.kh.jdbc.board.model.vo.Board;
import edu.kh.jdbc.board.model.vo.Reply;
/**
* @author user1
*
*/
public class BoardDAO {
// JDBC 객체 참조용 변수 선언(java.sql)
private Statement stmt;
private PreparedStatement pstmt;
private ResultSet rs;
// SQL 내용을 저장할 Properties 객체 참조 변수 선언
private Properties prop;
// 기본 생성자(board-sql.xml 파일 읽어오기(Properties))
public BoardDAO() {
try {
prop = new Properties();
// xml 파일 읽어오기
prop.loadFromXML(new FileInputStream("board-sql.xml"));
} catch(Exception e) {
e.printStackTrace();
}
}
/** 게시글 목록 조회 DAO
* @param conn
* @return boardList
* @throws Exception
*/
public List<Board> selectAll(Connection conn) throws Exception {
// 결과 저장용 변수
List<Board> boardList = new ArrayList<Board>();
try {
// 1) SQL 작성
String sql = prop.getProperty("selectAll");
// 2) Statement 생성
stmt = conn.createStatement();
// 3) SQL 수행(SELECT) 후 결과 반환 받기(ResultSet)
rs = stmt.executeQuery(sql);
// 4) ResultSet을 한 행씩(rs.next()) 모두 접근
while(rs.next()) {
// 5) 현재 행에서 컬럼명을 이용해서 컬럼 값 얻어오기
int boardNo = rs.getInt("BOARD_NO");
String boardTitle = rs.getString("BOARD_TITLE");
Date createDate = rs.getDate("CREATE_DATE");
int readCount = rs.getInt("READ_COUNT");
String memberName = rs.getString("MEMBER_NM");
int replyCount = rs.getInt("REPLY_COUNT");
// 6) Board 객체를 생성하여 컬럼 값 담기
Board board = new Board(boardNo, boardTitle, createDate, readCount, memberName, replyCount);
// 7) Board 객체를 boardList에 추가
boardList.add(board);
}
} finally {
// 8) JDBC 자원 반환(Connection 제외)
close(rs);
close(stmt);
}
// 결과 반환
return boardList;
}
/** 특정 게시글 상세 조회 DAO
* @param conn
* @param boardNo
* @return board
* @throws Exception
*/
public Board selectOne(Connection conn, int boardNo) throws Exception {
Board board = null; // 결과 저장용 변수
try {
// 1) SQL 작성
String sql = prop.getProperty("selectOne");
// 2) PreparedStatement 생성
pstmt = conn.prepareStatement(sql);
// 3) 위치 홀더 '?' 알맞은 값 세팅
pstmt.setInt(1, boardNo);
// 4) SQL 수행(SELECT) 후 결과 반환 받기 (ResultSet)
rs = pstmt.executeQuery();
// 5) 조회된 한 행(if)이 있을 경우 조회된 컬럼 값 얻어오기
if(rs.next()) {
// int boardNo = rs.getInt("BOARD_NO");
// 입력 받은 boardNo와 조회된 BOARD_NO는 같으므로
// 굳이 DB 조회 결과에서 얻어오지 않아도 된다.
String boardTitle = rs.getString("BOARD_TITLE");
Date createDate = rs.getDate("CREATE_DATE");
int readCount = rs.getInt("READ_COUNT");
String memberName = rs.getString("MEMBER_NM");
String boardContent = rs.getString("BOARD_CONTENT");
int memberNo = rs.getInt("MEMBER_NO");
// 6) Board 객체를 생성하여 컬럼 값 세팅
board = new Board();
board.setBoardNo(boardNo);
board.setBoardTitle(boardTitle);
board.setBoardContent(boardContent);
board.setCreateDate(createDate);
board.setReadCount(readCount);
board.setMemberName(memberName);
board.setMemberNo(memberNo);
}
} finally {
// 7) 사용한 JDBC 자원 반환
close(rs);
close(pstmt);
}
// 결과 반환
return board;
}
/** 특정 게시글 댓글 목록 조회 DAO
* @param conn
* @param boardNo
* @return replyList
* @throws Exception
*/
public List<Reply> selectReplyList(Connection conn, int boardNo) throws Exception {
List<Reply> replyList = new ArrayList<Reply>(); // 결과 저장용 변수
try {
// 1) SQL 작성
String sql = prop.getProperty("selectReplyList");
// 2) PreparedStatement 생성
pstmt = conn.prepareStatement(sql);
// 3) 위치 홀더에 알맞은 값 대입
pstmt.setInt(1, boardNo);
// 4) SQL(SELECT) 수행 후 결과(ResultSet) 반환 받기
rs = pstmt.executeQuery();
// 5) 조회된 결과를 한 행씩 접근(while(rs.next))
// -> 각 행별로 컬럼 값 얻어오기
while(rs.next()) {
int replyNo = rs.getInt("REPLY_NO");
String replyContent = rs.getString("REPLY_CONTENT");
Date createDate = rs.getDate("CREATE_DATE");
int memberNo = rs.getInt("MEMBER_NO");
String memberName = rs.getString("MEMBER_NM");
// boardNo은 매개변수 사용
// 6) Reply 객체를 생성하여 컬럼 값 담기
Reply reply = new Reply();
reply.setReplyNo(replyNo);
reply.setReplyContent(replyContent);
reply.setCreateDate(createDate);
reply.setMemberNo(memberNo);
reply.setMemberName(memberName);
reply.setBoardNo(boardNo);
// 7) replyList에 Reply 객체 추가
replyList.add(reply);
}
} finally {
// 8) JDBC 객체 자원 반환
close(rs);
close(pstmt);
}
// 결과 반환
return replyList;
}
/** 게시글 조회수 증가 DAO
* @param conn
* @param boardNo
* @return result
* @throws Exception
*/
public int increaseReadCount(Connection conn, int boardNo) throws Exception {
int result = 0; // 결과 저장용 변수
try {
String sql = prop.getProperty("increaseReadCount");
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, boardNo);
result = pstmt.executeUpdate();
} finally {
close(pstmt);
}
return result;
}
/** 게시글 삭제 DAO
* @param conn
* @param boardNo
* @return result
* @throws Exception
*/
public int deleteBoard(Connection conn, int boardNo) throws Exception {
int result = 0; // 결과 저장용 변수
try {
String sql = prop.getProperty("deleteBoard");
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, boardNo);
result = pstmt.executeUpdate();
} finally {
close(pstmt);
}
return result;
}
/** 게시글 수정 DAO
* @param conn
* @param board
* @return result
* @throws Exception
*/
public int updateBoard(Connection conn, Board board) throws Exception {
int result = 0;
try {
String sql = prop.getProperty("updateBoard");
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, board.getBoardTitle());
pstmt.setString(2, board.getBoardContent());
pstmt.setInt(3, board.getBoardNo());
result = pstmt.executeUpdate();
} finally {
close(pstmt);
}
return result;
}
/** 댓글 작성 DAO
* @param conn
* @param reply
* @return result
* @throws Exception
*/
public int insertReply(Connection conn, Reply reply) throws Exception {
// 결과 저장용 변수 선언
int result = 0;
try {
// SQL 작성
String sql = prop.getProperty("insertReply");
// PreparedStatement 생성
pstmt = conn.prepareStatement(sql);
// 위치 홀더에 값 세팅
pstmt.setString(1, reply.getReplyContent());
pstmt.setInt(2, reply.getMemberNo());
pstmt.setInt(3, reply.getBoardNo());
// 실행
result = pstmt.executeUpdate();
} finally {
// JDBC 객체 자원 반환
close(pstmt);
}
// 결과 반환
return result;
}
/** 댓글 수정 DAO
* @param conn
* @param reply
* @return result
* @throws Exception
*/
public int updateReply(Connection conn, Reply reply) throws Exception {
int result = 0;
try {
String sql = prop.getProperty("updateReply");
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, reply.getReplyContent());
pstmt.setInt(2, reply.getReplyNo());
result = pstmt.executeUpdate();
} finally {
close(pstmt);
}
return result;
}
/** 댓글 삭제 DAO
* @param conn
* @param replyNo
* @return result
* @throws Exception
*/
public int deleteReply(Connection conn, int replyNo) throws Exception {
int result = 0;
try {
String sql = prop.getProperty("deleteReply");
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, replyNo);
result = pstmt.executeUpdate();
} finally {
close(pstmt);
}
return result;
}
/** 게시글 작성 DAO
* @param conn
* @param board
* @return result
* @throws Exception
*/
public int insertBoard(Connection conn, Board board) throws Exception{
int result = 0;
try {
String sql = prop.getProperty("insertBoard");
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, board.getBoardTitle());
pstmt.setString(2, board.getBoardContent());
pstmt.setInt(3, board.getMemberNo());
result = pstmt.executeUpdate();
} finally {
close(pstmt);
}
return result;
}
/** 게시글 검색 DAO
* @param conn
* @param menuNum
* @param keyword
* @return boardList
* @throws Exception
*/
public List<Board> searchBoard(Connection conn, int menuNum, String keyword) throws Exception {
// 결과 저장용 변수
List<Board> boardList = new ArrayList<Board>();
try {
// SQL 작성(menuNum에 따라서 SQL 조합)
String sqp = prop.getProperty("searchBoard1")
+ prop.getProperty("condition" + menuNum)
+ prop.getProperty("searchBoard2");
pstmt = conn.prepareStatement(sqp);
// 위치 홀더에 알맞은 값 세팅
// * 주의 *
// -> 제목 + 내용을 검색하는 조건(3번)은 혼자만 위치 홀더가 2개이다!!
pstmt.setString(1, keyword);
if(menuNum == 3) pstmt.setString(2, keyword);
rs = pstmt.executeQuery(); // SELECT문 수행 중 결과 ResultSet 변환
while(rs.next()) {
int boardNo = rs.getInt("BOARD_NO");
String boardTitle = rs.getString("BOARD_TITLE");
Date createDate = rs.getDate("CREATE_DATE");
int readCount = rs.getInt("READ_COUNT");
String memberName = rs.getString("MEMBER_NM");
int replyCount = rs.getInt("REPLY_COUNT");
Board board = new Board(boardNo, boardTitle, createDate, readCount, memberName, replyCount);
boardList.add(board);
}
} finally {
close(rs);
close(pstmt);
}
return boardList;
}
}
package edu.kh.jdbc.board.model.vo;
import java.sql.Date;
import java.util.List;
// VO(Value Object) : 값 저장용 객체
// * 꼭 테이블과 같은 모양일 필요가 없다!
// -> 어떤 데이터를 저장하여 옮기고 싶은지에 따라 필드 구성이 달라짐
public class Board {
// 게시글 목록 조회
private int boardNo;
private String boardTitle;
private Date createDate;
private int readCount;
private String memberName;
private int replyCount;
// 게시글 상세 조회
private String boardContent;
private List<Reply> replyList;
// 게시글 수정, 삭제
private int memberNo;
// 기본 생성자
public Board() {}
// 목록 / 검색용 생성자
public Board(int boardNo, String boardTitle, Date createDate, int readCount, String memberName, int replyCount) {
super();
this.boardNo = boardNo;
this.boardTitle = boardTitle;
this.createDate = createDate;
this.readCount = readCount;
this.memberName = memberName;
this.replyCount = replyCount;
}
public int getBoardNo() {
return boardNo;
}
public void setBoardNo(int boardNo) {
this.boardNo = boardNo;
}
public String getBoardTitle() {
return boardTitle;
}
public void setBoardTitle(String boardTitle) {
this.boardTitle = boardTitle;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
public int getReadCount() {
return readCount;
}
public void setReadCount(int readCount) {
this.readCount = readCount;
}
public String getMemberName() {
return memberName;
}
public void setMemberName(String memberName) {
this.memberName = memberName;
}
public int getReplyCount() {
return replyCount;
}
public void setReplyCount(int replyCount) {
this.replyCount = replyCount;
}
public String getBoardContent() {
return boardContent;
}
public void setBoardContent(String boardContent) {
this.boardContent = boardContent;
}
public List<Reply> getReplyList() {
return replyList;
}
public void setReplyList(List<Reply> replyList) {
this.replyList = replyList;
}
public int getMemberNo() {
return memberNo;
}
public void setMemberNo(int memberNo) {
this.memberNo = memberNo;
}
@Override
public String toString() {
return "Board [boardNo=" + boardNo + ", boardTitle=" + boardTitle + ", createDate=" + createDate
+ ", readCount=" + readCount + ", memberName=" + memberName + ", replyCount=" + replyCount
+ ", boardContent=" + boardContent + ", replyList=" + replyList + ", memberNo=" + memberNo + "]";
}
}
package edu.kh.jdbc.board.model.vo;
import java.sql.Date;
public class Reply {
private int replyNo;
private String replyContent;
private Date createDate;
private int memberNo;
private String memberName;
private int boardNo;
public Reply() {}
public int getReplyNo() {
return replyNo;
}
public void setReplyNo(int replyNo) {
this.replyNo = replyNo;
}
public String getReplyContent() {
return replyContent;
}
public void setReplyContent(String replyContent) {
this.replyContent = replyContent;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
public int getMemberNo() {
return memberNo;
}
public void setMemberNo(int memberNo) {
this.memberNo = memberNo;
}
public String getMemberName() {
return memberName;
}
public void setMemberName(String memberName) {
this.memberName = memberName;
}
public int getBoardNo() {
return boardNo;
}
public void setBoardNo(int boardNo) {
this.boardNo = boardNo;
}
@Override
public String toString() {
return "Reply [replyNo=" + replyNo + ", replyContent=" + replyContent + ", createDate=" + createDate
+ ", memberNo=" + memberNo + ", memberName=" + memberName + ", boardNo=" + boardNo + "]";
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>Board Service SQL</comment>
<!-- 게시글 목록 조회 + 댓글 개수 -->
<entry key="selectAll">
SELECT BOARD_NO, BOARD_TITLE, CREATE_DATE, READ_COUNT, MEMBER_NM,
(SELECT COUNT(*) FROM REPLY R
WHERE R.BOARD_NO = B.BOARD_NO) REPLY_COUNT
FROM BOARD B
JOIN MEMBER USING(MEMBER_NO)
ORDER BY BOARD_NO DESC
</entry>
<!-- 특정 게시글 상세 조회 -->
<entry key="selectOne">
SELECT B.*, MEMBER_NM
FROM BOARD B
JOIN MEMBER M ON(B.MEMBER_NO = M.MEMBER_NO)
WHERE BOARD_NO = ?
</entry>
<!-- 특정 게시글 댓글 목록 조회 -->
<entry key="selectReplyList">
SELECT R.*, MEMBER_NM
FROM REPLY R
JOIN MEMBER M ON(R.MEMBER_NO = M.MEMBER_NO)
WHERE BOARD_NO = ?
ORDER BY REPLY_NO
</entry>
<!-- 게시글 조회수 증가 -->
<entry key="increaseReadCount">
UPDATE BOARD SET
READ_COUNT = READ_COUNT + 1
WHERE BOARD_NO = ?
</entry>
<!-- 게시글 삭제 -->
<entry key="deleteBoard">
DELETE FROM BOARD
WHERE BOARD_NO = ?
</entry>
<!-- 게시글 수정 -->
<entry key="updateBoard">
UPDATE BOARD SET
BOARD_TITLE = ?,
BOARD_CONTENT = ?
WHERE BOARD_NO = ?
</entry>
<!-- 댓글 작성 -->
<entry key="insertReply">
INSERT INTO REPLY
VALUES(SEQ_REPLY_NO.NEXTVAL, ?, DEFAULT, ?, ?)
</entry>
<!-- 댓글 수정 -->
<entry key="updateReply">
UPDATE REPLY SET
REPLY_CONTENT = ?
WHERE REPLY_NO = ?
</entry>
<!-- 댓글 삭제 -->
<entry key="deleteReply">
DELETE FROM REPLY
WHERE REPLY_NO = ?
</entry>
<!-- 게시글 작성 -->
<entry key="insertBoard">
INSERT INTO BOARD
VALUES(SEQ_BOARD_NO.NEXTVAL, ?, ?, DEFAULT, DEFAULT, ?)
</entry>
<!-- 게시글 검색1 -->
<entry key="searchBoard1">
SELECT BOARD_NO, BOARD_TITLE, CREATE_DATE, READ_COUNT, MEMBER_NM,
(SELECT COUNT(*) FROM REPLY R
WHERE R.BOARD_NO = B.BOARD_NO) REPLY_COUNT
FROM BOARD B
JOIN MEMBER USING(MEMBER_NO)
</entry>
<!-- 게시글 검색2 -->
<entry key="searchBoard2">
ORDER BY BOARD_NO DESC
</entry>
<!-- 검색 조건 1(제목) -->
<entry key="condition1">
WHERE BOARD_TITLE LIKE '%' || ? || '%'
</entry>
<!-- 검색 조건 2(내용) -->
<entry key="condition2">
WHERE BOARD_CONTENT LIKE '%' || ? || '%'
</entry>
<!-- 검색 조건 3(제목 + 내용) -->
<entry key="condition3">
WHERE BOARD_TITLE LIKE '%' || ? || '%'
OR BOARD_CONTENT LIKE '%' || ? || '%'
</entry>
<!-- 검색 조건 4(작성자) -->
<entry key="condition4">
WHERE MEMBER_NM LIKE '%' || ? || '%'
</entry>
</properties>