지금까지 학습한 JDBC를 활용해 CRUD( Create, Read, Update, Delete ) 기능이 포함된 게시판을 구현해보자.
실행 결과를 보고 코드 작성하는 연습 해보자.
메인 메뉴
▷ 실행 결과
▶ BoardManager 클래스 : 실제 게시판을 관리하는 클래스
① list( ) 메서드 : 화면에 게시글 목록을 출력하는 메서드 → list( ) 메서드 안에서 mainMenu( ) 메서드 호출
② mainMenu( ) 메서드 : 화면 하단에 메인 메뉴를 출력하는 메서드
package bbs.mariadb.controller;
import static bbs.mariadb.util.BbsIO.*;
// static 속성을 모두 여기에 추가하라는 의미
// p(), pl()메서드가 BoardManager클래스의 메서드인 것처럼 호출 가능
public class BoardManager {
// ① 화면에 게시글 목록 출력 메서드
public void list(){
// BoardApp에서 list()메서드에 접근 가능하도록, public으로 지정
pl(""); // 화면에 빈줄 출력
pl(" >>> [게시물 목록] <<< ");
pl("-----------------------------------------------------");
// %-6s : 왼쪽 정렬(-), 총 크기(6칸), 문자열 출력
System.out.printf("%-6s%-12s%-16s%-40s\n",
"no", "writer", "date", "title");
//no writer date title → 이런식으로 출력됨
pl("-----------------------------------------------------");
// 데모 게시글로, 나중에 주석처리할 예정
System.out.printf("%-6s%-12s%-16s%-40s\n",
"1", "봄", "2023-05-30", "게시판을 만들었어요^^;");
System.out.printf("%-6s%-12s%-16s%-40s\n",
"2", "여름", "2023-06-01", "앗! 1등을 노렸는데...");
System.out.printf("%-6s%-12s%-16s%-40s\n",
"3", "가을", "2023-06-02", "올 여름은 비가 너무 온대요");
// 데모 게시글 끝
// list()메서드 내에서 하단에 메인메뉴 호출
mainMenu();
}
// ② 화면 하단에 메인메뉴 메서드 호출
public void mainMenu(){
pl("");
pl("=====================================================");
pl("메인 메뉴 : 1. Create | 2. Read | 3. Clear | 4. Exit ");
p("메뉴 선택 : ");
pl("");
}
}
▶ BbsIO 클래스 : 출력과 관련된 p( ) 메서드와 pl( ) 메서드 정의
package bbs.mariadb.util;
public class BbsIO {
public static void p(String msg){
System.out.print(msg);
}
public static void pl(String msg) {
p(msg + "\n");
}
}
▶ BoardExamplePrototypeApp 클래스 : main( ) 메서드 내에서 BoardManager 객체를 생성한 후, list( ) 메서드 호출함
package bbs.mariadb.app;
import bbs.mariadb.controller.BoardManager;
import static bbs.mariadb.util.BbsIO.*;
public class BoardExamplePrototypeApp {
public static void main(String[] args) {
BoardManager boardManager = new BoardManager();
boardManager.list();
pl(" >>> 프로그램을 마칩니다. <<< ");
}
▷ 출력 결과
BoardExamplePrototypeApp 클래스 실행했으나 오류가 났다 MariaDB Driver 연결을 깜빡함^^;
연결 후, 다시 실행!
메인 메뉴 선택 기능
▷ 실행 결과
메인 메뉴의 1 ~ 4 중 하나 선택 시, 해당 메서드가 실행되도록 작성해보자.
게시판을 구현하는 단계를 파악해보기 위해 BoardManager 클래스를 복사해 BoardManager2 클래스에 기능을 구현해보자.
( BoardManager 클래스 클릭 후 오른쪽클릭 - [ Copy ] - [ Paste ] 클릭하면 다음과 같은 창이 뜸 - [ Ok ] )
▶ BoardManager2 클래스
① 콘솔창에서 키보드로부터 입력을 받기 위해 Scanner 필요
② 각 메인 메뉴에 대한 메서드 추가
ex ) 1. Create 선택 시, create( ) 메서드 호출
→ 이와 같은 방식으로 메인 메뉴 4개에 대한 각각의 메서드를 생성
package bbs.mariadb.controller;
import static bbs.mariadb.util.BbsIO.*;
import java.util.Scanner;
// 실제 게시판을 관리하는 클래스
public class BoardManager2 {
// * 멤버변수
private Scanner scanner;
// * 생성자
public BoardManager2(){
scanner = new Scanner(System.in);
}
// * 속성메서드(getter/setter)
// * 기능메서드
//화면에 게시글 목록 출력 메서드
public void list(){
pl(""); // 화면에 빈줄 출력
pl(" >>> [게시물 목록] <<< ");
pl("-----------------------------------------------------");
// %-6s : 왼쪽 정렬(-), 총 크기(6칸), 문자열 출력
System.out.printf("%-6s%-12s%-16s%-40s\n",
"no", "writer", "date", "title");
//no writer date title
pl("-----------------------------------------------------");
// 데모 게시글로, 나중에 주석처리할 예정
System.out.printf("%-6s%-12s%-16s%-40s\n",
"1", "봄", "2023-05-30", "게시판을 만들었어요^^;");
System.out.printf("%-6s%-12s%-16s%-40s\n",
"2", "여름", "2023-06-01", "앗! 1등을 노렸는데...");
System.out.printf("%-6s%-12s%-16s%-40s\n",
"3", "가을", "2023-06-02", "올 여름은 비가 너무 온대요");
// 데모 게시글 끝
// list()메서드 내에서 하단에 출력될 메인메뉴 호출
mainMenu();
}
// 화면 화단에 메인메뉴 메서드
public void mainMenu(){
pl("");
pl("=====================================================");
pl("메인 메뉴 : 1. Create | 2. Read | 3. Clear | 4. Exit ");
p("메뉴 선택 : ");
// * 스캐너 이용해 메뉴를 선택함
String menuNo = scanner.nextLine();
// Enter 키 이전까지 입력된 문자열을 읽어 String 변수에 저장
// * 선택한 메뉴 처리 시작
switch(menuNo) {
case "1" : // 1. Create를 선택한 경우
create();
break;
case "2" : // 2. Read를 선택한 경우
read();
break;
case "3" : // 3. Clear를 선택한 경우
clear();
break;
case "4" : // 4. Exit를 선택한 경우
exit();
break;
default :
pl("메뉴를 잘못 선택하셨습니다.");
list(); // * 재귀 호출
// list()메서드가 계속 자기자신을 호출하는 상황
// -> 입력 스트림( = Scanner 객체)에 의해 blocking되어
// 재귀를 빠져나갈 수 있음
break;
} // 선택한 메뉴처리 끝
}
// * 메뉴별 각각의 메서드 정의
// 1. Create() 메서드
public void create() {
pl("*** create() 메서드 실행됨 ");
list(); // 다시 게시물의 목록을 출력하는 list() 메서드 호출
}
// 2. Read() 메서드
public void read() {
pl("*** read() 메서드 실행됨 ");
list();
}
// 3. Clear() 메서드
public void clear() {
pl("*** clear() 메서드 실행됨 ");
list();
}
// 4. Exit() 메서드
public void exit() {
pl("\n*** 프로그램 종료 ***");
}
}
상단과 같이 하지 않고, 아래 하단의 방식으로 한 이유 )
→ 이유가 뭐였지..?
▶ BoardExamplePrototypeApp 클래스
① import문과 객체 생성 시, 클래스명을 BoardManager2로 변경
② BoardManager2 클래스에서 생성자의 접근제어자를 'public'으로 지정해야 함
( ∵ BoardExamplePrototypeApp 클래스는 package bbs.mariadb.app;
BoardManager2 클래스는 package bbs.mariadb.controller;
⇒ 즉, 서로 다른 패키지에 있으므로 접근제어자가 (default) 일 경우, 같은 패키지에 속한 클래스에서만 사용할 수 있기 때문 )
package bbs.mariadb.app;
import bbs.mariadb.controller.BoardManager2;
import static bbs.mariadb.util.BbsIO.*;
public class BoardExamplePrototypeApp {
public static void main(String[] args) {
BoardManager2 boardManager = new BoardManager2();
boardManager.list();
pl(" >>> 프로그램을 마칩니다. <<< ");
}
}
▷ 출력 결과 : 실행 결과와 동일하게 출력됨
Board 클래스 작성
게시판을 간단히 구현하기 위해 DTO 클래스를 이용하자 (→ 확인)
▶ Board 클래스
① boards 테이블의 한 개의 행( 게시물 )을 저장할 Board 클래스 작성
② 컬럼 개수와 타입에 맞게 필드 선언
→ DB에서 테이블 구조 먼저 확인한 후, 컬럼명 복사해 멤버변수 생성하자.
※ 이번 게시판 구현에서는 첨부파일은 제외함
③ lombok @Data 어노테이션을 이용해 생성자, Getter, Setter, toString( ) 메서드를 자동 생성시킴
→ lombok를 사용하지 말고 직접 생성해 연습해보자
[ Source ] - [ Generate Constructor using Fields ] : 생성자 생성
[ Source ] - [ Generate Getters and Setters ] : 속성함수 생성
[ Source ] - [ Generate toString( ) ] : toString( ) 메서드 생성
( Object 클래스의 toString( ) 메서드를 재정의 → '@Override' 반드시 붙이기 )
package bbs.mariadb.model;
import java.sql.Blob;
import java.util.Date;
public class Board {
// 멤버변수
private int bno;
private String btitle;
private String bcontent;
private String bwriter;
private Date bdate;
private String bfilename;
private Blob bfiledata;
// 생성자
public Board(int bno, String btitle, String bcontent, String bwriter, Date bdate) {
super();
this.bno = bno;
this.btitle = btitle;
this.bcontent = bcontent;
this.bwriter = bwriter;
this.bdate = bdate;
}
public Board() {
}
// 속성함수
public int getBno() {
return bno;
}
public void setBno(int bno) {
this.bno = bno;
}
public String getBtitle() {
return btitle;
}
public void setBtitle(String btitle) {
this.btitle = btitle;
}
public String getBcontent() {
return bcontent;
}
public void setBcontent(String bcontent) {
this.bcontent = bcontent;
}
public String getBwriter() {
return bwriter;
}
public void setBwriter(String bwriter) {
this.bwriter = bwriter;
}
public Date getBdate() {
return bdate;
}
public void setBdate(Date bdate) {
this.bdate = bdate;
}
// toString() -> Object클래스의 toString() 메서드를 재정의한다는 '@Override' 반드시 붙이기
@Override
public String toString() {
return "Board [bno=" + bno + ", btitle=" + btitle + ", bcontent=" + bcontent + ", bwriter=" + bwriter
+ ", bdate=" + bdate + "]";
}
}
게시물 목록 기능
▷ 실행 결과
▶ BoardManager3 클래스
boards 테이블에서 모든 게시물 정보들을 가져온 다음, 게시물 목록으로 출력해보자
그렇게 하기 위해서는 프로그램을 짜는 순서에 대해 생각해보자.
➊ 우선, DB 연결이 필요하므로 Connection 객체 생성이 제일 중요
❷ String 타입의 sql문 작성 : SELECT문
❸ 이 sql문을 전달하는 역할인 명령객체 생성
Statement 객체보다는 매개변수화된 sql문을 이용하는 PreparedStatement 객체를 사용하자.
PreparedStatement 객체는 Connection의 prepareStatement( ) 메서드 이용하며, 이 때 매개변수로 sql을 넘겨줌
❹ executeQuery( ) 메서드 이용 : 수행 결과로, ResultSet 객체의 값을 반환
❺ 반복문을 통해 게시물 정보를 출력함
❻ ResultSet → Prestatement → Connection 순으로 닫음
( Connection 객체의 경우, 추후 종료 기능에서! )
package bbs.mariadb.controller;
import static bbs.mariadb.util.BbsIO.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Scanner;
import bbs.mariadb.model.Board;
// 실제 게시판을 관리하는 클래스
public class BoardManager3 {
//화면에 게시글 목록 출력 메서드
// 멤버변수
private Scanner scanner;
// * Connection 객체는 BoardManager3 클래스 전역에서 사용해야 하므로 멤버변수로 선언
private Connection conn;
// * 멤버상수
private final String JDBC_DRIVER = "org.mariadb.jdbc.Driver";
private final String JDBC_URL = "jdbc:mariadb://localhost/thisisjava";
private final String USER = "root";
private final String PASSWORD = "mariadb";
// 생성자
public BoardManager3(){
scanner = new Scanner(System.in);
createConnection(); // * 속성메서드로 생성한 후, 생성자에서 호출하는 방식
}
// 기능메서드
// * createConnection() 메서드로 따로 정의
public void createConnection() {
try {
// 드라이버 로딩
Class.forName(JDBC_DRIVER);
// MariaDB와 연결
conn = DriverManager.getConnection(
JDBC_URL, USER, PASSWORD);
} catch(Exception e) {
e.printStackTrace();
exit();
}
}
public void list(){
pl(""); // 화면에 빈줄 출력
pl(" >>> [게시물 목록] <<< ");
pl("-----------------------------------------------------");
// %-6s : 왼쪽 정렬(-), 총 크기(6칸), 문자열 출력
System.out.printf("%-6s%-12s%-16s%-40s\n",
"no", "writer", "date", "title");
//no writer date title
pl("-----------------------------------------------------");
// * 데모 게시글 주석 처리
// System.out.printf("%-6s%-12s%-16s%-40s\n",
// "1", "봄", "2023-05-30", "게시판을 만들었어요^^;");
// System.out.printf("%-6s%-12s%-16s%-40s\n",
// "2", "여름", "2023-06-01", "앗! 1등을 노렸는데...");
// System.out.printf("%-6s%-12s%-16s%-40s\n",
// "3", "가을", "2023-06-02", "올 여름은 비가 너무 온대요");
// 데모 게시글 끝
// * boards 테이블에서 게시물 정보를 가져와 출력하기
String sql = """
SELECT bno, btitle, bcontent, bwriter, bdate
FROM boards
ORDER BY bno DESC ;
""";
// 가장 최근 게시물부터 보기 위해 내림차순 정렬
try {
PreparedStatement pstmt = conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery();
while(rs.next()) { // rs가 레코드를 갖는다면, 루프문 반복
Board board = new Board(); // DTO객체인 board에 데이터를 모두 담을 계획
board.setBno(rs.getInt("bno"));
board.setBtitle(rs.getString("btitle"));
board.setBcontent(rs.getString("bcontent"));
board.setBwriter(rs.getString("bwriter"));
board.setBdate(rs.getDate("bdate"));
// board 내용 출력
System.out.printf("%-6s%-12s%-16s%-40s\n",
board.getBno(),
board.getBtitle(),
board.getBdate(),
board.getBtitle());
}
// * boards 테이블에 있는 게시물 정보 출력 끝
// * while문 이후에 연결 끊기
rs.close();
pstmt.close();
} catch(SQLException e) {
e.printStackTrace();
exit(); // 에러가 날 경우, 종료시킴
}
// list()메서드 내에서 하단에 출력될 메인메뉴 호출
mainMenu();
}
// 화면 하단에 메인메뉴 메서드
public void mainMenu(){
pl("");
pl("=====================================================");
pl("메인 메뉴 : 1. Create | 2. Read | 3. Clear | 4. Exit ");
p("메뉴 선택 : ");
// 스캐너 이용 메뉴를 선택함
String menuNo = scanner.nextLine();
// 선택한 메뉴 처리 시작
switch(menuNo) {
case "1" : // 1. Create를 선택한 경우
create();
break;
case "2" : // 2. Read를 선택한 경우
read();
break;
case "3" : // 3. Clear를 선택한 경우
clear();
break;
case "4" : // 4. Exit를 선택한 경우
exit();
break;
default :
pl("메뉴를 잘못 선택하셨습니다.");
list(); // 2+) 재귀 호출 -> 공유방 문서 확인
// list()메서드가 계속 자기자신을 호출하는 상황
// -> 입력 스트림( = Scanner 객체)에 의해 blocking되어
// 재귀를 빠져나갈 수 있음
break;
} // 선택한 메뉴처리 끝
}
// 메뉴별 각각의 메서드 정의
// 1. Create() 메서드
public void create() {
pl("*** create() 메서드 실행됨 ");
list();
}
// 2. Read() 메서드
public void read() {
pl("*** read() 메서드 실행됨 ");
list();
}
// 3. Clear() 메서드
public void clear() {
pl("*** clear() 메서드 실행됨 ");
list();
}
// 4. Exit() 메서드
public void exit() {
// 프로그램을 종료함
// 0 : 프로그램이 잘 종료되었다는 의미
pl("\n*** 프로그램 종료 ***");
System.exit(0);
}
}
'백엔드 > JAVA' 카테고리의 다른 글
입출력 스트림 (0) | 2023.06.11 |
---|---|
게시판 구현 (2) (0) | 2023.06.07 |
데이터 입출력 (2) (0) | 2023.05.31 |
데이터 입출력(1) (0) | 2023.05.30 |
JDBC 드라이버 다운로드 및 등록 (0) | 2023.05.23 |