백엔드/JAVA

데이터 입출력 (2)

두개의 문 2023. 5. 31. 17:16
데이터 수정

 

JDBC를 이용해 UPDATE문을 실행해보자.

boards 테이블에 저장된 게시물 중에서 bno가 3인 게시물의 btitle, bcontent, bfilename, bfiledata를 변경해보자.

package mariadb;

import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class BoardUpdateExampleApp {

	public static void main(String[] args) {
		Connection conn = null;
		
		String JDBC_DRIVER = "org.mariadb.jdbc.Driver";
		String JDBC_URL = "jdbc:mariadb://localhost:3306/thisisjava";
		String USER = "root";
		String PASSWORD = "mariadb";
		
		try {
			// JDBC_DRIVER 등록 
			Class.forName(JDBC_DRIVER);
			
			// 연결
			conn = DriverManager.getConnection(JDBC_URL, USER, PASSWORD);
			
			// 매개변수화된 SQL문 작성
			String sql = new StringBuilder()
					.append("UPDATE boards SET")
					.append("btitle = ?, ")
					.append("bcontent = ?, ")
					.append("bfilename = ?, ")
					.append("bfiledata = ?, ")
					.append("WHERE bno = ?")
					.toString();
			
			// PrepareStatement 객체 얻기 및 값 지정
			PreparedStatement pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, "눈사람");
			pstmt.setString(2, "눈으로 만든 사람");
			pstmt.setString(3, "snowman.jpg");
			pstmt.setBlob(4, new FileInputStream("src/mariadb/images/snowman.jpg"));
			pstmt.setInt(5, 3);
			
			// SQL문 실행
			int rows = pstmt.executeUpdate();
			System.out.println("수정된 행 수 : " + rows);
			
			// PreparedStatement 닫기
			pstmt.close();
			
		} catch(Exception e) {
			e.printStackTrace();
		} finally {
			if (conn != null ) {
				try {
					conn.close();
				} catch (SQLException e) {}			
			}	
		}
	}
}

 

※ 오류 발생 : SQLSyntaxErrorException 에러

java.sql.SQLSyntaxErrorException: (conn=80) You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'WHERE bno = 3' at line 1

- 로그 이용해 DB와의 연결까지는 제대로 진행됨을 알 수 있었다.

- 구글 검색 결과, SQL Syntax의 규칙을 위반할 경우, SQLSyntaxErrorException가 발생한다고 한다.

- 그래서 오타가 있는지 살펴보았다.

 

아무리 봐도 어떤 문법에서 오류가 났는지 모르겠다. 

 

 

 


 사용자 정보 읽어오기 - DTO 클래스 

 

package mariadb;

import lombok.Data;

// @ 어노테이션 : 특수한 기능을 실행하는 자바의 실행 주석
@Data	// lombok 라이브러리에게 생성자, setter/getter 메서드를 생성하라는 의미
public class User {
	// 멤버변수 ( 접근제어자 : private )
	private String userId;
	private String userName;
	private String userPassword;
	private int    userAge;
	private String userEmail;

}

- 멤버 변수의 접근제어자 : private로 지정
  → 속성함수 (getter/setter함수)를 이용해 외부에서 접근하자

- Getter / Setter 함수 만드는 방법 
 ① 직접 입력
 ② 이클립스의 자동 생성 방법 ( Source - Generate Getters and Setters... )
 ③ 롬복(lombok)이라는 개발 지원툴 라이브러리 이용
     프로젝트 개발 실행 시, 자동생성

 

 

 


lombok 설치 방법

 

▶ 맥북 설치 방법

 

① 구글 검색 - 홈페이지 이동 - Download 1.18.28 다운로드 - lombok.jar 파일 다운로드됨

② 터미널 - 다운로드 파일로 접근 - 롬복 실행 

 

③ 아래와 같이 Installer 창이 뜸 - [ Specify location ] 클릭 → 최종적으로 SpringToolSuite4.ini 선택 - [ Install / Update ]

    → 성공적으로 다운로드되었다는 창이 뜸 

    ( dev / ide / workspace-spring-tool-suite-4-4.18.0.RELEASE / SpringToolSuite4 / Contents / Eclipse 폴더 내에 SpringToolSuite4.ini 존재함 )

 

 

▶ window에서 설치하는 방법

( lombok 다운로드 방법은 위와 동일 )

① lombok.jar 파일이 다운된 경로 복사 → 명령 프롬프트 창에 아래와 같이 입력 후 Enter

② Installer 창 - [ Specify location ] - dev\ide\sts-4.18.0.RELEASE\STS4.exe 선택 → [ Install / Update ] 클릭

