주차 관리 시스템(1)

Kim taegwan·2026년 4월 17일

주차 관리 시스템을 만들어 보기로 했다.
정기권 기능,주차 기록,주차 구역,관리자로 인가 처리등 이런 기능들을 넣기로 했다.

테이블을 먼저 설계해보았다.


이렇게 4개의 dto를 설계했다.

AdminsDAO

package com.tenco.dao;

import com.tenco.db.DBConnection;
import com.tenco.model.Admin;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
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 java.util.Scanner;

public class AdminsDAO {

    // 1. 로그인
    // 2. 관리자 추가
    // 3. 관리자 삭제
    // 4. 관리자 조회

    // 1. 로그인--------------------------------------------
    public Admin login(String userId, String password) throws SQLException {
        String sql = """
                SELECT * FROM admins WHERE user_id = ?
                """;

        try (Connection conn = DBConnection.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)
        ) {
            pstmt.setString(1, userId);

            try (ResultSet rs = pstmt.executeQuery()) {
                // 1. 다중 행인지 단일 행인지 쿼리 출력값 확인
                // 단일행 -> 1 row가 나오거나 아예 안나오거나
                if (rs.next()) {
                    String encryptedPassword = rs.getString("password");
                    if (!encrypt(password).equals(encryptedPassword)) {
                        return null;
                    }
                    Admin admin = new Admin();
                    admin.setUserId(rs.getString("user_id"));
                    admin.setName(rs.getString("name"));
                    return admin;
                } else {
                    return null;
                }
            } // end of rs
        } // end if pstmt
    } // end of login

    // 2. 관리자 추가 --------------------------
    public boolean addAdmin(Admin admin) throws SQLException{

        String sql = """
                INSERT INTO admins ( user_id , password, name) VALUES (? , ? ,?)
                """;
        try (Connection conn = DBConnection.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)
        ) {
            pstmt.setString(1, admin.getUserId());
            pstmt.setString(2, encrypt(admin.getPassword()));
            pstmt.setString(3, admin.getName());


            int rows = pstmt.executeUpdate();

            return rows > 0;
        } // end of pstmt
    } // end of updateAdmin

    // 3. 관리자 삭제 -------------------------------
    public boolean deleteAdmin(String userId) throws SQLException {
        String sql = """
                
                UPDATE admins 
                SET is_available = false
                WHERE user_id = ?
                
                """;
        try (Connection conn = DBConnection.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)
        ) {
            pstmt.setString(1, userId);
            int rows = pstmt.executeUpdate();
            return rows > 0;
        }

    }


    // 4. 관리자 조회 -----------------------------
    public List<Admin> getAdminList() throws SQLException {
        List<Admin> adminList = new ArrayList<>();
        String sql = """
                SELECT * FROM admins WHERE is_available = TRUE
                """;

        try (Connection conn = DBConnection.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql);
             ResultSet rs = pstmt.executeQuery()
        ) {
            while (rs.next()) {
                Admin admin = Admin.builder()
                        .id(rs.getInt("id"))
                        .userId(rs.getString("user_id"))
                        .name(rs.getString("name"))
                        .createdAt(rs.getTimestamp("created_at").toLocalDateTime())
                        .build();
                adminList.add(admin);
            }
        }
        return adminList;
    }

    // 비밀번호 SHA-256 해싱
    public static String encrypt(String text) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            md.update(text.getBytes());
            byte[] byteData = md.digest();
            StringBuilder sb = new StringBuilder();
            for (byte b : byteData) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }

로그인,관리자 dao를 설계했다.
비밀번호는 SHA-256알고리즘으로 해싱처리를 했다. 그래서 DB에서 비밀번호를 select해서 알 수 없다.

if (!encrypt(password).equals(encryptedPassword)) {
                        return null; }

이렇게 알고리즘 encrypt에 비밀번호를 넣어서 암호화된걸 다시 string으로 변환시켜서 나온 (encryptedPassword)를 비교해서 맞으면 반환하게 로직을 짰다.


MonthlyPassDAO

package com.tenco.dao;

import com.tenco.db.DBConnection;
import com.tenco.model.MonthlyPass;

import java.math.BigDecimal;
import java.sql.*;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

public class MonthlyPassDAO {

    // 정기권 조회 , 정기권 등록 , 정기권 삭제 , 기간 내 차량 요금 면제 , 기간 연장

