<프로그램의 개발 목적 및 배경>
평소에 알바를 하면서 사장님이 매출과 재료 주문 문제로 고민하시는 모습을 자주 보았다. 이 경험을 바탕으로 매출을 분석해 손님 수에 맞춰 재료 주문을 효율적으로 관리할 수 있는 프로그램을 개발하고자 한다.
<프로그램 활용 예정자 및 주요 기능>
시흥시 자영업자들을 위해 가게 매출이 어느 요일, 날씨, 계절에 가장 높은지 분석해주는 프로그램을 제작할 예정이다. 또한 시흥시의 유동인구를 시간대, 성별로 구분해서 나타낼 것이다.
1. 가게 추가, 매출 분석, 유동인구 조회, 저장 후 종료 중에서 사용자가 선택한다.
2. 가게 이름을 입력한다.
3. 월~일 번호를 매겨 선택한다.
4. 맑음, 흐림, 눈/비 번호를 매겨 선택한다.
5. 봄, 여름, 가을, 겨울 번호를 매겨 선택한다.
6. 매출을 입력한다.
7. 파일 쓰기를 통해 지금까지 입력한 것을 저장한다.
8. 파일 읽기를 통해 자신의 가게를 찾아 매출이 평균적으로 어느 요일, 날씨, 계절에 가장 높은지 알려준다.
9. 유동인구 조회에서 사용자가 시간을 입력하면 유동인구를 알려준다.
<프로젝트 개발과정>
※ 시흥시의 유동인구 데이터는 경기데이터드림에서 txt파일로 다운을 받아 프로그램에 구현함.
1. 클래스는 Day, Weather, Season, Store, Main로 나누었고, 클래스를 작성하면서 필요한 메소드를 구성하였다.
Day 클래스: 사용자로부터 요일을 선택받고, 요일에 대한 정보를 반환함
Weather 클래스: 사용자로부터 날씨를 선택받고, 날씨에 대한 정보를 반환함
Season 클래스: 사용자로부터 계절을 선택받고, 계절에 대한 정보를 반환함
Store 클래스: 매출, 날씨, 요일 등 가게의 여러 정보를 포함하며 유동인구 정보를 불러옴
Main 클래스: 화면 구성 및 선택
2. 매출 프로그램 먼저 프로그래밍 후, 유동인구와 관련한 정보를 작성했다.
3. 매출 데이터를 요일, 날씨, 계절별로 나누어 평균을 계산하기 위해 HashMap을 사용했다. HashMap을 사용하여 각 요일, 날씨, 계절을 저장하고, 해당하는 매출 데이터를 ArrayList로 관리한다.
daySalesMap, weatherSalesMap, seasonSalesMap으로 나누어 사용했음
computeIfAbsent메소드를 사용해 매출 데이터를 각각의 리스트에 추가함
4. 평균매출 계산
for문이나 for-each문을 활용하여 배열을 순회하고 매출 데이터를 추출함
calculateAverage 메소드를 통해 매출의 합을 구하고 리스트의 크기로 나누어 평균 매출을 반환함
5. 유동인구 데이터 추가
텍스트파일로 다운받은 데이터들이 띄어쓰기로 구분이 되어있어 trim을 사용함
변수를 설정하는 방법 말고도 scanner를 사용하여 파일을 한 줄씩 읽어들이는 방법도 있어 사용해보았음
성별, 나이로 나눠서 유동인구가 출력되며 totalPopulation변수에 각각의 유동인구를 더하는 방식으로 총합을 계산하여 맨 위에 출력함
<소스코드>
Day, Weather, Season, Store, Main 클래스
//유동인구에서 소수점은 기지국단위로 수집된 인구를 주변셀(50*50)으로 나누어 배분하면서 발생됨
import java.io.*;
import java.util.*;
class Day {
String day;
void selectDay() {
Scanner sc = new Scanner(System.in);
int selectDay;
do {
System.out.println("요일 선택: 1. 월요일 2. 화요일 3. 수요일 4. 목요일 5. 금요일 6. 토요일 7. 일요일");
selectDay = sc.nextInt();
if (selectDay < 1 || selectDay > 7) {
System.out.println("잘못된 입력");
}
} while (selectDay < 1 || selectDay > 7);
switch (selectDay) {
case 1:
day = "월요일";
break;
case 2:
day = "화요일";
break;
case 3:
day = "수요일";
break;
case 4:
day = "목요일";
break;
case 5:
day = "금요일";
break;
case 6:
day = "토요일";
break;
case 7:
day = "일요일";
break;
}
}
static String getDayName(int dayValue) {
String[] days = {"월요일", "화요일", "수요일", "목요일", "금요일", "토요일", "일요일"};
return days[dayValue - 1]; // 배열이므로 0부터 시작함. 1을 빼줌.
}
}
class Weather {
String weather;
void selectWeather() {
Scanner sc = new Scanner(System.in);
int selectWeather;
do {
System.out.println("날씨 선택: 1. 맑음 2. 흐림 3. 눈/비");
selectWeather = sc.nextInt();
if (selectWeather < 1 || selectWeather > 3) {
System.out.println("잘못된 입력");
}
} while (selectWeather < 1 || selectWeather > 3);
switch (selectWeather) {
case 1:
weather = "맑음";
break;
case 2:
weather = "흐림";
break;
case 3:
weather = "눈/비";
break;
}
}
}
class Season {
String season;
void selectSeason() {
Scanner sc = new Scanner(System.in);
int selectSeason;
do {
System.out.println("계절 선택: 1. 봄 2. 여름 3. 가을 4. 겨울");
selectSeason = sc.nextInt();
if (selectSeason < 1 || selectSeason > 4) {
System.out.println("잘못된 입력");
}
} while (selectSeason < 1 || selectSeason > 4);
switch (selectSeason) {
case 1:
season = "봄";
break;
case 2:
season = "여름";
break;
case 3:
season = "가을";
break;
case 4:
season = "겨울";
break;
}
}
}
class Store {
String storeName;
String weather;
long sales;
String season;
int dayValue;
static HashMap<String, ArrayList<Store>> storeMap = new HashMap<>(); //배열은 크기가 고정되어있지만 ArrayList는 동적으로 조정가능, HashMap은 맵(Map) 인터페이스를 구현한 클래스이며 키와 값을 쌍으로 저장하는 자료구조
Store() {
}
Store(String a, int b, String c, String d, long e) {
storeName = a;
dayValue = b;
weather = c;
season = d;
sales = e;
}
void storeInformation() {
Scanner sc = new Scanner(System.in);
System.out.print("가게 이름 입력: ");
storeName = sc.nextLine();
Season s = new Season();
s.selectSeason();
season = s.season;
Weather w = new Weather();
w.selectWeather();
weather = w.weather;
Day d = new Day();
d.selectDay();
dayValue = Arrays.asList("월요일", "화요일", "수요일", "목요일", "금요일", "토요일", "일요일").indexOf(d.day) + 1; //문자열 배열을 List 형태로 변환, indexOf() 메소드는 0부터 시작하는 인덱스를 반환
System.out.print("매출 입력: ");
sales = sc.nextLong();
}
void saveStoreData() {
try(FileWriter out = new FileWriter("List.txt", true)){
out.write(storeName + "," + dayValue + "," + weather + "," + season + "," + sales + "\n");
} catch (IOException e) {
System.out.println("파일 저장 중 오류 발생");
}
}
static void loadStoreData() {
storeMap.clear(); //clear메소드는 HashMap에서 제공되며 맵에 저장된 모든 데이터를 삭제하여 맵의 크기가 0이 됨. 여기서는 이게 없으면 기존 데이터가 새로운 데이터와 함께 누적되기에 가게 데이터가 중복 저장될 수 있음.
try {
FileReader in = new FileReader("List.txt");
Scanner sc = new Scanner(in); //파일에서 데이터를 읽기 위한 방법이므로 System.in이 아닌 in으로 써주었음. System.in은 사용자로부터 실시간으로 데이터를 입력받을 때 사용함. FileReader는 한 문자 단위로만 가져올 수 있으므로 Scanner를 사용했음. BufferedReader를 사용해도 문제없다.
while (sc.hasNextLine()) {
String line = sc.nextLine();
String[] data = line.split(",");
String storeName = data[0];
int dayValue = Integer.parseInt(data[1]);
String weather = data[2];
String season = data[3];
long sales = Long.parseLong(data[4]);
Store s = new Store(storeName, dayValue, weather, season, sales);
storeMap.putIfAbsent(storeName, new ArrayList<>()); //putIfAbsent()메소드는 주어진 키가 맵에 존재하지 않을 때만 값을 추가. 여기서는 storeMap에 storeName이 없다면, 새로운 빈 ArrayList를 추가하는 코드
storeMap.get(storeName).add(s); //storeName에 해당하는 ArrayList<Store>에 s라는 Store 객체를 추가
}
} catch (Exception e) {
System.out.println("오류발생");
}
}
static void averageSales(String storeName) {
ArrayList<Store> stores = storeMap.get(storeName); //storeName에 해당하는 ArrayList<Store>를 가져와서 그 값을 stores라는 변수에 할당하는 코드
HashMap<Integer, ArrayList<Long>> daySalesMap = new HashMap<>();
HashMap<String, ArrayList<Long>> weatherSalesMap = new HashMap<>();
HashMap<String, ArrayList<Long>> seasonSalesMap = new HashMap<>();
for (Store store : stores) { //for-each문. 앞에는 자료형 변수명이고 뒤에는 배열이름 또는 컬렉션 객체를 씀. store 변수는 stores 리스트 안에 있는 각 Store 객체를 하나씩 반복
daySalesMap.computeIfAbsent(store.dayValue, k -> new ArrayList<>()).add(store.sales);
weatherSalesMap.computeIfAbsent(store.weather, k -> new ArrayList<>()).add(store.sales);
seasonSalesMap.computeIfAbsent(store.season, k -> new ArrayList<>()).add(store.sales);
} //computeIfAbsent()메소드는 주어진 키가 맵에 존재하지 않으면 지정된 키에 대해 새로운 값을 만들어 추가함. k는 store.dayValue같은 변수를 나타냄. daySalesMap에 store.dayValue라는 키가 없으면 새로운 빈 리스트를 만들어서 키를 저장하고 이 리스트에 add메소드에 있는 값 추가
System.out.println("\n<요일별>:");
double maxDayAvg = 0;
int highestDay = -1;
for (int day = 1; day <= 7; day++) {
if (daySalesMap.containsKey(day)) {
double avg = calculateAverage(daySalesMap.get(day));
System.out.printf("%s 평균 매출: %.2f\n", Day.getDayName(day), avg); //%.2f는 소수점 2자리까지 출력, Day.getDayName(day)는 day에 해당하는 요일 이름을 반환하는 메소드로, 예를 들어 1이면 "월요일" 출력
if (avg > maxDayAvg) {
maxDayAvg = avg;
highestDay = day;
} //계산된 avg가 현재까지 구한 최고 평균 매출 maxDayAvg보다 큰지 확인
}
}
System.out.println("\n<날씨별>: ");
String[] weatherOrder = {"맑음", "흐림", "눈/비"};
String highestWeather = "없음";
double maxWeatherAvg = 0;
for (String weather : weatherOrder) {
if (weatherSalesMap.containsKey(weather)) {
double avg = calculateAverage(weatherSalesMap.get(weather));
System.out.printf("%s 평균 매출: %.2f\n", weather, avg);
if (avg > maxWeatherAvg) {
maxWeatherAvg = avg;
highestWeather = weather;
}
}
}
System.out.println("\n<계절별>: ");
String[] seasonsOrder = {"봄", "여름", "가을", "겨울"};
String highestSeason = "없음";
double maxSeasonAvg = 0;
for (String season : seasonsOrder) {
if (seasonSalesMap.containsKey(season)) {
double avg = calculateAverage(seasonSalesMap.get(season));
System.out.printf("%s 평균 매출: %.2f\n", season, avg);
if (avg > maxSeasonAvg) {
maxSeasonAvg = avg;
highestSeason = season;
}
}
}
System.out.println("\n최고 매출 요일: " + Day.getDayName(highestDay));
System.out.println("최고 매출 날씨: " + highestWeather);
System.out.println("최고 매출 계절: " + highestSeason);
}
static double calculateAverage(ArrayList<Long> salesList) { //평균매출 계산
long total = 0;
for (Long sale : salesList) {
total += sale;
}
return (double) total / salesList.size(); //.size()는 컬렉션에 저장된 요소의 개수 반환
}
static void population(int time) {
try {
Scanner sc = new Scanner(new File("시흥시 유동인구.txt")); //new Scanner(new File(...))은 파일에서 데이터를 읽어올 때 사용하는 방법
while (sc.hasNextLine()) {
String line = sc.nextLine();
String[] data = line.trim().split("\\s+"); // \\s를 통해 공백 문자로 구분함
if (data.length < 28) {
System.out.println("잘못된 데이터 형식: " + line);
continue; //28보다 크면 넘어감
}
try {
int timeCode = Integer.parseInt(data[2]);
if (timeCode == time) {
float totalPopulation = 0; //유동인구 총합
for (int i = 4; i <= 16; i++) {
double malePopulation = Double.parseDouble(data[i]);
double femalePopulation = Double.parseDouble(data[i + 13]);
double ageGroupTotal = malePopulation + femalePopulation;
totalPopulation += (float) ageGroupTotal;
}
System.out.println("\n" + "<시흥시 유동인구 데이터>");
System.out.println(time + "시 ~ " + time + "시 59분 " + "유동인구 총합: " + totalPopulation);
System.out.println("남성 00-09세: " + data[4]);
System.out.println("남성 10-14세: " + data[5]);
System.out.println("남성 15-19세: " + data[6]);
System.out.println("남성 20-24세: " + data[7]);
System.out.println("남성 25-29세: " + data[8]);
System.out.println("남성 30-34세: " + data[9]);
System.out.println("남성 35-39세: " + data[10]);
System.out.println("남성 40-44세: " + data[11]);
System.out.println("남성 45-49세: " + data[12]);
System.out.println("남성 50-54세: " + data[13]);
System.out.println("남성 55-59세: " + data[14]);
System.out.println("남성 60-64세: " + data[15]);
System.out.println("남성 65-69세: " + data[16] + "\n");
System.out.println("여성 00-09세: " + data[17]);
System.out.println("여성 10-14세: " + data[18]);
System.out.println("여성 15-19세: " + data[19]);
System.out.println("여성 20-24세: " + data[20]);
System.out.println("여성 25-29세: " + data[21]);
System.out.println("여성 30-34세: " + data[22]);
System.out.println("여성 35-39세: " + data[23]);
System.out.println("여성 40-44세: " + data[24]);
System.out.println("여성 45-49세: " + data[25]);
System.out.println("여성 50-54세: " + data[26]);
System.out.println("여성 55-59세: " + data[27]);
System.out.println("여성 60-64세: " + data[28]);
System.out.println("여성 65-69세: " + data[29]);
break;
}
} catch (Exception e) {
System.out.println("오류발생");
}
}
} catch (FileNotFoundException e) {
System.out.println("시흥시 유동인구.txt 파일을 찾을 수 없습니다.");
}
}
}
class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
Store.loadStoreData();
while (true) {
System.out.println("\n1. 가게 추가");
System.out.println("2. 매출 분석");
System.out.println("3. 유동인구 조회");
System.out.println("4. 저장 후 종료");
System.out.print("선택: ");
while (!sc.hasNextInt()) {
System.out.println("유효한 숫자를 입력하세요.");
sc.next();
}
int choice = sc.nextInt();
sc.nextLine();
switch (choice) {
case 1:
Store newStore = new Store();
newStore.storeInformation();
Store.storeMap.computeIfAbsent(newStore.storeName, k -> new ArrayList<>()).add(newStore);
newStore.saveStoreData(); //콘마로 구분하여 저장
System.out.println("가게 정보가 저장되었습니다.");
break;
case 2:
System.out.print("분석할 가게 이름을 입력하세요: ");
String storeName = sc.nextLine();
Store.averageSales(storeName);
break;
case 3:
System.out.print("조회할 시간을 입력하세요 (0-23): ");
int time = sc.nextInt();
Store.population(time);
break;
case 4:
System.out.println("프로그램을 종료합니다.");
sc.close();
return;
default:
System.out.println("잘못된 선택입니다. 다시 시도해주세요.");
break;
}
}
}
}
시흥시 유동인구.txt
41390 시흥시 0 . 1710.4 1957.13 3449.86 4137.1 4024.98 3753.28 4696.59 3966.09 3880.23 3609.53 2877.76 1543.76 765.1 1543.95 1498.74 2481.01 3604.12 3349.13 2836.13 3627.83 3207.09 3058.15 2934.41 2281.49 1513.49 600.26
41390 시흥시 1 . 1294.31 1682.85 2660.73 2832.22 2930.54 2808.46 3656.57 3097.97 3283.9 2901.1 2520.58 1384.18 676.7 1343.02 1296.31 1677.52 2290.65 2047.51 2296.15 2843.16 2330.99 2789.38 2464.78 2077.85 1288.53 546.12
41390 시흥시 2 . 1227.16 1638.28 2270.33 2581.11 2857.59 2593.23 3509.86 3117.69 3233.63 2819.67 2383.68 1482.03 708.04 1228.97 1318.31 1704.87 2126.25 2122.42 2110.07 2715.58 2434.34 2612.2 2276.35 1967.52 1251.57 650.22
41390 시흥시 3 . 1142.21 1517.72 2176.17 2433.77 2602.21 2565.81 3480.9 2871.87 3117.02 2839.71 2467.21 1347.76 691.79 1393.64 1174.03 1378.04 1951.02 2150.95 2057.78 2554.6 2236.98 2713.74 2221.51 2088.27 1410.54 670.25
41390 시흥시 4 . 1521.08 1960.64 2863.18 3388.42 3241.98 3081.33 3937.09 3476.99 3585.91 3550.13 2961.03 1672.1 849.87 1538.5 1298.44 2231.97 2973.7 2931.01 2453.2 3231.51 2556.78 2933.46 2614.62 2326.28 1711.25 665.08
41390 시흥시 5 . 1297.11 1681.15 2230.68 2437.33 2870.84 2741.95 4059.5 3449.59 3771.56 3480.28 2999.58 1833.37 946.38 1315.17 1232.98 1402.76 1901.34 2046.59 2049.8 2959.9 2600.78 2969.51 2650.51 2270.56 1620.12 717.27
41390 시흥시 6 . 1917.15 2358.76 3356.29 3717.01 3752.03 3544.81 4546.07 4053.8 4278.81 3999.8 3692.82 2137.28 951.04 1690.94 1774.82 2519.27 3531.86 3062.63 2866.66 3802.72 3123.01 3513.88 3150.59 2967.62 1927.58 892.37
41390 시흥시 7 . 1652.89 2142.74 3726.38 3512.57 4264.64 3801.59 5048.75 4939.14 5483.02 5565.45 5114.13 2842.08 1480.94 1558.28 1788.36 2557.87 2950.07 3038.43 2717.38 4128.39 3410.29 3971.67 3786.59 3445.95 2294.31 1139.92
41390 시흥시 8 . 2135.21 2441.04 3220.09 4180.65 4368.17 4232.27 5528.1 5033.93 5452.41 5020.71 4560.53 2592.32 1232.74 1836.94 1619.42 2771.97 3607.85 3537.6 3446.19 4254.61 3711.71 4241.56 4064.03 3824.05 2500.67 1054.39
41390 시흥시 9 . 2891.8 3035.78 3287.49 3943.93 4342.1 3963.15 5578.21 5839.87 6803.91 6755.29 6755.91 4030.37 1986.34 2908.78 2626.44 2010.08 2779.33 3080.52 3816.85 5153.43 4559.67 5226.42 4823.55 4716.09 3285.94 1608.27
41390 시흥시 10 . 2870.15 3051.45 3814.23 4001.93 4548.15 4013.81 6228.76 6321.14 7164.1 7273.4 7427.3 4198.42 2250.76 2828.41 2576.82 2085.65 2958.09 3469.83 4194.28 5804.26 5095.98 5867.34 5720.69 5058.09 3560.59 1854.03
41390 시흥시 11 . 3694.33 3407.08 4228.52 5260.65 5580.2 5586.88 7725.22 6841.24 7552.58 7060.77 6809.14 4020.43 2034.11 3128.37 2782.76 3571.97 4903.14 5010.95 5319.91 6663.17 5692.24 6629 6478.14 5639.27 3655.03 1950.89
41390 시흥시 12 . 3083.96 3295.57 4462.23 4689.4 5235.88 5078.47 6779.19 7057.05 8302.88 8620.43 8088.25 4873.32 2528.89 3235.65 2862.74 2824.38 3489.38 4427.23 4597.68 6503.55 5597.72 6870.05 6815.51 5814.68 3968.72 1936.77
41390 시흥시 13 . 3588.79 4047.39 4744.05 4492.48 4690.67 4847.85 6359.93 6969.59 7923.19 7891.61 7978.25 4791.8 2526.66 3625.07 3131.66 2896.04 3376.99 4356.15 4580.6 6721.23 5903.92 7157.99 7184.62 6104.02 4035.92 1915.38
41390 시흥시 14 . 4523.66 4442.73 6220.71 6486.26 7503.48 6708.14 8890.75 7887.63 8823.98 8667.18 7704.08 4571.14 2334.21 4257.77 4150.13 5391.63 6815.45 6949.24 6482.3 8060.1 7075.19 8274.62 7841.84 7051.92 4559.7 2355.83
41390 시흥시 15 . 3638.54 3560.76 4595.28 4491.15 4713.85 4562.3 6797.58 6353.11 7309.81 7617.69 7681.64 4532.74 2453.82 4173.3 3070.07 2725.7 3375.64 4111.11 4464.03 6105.4 5409.81 6242.14 6509.57 5888.26 3746.4 1733.01
41390 시흥시 16 . 3914.04 3956.24 4808.64 5648.92 6692.49 6092.12 8534.57 7222.07 7660.8 7103.83 6548.88 3655 1927.43 3983.69 3987.36 4119.77 5341.67 5494.25 5603.76 7373.88 6148.39 7110.43 6218.18 5144.32 3269.04 1837
41390 시흥시 17 . 4751.11 4328.29 5587.67 4735.13 5244.64 4894.45 6662.47 7106.96 7315.87 7185.04 6621.51 3682.91 1916.35 4679.72 3570.35 3955.77 3728.31 4494.04 4714.89 6543.44 5567.51 6414.66 6125.12 5031.65 3485.15 1379.6
41390 시흥시 18 . 3321.34 4142.5 6017.04 5805.9 6189.65 6288.88 8014.56 7343.7 7479.6 7597.03 6418.47 3520.81 1669.95 3428.78 3348.81 4186.22 5384.67 5433.93 4982.95 7220.29 5864.42 6737.73 5954.25 4783.58 3029.77 1250.62
41390 시흥시 19 . 3639.99 4204.6 4650.97 4748.62 5184.67 4969.81 6972.74 6368.11 6352.23 6158.62 5424.65 3003.72 1324.1 3674.86 3518.07 3182.25 4141.63 4362.36 4354.31 6035.05 5418.7 5949.09 5420.1 4340.52 2660.89 1092.42
41390 시흥시 20 . 3601.3 4465.87 5116.21 5470.03 5913.01 5549.44 7576.85 6777.99 6845.48 6380.44 5661.57 2926.37 1299.25 3344.48 3705.51 3984.51 4924.77 4920.48 5097.43 6455.19 5754.71 6218.39 5287.01 4105.14 2441.94 1124.51
41390 시흥시 21 . 2959.48 4513.56 6045.33 5917.78 6283.64 5957.57 7669.79 7054.96 7315.13 6770.51 5369.75 2889.97 1376.1 3047.39 3501.99 4591.68 5060.28 5290.72 4999.16 6889.32 5396.24 6112.65 5303.3 4277.51 2780.1 1275.84
41390 시흥시 22 . 2568.83 3613.98 5100.64 5272.28 5489.76 5403.23 7154.11 6104.87 6374.87 5622.28 4674.67 2607.5 1093.38 2611.49 3115.69 3668.88 4721.2 4437.83 4343.61 6134.12 4945.97 5448.6 4560.76 3673.6 2384.22 973.12
41390 시흥시 23 . 1992.31 2913.16 4805.83 5023.94 5122.31 4776.18 5782.54 4830.54 5151.17 4816.26 3995.95 2255.09 1005.85 2186.79 2354.4 3430.01 4819.63 4268.89 3922.03 5053.24 4116.42 4510.23 3995.35 3215.95 2156.79 954.59
<실행결과>
<간단한 후기>
저번 프로젝트는 자바에 대해 거의 아무것도 모른채로 진행했던 과제라서 코드에 대한 이해를 완벽하게 하지 못했고 gpt의 도움도 많이 받았었다. 하지만 이번 프로젝트에서는 코드를 보다 효율적으로 작성하면서 교수님이 알려주신 것들을 최대한 많이 활용해서 나름? 만족스러운 결과가 나온 것 같다ㅎㅎ
'Project' 카테고리의 다른 글
[개인 프로젝트/java] 로그인 및 회원가입 시스템 구현 (0) | 2024.06.21 |
---|