백엔드/JAVA

게시판 구현 (2)

두개의 문 2023. 6. 7. 20:35

 

게시물 생성 기능

 

▷ 실행 결과

 

 

 

▶ BoardManager4 클래스

메인 메뉴에서 '1. Create' 선택 시, 새로운 게시물의 제목, 내용, 작성자를 키보드로 입력받고,

보조 메뉴에서 '1.Ok'를 선택 시, boards 테이블에 새로운 게시물이 저장되도록 해보자.

 

package bbs.mariadb.controller;

import static bbs.mariadb.util.BbsIO.p;
import static bbs.mariadb.util.BbsIO.pl;
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 BoardManager4 {
	//화면에 게시글 목록 출력 메서드
	
	// 멤버변수
	private Scanner scanner;
	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 BoardManager4(){
		scanner = new Scanner(System.in);	
		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", "올 여름은 비가 너무 온대요");
		// 데모 게시글 끝
		
		// 진짜 게시물 목록 출력 시작
		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.getBwriter(),
						  board.getBdate(), 
						  board.getBtitle());
			
			}
			// 진짜 게시물 목록 출력 끝 
			
			// 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("메뉴 선택 : ");
		
		// 스캐너 이용 메뉴를 선택함 -> 변수 menuNo에 저장
		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() {
		// * 1 ) 자료 입력받기 시작 
       		// ❶ 먼저 비어있는 새로운 DTO 객체 생성
		Board boardDTO = new Board();		// *4 디버그 중단점 
		pl("[ 새로운 게시물을 입력해주세요.]");
		p("제목 : ");
		boardDTO.setBtitle(scanner.nextLine());	
        	// ❷ 스캐너로부터 입력받은 내용을 boardDTO의 제목에 저장
		p("내용 : ");
		boardDTO.setBcontent(scanner.nextLine()); 
		p("작성자 : ");
		boardDTO.setBwriter(scanner.nextLine());
		// * 자료 입력받기 끝
		
		// * 2 ) 보조 메뉴 출력 : 자료 저장하기 전 확인하기 대화창 
		pl("=====================================================");
		// 메뉴 출력
		pl("보조 메뉴 : 1. Ok | 2. Cancel ");
		// 메뉴 선택하는 입력창
		p("메뉴 선택 : ");
		String menuNo = scanner.nextLine();
		// 선택된 메뉴 번호 처리
		if (menuNo.equals("1")) {	
			// MariaDB에 새 게시물 저장		=> 이 블럭 실행 후, list()메서드 호출 시, 기능중복되므로 호출하면 안됨
			// (1) INSERT sql 문자열을 만든다
			String sql = """
				INSERT INTO boards 
					(btitle, bcontent, bwriter, bdate)
					VALUES (?, ?, ?, now());
				""";
			
			PreparedStatement pstmt;
			try {
			// (2) PreparedStatement 준비
				pstmt = conn.prepareStatement(sql);
			// (3) PreparedStatement 객체의 파라미터를 저장한다
				pstmt.setString(1, boardDTO.getBtitle());
				pstmt.setString(2, boardDTO.getBcontent());
				pstmt.setString(3, boardDTO.getBwriter());
		
			// (4) PreparedStatement 객체 질의문 실행
				pstmt.executeUpdate();
				
			// (5) PreparedStatement 객체 종료
				pstmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
				exit();
			} catch (Exception e) {
				e.printStackTrace();
				exit();
			}
		} //else {
			// 입력취소 -> 목록으로 돌아감		=> 사실 불필요함(if문 아래 list()메서드 호출 하므로)	
		//}
		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);
	}
	
}

 

① 스캐너로부터 입력받은 문자열을 변수 menuNo에 저장

② menuNo가 1일 경우, 보조메뉴의 '1.Ok'를 의미하므로 새로운 정보가 게시물에 저장됨

이 때, ==가 아닌 equals( ) 메서드를 이용해 비교 ( ∵ 참조 주소가 아닌 문자열의 내용이 같은지 비교 )

 

 

 


게시물 읽기 기능

 

▷ 실행 결과

 

▶ BoardManager5 클래스

메인 메뉴에서 '2. Read' 선택 시, 게시물의 번호를 키보드로 입력받고, boards 테이블에 있는 해당 게시물을 가져와서 출력해보자.

 

 

package bbs.mariadb.controller;

