프로젝트 개요
-
구현 목표
- 중고 거래 플랫폼 관리자 파트(관리자 메뉴, 회원 관리, 중고 물품 관리, 고객센터 FAQ)를 구현한다.
-
활동 내용
- 1. File Input/Ouput, Collection, Open API 등의 기술을 적용하여 기능을 구현한다.
- 2. 상품 카테고리 및 거래방식, 물품 정렬 기능으로 편리한 거래 기능을 제공한다.
- 3. 관리자가 전체 회원을 관리할 수 있도록 하고, 판매 중인 물품, 판매된 물품 정보에 대하여 분석한 정보를 제공한다.
- Category
- Period
- GitHub
Java Console 프로젝트 | |
2023.08.16.~2023.08.24. | |
https://github.com/Isaac-Seungwon/daitso.git |
관리자 메인 페이지 화면 출력 클래스
package com.project.cow.admin;
import java.util.Scanner;
import com.project.cow.Main;
public class AdminMenu {
/**
* 관리자 메인 페이지 화면 출력 클래스
* @author 이승원
* 목적: 관리자의 메인 메뉴 화면을 출력하고 관리 기능을 실행하는 클래스
* 기능:
* - 회원 관리, 블랙리스트 관리, 중고 물품 관리, 고객센터 Q&A, 지역 우편함, 중고거래 제한물품 관리 등의 기능을 제공한다.
* - 사용자의 선택에 따라 해당 기능을 실행하거나 메인 메뉴로 돌아갈 수 있다.
*/
/**
* 관리자 메인 메뉴 메소드
*/
Scanner scan = new Scanner(System.in);
public void adminMenu() {
while (true) {
// 관리자 메인 메뉴 화면 출력
AdminMenu.printMenu("관리자 메인 메뉴");
AdminMenu.printOption("회원 관리", "블랙리스트 관리", "중고 물품 관리", "고객센터 F A Q", "중고거래 제한물품");
String input = scan.nextLine().trim();
if (input.equals("1")) {
// 회원 관리
MemberCheck.adminMemberCheck();
} else if (input.equals("2")) {
// 블랙리스트 관리
BlackListManagement.blackListScreen();
} else if (input.equals("3")) {
// 중고 물품 관리
StuffCheck.adminStuffCheck();
} else if (input.equals("4")) {
// 고객센터 F A Q
MemberQuestion.adminFAQCheck();
} else if (input.equals("5")) {
// 중고거래 제한물품
ProhibitedItems.prohibitScreen();
} else {
Main.MainScreen();
}
}
}
/**
* 메뉴의 주어진 옵션과 '돌아가기' 옵션을 출력하는 메소드
* @param options 출력할 옵션
*/
public static void printOption(String... options) {
for (int i = 0; i < options.length; i++) {
System.out.println((i + 1) + ". " + options[i]);
}
System.out.println("0. 돌아가기");
AdminMenu.printLine();
System.out.print("번호 입력: ");
}
/**
* 주어진 문자열을 가운데 정렬하여 출력하는 메소드
* @param text 출력할 문자열
*/
public static void printMenu(String text) {
String line = "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━";
int totalWidth = line.length() / 2; // 총 출력 폭 설정(75)
String formattedText = centerText(text, totalWidth);
AdminMenu.printLine();
System.out.println(formattedText);
AdminMenu.printLine();
}
/**
* 주어진 문자열을 주어진 폭에 맞게 가운데 정렬하여 반환하는 메소드
* @param text 가운데 정렬할 문자열
* @param width 문자열을 정렬할 폭
* @return 가운데 정렬된 문자열
*/
public static String centerText(String text, int width) {
return String.format("%" + width + "s", text);
}
/**
* 가운데 정렬된 선을 출력하는 메소드
*/
public static void printLine() {
String line = "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━";
System.out.println(line);
}
}
관리자 회원 관리 클래스
package com.project.cow.admin;
import java.util.Scanner;
public class MemberCheck {
/**
* 관리자 회원 관리 클래스
* @author 이승원
* 목적: 관리자가 회원 관리 기능을 수행하는 클래스
* 기능:
* - 회원 관리 메뉴를 표시하고 사용자의 선택에 따라 회원 관리 기능을 실행한다.
* - 회원 목록 조회, 회원 검색, 회원 삭제 기능을 제공한다.
*/
/**
* 관리자 회원 관리 메소드
*/
public static void adminMemberCheck() {
Scanner scan = new Scanner(System.in);
String sortCriterion = "1++등급";
String[] rateCriterionList = { "돌아가기", "1++등급", "1+등급", "1등급", "2등급", "3등급" }; // 등급별 정렬 기준
while (true) {
// 메인 메뉴 표시 및 사용자 선택
AdminMenu.printMenu("회원 관리");
System.out.println("[회원 관리 기능]");
AdminMenu.printOption("전체 회원 목록 조회", "회원 검색", "회원 삭제");
String manageChoice = scan.nextLine().trim();
if (manageChoice.equals("1")) { // 전체 회원 목록 조회
MemberListDisplay.sortMemberList(sortCriterion, rateCriterionList);
} else if (manageChoice.equals("2")) { // 회원 검색
MemberSearch.searchMember(scan);
} else if (manageChoice.equals("3")) { // 회원 삭제
MemberRemove.removeMember(scan);
} else { // 로그인 메뉴
return;
}
}
}
}
관리자 전체 회원 목록 조회 클래스
package com.project.cow.admin;
import java.util.Comparator;
import java.util.Scanner;
import java.util.Stack;
import java.util.regex.Pattern;
import com.project.cow.data.MemberData;
import com.project.cow.data.object.Member;
public class MemberListDisplay {
/**
* 관리자 전체 회원 목록 조회 클래스
* @author 이승원
* 목적: 관리자가 전체 회원 목록을 조회하고 정렬하는 기능을 제공하는 클래스
* 기능:
* - 사용자 선택에 따라 다양한 정렬 방식으로 회원 정보를 출력한다.
* - 등급별, 이름순, 나이순, 주소별 기준으로 회원 정보를 정렬하여 출력한다.
* - 회원 정보를 화면에 표시할 때 페이지 단위로 나눠서 보여주고 다음/이전 페이지로 이동할 수 있다.
*/
static Scanner scan = new Scanner(System.in);
/**
* 회원 목록 조회 메인 메소드
* @param defaultSortCriterion 기본 정렬 기준
* @param rateCriterionList 등급 정렬 기준 리스트
*/
public static void sortMemberList(String defaultSortCriterion, String[] rateCriterionList) {
while (true) {
// 회원 목록 옵션 표시 및 사용자 선택
AdminMenu.printMenu("전체 회원 목록 조회");
String sortProcess = chooseSortProcess();
if (!Pattern.matches("[1234]", sortProcess)) {
return;
}
// 정렬 기준 선택
String sortCriterion = getSortCriterion(sortProcess, rateCriterionList);
// 사용자 선택에 따라 정렬 및 출력 수행
sortAndPrintMember(sortCriterion);
}
}
/**
* 정렬 기준 선택 메소드
* @param sortProcess 정렬 옵션
* @param rateCriterionList 등급 정렬 기준 리스트
* @return 선택된 정렬 기준
*/
private static String getSortCriterion(String sortProcess, String[] rateCriterionList) {
String sortCriterion = "0";
if (sortProcess.equals("1")) { // 등급 옵션 표시 및 사용자 선택
System.out.println("[등급별 정렬]");
AdminMenu.printOption("1++등급 정렬", "1+등급 정렬", "1등급 정렬", "2등급 정렬", "3등급 정렬");
String rateCriterion = scan.nextLine().trim();
if (Pattern.matches("[1234]", rateCriterion)) {
sortCriterion = rateCriterionList[Integer.parseInt(rateCriterion)];
}
} else if (sortProcess.equals("2")) {
sortCriterion = "이름순";
} else if (sortProcess.equals("3")) {
sortCriterion = "나이순";
} else if (sortProcess.equals("4")) {
sortCriterion = "주소별";
}
return sortCriterion;
}
/**
* 회원을 정렬하고 출력하는 메소드
* @param sortCriterion 정렬 기준
*/
private static void sortAndPrintMember(String sortCriterion) {
int groupDataCount = 0;
String groupChoice;
Stack lastRangeData = new Stack<>(); // 화면에 출력된 마지막 회원 번호
lastRangeData.push(0);
// 회원 정렬 수행
performSorting(sortCriterion);
while (true) {
if (!sortCriterion.equals("0")) {
AdminMenu.printMenu("회원 목록");
// 회원 정보 출력
displayMemberInfo(sortCriterion, lastRangeData, groupDataCount);
} else {
return;
}
groupChoice = scan.nextLine();
groupDataCount = 0;
if (groupChoice.equals("1")) { // 다음 100명 보기
} else if (lastRangeData.size() > 1 && groupChoice.equals("2")) { // 이전 100명 보기
lastRangeData.pop();
lastRangeData.pop();
if (lastRangeData.isEmpty()) {
lastRangeData.push(0);
}
} else { // 돌아가기
return;
}
}
}
/**
* 정렬 방식 선택 메소드
* @param scan Scanner 사용자 입력
*/
private static String chooseSortProcess() {
// 정렬 방식 옵션 표시 및 사용자 선택
System.out.println("[회원 목록 정렬]");
AdminMenu.printOption("등급별 정렬", "이름순 정렬", "나이순 정렬", "주소별 정렬");
return scan.nextLine().trim();
}
/**
* 정렬 기준별 회원 정보 출력 메소드
* @param sortCriterion 정렬 기준
* @param lastData 마지막 데이터 스택
* @param dataCount 출력된 데이터 개수
*/
private static void displayMemberInfo(String sortCriterion, Stack lastData, int dataCount) {
displayMemberHeader(); // 헤더 출력
// 회원 정보 출력
for (Member member : MemberData.list) {
if (dataCount <= 100) {
if (lastData.isEmpty() || Integer.parseInt(member.getNo()) > lastData.peek()) {
if (sortCriterion.matches("^(이름순|나이순|주소별)$")) {
// 이름순, 나이순, 주소별 출력
printMemberInfo(member);
dataCount++;
} else {
// 등급순 출력
if (member.getGrade().equals(sortCriterion)) {
printMemberInfo(member);
dataCount++;
}
}
}
if (dataCount > 100) {
lastData.push(Integer.parseInt(member.getNo()));
}
}
}
if (!sortCriterion.equals("0")) { // 정보 출력 및 다음 동작 선택
System.out.printf("정렬: %s (총 회원 수 %d명)%n", sortCriterion, MemberData.list.size());
displayDataList(sortCriterion, lastData.size());
} else {
return;
}
}
/**
* 등급별, 이름순, 나이순, 주소별 정렬 메소드
* @param sortCriterion 정렬 기준
*/
private static void performSorting(String sortCriterion) {
if (sortCriterion.equals("이름순")) {
MemberData.list.sort(Comparator.comparing(member -> member.getName()));
} else if (sortCriterion.equals("나이순")) {
MemberData.list.sort((member1, member2) -> {
int ageComparison = Integer.compare(calculateAge(member1.getJumin()), calculateAge(member1.getJumin()));
if (ageComparison == 0) { // 생년이 같은 경우 생월로 내림차순 정렬
int month1 = Integer.parseInt(member1.getJumin().substring(2, 4));
int month2 = Integer.parseInt(member2.getJumin().substring(2, 4));
if (month1 == month2) { // 생월이 같은 경우 생일로 내림차순 정렬
int day1 = Integer.parseInt(member1.getJumin().substring(4, 6));
int day2 = Integer.parseInt(member2.getJumin().substring(4, 6));
return Integer.compare(day2, day1);
}
return Integer.compare(month2, month1);
}
return ageComparison;
});
} else if (sortCriterion.equals("주소별")) {
MemberData.list.sort(Comparator.comparing(member -> member.getAddress()));
String currentAddress = "";
System.out.print("주소 정렬 순서:");
for (Member member : MemberData.list) {
String address = member.getAddress();
if (!address.equals(currentAddress)) {
System.out.printf(" %s", address);
currentAddress = address;
}
}
System.out.println();
} else {
MemberData.list.sort(Comparator.comparing(member -> member.getGrade()));
}
}
/**
* 주민번호를 이용한 나이 계산 메소드
* @param jumin 주민번호
* @return 계산된 나이
*/
private static int calculateAge(String jumin) {
int birthYear = Integer.parseInt(jumin.substring(0, 2));
int currentYear = 2023;
int age = currentYear - (1900 + birthYear) + 1;
if (age > 100) {
age = age - 100;
}
return age;
}
/**
* 회원 정보를 출력하는 메소드
* @param member 회원 정보 데이터 객체
*/
static void printMemberInfo(Member member) {
System.out.printf(" %-4s %5s %-16s %-12s %13s %14s %-24s %-5s", member.getNo(), member.getName(), member.getId(), member.getPwd(), member.getTel(), member.getJumin(), member.getEmail(), member.getAddress());
for (int i = 0; i < 4 - member.getAddress().length(); i++) { // 띄어쓰기 간격 조절
System.out.print(" ");
}
System.out.printf("%16s %,9d %9s\r\n", member.getAccount(), Integer.parseInt(member.getMoney()), member.getGrade());
}
/**
* 회원 목록의 헤더를 출력하는 메소드
*/
public static void displayMemberHeader() {
System.out.println("[번호] [이름] [아이디] [비밀번호] [전화번호] [주민번호] [이메일] [주소] [계좌번호] [보유금액] [회원등급]");
}
/**
* 회원 정보 범위를 출력하는 화면을 표시하는 메소드
* @param sortCriterion 정렬 기준
* @param lastRangeDataSize 마지막 범위 데이터 크기
*/
private static void displayDataList(String sortCriterion, int lastRangeDataSize) {
AdminMenu.printLine();
System.out.println("1. 다음 100명 보기");
if (lastRangeDataSize > 2) {
System.out.println("2. 이전 100명 보기");
}
System.out.println("0. 돌아가기");
AdminMenu.printLine();
System.out.print("번호 입력: ");
}
}
관리자 회원 검색 클래스
package com.project.cow.admin;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import com.project.cow.constant.Constant;
import com.project.cow.data.MemberData;
import com.project.cow.data.SellingStuffData;
import com.project.cow.data.SoldOutStuffData;
import com.project.cow.data.object.Member;
import com.project.cow.data.object.SellingStuff;
import com.project.cow.data.object.SoldOutStuff;
public class MemberSearch {
/**
* 관리자 회원 검색 클래스
* @author 이승원
* 목적: 관리자가 회원 정보를 검색하는 기능을 제공하는 클래스
* 기능:
* - 회원 번호, 이름, 아이디로 검색한 회원 정보를 출력한다.
* - 검색한 회원의 판매한 물품과 구매한 물품 정보를 출력한다.
*/
static Scanner scan = new Scanner(System.in);
/**
* 회원 검색 기능을 수행하는 메소드
* @param scan Scanner 사용자 입력
*/
public static void searchMember(Scanner scan) {
AdminMenu.printMenu("회원 검색");
System.out.print("검색할 회원 번호, 이름 또는 아이디 입력: ");
String searchKeyword = scan.nextLine().trim();
displaySearchResult(searchKeyword); // 검색 결과 출력
}
/**
* 검색 결과를 출력하고 검색된 회원 수를 보여주는 메소드
* @param keyword 검색 키워드 (회원 번호, 이름, 아이디)
*/
private static void displaySearchResult(String keyword) {
AdminMenu.printMenu("회원 목록");
List foundMembers = new ArrayList<>();
for (Member member : MemberData.list) {
// 회원 번호, 이름, 아이디 중 검색 키워드와 일치하는지 확인
if (member.getNo().equals(keyword) || member.getName().equals(keyword) || member.getId().equals(keyword)) {
foundMembers.add(member);
MemberListDisplay.displayMemberHeader(); // 헤더 출력
MemberListDisplay.printMemberInfo(member); // 회원 출력
sellingStuffMember(member); // 회원의 판매 물품 출력
soldOutStuffMember(member); // 회원의 구매 물품 출력
AdminMenu.printLine();
}
}
int foundCount = foundMembers.size();
if (foundCount == 0) {
System.out.println("검색 결과가 없습니다.");
} else {
System.out.printf("%d명의 회원이 검색되었습니다.%n", foundCount);
}
scan.nextLine();
}
/**
* 회원이 판매한 물품 목록을 출력하는 메소드
* @param member 회원 객체
* @param displayStuffNo 판매 물품 번호를 저장하는 Set
*/
private static void sellingStuffMember(Member member) {
int sellOrBuyCount = 0;
for (SellingStuff stuff : SellingStuffData.sellingList) {
if (member.getNo().equals(stuff.getSellerNo())) {
sellOrBuyCount++;
}
}
if (sellOrBuyCount > 0) {
System.out.println();
System.out.printf("[판매 물품]\n");
System.out.println("[번호] [품명] [상품품질] [가격] [판매자] [거래방법] [지불방법] [판매시작일] [판매마감일] [찜횟수]");
for (SellingStuff stuff : SellingStuffData.sellingList) {
if (member.getNo().equals(stuff.getSellerNo())) {
System.out.printf(" %4s %-16s\t\t%s %10s", stuff.getNo(), stuff.getName(), Constant.Condition(stuff.getCondition()), stuff.getPrice());
// 해당 물품의 판매자 정보 출력
for (Member seller : MemberData.list) {
if (seller.getNo().equals(stuff.getSellerNo())) {
System.out.printf(" %6s ", seller.getName());
}
}
System.out.printf(" %-9s \t %-13s\t%-15s %-15s %3s\r\n", Constant.Method(stuff.getMethod()), Constant.Payment(stuff.getPayment()), stuff.getFrom(), stuff.getUntil(),
stuff.getLike());
}
}
}
}
/**
* 회원이 구매한 물품 목록을 출력하는 메소드
* @param member 회원 객체
*/
private static void soldOutStuffMember(Member member) {
int sellOrBuyCount = 0;
for (SoldOutStuff stuff : SoldOutStuffData.soldOutList) {
if (member.getNo().equals(stuff.getBuyerNo())) {
sellOrBuyCount++;
}
}
if (sellOrBuyCount > 0) {
System.out.println();
System.out.printf("[구매 물품]\n");
System.out.println(
"[번호] [품명] [카테고리] [상품품질] [가격] [거래방법] [지불방법] [구매날짜] [판매자]");
for (SoldOutStuff stuff : SoldOutStuffData.soldOutList) {
if (member.getNo().equals(stuff.getBuyerNo())) {
sellOrBuyCount++;
System.out.printf("%5s\t%-14s\t%s", stuff.getNo(), stuff.getName(), Constant.Category(stuff.getCategory()));
if (Constant.Category(stuff.getCategory()).length() > 6) {
System.out.print("");
} else {
System.out.print("\t");
}
System.out.printf("\t\t%3s\t %,9d\t\t%-6s\t%-6s\t%-10s", Constant.Condition(stuff.getCondition()),
Integer.parseInt(stuff.getPrice()), Constant.Method(stuff.getMethod()), Constant.Payment(stuff.getPayment()),
stuff.getWhen());
// 해당 물품의 판매자 정보 출력
for (Member seller : MemberData.list) {
if (seller.getNo().equals(stuff.getSellerNo())) {
System.out.printf(" %6s\r\n", seller.getName());
}
}
}
}
}
}
}
관리자 회원 삭제 클래스
package com.project.cow.admin;
import java.util.Scanner;
import java.util.Set;
import java.util.TreeSet;
import com.project.cow.data.MemberData;
import com.project.cow.data.object.Member;
public class MemberRemove {
/**
* 관리자 회원 삭제 클래스
* @author 이승원
* 목적: 관리자가 회원 정보를 삭제하는 기능을 제공하는 클래스
* 기능:
* - 검색한 회원 정보를 출력하고 선택한 회원을 삭제할 수 있다.
* - 회원을 삭제하여 회원 정보 파일이 수정되면 파일을 업데이트한다.
*/
public static final String MEMBER_LIST = "data\\member.txt"; // 회원 정보 파일 경로
static Scanner scan = new Scanner(System.in);
/**
* 회원 삭제 기능을 수행하는 메인 메소드
* @param scan Scanner 사용자 입력
*/
public static void removeMember(Scanner scan) {
AdminMenu.printMenu("회원 삭제");
System.out.print("삭제할 회원 번호, 이름 또는 아이디 입력: ");
String deleteKeyword = scan.nextLine().trim();
// 검색 결과 출력 및 회원 선택
Set selectedMemberList = searchAndSelectMember(deleteKeyword);
if (!selectedMemberList.isEmpty()) {
AdminMenu.printLine();
System.out.print("위 회원들 중 삭제할 회원 번호를 입력하세요: ");
int deleteIndex = Integer.parseInt(scan.nextLine().trim()) - 1;
if (deleteIndex >= 0 && deleteIndex < MemberData.list.size()) {
Member selectedMember = MemberData.list.get(deleteIndex);
AdminMenu.printLine();
MemberListDisplay.printMemberInfo(selectedMember);
System.out.print("위 회원을 삭제하시겠습니까? (y/n): ");
String confirm = scan.nextLine().trim();
if (confirm.equalsIgnoreCase("y")) {
performMemberRemove(selectedMember);
} else {
System.out.println("삭제가 취소되었습니다.");
scan.nextLine();
}
} else {
System.out.println("유효하지 않은 회원 번호입니다.");
scan.nextLine();
}
} else {
System.out.println("해당 회원을 찾을 수 없습니다.");
scan.nextLine();
}
}
/**
* 회원 정보 삭제를 수행하는 메소드
* @param selectedMember 선택된 회원의 정보 객체
*/
private static void performMemberRemove(Member selectedMember) {
MemberData.list.remove(selectedMember);
MemberData.save(); // 회원 정보 파일 업데이트
System.out.println("회원이 삭제되었습니다.");
scan.nextLine();
}
/**
* 검색한 회원 정보를 출력하고 선택한 회원의 인덱스를 반환하는 메소드
* @param keyword 검색 키워드 (회원 번호, 이름 또는 아이디)
* @return 선택된 회원의 인덱스를 담은 TreeSet
*/
private static Set searchAndSelectMember(String keyword) {
// TreeSet을 사용하여 중복 없이 선택된 회원 인덱스 저장
Set selectedMember = new TreeSet<>();
AdminMenu.printMenu("회원 목록");
MemberListDisplay.displayMemberHeader(); // 헤더 출력
int index = 0; // 회원 인덱스
for (Member member : MemberData.list) {
if (member.getNo().equals(keyword) || member.getName().equals(keyword)) {
MemberListDisplay.printMemberInfo(member);
selectedMember.add(index);
}
index++;
}
return selectedMember; // 삭제할 회원 정보 객체
}
}
관리자 FAQ 및 답변 관리 클래스
package com.project.cow.admin;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;
public class MemberQuestion {
/**
* 관리자 FAQ 및 답변 관리 클래스
* @author 이승원
* 목적: 관리자가 FAQ 게시판을 확인하고 답변을 수정하는 클래스
* 기능:
* - FAQ 게시판 출력 및 답변 수정 기능을 제공한다.
*/
private static final String QNA_LIST = "data\\FAQ.txt"; // FAQ 정보 파일 경로
private static ArrayList qnaDataList = new ArrayList<>(); // FAQ 정보 배열
static Scanner scan = new Scanner(System.in);
/**
* FAQ 및 답변 게시판을 화면에 출력하는 메인 메소드
*/
public static void adminFAQCheck() {
while (true) {
AdminMenu.printMenu("고객센터 F A Q");
System.out.println("[F A Q 관리 기능]");
AdminMenu.printOption("F A Q 게시판", "F A Q 답변 수정");
String manageChoice = scan.nextLine().trim();
if (manageChoice.equals("1")) { // 자주 묻는 질문 확인
displayFAQ();
System.out.println();
System.out.println("Enter를 누르면 이전 화면으로 돌아갑니다.");
scan.nextLine();
} else if (manageChoice.equals("2")) { // 자주 묻는 질문 수정
displayFAQ();
modifyFAQAnswer();
} else {
return;
}
}
}
/**
* FAQ 및 답변 게시판을 화면에 출력하는 메소드
*/
private static void displayFAQ() {
AdminMenu.printMenu("F A Q 게시판");
for (String[] data : qnaDataList) {
String index = data[0];
String viewCount = data[1];
String question = data[2];
String answer = data[3];
System.out.println("번호: " + index);
System.out.println("조회수: " + viewCount);
System.out.println("질문: " + question);
System.out.println("답변: " + answer);
AdminMenu.printLine();
}
}
/**
* FAQ 답변을 수정하는 메소드
*/
private static void modifyFAQAnswer() {
System.out.print("답변할 질문 번호 입력(0 입력 시, 관리자 화면으로 이동): ");
String questionNumber = scan.nextLine().trim();
int index = Integer.parseInt(questionNumber);
if (index >= 1 && index <= qnaDataList.size()) {
System.out.print("답변 입력: ");
String answer = scan.nextLine().trim();
qnaDataList.get(index - 1)[3] = answer; // 답변을 데이터 목록에 저장
saveFAQInfo(); // 수정된 FAQ 업데이트
System.out.printf("%d번 답변을 수정하였습니다.\n", index);
}else if(index == 0) {
return;
}
else {
System.out.println("유효하지 않은 질문 번호입니다.");
modifyFAQAnswer();
}
System.out.println();
System.out.println("Enter를 누르면 이전 화면으로 돌아갑니다.");
scan.nextLine();
}
/**
* FAQ 데이터를 파일에 저장하는 메소드
*/
public static void saveFAQInfo() {
try {
FileWriter writer = new FileWriter(QNA_LIST);
for (String[] data : qnaDataList) {
writer.write(String.join(",", data) + "\n");
}
writer.close();
} catch (IOException e) {
System.out.println("saveFAQInfo 오류");
e.printStackTrace();
}
}
/**
* FAQ 데이터를 파일에서 로드하는 메소드
*/
public static void loadFAQInfo() {
try {
BufferedReader reader = new BufferedReader(new FileReader(QNA_LIST));
String qna;
while ((qna = reader.readLine()) != null) {
String[] data = qna.split(",");
qnaDataList.add(data);
}
reader.close();
} catch (IOException e) {
System.out.println("loadFAQInfo Error");
e.printStackTrace();
}
}
}
중고 물품 현황 분석 클래스
package com.project.cow.admin;
import java.util.List;
import java.util.Scanner;
import com.project.cow.data.SellingStuffData;
import com.project.cow.data.SoldOutStuffData;
import com.project.cow.data.object.SellingStuff;
import com.project.cow.data.object.SoldOutStuff;
public class StuffCheck {
/**
* 중고 물품 현황 분석 클래스
* @author 이승원
* 목적: 판매 중 및 판매 완료된 물품의 현황을 분석하고 조회하는 클래스
* 기능:
* - 판매중인 물품 및 판매된 물품의 현황을 조회할 수 있다.
* - 물품의 카테고리별 판매 현황 및 인기 물품을 분석하여 1위부터 5위까지 출력한다.
*/
public interface Stuff {
String getCategory();
String getName();
}
static Scanner scan = new Scanner(System.in);
/**
* 관리자가 중고 물품을 확인하는 메인 메소드
*/
public static void adminStuffCheck() {
stuffStatusCheck();
}
/**
* 중고 물품 관리 메뉴를 처리하는 메소드
*/
private static void stuffStatusCheck() {
while (true) {
AdminMenu.printMenu("중고 물품 관리");
AdminMenu.printOption("판매중인 물품 현황", "판매된 물품 현황");
String searchChoice = scan.nextLine().trim();
if (searchChoice.equals("1")) { // 판매중인 물품 현황
analyzeSellingStuff();
} else if (searchChoice.equals("2")) { // 판매된 물품 현황
analyzeSoldOutStuff();
} else {
return;
}
}
}
/**
* 판매중인 물품 분석 기능을 수행하는 메소드
*/
private static void analyzeSellingStuff() {
String startDate = null;
String endDate = null;
// 처음 판매를 시작한 물품, 마지막에 판매를 종료하는 물품의 날짜를 찾음
for (SellingStuff stuff : SellingStuffData.sellingList) {
String sellStartDate = stuff.getFrom();
String sellEndDate = stuff.getUntil();
if (startDate == null || sellStartDate.compareTo(startDate) < 0) {
startDate = sellStartDate; // 물품 검색을 시작할 날짜
}
if (endDate == null || sellEndDate.compareTo(endDate) > 0) {
endDate = sellEndDate; // 물품 검색을 끝낼 날짜
}
}
// 판매중인 물품 현황 출력
displayStuffStatus(SellingStuffData.sellingList, startDate, endDate);
}
/**
* 판매된 물품 분석 기능을 수행하는 메소드
*/
private static void analyzeSoldOutStuff() {
String startDate = null;
String endDate = null;
// 처음 판매된 물품, 마지막에 판매된 물품의 날짜를 찾음
for (SoldOutStuff stuff : SoldOutStuffData.soldOutList) {
String soldDate = stuff.getWhen();
if (startDate == null || soldDate.compareTo(startDate) < 0) {
startDate = soldDate; // 물품 검색을 시작할 날짜
}
if (endDate == null || soldDate.compareTo(endDate) > 0) {
endDate = soldDate; // 물품 검색을 끝낼 날짜
}
}
// 판매중인 물품 현황 출력
displayStuffStatus(SoldOutStuffData.soldOutList, startDate, endDate);
}
/**
* 물품 현황을 출력하는 메소드
* @param stuffList 물품 정보 객체 리스트
* @param startDate 검색 시작 날짜
* @param endDate 검색 종료 날짜
*/
private static void displayStuffStatus(List extends Stuff> stuffList, String startDate, String endDate) {
int stuffCount = 0;
int[] stuffCategory = new int[12]; // 카테고리별 물품 개수 배열
int[] topStuffCategory; // 인기 있는 카테고리 배열
String[] stuffName = new String[stuffList.size()]; // 물품 이름 배열
String[] topStuffName = new String[5]; // 인기 있는 물품 이름 배열
int[] topStuffCount = new int[5]; // 인기 있는 물품 판매 수 배열
// 물품 정보 업데이트 및 물품 개수 계산
stuffCount = updateStuffInfo(stuffList, stuffCategory, stuffName);
System.out.printf("%s ~ %s까지의 매물 현황을 조회합니다.\n", startDate, endDate);
scan.nextLine();
if (stuffCount <= 0) {
System.out.println("판매중인 물품이 없습니다.");
scan.nextLine();
} else {
AdminMenu.printMenu("물품 현황 조회");
System.out.printf("검색 기간: %s ~ %s\n", startDate, endDate);
System.out.printf("검색된 물품 수: %,d개\n", stuffCount);
topStuffCategory = calculateTopCategory(stuffCategory); // 상위 카테고리 계산
displayCategoryRanking(topStuffCategory, stuffCategory); // 카테고리별 순위 및 개수 출력
// 인기 있는 물품 이름 업데이트
for (Stuff stuff : stuffList) {
updateTopStuff(stuff, topStuffName, topStuffCount, stuffCategory);
}
displayStuffRanking(topStuffName, topStuffCount); // 인기 물품 순위 출력
AdminMenu.printLine();
System.out.println("물품 현황 조회가 완료되었습니다.");
scan.nextLine();
}
}
/**
* 물품 정보를 업데이트하고 물품 개수를 계산하는 메소드
* @param stuffList 물품 정보 객체 리스트
* @param stuffCategory 카테고리별 물품 개수를 저장하는 배열
* @param stuffName 물품 이름을 저장하는 배열
* @return 업데이트된 물품 개수
*/
private static int updateStuffInfo(List extends Stuff> stuffList, int[] stuffCategory, String[] stuffName) {
int stuffCount = 0;
for (Stuff stuff : stuffList) {
updateCategoryCount(stuffCategory, stuff); // 카테고리별 물품 개수 업데이트
stuffName[stuffCount] = stuff.getName(); // 물품 이름 저장
stuffCount++; // 물품 개수 누적
}
return stuffCount;
}
/**
* 물품의 카테고리별 개수를 업데이트하는 메소드
* @param stuffCategory 카테고리 배열
* @param stuff 물품 정보 객체
*/
private static void updateCategoryCount(int[] stuffCategory, Stuff stuff) {
// 물품의 카테고리를 가져와 해당 카테고리 인덱스로 초기화
int index = Integer.parseInt(stuff.getCategory()) - 1;
stuffCategory[index] += 1; // 해당 카테고리의 물품 개수 증가
}
/**
* 인기 물품을 업데이트하는 메소드
* @param stuff 물품 정보 객체
* @param topStuffName 인기 물품 배열
* @param topStuffCount 인기 물품 카운트 배열
* @param stuffCategory 카테고리 배열
*/
private static void updateTopStuff(Stuff stuff, String[] topStuffName, int[] topStuffCount, int[] stuffCategory) {
for (int i = 0; i < 5; i++) {
// 인기 물품 배열의 i번째가 비어있거나 카테고리의 판매 수가 인기 물품 배열의 i번째 판매 수보다 큰 경우
if (topStuffName[i] == null || topStuffCount[i] < stuffCategory[Integer.parseInt(stuff.getCategory()) - 1]) {
// 인기 물품 배열을 오른쪽으로 한 칸씩 이동
for (int j = 4; j > i; j--) {
topStuffName[j] = topStuffName[j - 1];
topStuffCount[j] = topStuffCount[j - 1];
}
// 해당 카테고리의 물품 이름과 판매 수를 인기 물품 배열에 삽입
topStuffName[i] = stuff.getName();
topStuffCount[i] = stuffCategory[Integer.parseInt(stuff.getCategory()) - 1];
break;
}
}
}
/**
* 인기 물품 순위를 출력하는 메소드
* @param topStuffName 인기 물품 배열
* @param topStuffCount 인기 물품 카운트 배열
*/
private static void displayStuffRanking(String[] topStuffName, int[] topStuffCount) {
System.out.println();
System.out.println("[인기 물품 순위]");
// 순위와 함께 인기 물품 이름 및 판매 수 출력
for (int i = 0; i < 5; i++) {
if (topStuffName[i] != null) {
System.out.printf("%d위 %s (%d개)\n", i + 1, topStuffName[i], topStuffCount[i]);
}
}
}
/**
* 인기 카테고리 순위를 계산하는 메소드
* @param stuffCategory 카테고리 배열
* @return 상위 카테고리 배열
*/
private static int[] calculateTopCategory(int[] stuffCategory) {
int[] topCategory = new int[5];
for (int i = 0; i < 5; i++) {
// 각 상위 카테고리의 초기 최대값 및 인덱스 설정
int maxCount = -1; // 최대 판매 수 초기값 설정
int maxIndex = -1; // 최대 판매 수를 가진 카테고리 인덱스 초기값 설정
for (int j = 0; j < stuffCategory.length; j++) {
// 해당 카테고리의 판매 수가 최대값이면서 상위 카테고리 배열에 포함되지 않은 경우
if (stuffCategory[j] > maxCount && !contains(topCategory, j)) {
maxCount = stuffCategory[j]; // 최대 판매 수 업데이트
maxIndex = j; // 최대 판매 수를 가진 카테고리 인덱스 업데이트
}
}
// 최대값을 가지는 카테고리의 인덱스를 상위 카테고리 배열에 삽입
topCategory[i] = maxIndex;
}
return topCategory;
}
/**
* 인기 카테고리 순위를 출력하는 메소드
* @param topCategorie 상위 카테고리 배열
* @param stuffCategory 카테고리별 물품 개수 배열
*/
private static void displayCategoryRanking(int[] topCategorie, int[] stuffCategory) {
System.out.println();
System.out.println("[인기 카테고리 순위]");
// 순위와 함께 해당 카테고리의 이름 및 물품 개수를 출력
for (int i = 0; i < 5; i++) {
int categoryIndex = topCategorie[i];
String categoryName = getCategoryName(categoryIndex + 1);
int categoryItemCount = stuffCategory[categoryIndex];
System.out.printf("%d위 %s (%d개)\n", i + 1, categoryName, categoryItemCount);
}
}
/**
* 배열 내에서 특정 값이 존재하는지 확인하는 메소드
* @param array 배열
* @param value 확인할 값
* @return 값의 존재 여부
*/
private static boolean contains(int[] array, int value) {
for (int element : array) {
if (element == value) {
// 배열 요소가 특정 값과 일치하는 경우 true 반환
return true;
}
}
return false;
}
/**
* 카테고리 번호에 해당하는 카테고리 이름을 반환하는 메소드
* @param stuffCategory 카테고리 번호
* @return 카테고리 이름
*/
public static String getCategoryName(int stuffCategory) {
switch (stuffCategory) {
case 1:
return "가구/인테리어/생활/주방";
case 2:
return "디지털 기기";
case 3:
return "여성잡화";
case 4:
return "남성잡화";
case 5:
return "가공식품";
case 6:
return "스포츠/레저";
case 7:
return "취미/게임/음반";
case 8:
return "뷰티/미용";
case 9:
return "반려동물용품";
case 10:
return "티켓/교환권/도서";
case 11:
return "기타 중고물품";
default:
return "카테고리 미등록";
}
}
}
국토교통부 지하철 TAGO API
package com.project.cow.member;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Scanner;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import com.project.cow.admin.AdminMenu;
public class Locker {
/**
* 제3자 안전 거래 보관함 위치 찾기 클래스
*
* @author 이승원
* 목적: 사용자에게 보관함 위치를 제공하고 지하철 역 주변의 보관함 정보를 조회하는 기능을 제공하는 클래스
*/
Scanner scan = new Scanner(System.in);
/*
* 화면 출력 메소드
*/
public void screen() {
AdminMenu.printMenu("보관함 위치 찾기");
areaList();
AdminMenu.printLine();
System.out.println("지역을 선택해주세요.");
System.out.println("0을 선택하면 이전 화면으로 돌아갑니다.");
System.out.print("번호입력:");
areaSelect(scan.nextLine());
chooseReturn();
}
/*
* 보관함 위치 메뉴 출력 및 선택 메서드
*/
private void chooseReturn() {
System.out.println("다른 지역 보관함 위치를 보시겠습니까?");
System.out.println();
System.out.println("1.보기\t0.나가기");
System.out.print("번호입력:");
String no = scan.nextLine();
if (no.equals("1")) {
System.out.println();
System.out.println();
screen();
} else if (no.equals("0")) {
System.out.println();
System.out.println();
MemberMenu.membermenu();
} else {
System.out.println();
System.out.println("잘못된 입력입니다. 다시 입력해주세요.");
chooseReturn();
}
}
/*
* 지역 선택 메서드
*/
private void areaSelect(String no) {
String area = "";
String id = "";
switch (no) {
case "0":
System.out.println("Enter를 누르면 이전 화면으로 돌아갑니다.");
scan.nextLine();
MemberMenu.membermenu();
break;
case "1":
area = "종로3가";
id = "MTRS13319";
break;
case "2":
area = "서울";
id = "MTRS11150";
break;
case "3":
area = "용산";
id = "MTRKR1135";
break;
case "4":
area = "왕십리";
id = "MTRS12208";
break;
case "5":
area = "강변";
id = "MTRS12214";
break;
case "6":
area = "동대문";
id = "MTRS14421";
break;
case "7":
area = "상봉";
id = "MTRKRK2K120";
break;
case "8":
area = "안암";
id = "MTRS162640";
break;
case "9":
area = "미아";
id = "MTRS14415";
break;
case "10":
area = "도봉";
id = "MTRKR10114";
break;
case "11":
area = "노원";
id = "MTRS172715";
break;
case "12":
area = "연신내";
id = "MTRS13311";
break;
case "13":
area = "서대문";
id = "MTRS152533";
break;
case "14":
area = "홍대입구";
id = "MTRS12239";
break;
case "15":
area = "목동";
id = "MTRS152521";
break;
case "16":
area = "개화";
id = "MTRS990901";
break;
case "17":
area = "구로";
id = "MTRKR1P141";
break;
case "18":
area = "금천구청";
id = "MTRKR1P144";
break;
case "19":
area = "여의도";
id = "MTRS152527";
break;
case "20":
area = "노량진";
id = "MTRKR1136";
break;
case "21":
area = "서울대입구";
id = "MTRS12228";
break;
case "22":
area = "서초";
id = "MTRS12224";
break;
case "23":
area = "강남";
id = "MTRS12222";
break;
case "24":
area = "잠실";
id = "MTRS12216";
break;
case "25":
area = "천호";
id = "MTRS152548";
break;
default:
System.out.println("잘못된 입력입니다. 다시 입력해주세요.");
screen();
}
System.out.println();
findMetro(area, id);
}
/*
* 지하철 역 정보 조회 메소드
*/
private void findMetro(String area, String id) {
String url = "http://apis.data.go.kr/1613000/SubwayInfoarchive/getKwrdFndSubwaySttnList?";
url += "archiveKey=oMmFtyn6y40ikar6b1ETbGrMTEdFmfRJyqTn%2B7H85I9D0W8TV2G4fFbKUfcRmGChZCArFikDa%2B2H629%2FdLIJXA%3D%3D";
url += "&_type=json";
url += "&numOfRows=10";
url += "&pageNo=1";
url += "&subwayStationName=" + URLEncoder.encode(area);
try {
URL obj_url = new URL(url);
HttpURLConnection conn = (HttpURLConnection) obj_url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Content-type", "application/json");
BufferedReader reader = null;
if (conn.getResponseCode() >= 200 && conn.getResponseCode() <= 300) {
reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
} else {
reader = new BufferedReader(new InputStreamReader(conn.getErrorStream()));
}
JSONParser parser = new JSONParser();
JSONObject root = (JSONObject) parser.parse(reader);
JSONObject response = (JSONObject) root.get("response");
JSONObject body = (JSONObject) response.get("body");
JSONObject items = (JSONObject) body.get("items");
ArrayList temp = new ArrayList();
if (items.get("item") instanceof JSONObject) {
JSONObject item = (JSONObject) items.get("item");
System.out.println("이 지역 보관함은 " + item.get("subwayStationName") + "역 1번 출구 옆에 있습니다.");
AdminMenu.printLine();
} else {
JSONArray arr = (JSONArray) items.get("item");
for (Object obj : arr) {
JSONObject item = (JSONObject) obj;
if (item.get("subwayStationId").equals(id)) {
System.out.println("이 지역 보관함은 " + item.get("subwayStationName") + "역 1번 출구 옆에 있습니다.");
AdminMenu.printLine();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/*
* 지역 리스트 출력 메소드
*/
private void areaList() {
String area = "1.종로구 " + " 2.중구 " + " 3.용산구 " + " 4.성동구 " + " 5.광진구\n" + "6.동대문구 " + " 7.중랑구 " + "8.성북구 "
+ " 9.강북구 " + " 10.도봉구\n" + "11.노원구 " + " 12.은평구 " + " 13.서대문구 " + " 14.마포구 " + " 15.양천구\n" + "16.강서구 "
+ " 17.구로구 " + " 18.금천구 " + " 19.영등포구 " + " 20.동작구\n" + "21.관악구 " + " 22.서초구 " + " 23.강남구 " + " 24.송파구 "
+ " 25.강동구\n";
System.out.println(area);
}
}
프로젝트 후기
자바 프로젝트는 자바 수업에서 배운 내용들을 적용해 볼 수 있는 유익한 시간이었다. 여러 기술적인 문제와 마주쳤으며, 팀 내에서 맡은 업무를 구현하기 위해 다양한 시도를 하게 되었다. 이러한 과정에서 시행착오가 있기도 했지만, 문제 해결 방법을 익히고, 학습한 기술을 적용하여 언어와 해당 기술에 대한 이해도를 높일 수 있었다고 생각한다.
나는 2023년 4학년 1학기에 대학교에서 [프로젝트 관리] 수업을 수강하였다. 당시에 팀 프로젝트를 할 때 지켜야 할 코드 규칙(클래스 및 메소드 이름, 줄 간격 등)과 주석을 작성하는 방법 등에 대해서 배운 적이 있다. 당시에 공부한 내용을 실제로 적용한 결과 서로의 코드를 이해하는 데 도움이 되어서 신기했다. 이런 규칙들을 의도적으로 생각하면서 작업하다 보니 협업에서 요구되는 규칙들을 자연스럽게 익히는 데 도움이 되었다.
팀 프로젝트를 시작하면서 [중고 물품 거래 플랫폼]으로 주제를 선정하고, 요구분석서, 순서도, 기능명세서를 작성하기로 하였다. 프로그램을 만드는데 산출물이 있다는 것은 대학교에서 배워서 알고 있었지만, 어떻게 작성해야 하는 것인지 알지 못했다. 팀장님이 요구분석서, 순서도, 기능명세서 중 작성할 서류에 인원을 배정했고, 나를 포함한 4명이 요구 분석서를 작성하게 되었다. 나는 산출물을 확인해 보면서 산출물의 내용이 방대해질 것을 고려하여 서류를 작성하기 이전에 몇 가지 규칙을 세워야겠다는 생각이 들었다.
처음에 틀을 제대로 잡아야 나중에 서류 전체를 수정하는 불상사가 생기지 않을 것이었다. 그래서 ‘회원 공통 기능’, ‘구매자 기능’, ‘판매자 기능’, ‘관리자 기능’으로 구현할 기능을 4가지로 분류하여 팀원들과 1개 파트를 담당하고, ‘업무 영역’, ‘요구사항 명’, ‘개요’, ‘상세 설명’, ‘제약사항’을 작성하도록 양식을 제공했다. 무턱대고 빨리 시작하는 게 아니라 조금 시간이 걸리더라도 팀원들과 소통하면서 틀을 잡은 게 오히려 빠르게 다음 단계로 넘어가고, 업무의 완성도를 높이는 데 도움이 되었던 거 같다.
나는 관리자의 회원 관리, 중고 물품 관리, 고객센터 FAQ 기능을 구현하는 업무를 담당하였다. 코드를 작성하면서 클래스와 메소드를 활용하여 코드의 가독성과 유지보수성을 높이고자 노력하였고, 이러한 기술을 활용하여 사용자 입력 처리, 데이터 정렬, 스트림, 출력 포맷팅 등의 개발 기술을 익힐 수 있었다.
팀원으로서의 후기
팀원으로서 습득한 기술을 프로젝트에 적용해가는 과정에서 많이 배웠고, 성취감을 느낄 수 있었다. 특히 팀원들과 협업하면서 개인적으로 Java 코드를 작성할 때와 어떻게 다른지, 협업할 때 Git과 Source tree를 어떻게 이용할 수 있는지 이해하게 되었다. 이 과정을 통해 내가 알게 된 것들을 팀원들과 공유하고, 문제를 해결하며 함께 배울 수 있어서 재밌고 즐거웠다.
학원을 오가는 광역버스 안에서 프로젝트를 하고 있으면 시간이 금방 갔다. 프로젝트에 책임감을 느꼈고, 다른 팀원들에게 도움이 되고 싶어서 맡은 일을 빠르게 마칠 수 있도록 프로젝트에 집중했다. 그렇게 막바지에 다른 팀원분들이 서류 작업을 마무리할 때, 나는 팀원들의 소스 코드를 수정하여 콘솔에 출력되는 화면을 통일하는 업무를 하게 되었다. 팀원들의 소스 코드를 읽어보았고, 해야 하는 일이 무엇이 있는지를 찾았다. 그렇게 보완할 점을 찾아서 팀원들에게 전달하였고, 버그를 픽스하는 과정에서 스스로 많이 배울 수 있었던 거 같다. 그러나 기술적인 문제 해결에서 발생하는 어려움뿐만 아니라 사람 사이의 관계에 대한 어려움이 프로젝트 중에 발생할 수 있다는 것을 알게 되었다.
나는 언제나 내가 틀릴 수도 있다고 생각한다. 프로젝트에 의견을 내는 데 있어서 내가 틀릴 수도 있고, 인간관계에 있어서 내 배려가 상대방에게는 불편하게 느껴질 수도 있다는 것을 안다. 이번 팀 프로젝트에서는 각자의 능력을 최대한 발휘하고, 프로젝트에 집중하려면 서로가 존중하는 태도를 갖춰야 한다는 걸 알게 되기도 했다. 계속 본인의 의견을 강요하고 감정적으로 팀원들을 불편하게 하는 태도는 전혀 도움이 되지 않는다. 이번 팀 프로젝트의 협업은 전체적으로 원활하게 진행되긴 했지만, 위와 같은 트러블이 발생하기도 했다. 이러한 경험으로 일부 손해를 감수하더라도 팀을 위한 선택을 해야겠다는 생각이 들었다.
개발자 후기
자바 콘솔 프로젝트를 통해 팀원들과 협업하면서 소스 코드를 작성하는 방법, Git과 Source tree를 활용하는 방법을 알게 되었다. 그리고 팀 내에서 서로를 존중으로 대하는 게 프로젝트 본연의 업무에 집중하고, 조직적으로 작업하는 데 있어서 매우 중요하다는 것을 느낄 수 있었다.
내가 가지고 있는 부족한 점을 잘 알았기에, 이번 프로젝트에서 성장을 위해서 더 열심히 임했던 거 같다. 팀원들과 소통하고, 진행 과정을 공유하면서 내가 가지고 있는 개발자로서의 부족한 점을 보완할 수 있었다.
팀장님께 조언을 얻고자 코드를 보여드린 적이 있는데, 가독성을 높여야 할 필요가 있다는 것을 알게 되었다. 그때 팀장님이 클래스와 메소드를 이용해 코드의 가독성을 높이는 게 좋겠다는 조언을 해 주셔서 코드를 모듈화하여 기능 단위로 분리해 재사용률을 높일 수 있게 했다. 작업 중간마다 팀원들의 평가와 조언을 들으면서 내가 가지고 있는 단점을 버리고, 팀원들의 조건을 행동으로 옮기려고 노력했다.
이번 프로젝트는 단순히 오류를 해결하는 것뿐만 아니라 다른 사람이 보기에도 이해하기 쉽게 코드를 작성하는 데 중점을 두었다. 프로젝트를 통해 협업에서 가장 기본이 되는 것은 다른 사람에 대한 배려라는 걸 깨달았다. 내가 만들었더라도 그건 나만 보는 코드가 아니기 때문에 이해하기 쉬운 주석을 다는 방법에 대해서 따로 공부하기도 했다. 향후 진행할 프로젝트에는 한 단계 더 나아가 보기에도 간결하면서 기능적으로도 안정된 코드를 짜는 걸 목표로 하려고 한다.