DB 연결을 하지 않고 콘솔 출력을 하는 프로젝트를 해보려고 한다.
DB 연결을 하지 않기 때문에 데이터는 배열을 활용하고자 한다.
이번 프로젝트는 학생의 정보를 출력하는 게시판을 구현하는 것을 목적으로 한다.
controller | service | vo | util | exception |
StudentApp | StudentService | Student | StudentUtils | MyRangeException |
- StudentApp
👉 Controller의 역할을 하는 클래스로 main 메서드를 포함하고 있다.
👉 숫자를 입력해야 할 때 다른 것을 입력하면, 숫자 타입이 아니라는 예외 처리를 하도록 하였다. (NumberFornetException)
import static student.StudentUtils.*;
public class StudentcApp {
public static void main(String[] args) {
StudentService service = new StudentService();
// 콘솔에 지속적인 출력을 위하여 while(true)로 구현
while (true) {
try {
System.out.println();
int menu = nextInt("1. 조회 2. 등록 3. 수정 4. 삭제 5. 종료 > ");
switch (menu) {
case 1:
service.list();
break;
case 2:
service.register();
break;
case 3:
service.modify();
break;
case 4:
service.remove();
break;
case 5:
// 종료를 선택하면 return 문이 수행되어 while 문을 종료한다.
return;
default:
// 목록으로 제시한 범위를 벗어나는 숫자를 입력 시
// 사용자 정의한 예외가 발생하도록 하였다.
throw new MyRangeException(1, 5);
}
}
// 예외 발생 시에 처리
catch (NumberFormatException e) {
System.out.println("숫자를 입력하세요");
}
catch (MyRangeException | RuntimeException e) {
System.out.println(e.getMessage());
}
}
}
}
- StudentService
👉 콘솔 프로그램에서 사용되는 CRUD 기능을 구현하였다.
👉 예외 처리를 직접 처리하지 않고 호출부에서 처리하도록 throws 하였다.
👉 학생 객체를 저장하기 위하여 배열을 사용하고 있기 때문에 초기 지정값을 채우면 2 배 늘어날 수 있도록 구현하였다.
import static student.StudentUtils.*;
public class StudentService {
// 학생 배열 10칸 지정
private Student[] students = new Student[10];
// 배열에 실제 저장된 학생 수
private int count;
// 성적순으로 정렬한 학생 배열
private Student[] sortedStudents = new Student[10];
// Test를 위한 학생 데이터
{
// students[count++] = new Student(count);
// students[count++] = new Student(count);
// students[count++] = new Student(count);
// students[count++] = new Student(count);
// students[count++] = new Student(count);
}
// 기능 구현부
// create
public void register() throws MyRangeException{
// 학생 배열 상태 확인
confirmStudentArray();
// 새로운 학생 등록
System.out.println();
String name = nextLine("등록하실 학생의 이름을 입력해 주세요. >> ");
int korean = confirmScore(nextInt("등록하실 학생의 국어 점수를 입력해 주세요. >> "));
int math = confirmScore(nextInt("등록하실 학생의 수학 점수를 입력해 주세요. >> "));
int english = confirmScore(nextInt("등록하실 학생의 영어 점수를 입력해 주세요. >> "));
// 등록된 학생이 없는지 확인
// count 가 0일 경우의 처리
int tmp = 1;
if (count > 0) {
tmp = students[count-1].getNo();
}
students[count++] = new Student(tmp, name, korean, math, english);
// 성적순 학생 정렬
sortStudents();
System.out.println("학생이 등록 되었습니다. ");
}
// Read
public void list() {
System.out.println();
// 등록된 학생 유무 확인
existStudent();
switch (nextInt("조회하실 목록을 선택해 주세요. 1. 전체 목록 2. 석차별 조회 >> ")) {
case 1:
listAll();
break;
case 2:
listRank();
break;
default:
break;
}
}
private listAll() {
System.out.println(" 학생 번호 " + " | " + " 이름 " + " | " + " 국어 점수 " + " | " + " 수학 점수 " + " | " + " 영어 점수 " + " | " + " 총점 " + " | " + " 평균 ");
// 배열의 길이만큼 돌리면 채워지지 않은 부분은 null로 출력된다.
// 학생이 저장된 만큼만 돌리면 저장된 학생만 출력하게 된다.
for (int i = 0; i < count; i++) {
System.out.printf("%s%n", students[i]);
}
}
private listRank() {
System.out.println(" 석차 번호 " + " | " + " 학생 번호 " + " | " + " 이름 " + " | " + " 국어 점수 " + " | " + " 수학 점수 " + " | " + " 영어 점수 " + " | " + " 총점 " + " | " + " 평균 ");
for (int i = 0; i < count; i++) {
System.out.printf("%5d %6c %s%n", (i + 1), ' ', sortedStudents[i]);
}
}
// Update
public void modify() {
// 등록된 학생 유무 확인
existStudent();
// 전체 목록 출력
listAll();
System.out.println();
// 학생 번호은 여기서 primary key 역할을 한다.
int no = nextInt("수정할 학생의 번호를 입력하세요. >> ");
System.out.println();
System.out.println(" 학생 번호 " + " | " + " 이름 " + " | " + " 국어 점수 " + " | " + " 수학 점수 " + " | " + " 영어 점수 " + " | " + " 총점 " + " | " + " 평균 ");
// 수정할 학생을 번호로 데이터를 찾아온다.
Student target = findBy(no);
System.out.println();
switch (nextInt("수정할 영역을 선택해주세요. 1. 이름 | 2. 국어 점수 | 3. 수학 점수 | 4. 영어 점수 >> ")) {
case 1:
// 수정 내용을 set 메서드로 반영
target.setName(nextLine("변경된 이름을 입력하세요. >> "));
System.out.println("변경이 완료되었습니다. ");
break;
case 2:
target.setKorean(nextInt("변경된 국어 점수를 입력하세요. >> "));
System.out.println("변경이 완료되었습니다. ");
break;
case 3:
target.setMath(nextInt("변경된 수학 점수를 입력하세요. >> "));
System.out.println("변경이 완료되었습니다. ");
break;
case 4:
target.setEnglish(nextInt("변경된 영어 점수를 입력하세요. >> "));
System.out.println("변경이 완료되었습니다. ");
break;
default:
break;
}
sortStudents();
listAll();
}
public void remove() {
// 등록된 학생 유무 확인
existStudent();
listAll();
int no = nextInt("삭제할 학생의 번호를 입력하세요. >>");
// 삭제 대상 학생 데이터가 존재할 경우
if(findBy(no) != null) {
// 배열을 복제하여 빠진만큼 줄인다.
System.arraycopy(students, no, students, no - 1, students.length - no);
count--;
System.out.println("삭제가 완료되었습니다.");
}
sortStudents();
listAll();
}
// 배열의 길이만큼 학생이 저장되어 있으면
// 배열의 길이를 두 배 늘린다.
private confirmStudentArray() {
if(count == students.length) {
Student[] tmp = new Student[students.length * 2];
System.arraycopy(students, 0, tmp, 0, students.length);
students = tmp;
}
}
// 학생 번호로 학생 정보 가져오기
private Student findBy(int no) {
// 목표하는 학생 정보를 담을 객체를 만든다.
Student target = new Student();
// 매개변수로 넘어온 번호와 일치하는 학생을 찾아서
for (int i = 0; i < count; i++) {
if(students[i].getNo() == no) {
System.out.printf("%s%n", students[i]);
// 생성한 객체에 저장한다.
target = students[i];
}
}
return target;
}
// 정렬된 학생 목록 만들기
private void sortStudents() {
// 원본 학생 배열을 복사
System.arraycopy(students, 0, sortedStudents, 0, students.length);
for (int j = 0; j < count - 1; j++) {
for (int i = 0; i < count - 1 - j; i++) {
// 평균 점수를 비교하여 정렬한다.
if(sortedStudents[i].avgScore() < sortedStudents[i+1].avgScore()) {
Student tmp = sortedStudents[i];
sortedStudents[i] = sortedStudents[i+1];
sortedStudents[i+1] = tmp;
}
}
}
}
// 입력한 학생 점수의 범위가 유효한지 확인
private int confirmScore(int score) throws MyRangeException {
// 점수 범위가 유효하지 않으면 예외를 발생시킨다.
if(score < 0 || score > 100) {
throw new MyRangeException();
}
return score;
}
// 배열에 저장된 학생 유무
private void existStudent() {
// count 가 0 인 경우
ifcount == 0) {
// 예외를 발생시킨다.
throw new RuntimeException("현재 등록된 학생이 없습니다.");
}
}
}
- Student
👉 멤버 변수에 직접적인 접근을 할 수 없는 대신 get과 set 메서드를 통하여 접근하도록 구현하였다.
public class Student {
// 학번
private int no;
// 이름
private String name;
// 국어
private int korean;
// 수학
private int math;
// 영어
private int english;
// 기본 생성자
public Student() {}
// Test 를 위한 생성자
public Student(int no) {
this(no, randomName(), randomScore(), randomScore(), randomScore());
}
// 매개변수를 통한 생성자
public Student(int no, String name, int korean, int math, int english) {
// set 메서드를 통해 입력
setNo(no);
setName(name);
setKorean(korean);
setMath(math);
setEnglish(english);
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getKorean() {
return korean;
}
// 점수가 입력되는 메서드에는
public void setKorean(int korean) {
// 별도로 값의 유효성을 확인할 수 있도록 하였다.
if (korean < 0 || korean > 100) {
// System.out.println("잘못된 범위");
korean = 0;
return;
}
this.korean = korean;
}
public int getMath() {
return math;
}
public void setMath(int math) {
if (math < 0 || math > 100) {
// System.out.println("잘못된 범위");
math = 0;
return;
}
this.math = math;
}
public int getEnglish() {
return english;
}
public void setEnglish(int english) {
if (english < 0 || english > 100) {
// System.out.println("잘못된 범위");
english = 0;
return;
}
this.english = english;
}
// 점수 총합
public int sumScore() {
return getKorean() + getMath() + getEnglish();
}
// 점수 평균
public double avgScore() {
return (int) (sumScore() * 100d / 3) / 100d;
}
@Override
public String toString() {
return String.format("%5d %11s %8d %14d %12d %11d %9.2f", no, name, korean, math, english, sumScore(), avgScore());
}
// test score
static int randomScore() {
return (int)(Math.random() * 41 + 60);
}
// test name
static String randomName() {
String[] arr = {"피카츄", "라이츄", "파이리", "꼬부기", "버터플", "야도란", "피존투", "또가스"};
return arr[(int)(Math.random() * 8)];
}
}
- StudentUtils
👉 콘솔 프로그램 특성상 반복되는 코드를 줄이기 위하여 해당 클래스를 만들었다.
👉 클래스 메서드로 만들어 해당 클래스의 인스턴스 생성 없이 접근 가능하도록 하였다.
import java.util.Scanner;
public class StudentUtils {
private static Scanner scanner = new Scanner(System.in);
public static String nextLine(String msg) {
System.out.print(msg);
return scanner.nextLine();
}
public static int nextInt(String msg) {
return Integer.parseInt(nextLine(msg));
}
}
- MyRangeException
👉 범위에 대한 예외 처리를 사용자화 하기 위해 만들었다.
👉 해당 예외로 처리할 수 있는 범위는 '점수'와 '목록'이 있다.
public class MyRangeException extends Exception{
// 생성 시에 별도로 지정하지 않으면 각각 0, 100으로 초기화
int begin;
int end = 100;
public MyRangeException() {}
public MyRangeException(int begin, int end) {
this.begin = begin;
this.end = end;
}
// getMessage() 메서드를 오버라이드함
@Override
public String getMessage() {
return String.format("입력 가능한 값의 범위는 %d 부터 %d 사이입니다.", begin, end);
}
}
해당 프로그램은 배열을 사용하고 있기 때문에 배열을 지속적으로 늘려가야 한다는 단점이 존재한다.
다음은 이 프로그램을 리스트로 사용하여 늘려주지 않아도 알아서 처리해주는 장점을 활용해 보고자 한다.
'JAVA > PROJECT' 카테고리의 다른 글
Project_03 : 콘솔 프로그램 Student - 리스트 활용 버전 (0) | 2022.09.27 |
---|---|
Project_01 : 상속과 인터페이스 예제 만들기 (0) | 2022.09.26 |