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

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

이렇게 4개의 dto를 설계했다.
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)를 비교해서 맞으면 반환하게 로직을 짰다.
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를 곱하는 것이다.