백엔드/JAVA

게시판 구현 (1)

두개의 문 2023. 6. 2. 23:33

지금까지 학습한 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