설계를 빡세게 해도 막상 코딩에 들어가면 복잡한게 당연하다 응응 ..
수업에서 짧게 배웠던 MVC 패턴을 적용하는 건 따라서 하면 됐는데 뷰를 구성하고 호출스택을 관리하는 부분이 어려웠다 호출스택을 좀 더 신경써야 한다는 점을 배웠다
1. 개발 환경
Language: Java, JDK 1.8
Database: oracle 11g
Editor: Eclipse
OS: Windows 10, MacOS(나만)
2. 시연
윈도우의 이클립스에서 실행한 모습을 녹화한 영상이다
아래에 기능별로 자세한 설명을 기술했다 (맥 터미널에서 실행)
0. 첫화면
프로그램을 실행하면 위 처럼 나타난다
1. 회원가입
회원가입을 선택하고 그에 맞는 정보를 입력한다
만약 잘못된 정보를 입력하면 잘못된 정보가 기입되었음을 알리고 다시 회원가입과 로그인을 선택하는 페이지가 나타난다.
💦 아쉬운 점
1. 입력예시를 사용자에게 보여주지 않은 점
2. 어떤 정보가 잘못 기입되었는지 자세히 알려주지 못한 점
3. 전화번호 정보를 저장하는 컬럼의 길이를 너무 짧게 잡아서 하이픈(-)을 이용해 전화번호를 입력하면 에러가 발생한다는 점
4. 전화번호나 이메일에 정규식 등을 이용해 형식을 정하지 못한 점
정확한 정보를 기입하면 회원가입이 완료되고 회원가입과 로그인을 선택하는 페이지로 돌아간다
2. 로그인
로그인 화면이다. 없는 아이디를 입력하거나 존재하는 아이디와 대응하지 못하는 비밀번호를 입력하면 로그인 정보가 일치하지 않는다는 메시지를 출력하고 다시 회원가입과 로그인을 선택하는 페이지로 이동한다.
로그인을 구현할 때 사용자가 아이디와 비밀번호 둘 중 어떤 정보가 잘못 입력되어 있는지를 정확히 알려주지 않도록 작성했다. 왜냐 하면, 어떤 정보가 잘못되었는지를 세세히 알려주면 악용의 사례가 있어 두루뭉술하게 알려준다는 이야기를 들은 적이 있기 때문이다
정확한 아이디와 비밀번호를 입력하면 다음 페이지로 이동한다는 메시지를 출력한다.
3. 접수하기
접수를 할 때 어느 지역, 무슨 시험, 몇 회차를 응시할 것인지를 사용자로부터 선택받고 결제 방식을 선택하도록 한다. 결제는 출력만 하고 구현을 하지는 않았다. 여기서 접수가 완료됐다는 메시지가 뜨면 사용자가 입력한 내용이 Register 테이블에 삽입되도록 구현했다
💦 아쉬운 점
1. 예외 처리를 제대로 하지 못한 점(입력예시와 맞지 않는 정보를 입력 시 NullPointerException이 발생한다.)
2. 원래는 접수한 시험이 맞는지 입력 내역을 출력하지 못한 점
3. 시험 코드(지역 코드)와 시험명(지역명)을 분리하지 못한 점
4. 마이페이지
마이페이지에서는 접수 내역을 확인하거나 회원정보 및 접수내역을 수정할 수 있다. 접수내역 확인을 선택하면 자신이 접수한 시험의 내역을 확인할 수 있고 시험코드와 지역코드를 확인할 수 있도록 아래에 출력시켰다.
접수하지 않고 접수내역을 확인하면 접수한 시험이 없다는 메시지가 출력된다
💦 아쉬운 점
1. 접수내역을 출력할 때 시험명, 지역명을 출력하지 못한 점
2. 프로그램 한바퀴를 돌고 다시 접수를 확인하면 접수내역과 함께 접수한 시험이 없다는 문구가 나타나는 점
5. 접수 취소
접수내역을 취소하는 메시지가 뜨고 y를 선택하면 접수가 취소된 후 접수페이지로 이동한다
💦 아쉬운 점
1. 접수내역을 취소하냐는 메시지에서 n을 입력하면 마이페이지로 이동해야 하는데 빼먹고 구현하지 못한 점
2. 접수페이지로 이동한다는 메시지가 출력된 후 엔터를 한 번 더 입력해야 접수페이지로 이동한다는 점
6. 비밀번호 수정
회원 정보 수정을 선택하고 비밀번호를 선택한 후 수정값을 입력하면 수정이 완료된다 전화번호와 이메일도 마찬가지로 작동한다
비밀번호 변경 전 로그인 실패
비밀번호 변경 후 로그인 성공
7. 회원 탈퇴
회원탈퇴를 선택하면 정말 탈퇴를 진행할 것인지를 묻는 안내문이 출력되고 y를 입력하면 탈퇴가 완료된다. n을 입력하면 뒤(회원 정보 수정 페이지)로 이동한다.
탈퇴 전 정보로 로그인을 시도하면 실패한다.
💦 아쉬운 점
1. n을 입력하면 어떠한 안내문도 없이 엔터를 한 번 더 입력해야 회원 수정 페이지로 이동한다는 점
2. n을 입력하면 회원 수정 페이지 보다는 마이페이지로 이동하는 게 더 낫다는 생각,,
3. 특히 신경 쓴 부분
3-1. 입장한 사용자를 받는 법
입장한 사용자를 eSession이라는 static 변수에 저장하였다. 이렇게 하면 현재 사용자의 값을 얻어오거나 설정할 때도 세션의 getter, setter 메서드만 사용하면 된다.
public class RegisterApplication {
public static ExamineeVO eSession = new ExamineeVO(); // 접속한 사용자를 저장하는 변수
public static RegisterVO rSession = new RegisterVO(); // 시험을 접수한 사용자를 저장하는 변수
public static void main(String[] args) throws Exception {
FrontController main = new FrontController();
main.process();
}
public static ExamineeVO geteSession() {
return eSession;
}
public static RegisterVO getrSession() {
return rSession;
}
}
개발하는 동안에 getSession() 메서드를 만든 것을 까먹고 바로 변수에다 저장했지만 다행히 큰 문제는 발생하지 않았다 다음에 사용할 때는 더 주의해서 사용하도록 할 것 명심명심
System.out.println("—————————————————— ✼ 수험장 선택 ✼ ————————————————");
/* 수험장을 선택하는 코드 */
System.out.println("——————————————————— ✼ 과목 선택 ✼ —————————————————");
/* 과목을 선택하는 코드 */
System.out.println("————————————————— ✼ 응시 회차 선택 ✼ ———————————————");
/* 응시 회차를 선택하는 코드*/
// 과목 코드 설정
RegisterApplication.rSession.setExamCode(choiceExamCode);
// 수험장+응시 회차 설정
RegisterApplication.rSession.setSiteCode(choiceExamSite.concat(choiceExamTurn));
// 응시자 아이디에 현재 사용자의 아이디 저장
RegisterApplication.rSession.setId(RegisterApplication.eSession.getId());
// insert하기 위한 응시자 객체 생성
RegisterVO registerExaminee = new RegisterVO(
RegisterApplication.rSession.getId(),
RegisterApplication.rSession.getExamCode(),
RegisterApplication.rSession.getSiteCode()
);
이렇게 세션을 이용해 현재 사용자의 정보를 접수 테이블에 넣을 수 있었다
3-2. Map을 이용한 자료구조
과목코드를 예로 들면 사용자에게 보여줄 시험 이름과 데이터베이스에 들어갈 시험 코드의 구성은 다르다 그래서 Map을 이용해서 시험 이름과 시험 코드를 일대일 대응시켰다 데이터베이스에 값을 삽입/수정/삭제할 때 사용하는 시험 코드는 키값으로, 사용자에게 보여주는 시험 이름은 밸류값으로 설정했다. 순서가 입력한대로 유지되어야 하므로 LinkedHashMap을 사용했다.
public Map<String, String> createExamCodeMap() {
Map<String, String> examMap = new LinkedHashMap<>();
examMap.put("ECE", "토목기사(ECE)");
examMap.put("ELA", "조경기사(ELA)");
examMap.put("EGS", "가스기사(EGS)");
examMap.put("EEW", "전기공사기사(EEW)");
examMap.put("EET", "전자기사(EET)");
examMap.put("EWD", "용접기사(EWD)");
examMap.put("ECI", "화공기사(ECI)");
examMap.put("EAT", "건축기사(EAT)");
examMap.put("EMM", "자동차정비기사(EMM)");
examMap.put("EIP", "정보처리기사(EIP)");
return examMap;
}
이를 메서드로 맵을 반환하도록 하였고 사용자가 입력한 시험명을 scanner로 받아서 코드로 반환하도록 하였다.
public String choiceExamCode(String choiceExamName) { // 사용자가 토목기사를 입력하면 ECE 반환
choiceExam = new HashMap<>();
String choiceExamCode = getKey(createExamCodeMap(), choiceExamName);
choiceExam.put(choiceExamCode, choiceExamName);
return choiceExamCode;
}
public static <K, V> K getKey(Map<K, V> map, V value) { // 밸류값으로 키값을 반환하는 메서드
for (K key : map.keySet()) {
if (value.equals(map.get(key))) {
return key;
}
}
return null;
}
이런식으로 수험장과 응시회차를 다뤘다 수험장 코드와 응시회차를 합쳐서 수험장 테이블의 PK값으로 쓰이고 있었기 때문에(ex. 서울 2회차 -> SE2) 두 값을 concat으로 묶는 작업이 중요했다.
4. 프로젝트를 진행하는 동안 아쉬웠던 점
4-1. 흐름 읽기가 어렵다 어려워
뷰와 컨트롤러를 왔다갔다하면서 어느 부분에서 어떤 메서드를 호출하고 어떻게 벗어날지를 정의하지 않고 코딩을 했더니 반복되면 안될 부분에서 반복됐고 입력되야할 부분에서 입력이 멈췄다(이건 아직도 스캐너 문제라고 생각하고 있긴 함 . . ㅎ)
한창 복잡하던 찰나에 결국 손으로 플로우차트를 그렸더니 그래도 정의가 쉬워졌고 s님께서 내가 마무리하지 못한 부분을 마저 처리해주셨다
4-2. 예외 처리를 하려면 조금 더 부지런해야해
뒷심 부족 + 이틀 연속 새벽에 마무리함 환장의 콜라보로 예외처리를 미뤄버렸다 특히나 시험명, 시험코드, 응시 회차를 잘못 입력했을 때 NullPointerException이 발생하는 건 금방 처리할 수 있었는데도 하지 않았다. 다음 프로젝트때에는 조금 더 뒷심을 발휘해볼까봐,, 그 부분이 아쉽다.
시간이 남는다면 프로젝트를 다시 작업하고 싶달가 ,, , , , 아쉬움이 많이 남는다
5. 소스코드를 확인하고 싶다면?
아래 깃허브에서 확인할 수 있다
GitHub - Mandoone402/mandoone
Contribute to Mandoone402/mandoone development by creating an account on GitHub.
github.com
이 글을 마지막으로 이번 프로젝트 회고는 마무리합니다 ,, , , , 그럼 안녕