import static bbs.mariadb.util.BbsIO.p;
import static bbs.mariadb.util.BbsIO.pl;
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 BoardManager5 {
	//화면에 게시글 목록 출력 메서드
	
	// 멤버변수
	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 BoardManager5(){
		scanner = new Scanner(System.in);	// *3 디버그
		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", "올 여름은 비가 너무 온대요");
		// 데모 게시글 끝
		
		// 진짜 게시물 목록 출력 시작
		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.getBwriter(),
						  board.getBdate(), 
						  board.getBtitle());
			
			}
			// 진짜 게시물 목록 출력 끝 
			
			// 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("메뉴 선택 : ");
		
		// 스캐너 이용 메뉴를 선택함 -> 변수 menuNo에 저장
		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() {
		// 1 자료 입력하기 시작 -> 먼저 비어있는 새로운 DTO 객체 생성
		Board boardDTO = new Board();		// *4 디버그 중단점 
		pl("[ 새로운 게시물을 입력해주세요.]");
		p("제목 : ");
		boardDTO.setBtitle(scanner.nextLine());	// 스캐너로부터 입력받은 내용을 boardDTO의 제목에 저장
		p("내용 : ");
		boardDTO.setBcontent(scanner.nextLine()); 
		p("작성자 : ");
		boardDTO.setBwriter(scanner.nextLine());
		// 4+)1 자료 입력하기 끝
		
		// 4+)2 자료 저장하기 전 확인하기 대화창 
		// => 보조메뉴 출력
		pl("=====================================================");
		// 메뉴 출력
		pl("보조 메뉴 : 1. Ok | 2. Cancel ");
		// 메뉴 선택하는 입력창
		p("메뉴 선택 : ");
		String menuNo = scanner.nextLine();
		// 선택된 메뉴 번호 처리
		if (menuNo.equals("1")) {		// ==이 아닌 equals로 비교한 이유 : 클래스 객체의 내용물(값) 비교
										// -> 주소비교가 아닌, 내용물이 같은지 비교해야 함(주소비교 시, 참조주소가 아닌 이상 다르다고 나옴)
			// MariaDB에 새 게시물 저장		=> 이 블럭 실행 후, list()메서드 호출 시, 기능중복되므로 호출하면 안됨
			// (1) INSERT sql 문자열을 만든다
			String sql = """
				INSERT INTO boards 
					(btitle, bcontent, bwriter, bdate)
					VALUES (?, ?, ?, now());
				""";
			
			PreparedStatement pstmt;
			try {
			// (2) PreparedStatement 준비
				pstmt = conn.prepareStatement(sql);
			// (3) PreparedStatement 객체의 파라미터를 저장한다
				pstmt.setString(1, boardDTO.getBtitle());
				pstmt.setString(2, boardDTO.getBcontent());
				pstmt.setString(3, boardDTO.getBwriter());
		
			// (4) PreparedStatement 객체 질의문 실행
				pstmt.executeUpdate();
				
			// (5) PreparedStatement 객체 종료
				pstmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
				exit();
			} catch (Exception e) {
				e.printStackTrace();
				exit();
			}
			
		
		
		} //else {
			// 입력취소 -> 목록으로 돌아감		=> 사실 불필요함(if문 아래 list()메서드 호출 하므로)	
		//}
		list();
	}
		// * 
		// 2. Read() 메서드
	public void read() {		// *5 디버그 중단점 
		// 보조메뉴 구현 : 상세 자료 보기할 게시물 번호 입력
		pl("---[ 게시물 읽기 ]---");
		p("bno : ");
        	// int bno = scanner.nextLine();
		int bno = Integer.parseInt(scanner.nextLine()); 
		
		// MariaDB로부터 레코드 가져오기
		try {
			String sql = """
				SELECT 
						bno, btitle, bcontent, bwriter, bdate
					FROM boards
					WHERE bno = ? ;
				""";		// bno가 PRIMARY KEY이므로 데이터가 하나만 나옴
			
			PreparedStatement pstmt = conn.prepareStatement(sql);
			// sql의 파라미터에 인수 지정
			pstmt.setInt(1, bno);
			// 쿼리 실행
			ResultSet rs = pstmt.executeQuery();
			if(rs.next()) {
				// board DTO 객체에 레코드 저장
				Board board = new 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"));
				
				// 저장한 레코드를 화면에 출력합니다. => 추후 View 클래스로 분리
				pl("#################################");
				pl("번호 : " + board.getBno());
				pl("제목 : " + board.getBtitle());
				pl("내용 : " + board.getBcontent());
				pl("작성자 : " + board.getBwriter());
				pl("날짜 : " + board.getBdate());
				pl("#################################");
						
			}
			
			rs.close();
			pstmt.close();
			
		} catch(SQLException e) {
			e.printStackTrace();
			exit();		// 문제 발생 시, 프로그램 종료
		}
		
		// 메서드 실행이 잘 되었는지 확인은 list()메서드 호출로 가능
		// 만약 문제가 있다면 exit()메서드로 프로그램 종료
		list();
	}
	
		// 3. Clear() 메서드
	public void clear() {
		pl("*** clear() 메서드 실행됨 ");
		list();
	}
	
		// 4. Exit() 메서드
	public void exit() {
			// 프로그램을 종료함
			// 0 : 프로그램이 잘 종료되었다는 의미
		pl("\n*** 프로그램 종료 ***");
		System.exit(0);
	}
}