③ 성공적으로 다운로드되었다는 창이 뜸 → 설치 완료 후, STS 종료한 뒤 재실행

※ 만약 lombok이 실행되지 않을 경우

   Build Path 클릭해서 이전에 했던 방식대로 Modulepath 아래에 적용시킨 후, Package Explorer 창에서 확인

   ⇒ [ Source ] - [ Generate Getters and Setters... ] 클릭 시, 아래 사진과 같이 이미 만들어졌다는 창이 뜸

        ∴ lombok @Data가 제대로 실행되고 있음

 

 


사용자 정보 읽기

 

users 테이블에서 userid가 winter인 사용자의 정보를 가져와 출력해보자.

먼저 users 테이블의 한 개의 행 ( 사용자 )을 저장할 User 클래스를 작성하자.

컬럼 개수와 타입에 맞게 필드를 선언하고, lombok @Data 어노테이션을 이용해서 Getter, Setter, toString( ) 메서드를 자동 생성시키자.

package mariadb;

import lombok.Data;

@Data	// @ 어노테이션 : 특수한 기능을 실행하는 자바의 실행 주석
public class User {
	// 멤버변수 ( 접근제어자 : private )
	private String userId;
	private String userName;
	private String userPassword;
	private int    userAge;
	private String userEmail;
}
 

① DTO 클래스

    즉, 데이터 클래스에서는 '@Data'를 사용하여 생성자, Getter / Setter, toString( ) 메서드를 자동으로 생성시킴

② 외부에서 멤버 변수에 접근할 수 있는 속성함수 ( Getter / Setter 함수 ) 작성하는 방법

    ❶ 직접 입력

    ❷ 이클립스의 자동 생성 방법 : [ Source ] - [ Generate Getters and Setters ]

    ❸ lombok이라는 개발 지원 툴 라이브러리 사용 → 프로젝트 개발 실행 시, 자동 생성

 

package mariadb;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

// DAO 클래스
public class UserSelectExampleApp {

	public static void main(String[] args) {
		Connection conn = null ;
		
		String JDBC_DRIVER = "org.mariadb.jdbc.Driver";
		String JDBC_URL = "jdbc:mariadb://localhost:3306/thisisjava";	
		String USER = "root";
		String PASSWORD = "mariadb";
		
		try {
			// 드라이버 찾기
			Class.forName(JDBC_DRIVER);
			System.out.println("DRIVER 로딩 성공!");
			// MariaDB와 연결
			conn = DriverManager.getConnection(JDBC_URL, USER, PASSWORD);
			System.out.println("MariaDB와 연결 성공!");
			
			// SELECT문 정의
			String sql = "" +
					"SELECT userid, username, userpassword, " +
					"		userage, useremail " +
					"	FROM users " +
					" 	WHERE userid = ? ";
			
			// preparedStatement 얻기 및 값 인수 지정
			PreparedStatement pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, "winter");
			
			// SQL 실행 후 결과 얻기 (executeQuery()메서드 : ResultSet 반환)
			ResultSet rs = pstmt.executeQuery();
			
			// 한 개의 레코드만 가져왔다고 가정하자.
			if(rs.next()) {	// 사용자 아이디 발견
				// DTO 클래스 사용
				// ① 생성자를 이용해 초기화
				User user = new User();
				// ② 속성함수 이용
				user.setUserId(rs.getString("userid"));
				user.setUserName(rs.getString("username"));
				user.setUserPassword(rs.getString("userpassword"));
				user.setUserAge(rs.getInt(4));
				user.setUserEmail(rs.getString(5));
				
				System.out.println(user);
				// println(object obj); -> user : 객체
				// println 메서드에 매개변수로 객체가 들어갈 경우,
				// 객체.toString()으로 변환하여 출력함
				
			} else {	
            	// SELECT 질의 결과, 데이터가 없는 경우
				System.out.println("사용자 아이디가 존재하지 않습니다.");
			}
			
		} catch(ClassNotFoundException e) {
			e.printStackTrace();
		} catch(SQLException e) {
			e.printStackTrace();
		} catch(Exception e) {
			e.printStackTrace();
		} finally {
			if(conn != null) {
				try {
					conn.close();
				} catch(SQLException e) {}
			}	
		}	
	}
}

 

※ 오류 발생

 

- lombok를 설치하고 Referenced Libraries에 적용시켰는데, Setter 속성함수가 정의가 되지 않았다고 한다.

- User 클래스에서 [ Source ] - [ Generate Getters and Setters ]한 결과, 생성 창이 뜬다.

- lombok 설치가 제대로 되지 않은 듯 하다.

 

⇒ 일단, User 클래스에 Setter 속성함수와 toString( ) 메서드를 직접 작성하고 나중에 해결하자.

 

