From 3e2a9244c21031d33c7fbf7b7c10a85d75236ef6 Mon Sep 17 00:00:00 2001 From: Jseungjin Date: Wed, 4 Dec 2024 03:58:46 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20login,=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85,=20=EA=B3=B5=EC=A7=80=EC=82=AC=ED=95=AD,=20=EA=B0=9C?= =?UTF-8?q?=EC=9D=B8=EB=B3=B4=EA=B4=80=ED=95=A8,=20=EB=82=B4=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=EC=88=98=EC=A0=95=20GUI=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Announcement.java | 94 ++++++ AnnouncementListFrame.java | 106 +++++++ DatabaseAuthInformation.java | 156 +++++++++ EditInfoFrame.java | 134 ++++++++ Library.java | 152 +++++++++ LoginFrame.java | 89 ++++++ MainPageFrame.java | 133 ++++++++ MyInfoFrame.java | 85 +++++ RegisterFrame.java | 158 ++++++++++ User.java | 593 ++++++++++++++++++++++++++++++++++- UserStorageFrame.java | 152 +++++++++ main.java | 50 +++ 12 files changed, 1894 insertions(+), 8 deletions(-) create mode 100644 Announcement.java create mode 100644 AnnouncementListFrame.java create mode 100644 DatabaseAuthInformation.java create mode 100644 EditInfoFrame.java create mode 100644 Library.java create mode 100644 LoginFrame.java create mode 100644 MainPageFrame.java create mode 100644 MyInfoFrame.java create mode 100644 RegisterFrame.java create mode 100644 UserStorageFrame.java create mode 100644 main.java diff --git a/Announcement.java b/Announcement.java new file mode 100644 index 0000000..faadd6e --- /dev/null +++ b/Announcement.java @@ -0,0 +1,94 @@ +package DBD_env_unification; + +import java.sql.Timestamp; + +public class Announcement { + private int textNumber; + private String title; + private String managerName; + private String type; + private Timestamp createDate; + private int views; + private String content; + + // 생성자 + public Announcement(int textNumber, String title, String managerName, String type, + Timestamp createDate, int views, String content) { + this.textNumber = textNumber; + this.title = title; + this.managerName = managerName; + this.type = type; + this.createDate = createDate; + this.views = views; + this.content = content; + } + + // Getter 및 Setter + public int getTextNumber() { + return textNumber; + } + + public void setTextNumber(int textNumber) { + this.textNumber = textNumber; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getManagerName() { + return managerName; + } + + public void setManagerName(String managerName) { + this.managerName = managerName; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public Timestamp getCreateDate() { + return createDate; + } + + public void setCreateDate(Timestamp createDate) { + this.createDate = createDate; + } + + public int getViews() { + return views; + } + + public void setViews(int views) { + this.views = views; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + // 출력 메서드 (옵션) + public void printAnnouncement() { + System.out.println("Text Number: " + textNumber); + System.out.println("Title: " + title); + System.out.println("Manager Name: " + managerName); + System.out.println("Type: " + type); + System.out.println("Create Date: " + createDate); + System.out.println("Views: " + views); + System.out.println("Content: " + content); + System.out.println("---------------------------------------------------"); + } +} diff --git a/AnnouncementListFrame.java b/AnnouncementListFrame.java new file mode 100644 index 0000000..936310a --- /dev/null +++ b/AnnouncementListFrame.java @@ -0,0 +1,106 @@ +package DBD_env_unification; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; +import java.util.ArrayList; + +public class AnnouncementListFrame extends JFrame { + private ArrayList announcements; // List에서 ArrayList로 변경 + private MainPageFrame mainPageFrame; + + public AnnouncementListFrame(MainPageFrame mainPageFrame, ArrayList announcements) { + super("공지사항 목록"); + this.mainPageFrame = mainPageFrame; + this.announcements = announcements; + + setLayout(new BorderLayout()); + + // 제목 라벨 설정 + JLabel titleLabel = new JLabel("공지사항 목록", SwingConstants.CENTER); + titleLabel.setFont(new Font("맑은 고딕", Font.BOLD, 24)); + titleLabel.setForeground(Color.BLACK); + add(titleLabel, BorderLayout.NORTH); + + // 공지사항 목록을 표시할 JList + DefaultListModel listModel = new DefaultListModel<>(); + for (Announcement announcement : announcements) { + listModel.addElement(announcement.getTitle()); // 제목만 추가 + } + + JList announcementList = new JList<>(listModel); + announcementList.setFont(new Font("맑은 고딕", Font.PLAIN, 16)); + announcementList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + JScrollPane scrollPane = new JScrollPane(announcementList); + add(scrollPane, BorderLayout.CENTER); + + // 창이 닫힐 때 메인 페이지 프레임을 다시 보이게 설정 + addWindowListener(new java.awt.event.WindowAdapter() { + public void windowClosing(java.awt.event.WindowEvent windowEvent) { + mainPageFrame.setVisible(true); // MainPageFrame을 다시 보이게 함 + } + }); + + // "뒤로 가기" 버튼 추가 + JButton backButton = new JButton("뒤로 가기"); + backButton.setFont(new Font("맑은 고딕", Font.PLAIN, 16)); + backButton.addActionListener(e -> { + // 뒤로 가기 버튼 클릭 시, MainPageFrame을 다시 보이게 하고 현재 프레임을 닫기 + mainPageFrame.setVisible(true); + dispose(); + }); + add(backButton, BorderLayout.SOUTH); + + // 공지사항 선택 시 본문을 보여주는 액션 + announcementList.addListSelectionListener(e -> { + if (!e.getValueIsAdjusting()) { + int selectedIndex = announcementList.getSelectedIndex(); + if (selectedIndex != -1) { + Announcement selectedAnnouncement = announcements.get(selectedIndex); + showAnnouncementDetails(selectedAnnouncement); + } + } + }); + + + + // 프레임 설정 + setSize(500, 400); + setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + setLocationRelativeTo(null); // 화면 가운데에 표시 + setVisible(true); + } + + // 선택한 공지사항의 본문을 보여주는 메서드 + private void showAnnouncementDetails(Announcement announcement) { + JFrame detailFrame = new JFrame("공지사항 상세보기"); + detailFrame.setLayout(new BorderLayout()); + + // 본문을 보여주는 JTextArea + JTextArea contentArea = new JTextArea(announcement.getContent()); + contentArea.setFont(new Font("맑은 고딕", Font.PLAIN, 14)); + contentArea.setLineWrap(true); + contentArea.setWrapStyleWord(true); + contentArea.setCaretPosition(0); + contentArea.setEditable(false); + + JScrollPane scrollPane = new JScrollPane(contentArea); + detailFrame.add(scrollPane, BorderLayout.CENTER); + + // 공지사항 상세정보 패널 + JPanel infoPanel = new JPanel(); + infoPanel.setLayout(new GridLayout(4, 1)); + + // 공지사항 정보 출력 + infoPanel.add(new JLabel("작성자: " + announcement.getManagerName())); + infoPanel.add(new JLabel("작성일: " + announcement.getCreateDate().toString())); + infoPanel.add(new JLabel("조회수: " + announcement.getViews())); + + detailFrame.add(infoPanel, BorderLayout.NORTH); + + // 상세보기 창 설정 + detailFrame.setSize(600, 400); + detailFrame.setLocationRelativeTo(null); // 화면 가운데에 표시 + detailFrame.setVisible(true); + } +} diff --git a/DatabaseAuthInformation.java b/DatabaseAuthInformation.java new file mode 100644 index 0000000..d1719cf --- /dev/null +++ b/DatabaseAuthInformation.java @@ -0,0 +1,156 @@ +package DBD_env_unification; + +import java.io.*; + +/* + * Written by Seonghun Lee on 6. Sep. 2020. + * + * This class parses the mysql database authentication file and stores the DB connection information. + * Setting the class member variables is only permitted in the parsing stage (parse_auth_info). + * */ +public class DatabaseAuthInformation { + private String host; + private String port; + private String database_name; + private String username; + private String password; + + /* + * Class Constructor with no argument. + * It initializes all member values as null. + * */ + public DatabaseAuthInformation() { + this.host = null; + this.port = null; + this.database_name = null; + this.username = null; + this.password = null; + } + + /* + * Parsing function based on given DB authentication file. + * This function check the file verification first, and then parse the given file. + * + * Parameter + * - auth_filepath: String + * Path of the local DB authentication file. + * + * Return + * - Boolean + * Return true for successful data parsing, and false otherwise. + * Wrong file path or any missing on DB connection information is also regarded as fail. + * */ + public boolean parse_auth_info(String auth_filepath) { + String host = null; + String port = null; + String database_name = null; + String username = null; + String password = null; + + /* Parse */ + try { + File file = new File(auth_filepath); + BufferedReader br = new BufferedReader(new FileReader(file)); + String line; + while ((line = br.readLine()) != null) { + if(line.length() == 0) continue; + if(line.charAt(0) == '#') continue; + + int line_length = line.length(); + if(line.substring(0, 4).equals("host")) host = line.substring(5, line_length); + else if(line.substring(0, 4).equals("port")) port = line.substring(5, line_length); + else if(line.substring(0, 8).equals("database")) database_name = line.substring(9, line_length); + else if(line.substring(0, 8).equals("username")) username = line.substring(9, line_length); + else if(line.substring(0, 8).equals("password")) password = line.substring(9, line_length); + } + } catch (IOException e) { + e.printStackTrace(); + return false; + } + + /* Verification */ + boolean flag_verified = true; + if(host == null) flag_verified = false; + if(port == null) flag_verified = false; + if(database_name == null) flag_verified = false; + if(username == null) flag_verified = false; + if(password == null) flag_verified = false; + if(!flag_verified) { + return false; + } + + /* Apply parsed values */ + this.host = host; + this.port = port; + this.database_name = database_name; + this.username = username; + this.password = password; + + return true; + } + + /* + * Getter for host member variable. + * + * Return + * - String + * Return the host member variable. + * */ + public String getHost() { + return host; + } + + /* + * Getter for port member variable. + * + * Return + * - String + * Return the port member variable. + * */ + public String getPort() { + return port; + } + + /* + * Getter for database name member variable. + * + * Return + * - String + * Return the database name member variable. + * */ + public String getDatabase_name() { + return database_name; + } + + /* + * Getter for username member variable. + * + * Return + * - String + * Return the username member variable. + * */ + public String getUsername() { + return username; + } + + /* + * Getter for password member variable. + * + * Return + * - String + * Return the password member variable. + * */ + public String getPassword() { + return password; + } + + /* + * Print all member variable for debug purpose. + * + * Return + * - None + * */ + public void debug_print() { + System.out.println("Host: " + this.host + ":" + this.port + "/" + this.database_name + "@" + this.username + ":" + this.password); + } +} diff --git a/EditInfoFrame.java b/EditInfoFrame.java new file mode 100644 index 0000000..7a660a7 --- /dev/null +++ b/EditInfoFrame.java @@ -0,0 +1,134 @@ +package DBD_env_unification; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +public class EditInfoFrame extends JFrame { + private JTextField idField, nameField, mailField, departmentField, positionField; + private JPasswordField passwordField; + private JButton saveButton; + private MainPageFrame mainPageFrame; + private User user; + + public EditInfoFrame(MainPageFrame mainPageFrame, User user, String user_id) { + super("내 정보 수정"); + this.mainPageFrame = mainPageFrame; + this.user = user; + + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + mainPageFrame.setVisible(true); + } + }); + + setLayout(new BorderLayout(10, 10)); + JPanel infoPanel = new JPanel(new GridBagLayout()); + infoPanel.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15)); + GridBagConstraints gbc = new GridBagConstraints(); + gbc.fill = GridBagConstraints.HORIZONTAL; + gbc.insets = new Insets(5, 5, 5, 5); + + // ID (읽기 전용) + gbc.gridx = 0; + gbc.gridy = 0; + infoPanel.add(new JLabel("ID:"), gbc); + idField = new JTextField(user_id); + idField.setEditable(false); + gbc.gridx = 1; + infoPanel.add(idField, gbc); + + // 이름 + gbc.gridx = 0; + gbc.gridy = 1; + infoPanel.add(new JLabel("이름:"), gbc); + nameField = new JTextField(user.getName()); + gbc.gridx = 1; + infoPanel.add(nameField, gbc); + + // 메일 + gbc.gridx = 0; + gbc.gridy = 2; + infoPanel.add(new JLabel("메일:"), gbc); + mailField = new JTextField(user.getEmail()); + gbc.gridx = 1; + infoPanel.add(mailField, gbc); + + // 비밀번호 + gbc.gridx = 0; + gbc.gridy = 3; + infoPanel.add(new JLabel("비밀번호:"), gbc); + passwordField = new JPasswordField(); + gbc.gridx = 1; + infoPanel.add(passwordField, gbc); + + // 학과 (읽기 전용) + gbc.gridx = 0; + gbc.gridy = 4; + infoPanel.add(new JLabel("학과:"), gbc); + departmentField = new JTextField(user.getDepartment()); + departmentField.setEditable(false); + gbc.gridx = 1; + infoPanel.add(departmentField, gbc); + + // 지위 (읽기 전용) + gbc.gridx = 0; + gbc.gridy = 5; + infoPanel.add(new JLabel("지위:"), gbc); + positionField = new JTextField(user.getStatus()); + positionField.setEditable(false); + gbc.gridx = 1; + infoPanel.add(positionField, gbc); + + // 저장 버튼 + saveButton = new JButton("저장"); + gbc.gridx = 0; + gbc.gridy = 6; + gbc.gridwidth = 2; + gbc.anchor = GridBagConstraints.CENTER; + infoPanel.add(saveButton, gbc); + + // 패널 추가 + add(infoPanel, BorderLayout.CENTER); + +// 저장 버튼 동작 + saveButton.addActionListener(e -> { + saveChanges(); // 정보 저장 처리 + + // 저장 후 현재 프레임 닫기 + dispose(); + + // 메인 프레임 다시 띄우기 + mainPageFrame.setVisible(true); + }); + + // 프레임 설정 + setSize(400, 300); + setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + setLocationRelativeTo(null); // 화면 가운데 표시 + setVisible(true); + } + + private void saveChanges() { + String updatedName = nameField.getText(); + String updatedMail = mailField.getText(); + String updatedPassword = new String(passwordField.getPassword()); + + boolean updateComplete = user.updateUser("NAME", updatedName); + updateComplete = updateComplete && user.updateUser("Mail", updatedMail); + if(!updatedPassword.isEmpty()){ + updateComplete = updateComplete && user.updateUser("Password", updatedPassword); + } + + if(!updateComplete){ + JOptionPane.showMessageDialog(this, + "회원정보를 변경하는 데 실패하였습니다.\n다시 시도해 주세요.", + "저장 실패", + JOptionPane.ERROR_MESSAGE); + } + } +} + diff --git a/Library.java b/Library.java new file mode 100644 index 0000000..26ff24f --- /dev/null +++ b/Library.java @@ -0,0 +1,152 @@ +package DBD_env_unification; + +import java.sql.*; +import java.util.Scanner; + +public class Library { + public static void main(String[] args) { + // DB 인증 정보를 담은 객체 생성 및 파일에서 정보 파싱 + DatabaseAuthInformation dbAuth = new DatabaseAuthInformation(); + boolean isParsed = dbAuth.parse_auth_info("C:\\Users\\fossj\\IdeaProjects\\java-MySQL-gradle\\src\\main\\resources\\mysql.auth"); + + if (!isParsed) { + System.out.println("DB 인증 정보를 파싱하는 데 실패했습니다."); + return; + } + + // DB 연결 정보 설정 + String url = "jdbc:mysql://" + dbAuth.getHost() + ":" + dbAuth.getPort() + "/" + dbAuth.getDatabase_name() + + "?useSSL=false&serverTimezone=UTC"; // SSL 설정과 타임존 추가 + String username = dbAuth.getUsername(); + String password = dbAuth.getPassword(); + + + // 간단한 SELECT 쿼리 실행 + String query = "SELECT * FROM storage"; // 테이블 이름과 컬럼명은 실제 DB 구조에 맞게 수정하세요. + + try (Connection conn = DriverManager.getConnection(url, username, password); + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(query)) { + + showAnnouncement(conn); + + // 결과 출력 + while (rs.next()) { + String id = rs.getString("Data_ID"); // 예시: 학번 + String userid = rs.getString("User_ID"); // 예시: 이름 + String major = rs.getString("Storage_folder"); // 예시: 전공 + int storage_id = rs.getInt("Storage_ID"); + + System.out.println("ID: " + userid + ", 책: " + id + ", 폴더: " + major + ", 저장 id: " + storage_id); + } + + } catch (Exception e) { + e.printStackTrace(); + } + } + + //유저 등록(회원가입) + public static void registerUser(Connection conn) { + Scanner scanner = new Scanner(System.in); + + // 입력받기 + System.out.print("사용자 ID: "); + String userId = scanner.nextLine(); + + System.out.print("비밀번호: "); + String password = scanner.nextLine(); + + System.out.print("회원 이름: "); + String name = scanner.nextLine(); + + System.out.print("메일: "); + String mail = scanner.nextLine(); + + + System.out.print("소속 학부: "); // 다른 테이블로부터 받아오는데 입력 필요..? + String department = scanner.nextLine(); + + System.out.print("신분: "); // 다른 테이블로부터 받아오는데 입력 필요..? + String status = scanner.nextLine(); + + try { + // 사용자 ID 중복 확인 + if (isUserIdDuplicate(conn, userId)) { + System.out.println("중복된 사용자 ID입니다. 다른 ID를 사용해주세요."); + return; + } + + // INSERT 쿼리 작성 + String sql = "INSERT INTO user (User_ID, NAME, Mail, Password, Department, Status) VALUES (?, ?, ?, ?, ?, ?)"; + try (PreparedStatement pstmt = conn.prepareStatement(sql)) { + pstmt.setString(1, userId); + pstmt.setString(2, name); + pstmt.setString(3, mail); + pstmt.setString(4, password); + pstmt.setString(5, department); + pstmt.setString(6, status); + + // 데이터베이스에 삽입 + int rows = pstmt.executeUpdate(); + if (rows > 0) { + System.out.println("회원 등록이 완료되었습니다!"); + } + } + + } catch (SQLException e) { + e.printStackTrace(); + } + } + + // 사용자 ID 중복 확인 함수 호출 + private static boolean isUserIdDuplicate(Connection conn, String userId) { + String sql = "{? = CALL isUserIdDuplicate(?)}"; // MySQL 함수 호출 구문 + try (CallableStatement stmt = conn.prepareCall(sql)) { + // 첫 번째 인자는 반환 값이므로 등록 + stmt.registerOutParameter(1, Types.BOOLEAN); + // 두 번째 인자는 입력 값 + stmt.setString(2, userId); + + // 함수 실행 + stmt.execute(); + + // 반환된 값 확인 + return stmt.getBoolean(1); + } catch (SQLException e) { + e.printStackTrace(); + return false; + } + } + + //모든 공지사항을 보여줌 + public static void showAnnouncement(Connection conn){ + String sql = "{CALL showAnnouncement()}"; // 저장 프로시저 호출 + try (CallableStatement stmt = conn.prepareCall(sql)) { + // 저장 프로시저 실행 + ResultSet rs = stmt.executeQuery(); + // 결과 처리 + while (rs.next()) { + int textNumber = rs.getInt("Text_number"); + String title = rs.getString("Title"); + String managerName = rs.getString("NAME"); + String type = rs.getString("Type"); + Timestamp createDate = rs.getTimestamp("Create_date"); + int views = rs.getInt("Views"); + String content = rs.getString("Content"); + + // 출력 + System.out.println("Text Number: " + textNumber); + System.out.println("Title: " + title); + System.out.println("Manager Name: " + managerName); + System.out.println("Type: " + type); + System.out.println("Create Date: " + createDate); + System.out.println("Views: " + views); + System.out.println("Content: " + content); + System.out.println("---------------------------------------------------"); + } + } catch (SQLException e) { + e.printStackTrace(); + } + } +} + diff --git a/LoginFrame.java b/LoginFrame.java new file mode 100644 index 0000000..52a17e3 --- /dev/null +++ b/LoginFrame.java @@ -0,0 +1,89 @@ +package DBD_env_unification; +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; + +public class LoginFrame extends JFrame { + private Library library; + public LoginFrame(Library library) { + // 프레임 기본 설정 + super("Login"); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setSize(400, 300); + setLayout(null); + + // 제목 라벨 + JLabel titleLabel = new JLabel("Library System"); + titleLabel.setFont(new Font("Serif", Font.BOLD, 20)); + titleLabel.setHorizontalAlignment(SwingConstants.CENTER); + titleLabel.setBounds(50, 20, 300, 30); + add(titleLabel); + + // ID 라벨과 입력 필드 + JLabel idLabel = new JLabel("ID:"); + idLabel.setFont(new Font("Arial", Font.PLAIN, 14)); + idLabel.setBounds(50, 70, 80, 25); + add(idLabel); + + JTextField idField = new JTextField(); + idField.setBounds(150, 70, 200, 25); + add(idField); + + // Password 라벨과 입력 필드 + JLabel passwordLabel = new JLabel("Password:"); + passwordLabel.setFont(new Font("Arial", Font.PLAIN, 14)); + passwordLabel.setBounds(50, 110, 80, 25); + add(passwordLabel); + + JPasswordField passwordField = new JPasswordField(); + passwordField.setBounds(150, 110, 200, 25); + add(passwordField); + + // 버튼 스타일 + JButton loginButton = new JButton("Login"); + JButton registerButton = new JButton("Register"); + + loginButton.setBounds(50, 160, 130, 35); + loginButton.setBackground(new Color(59, 89, 182)); + loginButton.setForeground(Color.WHITE); + loginButton.setFocusPainted(false); + loginButton.setFont(new Font("Tahoma", Font.BOLD, 12)); + loginButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + String id = idField.getText(); + String password = new String(passwordField.getPassword()); + if(library.login(id, password)){ + new MainPageFrame(library); + dispose(); // 로그인 창 닫기 + }else{ + JOptionPane.showMessageDialog(LoginFrame.this, + "아이디 또는 비밀번호가 일치하지 않습니다.", + "Login Failed", + JOptionPane.ERROR_MESSAGE); + } + } + }); + add(loginButton); + + registerButton.setBounds(220, 160, 130, 35); + registerButton.setBackground(new Color(76, 175, 80)); + registerButton.setForeground(Color.WHITE); + registerButton.setFocusPainted(false); + registerButton.setFont(new Font("Tahoma", Font.BOLD, 12)); + registerButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + setVisible(false); + new RegisterFrame(getThis(), library); // 회원가입 창 띄우기 + } + }); + add(registerButton); + setVisible(true); + } + + public LoginFrame getThis(){ + return this; + } + +} diff --git a/MainPageFrame.java b/MainPageFrame.java new file mode 100644 index 0000000..cb877d5 --- /dev/null +++ b/MainPageFrame.java @@ -0,0 +1,133 @@ +package DBD_env_unification; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; + +public class MainPageFrame extends JFrame { + private Library library; + + public MainPageFrame(Library library) { + // 프레임 기본 설정 + super("Library System - Main Page"); + this.library = library; + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setSize(500, 500); + setLayout(new GridBagLayout()); + GridBagConstraints gbc = new GridBagConstraints(); + + // 배경 색상 설정 + getContentPane().setBackground(new Color(245, 245, 245)); // 배경을 밝은 회색으로 설정 + + // 제목 라벨 설정 (글자 색깔을 검은색으로 변경) + JLabel titleLabel = new JLabel("Library System - Main Menu"); + titleLabel.setFont(new Font("맑은 고딕", Font.BOLD, 24)); // 한글 지원 폰트 사용 + titleLabel.setForeground(Color.BLACK); // 제목 색깔을 검은색으로 설정 + titleLabel.setHorizontalAlignment(SwingConstants.CENTER); + + // 제목 위치 설정 (위쪽 여백을 추가하여 위로 이동) + gbc.gridwidth = 2; + gbc.gridx = 0; + gbc.gridy = 0; + gbc.insets = new Insets(40, 0, 20, 0); // 위쪽 간격을 40으로 늘리고 아래쪽 간격을 20으로 설정 + add(titleLabel, gbc); + + // 버튼 스타일 설정 (어두운 파란색 계열로 통일) + JButton searchButton = createStyledButton("도서 검색"); + JButton modifyInfoButton = createStyledButton("내 정보 수정"); + JButton borrowReturnButton = createStyledButton("대출/반납/연장"); + JButton boardButton = createStyledButton("게시판"); + JButton noticeButton = createStyledButton("공지사항"); + JButton storageButton = createStyledButton("개인 보관함"); + + noticeButton.addActionListener(e -> { + // AnnouncementListFrame을 띄우는 코드 + new AnnouncementListFrame(getThis(), library.showAnnouncement() ); // announcements는 공지사항 리스트입니다. + setVisible(false); + }); + + modifyInfoButton.addActionListener(e -> { + // myInfoFrame을 띄우는 코드 + new MyInfoFrame(this); + setVisible(false); + }); + + storageButton.addActionListener(e -> { + // userStorageFrame을 띄우는 코드 + new UserStorageFrame(this); + setVisible(false); + }); + + // 각 버튼의 배치 (세로 간격을 띄움) + gbc.gridwidth = 1; + gbc.gridx = 0; + gbc.gridy = 1; + gbc.insets = new Insets(10, 10, 20, 10); // 버튼 간 세로 간격을 20으로 설정 + add(searchButton, gbc); + + gbc.gridx = 1; + add(modifyInfoButton, gbc); + + gbc.gridx = 0; + gbc.gridy = 2; + add(borrowReturnButton, gbc); + + gbc.gridx = 1; + add(boardButton, gbc); + + gbc.gridx = 0; + gbc.gridy = 3; + add(noticeButton, gbc); + + gbc.gridx = 1; + add(storageButton, gbc); + + // 프레임 보이기 + setVisible(true); + } + + // 스타일링된 버튼 생성 메서드 (색상 통일) + private JButton createStyledButton(String text) { + JButton button = new JButton(text); + button.setFont(new Font("맑은 고딕", Font.BOLD, 16)); // 한글 지원 폰트 사용 + button.setForeground(Color.WHITE); // 텍스트는 하얀색 + button.setBackground(new Color(21, 101, 192)); // 어두운 파란색 계열로 변경 + button.setFocusPainted(false); + button.setPreferredSize(new Dimension(180, 50)); + + // 버튼 둥글게 만들기 + button.setBorder(BorderFactory.createLineBorder(new Color(21, 101, 192), 2, true)); // 어두운 파란색 테두리 + button.setContentAreaFilled(false); // 배경을 투명하게 + button.setOpaque(true); // 배경이 투명하지 않도록 설정 + + // 버튼에 테두리 추가 + button.setBorder(BorderFactory.createCompoundBorder( + button.getBorder(), + BorderFactory.createEmptyBorder(5, 5, 5, 5) + )); + + // 마우스 오버 효과 + button.addMouseListener(new java.awt.event.MouseAdapter() { + @Override + public void mouseEntered(java.awt.event.MouseEvent evt) { + button.setBackground(new Color(26, 115, 176)); // 마우스를 올리면 색상 밝아짐 + } + + @Override + public void mouseExited(java.awt.event.MouseEvent evt) { + button.setBackground(new Color(21, 101, 192)); // 마우스를 떼면 원래 색상 + } + }); + + + return button; + } + + private MainPageFrame getThis(){ + return this; + } + + public Library getLibrary(){ + return library; + } +} diff --git a/MyInfoFrame.java b/MyInfoFrame.java new file mode 100644 index 0000000..dce3a38 --- /dev/null +++ b/MyInfoFrame.java @@ -0,0 +1,85 @@ +package DBD_env_unification; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +public class MyInfoFrame extends JFrame { + private JTextField idField; + private JPasswordField passwordField; + private JButton authButton; + + public MyInfoFrame(MainPageFrame mainPageFrame) { + super("내 정보 수정"); + + // 전체 레이아웃 설정 + setLayout(new BorderLayout(10, 10)); + JPanel authPanel = new JPanel(); + authPanel.setLayout(new GridBagLayout()); + authPanel.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15)); + + // GridBagConstraints 설정 + GridBagConstraints gbc = new GridBagConstraints(); + gbc.fill = GridBagConstraints.HORIZONTAL; + gbc.insets = new Insets(5, 5, 5, 5); // 컴포넌트 간 간격 + + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + mainPageFrame.setVisible(true); + } + }); + + // ID 레이블 및 텍스트 필드 + gbc.gridx = 0; + gbc.gridy = 0; + authPanel.add(new JLabel("ID:"), gbc); + + idField = new JTextField(15); + gbc.gridx = 1; + authPanel.add(idField, gbc); + + // 비밀번호 레이블 및 텍스트 필드 + gbc.gridx = 0; + gbc.gridy = 1; + authPanel.add(new JLabel("비밀번호:"), gbc); + + passwordField = new JPasswordField(15); + gbc.gridx = 1; + authPanel.add(passwordField, gbc); + + // 인증 버튼 + authButton = new JButton("인증"); + gbc.gridx = 0; + gbc.gridy = 2; + gbc.gridwidth = 2; // 버튼을 두 열에 걸치게 배치 + gbc.fill = GridBagConstraints.CENTER; + + // 버튼 크기 및 스타일 설정 + authButton.setPreferredSize(new Dimension(100, 30)); + authButton.addActionListener(e -> { + String id = idField.getText(); + String password = new String(passwordField.getPassword()); + if (mainPageFrame.getLibrary().login(id, password)) { + dispose(); + new EditInfoFrame(mainPageFrame, mainPageFrame.getLibrary().getUser(), id); + } else { + JOptionPane.showMessageDialog(this, + "ID 또는 비밀번호가 잘못되었습니다.", + "인증 오류", + JOptionPane.WARNING_MESSAGE); + } + }); + authPanel.add(authButton, gbc); + + // 패널 추가 + add(authPanel, BorderLayout.CENTER); + + // 프레임 설정 + setSize(400, 250); + setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + setLocationRelativeTo(null); // 화면 가운데에 표시 + setVisible(true); + } +} diff --git a/RegisterFrame.java b/RegisterFrame.java new file mode 100644 index 0000000..95aa72d --- /dev/null +++ b/RegisterFrame.java @@ -0,0 +1,158 @@ +package DBD_env_unification; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; +import java.sql.*; +import java.util.ArrayList; + +public class RegisterFrame extends JFrame { + private Library library; + private Connection conn; + public RegisterFrame(LoginFrame loginFrame, Library library) { + // 프레임 기본 설정 + super("Register"); + this.library = library; + this.conn = library.getConn(); + setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); // 창 닫기 설정 + setSize(400, 400); + setLayout(null); + + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + loginFrame.setVisible(true); + } + }); + + // 제목 라벨 + JLabel titleLabel = new JLabel("Register New User"); + titleLabel.setFont(new Font("Serif", Font.BOLD, 20)); + titleLabel.setHorizontalAlignment(SwingConstants.CENTER); + titleLabel.setBounds(50, 20, 300, 30); + add(titleLabel); + + // 사용자 정보 입력 필드 + JLabel idLabel = new JLabel("ID:"); + idLabel.setBounds(50, 70, 80, 25); + add(idLabel); + + JTextField idField = new JTextField(); + idField.setBounds(150, 70, 200, 25); + add(idField); + + JLabel passwordLabel = new JLabel("Password:"); + passwordLabel.setBounds(50, 110, 80, 25); + add(passwordLabel); + + JPasswordField passwordField = new JPasswordField(); + passwordField.setBounds(150, 110, 200, 25); + add(passwordField); + + JLabel nameLabel = new JLabel("Name:"); + nameLabel.setBounds(50, 150, 80, 25); + add(nameLabel); + + JTextField nameField = new JTextField(); + nameField.setBounds(150, 150, 200, 25); + add(nameField); + + JLabel mailLabel = new JLabel("Mail:"); + mailLabel.setBounds(50, 190, 80, 25); + add(mailLabel); + + JTextField mailField = new JTextField(); + mailField.setBounds(150, 190, 200, 25); + add(mailField); + + JLabel departmentLabel = new JLabel("Department:"); + departmentLabel.setBounds(50, 230, 80, 25); + add(departmentLabel); + + ArrayList departmentList = library.getDepartmentListFromDatabase(); + + // JComboBox 생성 + JComboBox departmentComboBox = new JComboBox<>(); + departmentComboBox.setBounds(150, 230, 200, 25); // 위치와 크기 설정 + add(departmentComboBox); + // 학부 목록을 JComboBox에 추가 + for (String department : departmentList) { + departmentComboBox.addItem(department); + } + + JLabel statusLabel = new JLabel("Status:"); + statusLabel.setBounds(50, 270, 80, 25); + add(statusLabel); + + // DB에서 status 값 가져오기 + ArrayList statusList = library.getStatusListFromDatabase(); + // 상태를 선택할 수 있는 JComboBox + JComboBox statusComboBox = new JComboBox<>(); + statusComboBox.setBounds(150, 270, 200, 25); + add(statusComboBox); + + for (String status : statusList) { + statusComboBox.addItem(status); + } + + // 회원가입 버튼 + JButton registerButton = new JButton("Register"); + registerButton.setBounds(150, 320, 100, 30); + registerButton.setBackground(new Color(76, 175, 80)); + registerButton.setForeground(Color.WHITE); + registerButton.setFocusPainted(false); + registerButton.setFont(new Font("Tahoma", Font.BOLD, 12)); + registerButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + // 입력 값 가져오기 + String id = idField.getText(); + String password = new String(passwordField.getPassword()); + String name = nameField.getText(); + String mail = mailField.getText(); + String department = (String) departmentComboBox.getSelectedItem(); + String status = (String) statusComboBox.getSelectedItem(); + + // Library 객체의 회원가입 메서드 호출 + try { + // 입력값이 비어 있는지 체크 + if (id.isEmpty() || password.isEmpty() || name.isEmpty() || mail.isEmpty()) { + JOptionPane.showMessageDialog(RegisterFrame.this, + "모든 필드를 입력해주세요.", + "Error", + JOptionPane.ERROR_MESSAGE); + } else if (library.isUserIdDuplicate(id)) { //중복 ID 확인 + // 중복된 ID가 있을 경우 경고 메시지 출력 + JOptionPane.showMessageDialog(RegisterFrame.this, + "중복된 사용자 ID입니다. 다른 ID를 사용해주세요.", + "ID 중복 오류", + JOptionPane.WARNING_MESSAGE); + return; + }else { + // 모든 필드가 비어있지 않고 중복 ID가 아니면 회원가입 진행 + library.registerUser(id, name, mail, password, department, status); + JOptionPane.showMessageDialog(RegisterFrame.this, + "회원가입이 완료되었습니다.", + "Success", + JOptionPane.INFORMATION_MESSAGE); + dispose(); // 회원가입 창 닫기 + loginFrame.setVisible(true); + } + } catch (Exception ex) { + JOptionPane.showMessageDialog(RegisterFrame.this, + "회원가입 중 오류가 발생했습니다.", + "Error", + JOptionPane.ERROR_MESSAGE); + } + } + }); + + add(registerButton); + + setVisible(true); + } + + + + +} diff --git a/User.java b/User.java index ee8b977..dfc29b1 100644 --- a/User.java +++ b/User.java @@ -1,6 +1,12 @@ package DBD_env_unification; import java.sql.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; +import java.sql.Date; +import java.time.LocalDate; +import java.time.temporal.ChronoUnit; public class User { private String user_id; @@ -8,8 +14,12 @@ public class User { private String email; private String department; private String status; + private List loanIds = new ArrayList(); // 대출 중인 자료 list + private List overdueIds = new ArrayList(); // 연체 자료 list + private Connection con; public User(String user_id, Connection con){ + this.con = con; String query = "select User_ID, NAME, Mail, Department, Status from user where User_ID = ?"; try (PreparedStatement preparedStatement = con.prepareStatement(query)) @@ -26,18 +36,585 @@ public User(String user_id, Connection con){ } catch (SQLException e) { System.out.println("Failed to select : " + e.getMessage()); } + initLoanList(con); + initExtendList(con); } - public void printUser(){ - System.out.println("사용자 정보"); - System.out.println("ID: "+user_id); - System.out.println("name: "+name); - System.out.println("email: "+email); - System.out.println("dep: "+department); - System.out.println("status: "+status); + public void borrowBook(int book_id, Connection con) { + + String checkStatusQuery = "SELECT Book_status FROM book WHERE Data_ID = ?"; + String insertLoanQuery = "INSERT INTO loan (User_ID, Data_ID, Start_time, End_time) VALUES (?, ?, NOW(), DATE_ADD(NOW(), INTERVAL 14 DAY))"; + if(loanIds.size()>=15){ + System.out.println("대출 가능한 자료 개수를 초과하였습니다. 대출이 불가능합니다."); + return; + } + + // 1. 도서 상태 확인 + try (PreparedStatement checkStatusStmt = con.prepareStatement(checkStatusQuery)) { + checkStatusStmt.setInt(1, book_id); + ResultSet resultSet = checkStatusStmt.executeQuery(); + if (resultSet.next()) { + String status = resultSet.getString("Book_status"); + if (!"대출 가능".equals(status)) { + System.out.println("해당 도서는 현재 대출이 불가능합니다."); + return; + } + } else { + System.out.println("해당 도서는 존재하지 않습니다."); + return; + } + + } catch (SQLException e) { + e.printStackTrace(); + } + + // 2. 대출 처리 + try (PreparedStatement insertLoanStmt = con.prepareStatement(insertLoanQuery)) { + con.setAutoCommit(false); + + // 대출 기록 추가 + insertLoanStmt.setString(1, this.user_id); + insertLoanStmt.setInt(2, book_id); + insertLoanStmt.executeUpdate(); + + con.commit(); + System.out.println("도서가 성공적으로 대출되었습니다."); + + String selectQuery = "SELECT loan_ID FROM loan WHERE User_ID = ? ORDER BY Start_time DESC LIMIT 1"; + PreparedStatement selectStmt = con.prepareStatement(selectQuery); + selectStmt.setString(1, this.user_id); + ResultSet rs1 = selectStmt.executeQuery(); + + if (rs1.next()) { + int loanID = rs1.getInt("loan_ID"); + loanIds.add(loanID); + } + } catch (SQLException e) { + try { + con.rollback(); + System.out.println("대출 처리 중 오류 발생, 롤백 수행"); + } catch (SQLException rollbackEx) { + rollbackEx.printStackTrace(); + } + e.printStackTrace(); + } finally { + try { + con.setAutoCommit(true); + } catch (SQLException ex) { + ex.printStackTrace(); + } + } + } + + // 반납하기 + public void returnBook(int loan_id, Connection con) { + if(loanIds.size()<1){ + System.out.println("대충 중인 자료가 존재하지 않습니다."); + return; + } + + // 대출 중인지 확인 + int i; + for(i = 0; i 오늘 날짜가 반납일로부터 3일전이면 연장 가능 -- 해당 코드 삭제 시 연장 확인 가능 + try (PreparedStatement checkStmt = con.prepareStatement(checksQuery)) { + checkStmt.setInt(1, loan_id); + ResultSet resultSet = checkStmt.executeQuery(); + if (resultSet.next()) { + Date sqlDate = resultSet.getDate("Start_time"); // 예제 날짜 (YYYY-MM-DD) + LocalDate today = LocalDate.now(); + LocalDate targetDate = sqlDate.toLocalDate(); + long daysDifference = ChronoUnit.DAYS.between(today, targetDate); + if (daysDifference > 3) { + System.out.println("반납 예정일 3일전부터 연장이 가능합니다."); + return; + } else if (daysDifference < 0) { + System.out.println("이미 반납 예정일이 지났습니다."); + return; + } + } else { + return; + } + + } catch (SQLException e) { + e.printStackTrace(); + } + + + String insertExtendQuery = "INSERT INTO `extend` (Extend_ID, Extend_time, New_End_time) VALUES (?, NOW(), DATE_ADD((SELECT End_time FROM loan WHERE Loan_ID = ?), INTERVAL 7 DAY))"; + try (PreparedStatement insertExtendStmt = con.prepareStatement(insertExtendQuery)) { + con.setAutoCommit(false); + + // 대출 기록 추가 + insertExtendStmt.setInt(1, loan_id); + insertExtendStmt.setInt(2, loan_id); + insertExtendStmt.executeUpdate(); + + con.commit(); + System.out.println("도서의 반납일자가 성공적으로 연장되었습니다."); + + } catch (SQLException e) { + try { + con.rollback(); + System.out.println("연장 처리 중 오류 발생, 롤백 수행"); + } catch (SQLException rollbackEx) { + rollbackEx.printStackTrace(); + } + e.printStackTrace(); + } finally { + try { + con.setAutoCommit(true); + } catch (SQLException ex) { + ex.printStackTrace(); + } + } + } + + + public void deleteUser(Connection conn) { + Scanner scanner = new Scanner(System.in); + + // 입력받기 + System.out.print("사용자 ID: "); + String userId = scanner.nextLine(); + + System.out.print("비밀번호: "); + String password = scanner.nextLine(); + + try { + // 사용자 ID와 비밀번호 확인 + if (!isUserCredentialsValid(conn, user_id, password)) { + System.out.println("잘못된 사용자 ID 또는 비밀번호입니다."); + return; + } + + // DELETE 쿼리 작성 + String sql = "DELETE FROM user WHERE User_ID = ?"; + try (PreparedStatement pstmt = conn.prepareStatement(sql)) { + pstmt.setString(1, userId); + + // 레코드 삭제 + int rows = pstmt.executeUpdate(); + if (rows > 0) { + System.out.println("회원 탈퇴가 완료되었습니다."); + } else { + System.out.println("회원 탈퇴에 실패했습니다."); + } + } + } catch (SQLException e) { + e.printStackTrace(); + } + } + + // 대출 현황 리스트 만들기 + public void initLoanList(Connection con) { + // 대출 중인 도서의 Loan_ID를 조회하기 위한 쿼리 + String checkLoanQuery = "SELECT Loan_ID FROM loan WHERE User_ID = ? "; + String checkReturnQuery = "SELECT Loan_ID FROM `return` WHERE Loan_ID = ? "; + + // 대출 중인 Loan_ID를 저장할 리스트 + + try (PreparedStatement checkLoanStmt = con.prepareStatement(checkLoanQuery)) { + checkLoanStmt.setString(1, user_id); + ResultSet ln_rs = checkLoanStmt.executeQuery(); + + // 결과에서 Loan_ID를 가져와 ArrayList에 저장 + while (ln_rs.next()) { + int loan_id = ln_rs.getInt("Loan_ID"); + try (PreparedStatement checkReturnStmt = con.prepareStatement(checkReturnQuery)) { + checkReturnStmt.setInt(1, loan_id); + ResultSet rt_rs = checkReturnStmt.executeQuery(); + if (!rt_rs.next()){ + loanIds.add(loan_id); // Loan_ID를 ArrayList에 추가 + } + } catch (SQLException e1) { + e1.printStackTrace(); + } + } + + } catch (SQLException e) { + e.printStackTrace(); + } + } + + // 대출 현황 출력하기 + public void printLoanList(Connection con) { + System.out.println("대출 현황"); + for (int i = 0; i < loanIds.size(); i++) { + System.out.println("<"+(i+1)+">"); + String query = + "select Loan_ID, Start_time, End_time, Data_ID from loan where Loan_ID = ?"; + String query1 = + "select Title, Author from data where Data_ID = ?"; + + String query2 = + "select Start_time from overdue where Overdue_ID = ?"; + + try (PreparedStatement preparedStatement = con.prepareStatement(query); + PreparedStatement preparedStatement1 = con.prepareStatement(query1); + PreparedStatement preparedStatement2 = con.prepareStatement(query2)) + { + preparedStatement.setInt(1, loanIds.get(i)); // user_id로 쿼리 실행 + ResultSet rs = preparedStatement.executeQuery(); + + if (rs.next()) { + + System.out.println("대출 ID: " + rs.getInt("Loan_ID")); + System.out.println("대출일: " + rs.getDate("Start_time")); + + preparedStatement2.setInt(1, rs.getInt("Loan_ID")); // user_id로 쿼리 실행 + ResultSet rs2 = preparedStatement2.executeQuery(); + + if (rs2.next()) { + System.out.println("반납 예정일: " + rs2.getDate("Start_time")); + } + + System.out.println("대출 자료"); + System.out.println("자료 ID: " + rs.getInt("Data_ID")); + + preparedStatement1.setInt(1, rs.getInt("Data_ID")); // user_id로 쿼리 실행 + ResultSet rs1 = preparedStatement1.executeQuery(); + + if (rs1.next()) { + System.out.println("제목: " + rs1.getString("Title")); + System.out.println("작가: " + rs1.getString("Author")); + } + } + + } catch (SQLException e) { + System.out.println("Failed to select : " + e.getMessage()); + } + } } -} + // 연체 리스트 초기화 + public void initExtendList(Connection con) { + overdueIds = new ArrayList<>(); + String query = "SELECT Overdue_ID FROM overdue WHERE End_time IS NULL AND Start_time < NOW()"; + try (PreparedStatement pstmt = con.prepareStatement(query)) + { + ResultSet rs = pstmt.executeQuery(); + while (rs.next()) { + int overdueId = rs.getInt("Overdue_ID"); + overdueIds.add(overdueId); + + String updateStatusQuery = "UPDATE overdue SET Status = 1 WHERE Overdue_ID = ?"; + try (PreparedStatement updateStmt = con.prepareStatement(updateStatusQuery)) { + updateStmt.setInt(1, overdueId); + updateStmt.executeUpdate(); + } + } + }catch(SQLException e){ + e.printStackTrace(); + } + } + + + + // 연체 자료 print 함수 + public void printOverdueList(Connection con) { + if (overdueIds.isEmpty()) { + System.out.println("연체된 자료가 없습니다."); + } else { + System.out.println("연체 자료 목록:"); + for (int i = 0; i < overdueIds.size(); i++) { + System.out.println("<"+(i+1)+">"); + String query = + "select Loan_ID, Start_time, End_time, Data_ID from loan where Loan_ID = ?"; + String query1 = + "select Title, Author from data where Data_ID = ?"; + + String query2 = + "select Start_time from overdue where Overdue_ID = ?"; + + try (PreparedStatement preparedStatement = con.prepareStatement(query); + PreparedStatement preparedStatement1 = con.prepareStatement(query1); + PreparedStatement preparedStatement2 = con.prepareStatement(query2)) + { + preparedStatement.setInt(1, overdueIds.get(i)); // user_id로 쿼리 실행 + ResultSet rs = preparedStatement.executeQuery(); + + if (rs.next()) { + + System.out.println("대출 ID: " + rs.getInt("Loan_ID")); + System.out.println("대출 자료"); + System.out.println("자료 ID: " + rs.getInt("Data_ID")); + + preparedStatement1.setInt(1, rs.getInt("Data_ID")); // user_id로 쿼리 실행 + ResultSet rs1 = preparedStatement1.executeQuery(); + + if (rs1.next()) { + System.out.println("제목: " + rs1.getString("Title")); + System.out.println("작가: " + rs1.getString("Author")); + } + preparedStatement2.setInt(1, rs.getInt("Loan_ID")); // user_id로 쿼리 실행 + ResultSet rs2 = preparedStatement2.executeQuery(); + + if (rs2.next()) { + System.out.println("반납 예정일: " + rs2.getDate("Start_time")); + } + System.out.println("연체료: " + calFine(overdueIds.get(i), con)); + } + + } catch (SQLException e) { + System.out.println("Failed to select : " + e.getMessage()); + } + } + } + } + + // 연체료 계산하기 + public int calFine(int loan_id, Connection con) { + int fine = -1; + String fineQuery = "SELECT calculate_fine(Start_time, NOW()) AS Fine FROM overdue WHERE Overdue_ID = ?"; + try (PreparedStatement pstmt = con.prepareStatement(fineQuery)) { + pstmt.setInt(1, loan_id); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) { + fine = rs.getInt("Fine"); + } + } catch (SQLException e) { + System.out.println("Failed to calculate : " + e.getMessage()); + } + return fine; + } + + // 연체료 결제하기 + + public void payFine(int loanId, Connection con){ + if (!overdueIds.contains(loanId)) { + System.out.println("해당 대출 ID는 연체료 결제 대상이 아닙니다."); + return; + } + if(loanIds.contains(loanId)) + { + System.out.println("반납 후 연체료 결제가 가능합니다."); + return; + } + + int fine = calFine(loanId, con); + + String updateFineQuery = "UPDATE overdue SET Fine = ?, Status = 1, End_time = NOW() WHERE Overdue_ID = ?"; + + try (PreparedStatement updateStmt = con.prepareStatement(updateFineQuery)) { + updateStmt.setInt(1, fine); + updateStmt.setInt(2, loanId); + updateStmt.executeUpdate(); + }catch (SQLException e) { + System.out.println("Failed to calculate : " + e.getMessage()); + } + + System.out.println("연체료 " + fine + "원 결제 완료되었습니다."); + overdueIds.remove((Integer) loanId); + } + + public boolean updateUser(String field, String new_value) { + + try { + + // UPDATE 쿼리 작성 + String sql = "UPDATE user SET " + field + " = ? WHERE User_ID = ?"; + try (PreparedStatement pstmt = con.prepareStatement(sql)) { + pstmt.setString(1, new_value); + pstmt.setString(2, user_id); + + // 레코드 업데이트 + int rows = pstmt.executeUpdate(); + return rows > 0; + } + } catch (SQLException e) { + e.printStackTrace(); + return false; + } + } + // 사용자 인증 함수 호출 + public boolean isUserCredentialsValid(Connection conn,String userId, String password) { + String sql = "{? = CALL isUserCredentialsValid(?, ?)}"; // MySQL 함수 호출 구문 + try (CallableStatement stmt = conn.prepareCall(sql)) { + // 첫 번째 인자는 반환 값이므로 등록 + stmt.registerOutParameter(1, Types.BOOLEAN); + // 두 번째, 세 번째 인자는 입력 값 + stmt.setString(2, userId); + stmt.setString(3, password); + // 함수 실행 + stmt.execute(); + + // 반환된 값 확인 + return stmt.getBoolean(1); + } catch (SQLException e) { + e.printStackTrace(); + return false; + } + } + + public void addToStorage(Connection conn, String userId, int dataId, String folder) { + String checkSql = "SELECT isDataExists(?)"; // isDataExists 함수 호출 + String addSql = "{CALL addToStorage(?, ?, ?)}"; // addToStorage 프로시저 호출 + + try (PreparedStatement checkStmt = conn.prepareStatement(checkSql)) { + // 데이터 존재 여부 확인 + checkStmt.setInt(1, dataId); + try (ResultSet rs = checkStmt.executeQuery()) { + if (rs.next() && rs.getBoolean(1)) { + // 데이터가 존재하면 addToStorage 호출 + try (CallableStatement addStmt = conn.prepareCall(addSql)) { + addStmt.setString(1, userId); + addStmt.setInt(2, dataId); + addStmt.setString(3, folder); + + addStmt.execute(); + System.out.println("Data added to storage successfully."); + } + } else { + System.out.println("Data with ID " + dataId + " does not exist."); + } + } + } catch (SQLException e) { + e.printStackTrace(); + } + } + + // 사용자 저장소를 가져오는 메서드 + public List showUsersStorage() { + String sql = "{CALL GetFilesByUserAndFolder(?)}"; // MySQL 함수 호출 구문 + List storageItems = new ArrayList<>(); + String currentFolder = ""; + + try (CallableStatement stmt = con.prepareCall(sql)) { + stmt.setString(1, user_id); + ResultSet rs = stmt.executeQuery(); + + while (rs.next()) { + String storageID = Integer.toString(rs.getInt("Storage_ID")); + String title = rs.getString("Title"); + String author = rs.getString("Author"); + String type = rs.getString("Type"); + String folder = rs.getString("Storage_folder"); + + // 폴더가 변경되었을 경우 새로운 폴더를 표시 + if (!currentFolder.equals(folder)) { + storageItems.add("-1"); + storageItems.add("== " + folder + " =="); + currentFolder = folder; + } + + // 도서 정보를 항목으로 추가 + storageItems.add(storageID); + storageItems.add("Title: " + title + ", Author: " + author + ", Type: " + type); + + } + } catch (SQLException e) { + e.printStackTrace(); + } + + return storageItems; + } + + public void deleteStorage(int storageId) { + String sql = "DELETE FROM storage WHERE Storage_ID = ?"; // MySQL 함수 호출 구문 + try (CallableStatement stmt = con.prepareCall(sql)) { + stmt.setInt(1, storageId); + stmt.executeUpdate(); + + } catch (SQLException e) { + e.printStackTrace(); + } + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getDepartment() { + return department; + } + + public void setDepartment(String department) { + this.department = department; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } +} \ No newline at end of file diff --git a/UserStorageFrame.java b/UserStorageFrame.java new file mode 100644 index 0000000..c873cc6 --- /dev/null +++ b/UserStorageFrame.java @@ -0,0 +1,152 @@ +package DBD_env_unification; +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.List; + +public class UserStorageFrame extends JFrame { + private JList storageList; + private DefaultListModel listModel; + private User user; + private ArrayList storage_id_list; + + private MainPageFrame mainPageFrame; // 이전 화면을 참조 + + public UserStorageFrame(MainPageFrame mainPageFrame) { + super("User Storage"); + + this.mainPageFrame = mainPageFrame; // 이전 화면 참조 저장 + this.user = mainPageFrame.getLibrary().getUser(); + this.storage_id_list = new ArrayList<>(); + + // 프레임 설정 + setSize(600, 400); + setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + setLayout(new BorderLayout()); + + // 배경 색상 설정 + getContentPane().setBackground(new Color(240, 240, 240)); // 밝은 회색 배경 + + // 제목 라벨 + JLabel titleLabel = new JLabel("User Storage", SwingConstants.CENTER); + titleLabel.setFont(new Font("맑은 고딕", Font.BOLD, 24)); // 제목 라벨에 한글 폰트 사용 + titleLabel.setForeground(new Color(59, 89, 182)); // 파란색 텍스트 + titleLabel.setPreferredSize(new Dimension(getWidth(), 50)); + add(titleLabel, BorderLayout.NORTH); + + // 버튼들 (삭제 및 뒤로가기) + JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 20, 10)); // 버튼들을 중앙에 배치하고 간격 조정 + + // 뒤로가기 버튼 + JButton backButton = new JButton("Back"); + styleButton(backButton); // 버튼 스타일 적용 + backButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + // 뒤로가기 버튼 동작 + mainPageFrame.setVisible(true); // 이전 화면 보이기 + dispose(); // 현재 화면 종료 + } + }); + + // 삭제 버튼 + JButton deleteButton = new JButton("Delete Selected"); + styleButton(deleteButton); // 버튼 스타일 적용 + deleteButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + deleteSelectedItem(); // 선택된 항목 삭제 + } + }); + + // 버튼들을 패널에 추가 + buttonPanel.add(backButton); + buttonPanel.add(deleteButton); + + // 버튼 패널을 화면 하단에 추가 + add(buttonPanel, BorderLayout.SOUTH); + + // 리스트 모델 설정 + listModel = new DefaultListModel<>(); + storageList = new JList<>(listModel); + storageList.setFont(new Font("맑은 고딕", Font.PLAIN, 16)); // JList에 한글 폰트 사용 + + // 텍스트 색상 설정 (배경과 대비를 높이기 위해) + storageList.setForeground(Color.BLACK); // 텍스트는 검은색 + storageList.setBackground(Color.WHITE); // 리스트 배경은 흰색 + + // 선택된 항목의 색상 설정 + storageList.setSelectionBackground(new Color(59, 89, 182)); // 선택된 항목은 파란색 배경 + storageList.setSelectionForeground(Color.WHITE); // 선택된 항목 텍스트는 흰색 + + storageList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + storageList.setBorder(BorderFactory.createLineBorder(new Color(200, 200, 200), 1)); + + JScrollPane scrollPane = new JScrollPane(storageList); + scrollPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + + // 데이터 불러오기 + loadUserStorage(); + + // 리스트 추가 + add(scrollPane, BorderLayout.CENTER); + + // 프레임 표시 + setLocationRelativeTo(null); // 화면 가운데 배치 + setVisible(true); + } + + private void loadUserStorage() { + List storageItems = user.showUsersStorage(); + + for (int i = 0; i < storageItems.size(); i++) { + String item = storageItems.get(i); + + // 홀수 번째 항목에 Storage_ID 추가 + if (i % 2 == 1) { + listModel.addElement(item); // Storage_ID + } else { + storage_id_list.add(item); + } + } + } + + private void deleteSelectedItem() { + // 선택된 항목의 인덱스 가져오기 + int selectedIndex = storageList.getSelectedIndex(); + + if (selectedIndex != -1) { // 항목이 선택되었을 경우 + String selectedItem = listModel.get(selectedIndex); + int selectedStorageId = Integer.parseInt(storage_id_list.get(selectedIndex)); + + // 폴더 항목인 경우 삭제하지 않음 + if (selectedItem.startsWith("==")) { + JOptionPane.showMessageDialog(this, "폴더는 삭제할 수 없습니다.", "삭제 실패", JOptionPane.ERROR_MESSAGE); + return; + } + + // 선택된 항목을 리스트에서 제거 + listModel.remove(selectedIndex); + + // 실제 데이터에서 항목 삭제 (예: 데이터베이스에서 삭제) + user.deleteStorage(selectedStorageId); // 이 메서드는 실제 데이터베이스나 사용자 저장소에서 항목을 삭제하는 메서드입니다. + } else { + JOptionPane.showMessageDialog(this, "선택된 항목이 없습니다.", "삭제 실패", JOptionPane.ERROR_MESSAGE); + } + } + + // 버튼 스타일을 설정하는 메서드 + private void styleButton(JButton button) { + button.setFont(new Font("맑은 고딕", Font.PLAIN, 16)); // 버튼 폰트 설정 + button.setPreferredSize(new Dimension(180, 40)); // 버튼 크기 설정 + button.setBackground(new Color(59, 89, 182)); // 버튼 배경색 파란색 + button.setForeground(Color.WHITE); // 버튼 텍스트는 흰색 + button.setFocusPainted(false); // 포커스 효과 없애기 + button.setBorder(BorderFactory.createEmptyBorder(10, 20, 10, 20)); // 버튼 안쪽 여백 추가 + button.setCursor(new Cursor(Cursor.HAND_CURSOR)); // 마우스 커서 손 모양으로 변경 + button.setFont(new Font("맑은 고딕", Font.BOLD, 16)); // 폰트 굵기 설정 + } +} diff --git a/main.java b/main.java new file mode 100644 index 0000000..3079e36 --- /dev/null +++ b/main.java @@ -0,0 +1,50 @@ +package DBD_env_unification; +import java.sql.*; +import java.util.Scanner; + +public class main { + public static void main(String[] args) { + // DB 인증 정보를 담은 객체 생성 및 파일에서 정보 파싱 + DatabaseAuthInformation dbAuth = new DatabaseAuthInformation(); + boolean isParsed = dbAuth.parse_auth_info("C:\\Users\\fossj\\IdeaProjects\\java-MySQL-gradle\\src\\main\\resources\\mysql.auth"); + + if (!isParsed) { + System.out.println("DB 인증 정보를 파싱하는 데 실패했습니다."); + return; + } + // DB 연결 정보 설정 + String url = "jdbc:mysql://" + dbAuth.getHost() + ":" + dbAuth.getPort() + "/" + dbAuth.getDatabase_name() + + "?useSSL=false&serverTimezone=UTC"; // SSL 설정과 타임존 추가 + String username = dbAuth.getUsername(); + String password = dbAuth.getPassword(); + Connection conn = null; + Statement stmt = null; + ResultSet rs = null; + // 간단한 SELECT 쿼리 실행 + String query = "SELECT * FROM storage"; // 테이블 이름과 컬럼명은 실제 DB 구조에 맞게 수정하세요. + + // 메인 프레임 생성 + + try{ + conn = DriverManager.getConnection(url, username, password); + stmt = conn.createStatement(); + rs = stmt.executeQuery(query); + + Library library = new Library(conn); + LoginFrame loginFrame = new LoginFrame(library); + // 결과 출력 + while (rs.next()) { + String id = rs.getString("Data_ID"); // 예시: 학번 + String userid = rs.getString("User_ID"); // 예시: 이름 + String major = rs.getString("Storage_folder"); // 예시: 전공 + int storage_id = rs.getInt("Storage_ID"); + System.out.println("ID: " + userid + ", 책: " + id + ", 폴더: " + major + ", 저장 id: " + storage_id); + } + + } catch (Exception e) { + e.printStackTrace(); + } + } + + +} \ No newline at end of file