① scanner.nextLine( ) 메서드 : String 타입 → 타입 변환 필수!

주석 처리된 부분은 에러 발생 : Type mismatch: cannot convert from String to int

 

 

 


게시물 수정 기능

 

▷ 실행 결과 

 

▶ BoardManager6 클래스

 

	// * 수정폼을 먼저 보인 후, 수정 요청이 OK이면 수정 / 아니면 list() 메서드 호출
	public void update(Board board){
		// 1. 수정 내용 입력 받기
			// 번호는 기본키 속성이므로 수정 불가
		pl("[수정 내용 입력]");
		p("제목 : ");
		board.setBtitle(scanner.nextLine());
		p("내용 : ");
		board.setBcontent(scanner.nextLine());
		p("작성자 : ");
		board.setBwriter(scanner.nextLine());
		
		// 2. 보조 메뉴 출력 - 수정한 내용을 저장할 것인지 취소할 것인지 확인
		pl("---------------------------------------");
		pl("보조 메뉴 : 1. Ok | 2. Cancel");
		p("메뉴 선택 : ");
		String menuNo = scanner.nextLine();
		// 보조메뉴 선택이 2개뿐이므로 switch문 대신 if구문 사용
		if (menuNo.equals("1")) {
			// 쿼리 내용 작성 및 SQL 작성
			try {
				String sql = """
						UPDATE boards 
							SET 
								btitle = ?,
								bcontent = ?,
								bwriter = ? 
							WHERE bno = ? ;
						""";
				PreparedStatement pstmt = conn.prepareStatement(sql);
				// ?에 값을 대입
				pstmt.setString(1, board.getBtitle());
				pstmt.setString(2, board.getBcontent());
				pstmt.setString(3, board.getBwriter());
				pstmt.setInt(4, board.getBno());
				
				// 질의문 실행
				int updateCount = pstmt.executeUpdate();
				// pstmt 종료 
				pstmt.close();
				
			} catch(Exception e) {
				e.printStackTrace();
				// 문제가 있는 경우, 프로그램 자동 종료
				exit();
			}
		}
		// 업데이트 결과, 수정된 내용을 보여주는 목록으로 돌아가기
		list();
		
//  어차피 list() 메서드 호출로 확인 가능 -> else 필요 없음
//		 else {
//			
//		}	
	}
	
	// 6++) 선택된 자료번호 삭제 기능
	public void delete(Board board) {
		// boards 테이블에서 실제 데이터 삭제
		try {
			String sql = """
					DELETE FROM boards WHERE bno = ?;
					""";
		
			PreparedStatement pstmt = conn.prepareStatement(sql);
			pstmt.setInt(1, board.getBno());
			int updateCount = pstmt.executeUpdate();
			pstmt.close();
			
		} catch(Exception e) {
			e.printStackTrace(); 
			// 문제가 있는 경우, 프로그램 자동 종료
			exit();
		}
		
		// 게시물 목록 출력
		list();	
	}

'백엔드 > JAVA' 카테고리의 다른 글

입출력 스트림  (0) 2023.06.11
게시판 구현 (1)  (0) 2023.06.02
데이터 입출력 (2)  (0) 2023.05.31
데이터 입출력(1)  (0) 2023.05.30
JDBC 드라이버 다운로드 및 등록  (0) 2023.05.23