▷ 출력 결과

 

 


게시물 정보 읽기

 

package mariadb;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class BoardSelectExample {

	public static void main(String[] args) {
		Connection conn = null;
		String JDBC_DRIVER = "org.mariadb.jdbc.Driver";
		String JDBC_URL = "jdbc:mariadb://localhost/thisisjava";
		String USER = "root";
		String PASSWORD = "mariadb";
				// -> 보안 )인증
		try {
			Class.forName(JDBC_DRIVER);
			System.out.println("DRIVER 로딩 성공!");
			conn = DriverManager.getConnection(JDBC_URL, USER, PASSWORD);
			System.out.println("MariaDB와 연결 성공!");
			
			// MariaDB에 질의할 SELECT SQL 정의
			String sql = "" +
					"SELECT " +
					"      bno, btitle, bcontent, bwriter, " +
					"      bdate, bfilename, bfiledata " +
					"   FROM boards " +
					"   WHERE bwriter = ?; ";
			
			// preparedStatement 명령객체 생성 및 인수 값 지정
			PreparedStatement pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, "winter");
		
			// SQL문 실행 후, ResultSet 값 얻기
			ResultSet rs = pstmt.executeQuery();
			
			while(rs.next()) {
				// 데이터 행을 읽고 각 컬럼 값을 대입하여 DTO 객체인 Board 객체 생성
				Board board = new Board();
					// 기본생성자를 통해 모든 멤버변수가 null값으로 초기화됨.
				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.setBfilename(rs.getString("bfilename"));
				board.setBfiledata(rs.getBlob("bfiledata"));
								   // 메모리로 올림
				
				// 콘솔에 내용출력
				System.out.println(board);
					// println()메서드의 매개변수로 참조변수가 들어오는 경우
					// 참조변수를 참조변수.toString()으로 변환해서 출력됨
				
				// board 객체의 bfiledata를 파일로 저장
				// board DTO객체의 Blob 형식 bfiledata의 참조주소를 
				// blob 변수에 저장
				// 참조라는 것은 원본데이터를 직접 접근할 수 있다.
				// 참조변수가 원본을 바꾸면 원본이 변한다.
				// 새로운 변수를 만들면 접근경로가 짧아진다. 접근하기 쉬워짐.
				
				Blob blob = board.getBfiledata();
					// board 테이블의 bfiledata를 읽어와서
					// Blob 타입의 참조변수 blob에 참조주소를 저장시킴 
				
				
				if(blob != null) {
					// getBinaryStream이라는 의미는 
					// blob 객체로부터 얻어온다 = 읽어온다(=read) = 입력한다(=input)
					InputStream is = blob.getBinaryStream();
					// 메모리에 있는 게 파일로 저장되어야 함.
					OutputStream os;
					
					String folderPath = "/Users/dahee/Desktop/temp/";
					String filepath = folderPath + board.getBfilename();
					File folder = new File(folderPath);
					
					if(!folder.exists()) {
						try {
							folder.mkdir();	// 폴더를 생성
							System.out.println("폴더를 생성했습니다!");
						} catch(Exception e) {
							e.printStackTrace();
						}
					}
					
					os = new FileOutputStream(filepath);		
					is.transferTo(os);
					os.flush();
					os.close();
					is.close();
				}
				rs.close();
				
				// preparedStatement 닫기
				pstmt.close();
			}
			
		} catch(ClassNotFoundException e) {
			e.printStackTrace();
		} catch(SQLException e) {
			e.printStackTrace();
		} catch(Exception e) {
			e.printStackTrace();
		} finally {
			if(conn != null) {
				try {
					conn.close();
				} catch(SQLException e) {}
			}
		}
	}
}

 

※ 맥에서 파일 폴더의 경로 위치정보 얻는 방법

❶ 해당 폴더에서 오른쪽 클릭 - [ 정보 가져오기 ] 클릭

❷ 해당 폴더의 정보 창이 뜸 - [ 위치 ] 에서 오른쪽 클릭 - [ 경로 이름으로 복사 ] → 붙여넣기하면 됨

 

 

▷ 출력 결과

① bfiledata 컬럼의 그림 데이터는 bfilename 컬럼 값을 파일명으로 해서 /Users/dahee/Desktop/temp/ 디렉토리에 저장됨

② 콘솔 출력 결과

※ 오류 발생 : Operation not permit on a closed resultSet

 

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

게시판 구현 (2)  (0) 2023.06.07
게시판 구현 (1)  (0) 2023.06.02
데이터 입출력(1)  (0) 2023.05.30
JDBC 드라이버 다운로드 및 등록  (0) 2023.05.23
H2 데이터베이스 연결 (2)  (0) 2023.05.22