일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- index %
- SUB함수
- 증가값
- 파일질라설치
- excel중복체크
- 소스트리인증실패
- is_check
- Parent
- FileZilla다운로드
- toFixed()
- selectoptions
- calc.plus
- addClass
- ctrl+/
- Math.round()
- selectedIndex
- removeClass
- push오류
- calc.minus
- 1521
- slideUp
- hide
- 파일질라설치오류
- 파일질라다운로드
- Math.floor()
- Excel
- Math.ceil()
- 주석이 먹히지 않을 때
- Git
- FileZilla설치
- Today
- Total
잡동사니에도 사랑을
[21.08.27] Interface 이용한 성적관리 프로그램 만들기1 (Score, ScoreDTO, ScoreImpl, ScoreMain, ScoreForm) 본문
[21.08.27] Interface 이용한 성적관리 프로그램 만들기1 (Score, ScoreDTO, ScoreImpl, ScoreMain, ScoreForm)
luvforjunk 2021. 8. 29. 16:37프로그램을 구현하기 위해 5가지의 클래스를 만들어주었다.
1. ScoreMain : 메인메소드로, 단순히 호출하기 위해 만드 형식상의 클래스
2. ScoreDTO : 단 한명의 사람에 대한 성적 정보를 담고 있는 클래스(1인분값)
3. Score : 성적관리에 필요한 기능들(입력, 출력, 학번검색 기능 등)을 만들어주기 위한 기본 틀을 가지고 있는 추상클래스(인터페이스)
4. ScoreImpl : Score 인터페이스를 Override하는 클래스로, 본격적인 기능들을 담당하는 클래스
5. ScoreForm : 윈도우 창의 기본 레이아웃과 버튼 이벤트들을 담당하는 클래스.
////////ScoreMain
package io;
public class ScoreMain {
public static void main(String[] args) {
new ScoreForm();
}
}
////////ScoreDTO
- 이 클래스의 핵심은 Serializable 인터페이스를 구현한다는 것인데, 이는 나중에 구현할 파일 입출력 할 때
이 클래스 전체를 꺼내고 입력받게 되는데 이 때 객체 직렬화를 진행해주지 않으면 에러로 인해 진행할 수 없게 된다.
직렬화를 시켜주기 위해서는 간단하게 Serializable 인터페이스를 implements해주면 된다.
하지만 모든 케이스가 단순히 인터페이스를 구현한다고 해서 다 가능하지는 않으며, 인터페이스를 상속받은 객체에
toString을 오버라이드해주면 직렬화가 완성된다.
package io;
import java.io.Serializable;
public class ScoreDTO implements Serializable {
private String hak;
private String name;
private int kor;
private int eng;
private int math;
private int tot;
private double avg;
public String getHak() {
return hak;
}
public void setHak(String hak) {
this.hak = hak;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getKor() {
return kor;
}
public void setKor(int kor) {
this.kor = kor;
}
public int getEng() {
return eng;
}
public void setEng(int eng) {
this.eng = eng;
}
public int getMath() {
return math;
}
public void setMath(int math) {
this.math = math;
}
public int getTot() {
return tot;
}
public void setTot(int tot) {
this.tot = tot;
}
public double getAvg() {
return avg;
}
public void setAvg(double avg) {
this.avg = avg;
}
}
////////Score(Interface)
package io;
import javax.swing.table.DefaultTableModel;
public interface Score {
public void intput(ScoreDTO dto);
public void print(DefaultTableModel model);
public void search(DefaultTableModel model);
public void tot_desc();
public void save();
public void load();
}
////////ScoreImpl
package io;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.table.DefaultTableModel;
public class ScoreImpl implements Score {
private List<ScoreDTO> list;
public ScoreImpl() { // 생성자
list = new ArrayList<ScoreDTO>();
}
@Override
public void intput(ScoreDTO dto) {
list.add(dto);
JOptionPane.showMessageDialog(null, "등록 완료"); // 여기선 This라는 Frame이 없으니 null로 잡아줌
}
@Override
public void print(DefaultTableModel model) {
model.setRowCount(0); // RowCount(0)의 의미는 그 안에 있는 모든 내용을 지우라는 의미
// 기존에 있는 걸 지우고 새로이 입력한 값들이 들어오게끔!!!
// ex) [io.ScoreDTO@b20281a]을 지우고 [io.ScoreDTO@b20281a, io.ScoreDTO@215d5581]
// 새로이 입력하면
// 우리 눈에는 [io.ScoreDTO@215d5581]만 새롭게 들어온 것처럼 보인다
for (ScoreDTO dto : list) {// 모든 데이터가 list에 죄다 쌓여 있다
Vector<String> v = new Vector<String>();
// 돌 때마다 Vector가 생겨야 한다. 한줄당 Vector로 들어가니까
v.add(dto.getHak());
v.add(dto.getName());
v.add(dto.getKor() + ""); // 숫자를 문자열로 변환 - dto.getKor()은 int기본형이다
v.add(dto.getEng() + "");
v.add(dto.getMath() + "");
v.add(dto.getTot() + "");
v.add(String.format("%2f", dto.getAvg()));
model.addRow(v); // Table에다 Vector를 붙이면 한줄이 붙게 되는 거지~~
} // for
} // interface의 구현체
@Override
public void search(DefaultTableModel model) {
String hak = JOptionPane.showInputDialog(null, "학번을 입력해주세요", "검색", JOptionPane.QUESTION_MESSAGE);
if (hak == null || hak.length() == 0)
return; // 만약에 취소버튼을 누르면 null값 가져온다 - 취소버튼 누르면 그냥 나가라~
// hak.length() == 0 - 글씨를 넣지도 않았는데 확인버튼이 눌러지는 걸 막기위해 써주는 것이고,
// 글자수가 0이면 입력을 안했다는 것을 의미
int sw = 0;
for (ScoreDTO dto : list) {
// = if(int i = 0; i<model.getRowcount(); i++) {
if (hak.equals(dto.getHak())) { // 학번이 테이블에 있는 학번이랑 같으냐
model.setRowCount(0); // 테이블에 있는 값을 초기화시키고
// list에서 꺼내온 내용을 Vector에 집어넣는다
Vector<String> v = new Vector<String>();
v.add(dto.getHak());
v.add(dto.getName());
v.add(dto.getKor() + "");
v.add(dto.getEng() + "");
v.add(dto.getMath() + "");
v.add(dto.getTot() + "");
v.add(String.format("%2f", dto.getAvg()));
model.addRow(v);
sw = 1;
}
} // for
if (sw == 0)
JOptionPane.showMessageDialog(null, "찾고자 하는 학번이 없습니다");
}
@Override
public void tot_desc() {
}
@Override
public void save() {
JFileChooser chooser = new JFileChooser();
int result = chooser.showSaveDialog(null); // 저장 다이얼로그
// int result 로 받는 건 저장 버튼이 눌렸는지 취소버튼이 눌렸는지 알기 위해서다
File file = null;
if (result == JFileChooser.APPROVE_OPTION) { // save버튼 눌렀으면
file = chooser.getSelectedFile(); // 선택한 파일을 가져와라
// * 객체는 IO를 통해서 못가니까 byte단위로 쪼개서 보내야 하는데
// 이 쪼개는 과정을 객체 직렬화한다고 한다
// byte 단위로 쪼개려면 DTO에 implements Serializable(직렬화) 입력
// Serializable은 추상메소드가 없으니 Override시켜줄 것도 없다
}
// ----------------------------------
if (file == null)
return; // 파일에서 선택하지 않고 취소를 누르면 null값이 들어온다 나가라~~
try {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
// 파일 집어넣기
for (ScoreDTO dto : list) {
oos.writeObject(dto); // dto를 넘겨줘라
} // for
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void load() {
}
}
// Interface : Score(부모) - 추상메소드
// Class : ScoreImpl(자식) - ScoreService 대신
// 모든 데이터를 받아 데이터를 뿌리고 함수들의 입력 출력 등의 결과창이 될 수 있도록 하는 역할이
// 바로 이 ScoreImpl
// ScoreImpl에 잡혀있는 모든 애들은 interface를 거쳐야하며
// 그 구현부는 ScoreImpl
// 생성할 때 ScoreImpl impl = new ScoreImpl(); // 1 : 1 관계
// Score score = new ScoreImpl(); 같은 생성이지만 결합도를 낮춰준다
// Inteface는 하나인데 Class가 여러개로 넘쳐나면 Class를 대표해 주는 것이 Interface(Score)가 하나뿐이다
// 클래스는 여러개인데 참조하는 부모가 하나뿐인 것이 좋다
// 항상 접근은 부모걸로 접근하고 생성은 자식걸로 생성하는 것이 좋다
////////ScoreForm
package io;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Vector;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.DefaultTableModel;
public class ScoreForm extends JFrame implements ActionListener {
private JLabel hakL, nameL, korL, engL, mathL;
private JTextField hakT, nameT, korT, engT, mathT;
private JButton inputBtn, printBtn, searchBtn, rankBtn, saveBtn, loadBtn;
private DefaultTableModel model;
private JTable table;
private Score score; // inteface 잡기
public ScoreForm() {
// JLabel 생성
hakL = new JLabel("학번");
nameL = new JLabel("이름");
korL = new JLabel("국어");
engL = new JLabel("영어");
mathL = new JLabel("수학");
// JTextField 생성
hakT = new JTextField("", 22); // 크기(22)를 안주면 쪼그라든다
// TextField는 크기가 없기 때문에 데이터가 들어갈 공간이 있어야 하니까 크기를 잡아준다
nameT = new JTextField("", 22);
korT = new JTextField("", 22);
engT = new JTextField("", 22);
mathT = new JTextField("", 22);
// JButton 생성
inputBtn = new JButton("입력");
printBtn = new JButton("출력");
searchBtn = new JButton("학번검색");
rankBtn = new JButton("순위");
saveBtn = new JButton("파일저장");
loadBtn = new JButton("파일읽기");
// JTable의 타이틀
Vector<String> vector = new Vector<String>();
vector.add("학번");
vector.add("이름");
vector.add("국어");
vector.add("영어");
vector.add("수학");
vector.add("총점");
vector.add("평균");
model = new DefaultTableModel(vector, 0);
table = new JTable(model);
// 화면에 뿌려주는 건 Table. 그 안에서 데이터를 넣다 뺏다 하는 역할은 model이 한다
JScrollPane scroll = new JScrollPane(table);
score = new ScoreImpl();
// Panel 생성
// West - 왼쪽
JPanel hakP = new JPanel(); // 학점 패널 위에
hakP.add(hakL); // 학점 라벨과
hakP.add(hakT); // 학점 텍스트필드를 넣어주고
JPanel nameP = new JPanel();
nameP.add(nameL);
nameP.add(nameT);
JPanel korP = new JPanel();
korP.add(korL);
korP.add(korT);
JPanel engP = new JPanel();
engP.add(engL);
engP.add(engT);
JPanel mathP = new JPanel();
mathP.add(mathL);
mathP.add(mathT);
JPanel p = new JPanel(new GridLayout(5, 1)); // 전체 패널 위에 균등하게 패널을 또 넣어줌(5행, 1열)
p.add(hakP); // 학점 패널
p.add(nameP); // 이름 패널
p.add(korP); // 국어 패널
p.add(engP); // 영어 패널
p.add(mathP); // 수학 패널
JPanel p2 = new JPanel(new GridLayout(1, 6, 5, 5)); // 또 다른 패널(p2)에 입력, 출력, 학번검색, 순위, 파일저장, 파일읽기 버튼을 넣어줌
p2.add(inputBtn);
p2.add(printBtn);
p2.add(searchBtn);
p2.add(rankBtn);
p2.add(saveBtn);
p2.add(loadBtn);
Container c = getContentPane(); // 패널을 넣어줄 Container를 생성
c.add("West", p); // 서쪽에 p를
c.add("South", p2); // 남쪽에 p2를
c.add("Center", scroll); // scroll은 기본 센터에 배치
setBounds(900, 100, 700, 300);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
// 이벤트
event(); // event 함수 호출!
// 원래는 이벤트 안에 6개의 버튼들의 이벤트들이 다 들어올테지만
// 지금보다 훨씬 더 많은 이벤트들을 다룰 수 있으니 event함수를 적어놓고
// event메소드를 만든 걸 호출 하는 식으로 만들어 준 것이다~~~
} // ScoreForm() - 생성자 끝!
// 메소드는 따로 잡을 수 있움
public void event() {
inputBtn.addActionListener(this);
printBtn.addActionListener(this);
searchBtn.addActionListener(this);
rankBtn.addActionListener(this);
saveBtn.addActionListener(this);
loadBtn.addActionListener(this);
}
@Override
public void actionPerformed(ActionEvent e) {
// 버튼들이 다 넘어오니까~
if (e.getSource() == inputBtn) { // 넘어오는 버튼이 inputBtn이냐~
input();
// 많은 데이터를 model에다 넣어야 하고 그 model을 Impl에다 뿌리려면 데이터를 보관해야 한다
// 데이터를 보관하려면 list가 필요하다. (list 대신 DB를 쓰기도)
// score.print(model);
// ScoreImpl에서는 JTable이 있는지 없는지 모르니
// model을 보내줘야한다 그래야 Table에 관련된 일을 할 수 있다
// 데이터를 넣고 빼는 역할은 model이 하고 있으니까
// score는 interface라 Score interface에 만들어진다
} else if (e.getSource() == printBtn) { // printBtn이냐~
score.print(model);
} else if (e.getSource() == searchBtn) { // searchBtn이냐~
score.search(model);
} else if (e.getSource() == rankBtn) { // rankBtn이냐~
score.tot_desc();
} else if (e.getSource() == saveBtn) { // saveBtn이냐~
score.save();
} else if (e.getSource() == loadBtn) { // loadBtn이냐~
score.load();
score.print(model); // 파일 안에 있는 걸 읽어오기
}
} // actionPerformed(ActionEvent e)
private void input() {
// JTextField에 입력된 데이터 얻기
String hak = hakT.getText(); // hak TextField에 hak 데이터 가져오기
// 그렇담 데이터가 들어왔는 지 어떻게 확인할 수 있을까?
// = if(hak.equals("")) {
if (hak.length() == 0) { // 글자수가 0? 아무 문자도 들어오지 않았다는 것
JOptionPane.showMessageDialog(this, "학번을 입력하세요");
return;
}
String name = nameT.getText();
int kor = Integer.parseInt(korT.getText()); // TextField에 들어오는 건 모두 문자열이다. 문자열 숫자로 바꿔버리자
int eng = Integer.parseInt(engT.getText()); //
int math = Integer.parseInt(mathT.getText());
// 계산
int tot = kor + eng + math;
double avg = (double) tot / 3;
ScoreDTO dto = new ScoreDTO();
// DTO를 만들어서 ScoreDTO안에 데이터들을 한곳으로 모아야 데이터를 들고 다니기 편하다
dto.setHak(hak);
dto.setName(name);
dto.setKor(kor);
dto.setEng(eng);
dto.setMath(math);
dto.setTot(tot);
dto.setAvg(avg);
// 첫번째 방법 - ScoreDTO를 list에 담아서 JTable에 뿌리고...파일에 보관
score.intput(dto);
// 두번째 방법- ScoreDTO를 가지고 ScoreDAO.java에서 DB에 insert한다
// 초기화 - 입력을 하고 저장하고 나면 다시 입력할 수 있도록 입력값을 초기화시켜줘야 한다
// 저장하고나서 글을 일일이 지워줄 수 없으니
hakT.setText("");
nameT.setText("");
korT.setText("");
engT.setText("");
mathT.setText("");
}
}
// 입력 버튼을 누름과 동시에 ActionPerformed쪽으로 넘어와서 actionperformed에서 inputBtn입니까?
// 하고 확인한 뒤 input메소드로 보낸다
// 자바에선 null을 하나의 상수로 인식한다
// 예를들어
// String a = null; String b = "";
// a + "apple" b = "apple"
// "nullapple" "apple"
// -> 결합이나 연산에는 null을 집어넣으면 안된다. null값 자체가 들어가버리기 때문
// 자바가 제공하는 메소드는 throws가 안된다
'JAVA_SE > 11_io' 카테고리의 다른 글
[21.08.25] ObjectWriteMain, ObjectReadMain, PersonDTO (0) | 2021.08.29 |
---|---|
[21.08.26] ByteStream (0) | 2021.08.29 |
[21.08.25] Timer(스톱워치) 만들기 (0) | 2021.08.26 |
[21.08.25] DataStream - type에 따라 파일에 데이터 넣고 꺼내는 방법 (0) | 2021.08.25 |
[21.08.25] 메모장 만들기(MenuPane, TryNotePad) (0) | 2021.08.25 |