목차
1. 요구사항
JDBC를 사용하여 학생 관리 시스템을 구축해 보자.
● 학생의 정보를 데이터베이스에 저장하고 관리하는 간단한 시스템을 구축합니다.
● 학생 정보를 추가, 조회, 수정, 삭제할 수 있는 기능을 구현합니다.
- 기능 요구사항
- 학생 정보 추가
- 학생 정보 조회
- 학생 정보 수정
- 학생 정보 삭제
- 비기능 요구사항
- 사용자 친화적인 콘솔 인터페이스 제공
- 적절한 예외 처리 및 로그 기록
- 데이터베이스 연결 풀 사용(HikariCP)
2. 프로젝트 설계
1. 데이터베이스 설계 및 테이블 생성
테이블 - tbstudent
컬럼 - id, name, age, email
create database studentdb;
CREATE TABLE students (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
age INT NOT NULL,
email VARCHAR(100) NOT NULL UNIQUE
);
2. 클래스 설계(자유롭게 설계)
package student_management;
public class ManagementRespositoryImpl implements ManagementRespository {
public static final String SELECT = " select * from students where name = ? ";
public static final String SELECT_ALL = " select * from students ";
public static final String INSERT_ALL = " insert into students(name, age, email) values (?,?,?) ";
public static final String UPDATE_AGE = " update students set age = ? where name = ? ";
public static final String UPDATE_EMAIL = " update students set email = ? where name = ? ";
public static final String DELETE = " delete from students where name = ? ";
@Override
public int addStudent(String name, int age, String email) throws SQLException {
int resultRowCount = 0;
try (Connection conn = DBConnectionManger.getConnection()) {
PreparedStatement pstmt = conn.prepareStatement(INSERT_ALL);
pstmt.setString(1, name);
pstmt.setInt(2, age);
pstmt.setString(3, email);
resultRowCount = pstmt.executeUpdate();
}
return resultRowCount;
}
@Override
public List<StudentDTO> viewStudent(String name) throws SQLException {
List<StudentDTO> list = new ArrayList<>();
try (Connection conn = DBConnectionManger.getConnection()) {
PreparedStatement pstmt = conn.prepareStatement(SELECT);
pstmt.setString(1, name);
if (name.equals("all")) {
pstmt = conn.prepareStatement(SELECT_ALL);
}
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
int id = rs.getInt(1);
String name1 = rs.getString(2);
int age = rs.getInt(3);
String email = rs.getString(4);
list.add(new StudentDTO(id, name1, age, email));
}
}
return list;
}
@Override
public int updateAge(String name, int age) throws SQLException {
int resultRowCount = 0;
try (Connection conn = DBConnectionManger.getConnection()){
PreparedStatement pstmt = conn.prepareStatement(UPDATE_AGE);
pstmt.setString(2, name);
pstmt.setInt(1, age);
resultRowCount = pstmt.executeUpdate();
}
return resultRowCount;
}
@Override
public int updateEmail(String name, String email) throws SQLException {
int resultRowCount = 0;
try (Connection conn = DBConnectionManger.getConnection()){
PreparedStatement pstmt = conn.prepareStatement(UPDATE_EMAIL);
pstmt.setString(2, name);
pstmt.setString(1, email);
resultRowCount = pstmt.executeUpdate();
}
return resultRowCount;
}
@Override
public int deleteStudent(String name) throws SQLException {
int resultRowCount = 0;
try (Connection conn = DBConnectionManger.getConnection()){
PreparedStatement pstmt = conn.prepareStatement(DELETE);
pstmt.setString(1, name);
resultRowCount = pstmt.executeUpdate();
}
return resultRowCount;
}
}
package student_management;
public class StudentManagementTest {
static final int INSERT = 1;
static final int SELECT = 2;
static final int UPDATE = 3;
static final int DELETE = 4;
static final int SELECT_ALL = 5;
static final int END = 0;
static String name;
static int age;
static String email;
public static void main(String[] args) {
try (Scanner sc = new Scanner(System.in)) {
ManagementRespositoryImpl respositoryImpl = new ManagementRespositoryImpl();
while (true) {
System.out.println();
printMenu();
int choice = sc.nextInt();
sc.nextLine();
switch (choice) {
case INSERT:
System.out.print("이름을 입력하세요 : ");
name = sc.nextLine();
name.trim();
System.out.print("나이를 입력하세요 : ");
try {
age = sc.nextInt();
sc.nextLine();
} catch (Exception e) {
System.out.println("숫자만 입력해주세요");
sc.nextLine();
break;
}
System.out.print("이메일을 입력하세요 : ");
email = sc.nextLine();
email.trim();
if (!isValidEmail(email)) {
System.out.println("잘못된 이메일 형식입니다.");
break;
}
try {
respositoryImpl.addStudent(name, age, email);
} catch (Exception e) {
System.out.println("입력 오류");
break;
}
break;
case SELECT:
System.out.print("이름을 입력하세요 : ");
name = sc.nextLine();
name.trim();
printStudent(respositoryImpl.viewStudent(name));
break;
case UPDATE:
System.out.println("이름을 입력하세요 : ");
name = sc.nextLine();
name.trim();
if (respositoryImpl.viewStudent(name).size() == 0) {
System.out.println("없는 이름입니다.");
break;
}
System.out.println("나이를 변경하려면 1번");
System.out.println("이메일을 변경하려면 2번");
int choice2 = sc.nextInt();
sc.nextLine();
if (choice2 == 1) {
System.out.println("나이를 입력하세요 : ");
try {
age = sc.nextInt();
sc.nextLine();
} catch (Exception e) {
System.out.println("숫자만 입력해주세요");
sc.nextLine();
break;
}
sc.nextLine();
respositoryImpl.updateAge(name, age);
} else if (choice2 == 2) {
System.out.print("이메일을 입력하세요 : ");
email = sc.nextLine();
email.trim();
if (!isValidEmail(email)) {
System.out.println("잘못된 이메일 형식입니다.");
break;
}
try {
respositoryImpl.updateEmail(name, email);
} catch (Exception e) {
System.out.println("입력오류");
}
} else {
System.out.println("잘못된 입력입니다.");
}
break;
case DELETE:
System.out.println("이름을 입력하세요 : ");
name = sc.nextLine();
name.trim();
respositoryImpl.deleteStudent(name);
break;
case SELECT_ALL:
printStudent(respositoryImpl.viewStudent("all"));
break;
case END:
return;
default :
System.out.println("올바른 숫자를 입력하세요");
sc.nextLine();
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static void printStudent(List<StudentDTO> viewStudent) {
for (StudentDTO studentDTO : viewStudent) {
System.out.println(studentDTO);
}
}
private static void printMenu() {
System.out.println("---------------------------------------------");
System.out.println("1. 학생 정보 추가");
System.out.println("2. 학생 정보 조회");
System.out.println("3. 학생 정보 수정");
System.out.println("4. 학생 정보 삭제");
System.out.println("5. 학생 전체 조회");
System.out.println("0. 종료");
System.out.print("옵션을 선택하세요 : ");
}
private static boolean isValidEmail(String email) {
// 이메일 유효성 검사 정규표현식
String emailRegex = "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$";
return email.matches(emailRegex);
}
}
3. 풀이 코드
package student_management.ver02;
import java.sql.Connection;
import java.sql.SQLException;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
// 싱글톤 패턴 - 단 하나의 객체만 필요함을 보장해야 된다면
// 싱글톤 패턴으로 설계할 수 있다.
public class DBConnectionManager {
// 자기 자신의 참조 주소값을 담을 변수 생성 단, private
private static DBConnectionManager instance;
private HikariDataSource dataSource;
// 생성자를 <---- 외부에서 생성자를 호출 못하게 막아야 한다.
private DBConnectionManager() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/studentdb?serverTimezone=Asia/Seoul");
config.setUsername("root");
config.setPassword("asd123");
config.setMaximumPoolSize(10);
dataSource = new HikariDataSource(config);
}
// 외부에서 클래스이름.getxxx 메서드를 만들어 주면 된다.
// 한 번에 하나의 스레드만 접근하도록 동기화 적용
public static synchronized DBConnectionManager getInstance() {
if (instance == null) {
instance = new DBConnectionManager();
}
return instance;
}
// Connection 객체를 반환( 구현체 - HikariCP 이다 )
public Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
}
package student_management.ver02;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import student_management.ver02.model.StudentDTO;
// 물론 기능 설계는 인터페이스를 먼저 작성하고 구현 클래스를 만드는 것이 좋다.
public class StudentDAO {
// 학생 정보 추가 기능 만들기
public void addStudent(StudentDTO dto) throws SQLException {
String query = " INSERT INTO students(name, age, email) VALUES(?, ?, ?) ";
try (Connection conn = DBConnectionManager.getInstance().getConnection()) {
PreparedStatement pstmt = conn.prepareStatement(query);
pstmt.setString(1, dto.getName());
pstmt.setInt(2, dto.getAge());
pstmt.setString(3, dto.getEmail());
pstmt.executeUpdate();
}
}
// 학생의 아이디로 조회하는 기능 만들기, (id)
public StudentDTO getStudentById(int id) throws SQLException {
String query = " SELECT * FROM students WHERE id = ? ";
try (Connection conn = DBConnectionManager.getInstance().getConnection()) {
PreparedStatement pstmt = conn.prepareStatement(query);
pstmt.setInt(1, id);
try (ResultSet rs = pstmt.executeQuery()) {
if (rs.next()) {
return new StudentDTO(rs.getInt("id"), rs.getString("name"), //
rs.getInt("age"), rs.getString("email"));
}
}
}
return null;
}
// 학생 전체 조회 기능
public List<StudentDTO> getAllStudents() throws SQLException {
// tip - 리스트라면 무조건 리스트를 생성하고 코드 작성
List<StudentDTO> list = new ArrayList<>();
String query = " SELECT * FROM students ";
try (Connection conn = DBConnectionManager.getInstance().getConnection()) {
PreparedStatement pstmt = conn.prepareStatement(query);
try (ResultSet rs = pstmt.executeQuery()) {
while (rs.next()) {
StudentDTO dto = new StudentDTO().builder().id(rs.getInt("id")).name(rs.getString("name")).age(rs.getInt("age"))
.email(rs.getString("email")).build();
list.add(dto);
}
}
}
return list;
}
// 학생 정보 수정하기
public void updateStudent(String name, StudentDTO dto) throws SQLException {
String query = " UPDATE students SET name = ?, age = ?, email = ? WHERE name = ? ";
try (Connection conn = DBConnectionManager.getInstance().getConnection()) {
PreparedStatement pstmt = conn.prepareStatement(query);
pstmt.setString(1, dto.getName());
pstmt.setInt(2, dto.getAge());
pstmt.setString(3, dto.getEmail());
pstmt.setString(4, name); // 조건값 세팅
pstmt.executeUpdate();
}
}
// 학생 정보 삭제하기
public void deleteStudent(int id) throws SQLException {
String query = " DELETE FROM students WHERE id = ? ";
try (Connection conn = DBConnectionManager.getInstance().getConnection()) {
PreparedStatement pstmt = conn.prepareStatement(query);
pstmt.setInt(1, id);
pstmt.executeUpdate();
}
}
}
package student_management.ver02;
import java.sql.SQLException;
import java.util.List;
import student_management.ver02.model.StudentDTO;
public class StudentManagementSystem {
private static final StudentDAO STUDENT_DAO = new StudentDAO();
public static void main(String[] args) {
// 사용자에게 보여주는 부분 꾸며 줘도 됨
try {
List<StudentDTO> list = STUDENT_DAO.getAllStudents();
System.out.println(list.size());
System.out.println(list.toString());
} catch (SQLException e) {
e.printStackTrace();
}
}
}
'Java > 자료구조' 카테고리의 다른 글
자료 구조(Data Structure) (0) | 2024.06.17 |
---|---|
JDBC에서의 예외 처리 - 9 (1) | 2024.06.17 |
JDBC 성능 최적화 - 8 (0) | 2024.06.17 |
JDBC를 활용한 CRUD 와 SOLID 원칙 - 7 (1) | 2024.06.14 |
JDBC 트랜잭션 관리와 배치 처리 - 6 (0) | 2024.06.12 |