    // 정기권 조회
    public List<MonthlyPass> findPassList() throws SQLException {
        List<MonthlyPass> mPassList = new ArrayList<>();

        String sql = """
                SELECT * FROM monthly_pass
                """;

        try (Connection conn = DBConnection.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql);
             ResultSet rs = pstmt.executeQuery()
        ) {
            while (rs.next()) {
                MonthlyPass mPass = MonthlyPass.builder()
                        .passId(rs.getInt("pass_id"))
                        .carNumber(rs.getString("car_number"))
                        .ownerName(rs.getString("owner_name"))
                        .phone(rs.getString("phone"))
                        .startDate(rs.getDate("start_date"))
                        .endDate(rs.getDate("end_date"))
                        .fee(rs.getBigDecimal("fee"))
                        .isAvailable(rs.getBoolean("is_available"))
                        .build();
                mPassList.add(mPass);
            } //end of while
        } // end of pstmt
        return mPassList;
    } // end of findPassList

    // 정기권 등록
    public boolean insert(MonthlyPass mPass) throws SQLException {

        String sql = """
                INSERT INTO monthly_pass ( car_number, owner_name, phone, start_date, end_date, fee)
                values ( ? , ? ,? ,? ,? ,?)
                """;
        try (Connection conn = DBConnection.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)
        ) {
            pstmt.setString(1, mPass.getCarNumber());
            pstmt.setString(2, mPass.getOwnerName());
            pstmt.setString(3, mPass.getPhone());
            pstmt.setDate(4, mPass.getStartDate());
            pstmt.setDate(5, mPass.getEndDate());
            pstmt.setBigDecimal(6, mPass.getFee());

            int rows = pstmt.executeUpdate();
            return rows >= 0;
        } // end of pstmt

    } // end of insert

    // 정기원 삭제
    public boolean soft_delete(String carNum) throws SQLException {

        String sql = """
                UPDATE monthly_pass
                set is_available = FALSE
                where car_number = ?
                """;

        try (Connection conn = DBConnection.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql);
        ) {
            pstmt.setString(1, carNum);
            pstmt.executeUpdate();

            return true;
        }
    } // end of soft_delete

    // 기간 내 차량 요금 면제

    public void check(String carNum) throws SQLException {
        List<MonthlyPass> mList = new ArrayList<>();
        String sql = """
                SELECT * FROM monthly_pass WHERE car_number = ? and is_available = 1;
                """;

        try (Connection conn = DBConnection.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql);

        ) {
            pstmt.setString(1, carNum);
            try (ResultSet rs = pstmt.executeQuery()) {
                while (rs.next()) {
                    MonthlyPass mPass = MonthlyPass.builder()
                            .passId(rs.getInt("pass_id"))
                            .carNumber(rs.getString("car_number"))
                            .ownerName(rs.getString("owner_name"))
                            .startDate(rs.getDate("start_date"))
                            .endDate(rs.getDate("end_date"))
                            .fee(rs.getBigDecimal("fee"))
                            .build();
                    mList.add(mPass);
                } // end of while
            } //end of rs
        } // end of pstmt

    } // end if check


    // 정기권 만료 알림
    public List<MonthlyPass> isNearExpiry() throws SQLException {
        List<MonthlyPass> mPass = new ArrayList<>();
        String sql = """
                SELECT * FROM monthly_pass WHERE end_date - CURRENT_DATE() <= 15
                """;

        try (Connection conn = DBConnection.getConnection();
             PreparedStatement tstmt = conn.prepareStatement(sql);
        ) {
            try (ResultSet rs = tstmt.executeQuery()) {
                while (rs.next()) {
                    MonthlyPass mList = MonthlyPass.builder()
                            .passId(rs.getInt("pass_id"))
                            .carNumber(rs.getString("car_number"))
                            .ownerName(rs.getString("owner_name"))
                            .startDate(rs.getDate("start_date"))
                            .endDate(rs.getDate("end_date"))
                            .fee(rs.getBigDecimal("fee"))
                            .build();
                    mPass.add(mList);
                } // end of while
            } // end of rs
        } // end of pstmt

        return mPass;
    } // end of isNearExpiry

    // 정기권 유효한지
    public boolean getMonthlyPassByCarNumber(String carNumber) throws SQLException {
        String sql = """
                SELECT is_available FROM monthly_pass WHERE car_number = ?
                """;

        try (Connection conn = DBConnection.getConnection();
             PreparedStatement stmt = conn.prepareStatement(sql)) {
            stmt.setString(1, carNumber);
            try (ResultSet rs = stmt.executeQuery()) {
                if (rs.next()) {
                    return rs.getBoolean("is_available");
                }
            }
            return false;
        }
    }

    // 정기권 연장
    public boolean getExtends(int date, String carNumber) throws SQLException {
        String sql = """
             
             UPDATE monthly_pass
             SET end_date = date_add(end_date,interval ? day)
             WHERE car_number = ?;
                """;

        try(Connection conn = DBConnection.getConnection();
            PreparedStatement pstmt = conn.prepareStatement(sql)
        ){
            pstmt.setInt(1,date);
            pstmt.setString(2,carNumber);

            pstmt.executeUpdate();
            return true;
        }
    }// end of getExtends

    // 정기권 요금
    public BigDecimal mPassFee(int month){

        BigDecimal basic = BigDecimal.valueOf(100000);

        return basic.multiply(BigDecimal.valueOf(month));
    }

} // end of class
SELECT *
FROM monthly_pass
WHERE DATEDIFF(end_date, CURRENT_DATE()) BETWEEN 0 AND 15;

정기권 만료가 된걸 list로 반환하기위한 sql문 이다. datediff는 첫번째 인자-두번째 인자 이다. 만약에 지난 날짜면 마이너스가 나오기 때문에 between 0이상 15이하를 넣어서 지난 날짜면 나오지 않게 만들었다.

     UPDATE monthly_pass
             SET end_date = date_add(end_date,interval ? day)
             WHERE car_number = ?;

이건 정기권 연장 sql문이다 end_date ?에 일정한값을 넣어 날짜를 더하는 함수이다.

  public BigDecimal mPassFee(int month){

        BigDecimal basic = BigDecimal.valueOf(100000);

        return basic.multiply(BigDecimal.valueOf(month));
    }

정기권 요금을 반환하는 sql문이다. 100000bigdecimal에 들어온 month를 곱하는 것이다.

0개의 댓글