2023.06.02
복습
InputStream / OutputStream
바이트 기반 입출력 스트림의 최상위 클래스(완전히 구현되어있지 않다) -> 추상 클래스
Reader / Writer
문자 기반 입출력 스트림의 최상위 클래스(추상클래스)
다운캐스팅은 모두 가능한 것이 아니기 때문에 instance of로 같은 계열을 확인한다면 다운캐스팅이 가능하다
1byet = 8bit
2진수 개 = 16진수
- 색을 16진수로 표현하기도 함 ex) ccc, f2f2f2
● 게시판 만들기
- 이것이 자바다54p
▶ 이론
* 커넥션 풀(Connection Pool) - 아직은 필요 없는 기능
- 다수의 클라이언트의 요청을 처리하는 서버 프로그램은 대부분 커넥션 풀(Connection Pool)을 사용한다.
- 커넥션 풀은 일정량의 Connection을 미리 생성시켜놓고, 서버에서 클라이언트의 요청을 처리할 때 Connection을 제공해주고 다시 반환받는 역할을 수행한다.
- Connection을 요청하면 만들어진 것이 있는지 확인하고 있으면 반환(재사용), 없으면 새로 만들어 반환
-> DB연결 속도가 빨라짐
* 게시판 구현
- 게시판은 기본적인 CRUD(Create, Read, Update, Delete) 기능이 포함되어 있음
* 콘솔프로그램 - 문자로 인터페이스 하는 것(cmd 활용?)
▶ 실습
2023.06.02 - [백엔드/자바] - 자바 - 24
- 데이터베이스 테이블 만들기 참고
* 메소드 list( ), mainMenu ( ), main ( )
main ( ) 메소드는 BoardManager 객체를 생성
list() 메소드는 게시물 목록을 출력하고 mainMenu() 메소드를 호출
* 리스트 영역 / 메뉴 영역으로 메소드를 크게 나누기
list() / mainMenu()
package : bbs.mariadb.app
▷ class : BoardExamplePrototypeApp
- 실행클래스
- 매니저 객체를 생성하고 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(" >>> 메인 프로그램을 마칩니다. <<<");
}
}
package : bbs.mariadb.controller
▷ class : BoardManager
- 실제 게시판을 관리하는 클래스
- list(), mainMenu() 메소드
- BoardExamplePrototypeApp(실행클래스)에서 접근 가능해야하므로 public
- 데모 게시글은 틀을 확인하기위해 작성한 것으로 실제 게시글을 작성하면 주석(또는 삭제) 처리
* 유틸클래스(mariadb.util.BbsIO) 만들어 활용
package bbs.mariadb.controller;
import static bbs.mariadb.util.BbsIO.*; // static 속성을 추가
public class BoardManager {
// 화면에 게시글 목록 출력 메소드
public void list() {
pl("");
pl("[게시물 목록]");
pl("------------------------------------------------------");
System.out.printf(
"%-6s%-12s%-16s%-40s\n", // 왼쪽 정렬, s(문자열)
"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", "올 여름은 비가 많이 온대요");
// 데모 게시글 끝
// 하단에 메인메뉴호출
mainMenu();
}
// 화면 하단에 메인메뉴 메소드
public void mainMenu() {
pl("");
pl("======================================================");
pl("메인 메뉴 : 1. Create | 2. Read | 3. Clear | 4. Exit");
p("메뉴 선택 : ");
pl("");
}
}
* BoardManager에 list(), mainMenu() 메소드 만들고 BoardExamplePrototypeApp클래스 main()에서 호출하기
* 클래스의 패키지 옮기기 - 정석
패키지명 오른쪽 마우스 > Refactor > Move > Create Package...
▷ BoardManager2 만들기(기능 추가)
- BoardManager이어서 작업
- 추가사항 :
1. 키보드 입력을 위해 Scanner 클래스 멤버변수로 추가
- mainMenu() 메소드에서 스캐너 이용
public class BoardManager2 {
// 1. 멤버변수
private Scanner scanner;
// 2. 생성자
public BoardManager2() { // App에서 호출하기 위함
scanner = new Scanner(System.in);
}
}
2. 각 메인메뉴 기능을 위한 메소드들 추가 - 선택한 메뉴 처리(switch 이용)
Create 메뉴 -> create()
Read 메뉴 -> read()
Clear 메뉴 -> clear()
Exit 메뉴 -> exit()
public void mainMenu() {
pl("");
pl("======================================================");
pl("메인 메뉴 : 1. Create | 2. Read | 3. Clear | 4. Exit");
p("메뉴 선택 : ");
// 스캐너를 이용 메뉴를 선택한다
String menuNo = scanner.nextLine();
// 선택한 메뉴처리
switch(menuNo) { // 람다식으로 활용 가능
// 1. Create를 선택한 경우
case "1" :
create();
break;
// 2. Read를 선택한 경우
case "2" :
read();
break;
// 3. Clear를 선택한 경우
case "3" :
clear();
break;
// 4. Exit 를 선택한 경우
case "4" :
exit();
break;
default :
pl("메뉴를 잘못선택하셨습니다.");
list(); // 재귀호출(list가 list를 부름)
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() {
pl("\n**** 프로그램 종료 ****");
// 프로그램을 종료한다
// 0 : 프로그램이 잘 종료되었습니다.
System.exit(0);
}
▷ boards 테이블의 한 개의 행(게시물)을 저장할 Board 클래스를 작성
- 파일을 넣는 bfilename과 bfiledata 컬럼은 지금 안할거라 제외
- 변수 선언을 위해 데이터베이스에서 sql 생성 활용 (오탈자 방지)
- 이클립스 generate 활용 (롬복의 @Data를 사용해도 됨)
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() {
}
// 파일을 넣는 bfilename과 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 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
@Override
public String toString() {
return "Board [bno=" + bno + ", btitle=" + btitle + ", bcontent=" + bcontent + ", bwriter=" + bwriter
+ ", bdate=" + bdate + "]";
}
}
▷ BoardManager3 만들기(기능 추가)
BoardManager2 이어서
* 추가기능
- DB 연결이 필요하므로 Connection 필드 추가
- 진짜 게시물 목록 출력 시작
-> boards 테이블에서 모든 게시물 정보들을 가져온 다음 게시물 목록으로 출력
// 멤버변수
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";
- 생성자에서 DB 연결
public BoardManager3() { // App에서 호출하기 위함
scanner = new Scanner(System.in);
createConnection();
}
//// 3. 속성메소드
public void createConnection() {
try {
Class.forName(JDBC_DRIVER);
// 연결하기
conn = DriverManager.getConnection(JDBC_URL, USER, PASSWORD);
} catch (Exception e) {
e.printStackTrace();
exit();
}
}
- 빌드패스 마리아디비 3.0.10
- list() 메소드 수정(데모 게시글로 작성했던 부분을 board 클래스와 sql문을 이용하여 출력하기)
//// 4. 기능메소드
// 화면에 게시글 목록 출력 메소드 시작
public void list() {
pl(""); // 화면에 빈줄 출력
pl("[게시물 목록]");
pl("------------------------------------------------------");
System.out.printf(
"%-6s%-12s%-16s%-40s\n", // 왼쪽 정렬, s(문자열)
"No", "writer", "date", "title");
pl("------------------------------------------------------");
// 진짜 게시물 목록 출력 시작
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()) { // 레코드를 가지고 있다면
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"));
// board 내용 출력
System.out.printf(
"%-6s%-12s%-16s%-40s\n", // 왼쪽 정렬, s(문자열)
board.getBno(),
board.getBwriter(),
board.getBdate(),
board.getBtitle());
}
// 진짜 게시물 목록 출력 끝
rs.close();
pstmt.close();
} catch(SQLException e) {
e.printStackTrace();
exit();
}
// 하단에 메인메뉴호출
mainMenu();
}
* 디버그
중단점 - 실행클래스의
BoardManager3 boardManager = new BoardManager3();
boardManager.list();
매니저클래스의
scanner = new Scanner(System.in);
▷ BoardManager4 만들기
* 기능추가 - 게시물 생성기능
- 메뉴에서 ‘1.Create’를 선택할 경우
- 매니저클래스의 create()메소드에서 만들어야함
- 키보드로 새로운 게시물(제목, 내용, 작성자)을 입력받기
- 보조메뉴 만들기(OK | Cancel)
- OK눌러서 저장하기(list()화면 실행)
- cancel 누르면 다시 create 입력화면
public class BoardManager4 {
...앞단 동일
// 화면 하단에 메인메뉴 메소드
public void mainMenu() {
pl("");
pl("======================================================");
pl("메인 메뉴 : 1. Create | 2. Read | 3. Clear | 4. Exit");
p("메뉴 선택 : ");
// 스캐너를 이용 메뉴를 선택한다
String menuNo = scanner.nextLine();
// 선택한 메뉴처리
switch(menuNo) {
// 1. Create를 선택한 경우
case "1" :
create();
break;
case "2" :
read();
break;
case "3" :
clear();
break;
case "4" :
exit();
break;
default :
pl("메뉴를 잘못선택하셨습니다.");
list();
break;
} // 선택한 메뉴처리 끝
}
// 1. Create
public void create() {
// 자료(게시물) 입력하기 시작
Board boardDTO = new Board();
pl("[새로운 게시물을 입력해주세요]");
p("제목 : ");
// 스캐너에 입력한 내용을 boardDTO객체에 저장
boardDTO.setBtitle(scanner.nextLine());
p("내용 : ");
boardDTO.setBcontent(scanner.nextLine());
p("작성자 : ");
boardDTO.setBwriter(scanner.nextLine());
// 자료 입력하기 끝
// 자료 저장하기전 확인 작업
// 보조메뉴 출력
pl("======================================================");
// 메뉴출력
pl("보조 메뉴 : 1. OK | 2. Cancel");
p("메뉴 선택 : ");
String menuNo = scanner.nextLine();
// 선택된 메뉴 번호 처리
if (menuNo.equals("1")) { // 내용물이 같은지 비교
// 마리아 디비에 새게시물 저장
String sql = """
INSERT INTO boards
(btitle, bcontent, bwriter, bdate)
VALUES (?, ?, ?, now());
""";
try {
PreparedStatement pstmt;
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, boardDTO.getBtitle()); // 값 저장
pstmt.setString(2, boardDTO.getBcontent());
pstmt.setString(3, boardDTO.getBwriter());
pstmt.executeUpdate();
pstmt.close();
} catch(SQLException e) {
e.printStackTrace();
exit();
} catch(Exception e) {
e.printStackTrace();
exit();
}
} else {
// 입력 취소, 목록으로 돌아감
}
// 입력내용이 board에 저장
list();
}
... 뒷단 동일
}
* create() 메소드를 만들기 위해서
DTO 객체에 데이터를 담아야하기 때문에 DTO 객체가 비어있어야한다
-> board가 새로 만들어져야함(new Board())
* 보조메뉴
equals : 객체의 값(내용물) 비교
== : 객체의 주소 비교
* 마리아 디비에 새게시물 저장
1. INSERT sql 문자열을 만든다
2. PreparedStatement 생성
3. PreparedStatement 객체의 파라미터 저장
4. PreparedStatement 객체 질의문 실행 - executeUpdate()
5. PreparedStatement 객체 종료
* set 값 설정하기
get 설장한 값 읽어오기
* 디버그
중단점 - Board boardDTO = new Board();
* next() 구분기호가 공백, nextLine() 구분기호가 \n
-> 같이 쓰면 안됨
▷ BoardManager5 만들기
* 게시물 읽기 기능 추가
- 메뉴에서 ‘2.Read’를 선택할 경우
- 게시물의 번호를 키보드로 입력받기(보조메뉴-bno)
- boards 테이블에 있는 해당 게시물을 가져와서 출력
public class BoardManager5 {
... 앞단 동일
// 2. Read
public void read() {
// 보조메뉴 구현(보고싶은 상세자료 게시물번호 입력)
pl("[게시물 읽기]");
p("bno : ");
int bno = Integer.parseInt(scanner.nextLine());
// 마리아디비로부터 레코드 가져오기
try {
String sql = """
SELECT
bno, btitle, bcontent, bwriter, bdate
FROM boards
WHERE bno = ?;
""";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, bno);
// 쿼리실행
ResultSet rs = pstmt.executeQuery();
if (rs.next()) {
// 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();
}
// 메소드 실행이 잘되었는지 확인은 리스트 메소드 호출로함
// 문제 있으면 exit() 함수로 프로그램 종료
list();
}
... 뒷단 동일
}
* nextLine()으로 받은 숫자는 문자열이기 때문에 정수로 변환을 해주어야한다.
-> Integer.parseInt(scanner.nextLine());
▷ BoardManager6 만들기
* 게시물 수정기능
- 게시물 읽기( ‘2.Read’)에 보조 메뉴 추가 : ‘1.Update | 2.Delete | 3.List’
public void read() {
.. 동일
// 저장한 레코드를 화면에 출력(view)
pl("===================================");
pl("번호 : " + board.getBno());
pl("제목 : " + board.getBtitle());
pl("내용 : " + board.getBcontent());
pl("작성자 : " + board.getBwriter());
pl("작성일자 : " + board.getBdate());
pl("===================================");
// 보조메뉴 출력
pl("---------------------------------------");
pl("보조메뉴 : 1.Update | 2.Delete | 3.List");
p("메뉴선택 : ");
String menuNo = scanner.nextLine();
pl("");
if(menuNo.equals("1")) {
update(board);
} else if(menuNo.equals("2")) {
delete(board);
}
}
rs.close();
pstmt.close();
.. 동일
}
- 보조 메뉴에서 ‘1.Update’를 선택했을 때 제목, 내용, 작성자의 수정 내용을 입력 기능
update() 메소드 추가
보조 메뉴에서 ‘1.Ok’를 선택했을 때 boards 테이블의 해당 게시물을 수정 기능
public void update(Board board) {
pl("[수정내용 입력]");
p("제목 : ");
board.setBtitle(scanner.nextLine());
p("내용 : ");
board.setBcontent(scanner.nextLine());
p("작성자 : ");
board.setBwriter(scanner.nextLine());
// 보조메뉴 출력
pl("---------------------------------------");
pl("보조메뉴 : 1. Ok | 2. Cancel");
pl("메뉴 선택 : ");
String menuNo = scanner.nextLine();
if(menuNo.equals("1")) {
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());
pstmt.executeUpdate();
pstmt.close();
} catch(Exception e) {
e.printStackTrace();
exit();
}
}
list();
}
- ‘2.Delete’를 선택했을 때 boards 테이블에서 해당 게시물을 삭제기능
delete() 메소드 추가
public void delete(Board board) {
try {
String sql = "DELETE FROM boards WHERE bno = ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, board.getBno());
pstmt.executeUpdate();
pstmt.close();
} catch(Exception e) {
e.printStackTrace();
exit();
}
list();
}
▷ BoardManager7 만들기
* 게시물 전체 삭제 기능
메인 메뉴에서 ‘3.Clear’를 선택하고 보조 메뉴에서 ‘1.Ok’를 선택했을 때 boards 테이블의 전체 게시물 정보 삭제 기능
// 3. Clear
public void clear() {
pl("[게시물 전체 삭제]");
pl("---------------------------------------");
pl("보조메뉴 : 1. Ok | 2. Cancel ");
p("메뉴 선택 : ");
String menuNo = scanner.nextLine();
if(menuNo.equals("1")) {
try {
String sql = "TRUNCATE TABLE boards";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.executeUpdate();
pstmt.close();
} catch(Exception e) {
e.printStackTrace();
exit();
}
}
list();
}
- TRUNCATE 빠르게 지워짐 log에 남지 않음
* 게시판 종료기능
메뉴에서 ‘4.Exit’를 선택하면 Connection을 닫고 프로그램을 종료
// 4. Exit
public void exit() {
// connection 객체 종료 후 프로그램 종료작업
if( conn != null ) {
try {
conn.close();
} catch(SQLException e) {
}
}
pl("\n** 게시판 종료 **");
// 프로그램을 종료한다
// 0 : 프로그램이 잘 종료되었다.
System.exit(0);
}
}
프로젝트에서 conn 닫기(위치는 매우 중요) - conn을 회수하고 종료를 찍어야함
'백엔드 > 자바' 카테고리의 다른 글
자바 - 29 (Stream) (0) | 2023.06.12 |
---|---|
자바 - 28 (재귀(Recursion) 알고리즘) (0) | 2023.06.08 |
자바 - 26 (Stream) (0) | 2023.06.02 |
자바 - 25 (트랜잭션) (0) | 2023.06.02 |
자바 - 24 (0) | 2023.06.02 |