본문 바로가기

JAVA

#11 PersonMenu MVC, Thread(스레드)

<PersonMenu를 MVC로 작성하기>    

1. 모델 com.encore.person.model

- Person.java (자바빈) : 필드(int no, String name, int age, String job)

- Model.java (데이터 관련 기능을 정의) : 필드 (Vector<Person> - 데이터 저장소)

==> 메소드 : 추가 insert, 삭제 delete, 수정 update, 조회 select

2. 뷰 com.encore.person.view

- MainView.java (시작 뷰, JTable을 통해 사람정보 출력)

필드 : JTable table

JButton bt_insert, bt_del, bt_update, bt_exit

- InputForm.java (사람정보 입력) - 타이틀: 입력폼

필드 : JTextField tf_name, tf_age, tf_job

JButton bt_submit, bt_cancel

bt_submit의 text - 입력

- UpForm.java (사람정보 수정) - 타이틀: 수정폼

필드 : InputForm.java와 동일

bt_submit의 text - 수정

3. 컨트롤러 com.encore.person.control

- Controller.java (전체 프로그램에 대한 흐름제어!!, main()포함)


<Controller>

package com.encore.person.control;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import java.awt.event.WindowAdapter;

import java.awt.event.WindowEvent;

import java.util.Vector;

import javax.swing.JOptionPane;

import com.encore.person.model.Model;

import com.encore.person.model.Person;

import com.encore.person.view.InputForm;

import com.encore.person.view.MainView;

import com.encore.person.view.UpForm;

public class Controller implements ActionListener{ // 뷰요청을 받기위한 Listener설정

//뷰등록

MainView mainv;

InputForm form;

UpForm upform;

//모델등록

Model m;

int no;//추가될 Person에 부여할 유일한 번호

int selNo;//수정요청시 저장할 번호

public Controller() {

mainv = new MainView();

form = new InputForm();

upform = new UpForm();

m = new Model();

eventUp();

}//생성자

private void eventUp() {//이벤트(소스) 등록

//메인뷰

mainv.bt_insert.addActionListener(this);

mainv.bt_update.addActionListener(this);

mainv.bt_del.addActionListener(this);

mainv.bt_exit.addActionListener(this);

//입력폼

form.bt_submit.addActionListener(this);

form.addWindowListener(new WindowAdapter() {

public void windowClosing(WindowEvent e) {

//입력폼 ----> 메인뷰

form.setVisible(false);

mainv.setVisible(true);

}

});

//수정폼

upform.bt_submit.addActionListener(this);

upform.addWindowListener(new WindowAdapter() {

public void windowClosing(WindowEvent e) {

//수정폼 ----> 메인뷰

upform.setVisible(false);

mainv.setVisible(true);

}

});

}//eventUp

@Override

public void actionPerformed(ActionEvent e) {//이벤트 처리부

Object ob = e.getSource();

if(ob==mainv.bt_insert) {//1.메인뷰:입력버튼 클릭 (입력폼 요청)

//4.화면이동: 메인뷰 ---> 입력폼

form.initText();

mainv.setVisible(false);

form.setVisible(true);

}else if(ob==form.bt_submit) {//1.입력폼:입력버튼 클릭 (Vector에 데이터 저장 요청)

//2.

String name = form.tf_name.getText().trim();

String age = form.tf_age.getText();

String job = form.tf_job.getText();

//5.유효성검사 (빈값 체크)

if(name ==null || name.equals("")) {

JOptionPane.showMessageDialog(form,"이름입력!!");

form.tf_name.requestFocus();

//return;

}else if(age.length() < 1) {

JOptionPane.showMessageDialog(form,"나이입력!!");

form.tf_age.requestFocus();

}else if(!age.matches("[\\d]+")){

JOptionPane.showMessageDialog(form,"숫자입력!!");

form.tf_age.setText("");//숫자아닌값을 초기화

form.tf_age.requestFocus();

}else if(job.length()==0) {

JOptionPane.showMessageDialog(form,"직업입력!!");

form.tf_job.requestFocus();

}else {//이름~직업: 정상적인 데이터

//뷰로부터 입력된 3개의 데이터를 한개의 변수(Person클래스)로 저장하기

Person addp = new Person(++no, name, Integer.parseInt(age), job);

//3.

m.insert(addp);//벡터에 p저장

Vector<Person> personv = m.selectAll(); //벡터의 전체 Person정 보 얻기

System.out.println(personv);

Vector<Object[]> paramv = m.personToArray(personv);

//Person벡터를 뷰가 원하는 Object[]벡터로 변환

mainv.displayTable(paramv);

//4.

form.setVisible(false);

mainv.setVisible(true);

}

}else if(ob==mainv.bt_update) {//1.메인뷰:수정버튼 클릭(수정폼을 요청)

int row = mainv.table.getSelectedRow(); //선택된 행의 (인덱스)정보

//선택된 행이 첫째행이라면 : row=0

//선택된 행이 두번째행이라면 : row=1

//선택된 행이 없다면 : row=-1

System.out.println("선택된 row="+ row);

if(row == -1) {//선택된 행이 없다면

JOptionPane.showMessageDialog(mainv,"수정하고자 하는 행을 선택!!");

return;//메소드 종료

}

selNo = (int) mainv.table.getValueAt(row, 0);// 0컬럼은 번호컬럼으로 고정!!

// getValueAt(행인덱스, 열인덱스)

Person oldp = m.select(selNo);//벡터에 저장된 Person정보 얻기

upform.tf_name.setText(oldp.getName());

upform.tf_age.setText(oldp.getAge()+""); //13+"" ---> "13"

//JTextField.setText(String text)

upform.tf_job.setText(oldp.getJob());

//mainv.table.getValueAt(행인덱스,열인덱스);

//System.out.println(mainv.table.getValueAt(0,0)); //첫번째 행의 번호 정보

//System.out.println(mainv.table.getValueAt(1,0)); //두번째 행의 번호 정보

//4. 메인뷰 ---> 수정폼

mainv.setVisible(false);

upform.setVisible(true);

}else if(ob == upform.bt_submit) {//1.수정폼: 수정버튼 클릭 ==> Vector데이터수정요청

//수정정보 얻기

String age = upform.tf_age.getText();

String job = upform.tf_job.getText();

// 13 ---> 문자열 변환 ----> 13+"" 또는 ""+13 ===> "13"

// "13" ---> 숫자 변환 ----> Integer.parseInt("13") ===> 13

//age,job을 newp로 묶어주기

Person newp = new Person(); //[no:0, name:null, age:0, job:null]

newp.setAge(Integer.parseInt(age)); //newp.setAge(int age)

//[no:0, name:null, age:14, job:null]

newp.setJob(job);//[no:0, name:null, age:14, job:"중학생"]

newp.setNo(selNo);//[no:1, name:null, age:14, job:"중학생"]

//Vector에 저장된 Person을 수정

m.update(newp);

//JTable에 변경된 Vector를 반영

Vector<Person> v = m.selectAll();//벡터 전체 조회

Vector<Object[]> v2 = m.personToArray(v);//메인뷰JTable원하는 벡터 변

mainv.displayTable(v2);

//mainv.displayTable(m.personToArray(m.selectAll()));

//페이지 이동 (수정폼(upform) ---> 메인뷰(mainv))

upform.setVisible(false);

mainv.setVisible(true);

}else if(ob == mainv.bt_del) {//1. 메인뷰: 삭제버튼클릭 ==> 특정번호의 Person을 Vector로 부터 삭제요청!!

//대화상자를 통한 삭제번호 입력

//JOptionPane.showInputDialog(Component parentComponent,Object message)

String delNo = JOptionPane.showInputDialog(mainv, "삭제번호:");

//Vector로 부터 일치하는 번호를 가진 Person삭제

boolean flag = m.delete(Integer.parseInt(delNo)); //"2" ----> 2

if(!flag) {

JOptionPane.showMessageDialog(mainv, "존재하지 않는 번호입니다!!");

return;

}

//삭제된 Vector의 갱신내용을 JTable 에 반영 - displayTable(Vector<Object[]>)

mainv.displayTable(m.personToArray (m.selectAll()));

// JTable갱신 <--- Vector<Object[]> <--- Vector<Person>

}else if(ob == mainv.bt_exit) {//1. 메인뷰: 종료버튼클릭 ==> 전체 응용프로그램 종료 요청!!

System.exit(0);

}

}//actionPerformed

public static void main(String[] args) {

new Controller();

}

<Model>

package com.encore.person.model;

import java.util.Vector;

public class Model {

Vector<Person> personV; //데이터 저장소 표현

public Model() {

personV = new Vector<>();

}

public void insert(Person addp) {//외부에서 전달받은 데이터를 Vector에 저장

personV.add(addp);

}

public Vector<Person> selectAll() {

//Vector에 저장된 모든 Person정보를 전달. ==> JTable출력 필요

return personV;

}

public void update(Person newp) {//외부에서 변경될 데이터(newPerson)를 전달받아

//Vector에 저장되어있는 기존 oldPerson을 수정

for(int i=0; i<personV.size(); i++) {//변경할 정보를 저장한 newp를 기존 oldPerson에 적용(변경)하기.

Person oldp = personV.get(i);//기존 저장된 Person정보

if(oldp.getNo() == newp.getNo()) {//일치한 번호를 찾았다면

oldp.setAge(newp.getAge());

oldp.setJob(newp.getJob());

break;

}

}//for

}//update

public boolean delete(int delNo) {//외부에서 삭제할 정보(no)를 받아

//Vector에 저장된 Person(no)중 일치하는 해당Person을 삭제

for(int i=0; i<personV.size(); i++) {//전체 Vector검색

Person oldp = personV.get(i);

if(oldp.getNo() == delNo) {//일치하는 번호 찾기

//해당 인덱스를 가진 Person을 벡터로 부터 삭제!!

personV.remove(i);//실제 데이터 삭제!!

//break;

return true;//삭제에 성공했음을 표현.

}

}//for

return false;//삭제에 실패!!

}//delete

public Person select(int selNo) {//외부에서 조회할 정보(no)를 받아

//Vector에서 일치하는 Person정보를 전달. ==> 수정폼에서 필요

for(int i=0; i<personV.size(); i++) {

Person p = personV.get(i);

if(p.getNo() == selNo) {

return p;

}

}

return null; //Person 못찾았음!!

}

//Vector<Person> personv ---변환---> Vector<Object[]> paramv

public Vector<Object[]> personToArray (Vector<Person> personv) {

Vector<Object[]> paramv = new Vector<>();

for(int i=0; i<personv.size(); i++) {

Person p = personv.get(i);

Object []rowdata= { p.getNo(), p.getName(), p.getAge(), p.getJob()};

paramv.add(rowdata);

}

return paramv;

}

}//Model

<Person>

package com.encore.person.model;

public class Person {// 입력폼에 입력된 데이터를 Person클래스로 묶어주기 위해서!!

private int no;

private String name;

private int age;

private String job;

public Person() {

// TODO Auto-generated constructor stub

}

public Person(int no, String name, int age, String job) {

super();

this.no = no;

this.name = name;

this.age = age;

this.job = job;

}

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 getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

public String getJob() {

return job;

}

public void setJob(String job) {

this.job = job;

}

@Override

public String toString() {

return "Person [no=" + no + ", name=" + name + ", age=" + age + ", job=" + job + "]";

}

}

<View>

package com.encore.person.view;

import javax.swing.JButton;

import javax.swing.JFrame;

import javax.swing.JLabel;

import javax.swing.JTextField;

public class InputForm extends JFrame{

JLabel la_name,la_age,la_job;

public JTextField tf_name,tf_age,tf_job;

public JButton bt_submit, bt_cancel;

public InputForm() {

setTitle("입력폼");

la_name = new JLabel("이름");

la_age = new JLabel("나이");

la_job = new JLabel("직업");

tf_name = new JTextField();

tf_age = new JTextField();

tf_job = new JTextField();

bt_submit = new JButton("입력");

bt_cancel = new JButton("취소");

la_name.setBounds(50,30, 30,30);

la_age.setBounds(50,80, 30,30);

la_job.setBounds(50,130, 30,30);

tf_name.setBounds(90,30, 130,30);

tf_age.setBounds(90,80, 130,30);

tf_job.setBounds(90,130, 130,30);

bt_submit.setBounds(60,180, 70,30);

bt_cancel.setBounds(140,180, 70,30);

setLayout(null);

add(la_name);

add(la_age);

add(la_job);

add(tf_name);

add(tf_age);

add(tf_job);

add(bt_submit);

add(bt_cancel);

setBounds(500,200,280,280);

//setVisible(true);

//setDefaultCloseOperation(EXIT_ON_CLOSE);

}//생성자

public void initText() {//텍스트필드 초기화

tf_name.setText("");

tf_age.setText("");

tf_job.setText("");

tf_name.requestFocus();

}

}//InputForm

package com.encore.person.view;

import java.util.Calendar;

import java.util.Vector;

import javax.swing.JButton;

import javax.swing.JFrame;

import javax.swing.JLabel;

import javax.swing.JPanel;

import javax.swing.JScrollPane;

import javax.swing.JTable;

import javax.swing.table.DefaultTableModel;

public class MainView extends JFrame implements Runnable{

DefaultTableModel dtm;

public JTable table;

JScrollPane scroll_table;

public JButton bt_insert, bt_update, bt_del, bt_exit;

JLabel la_time;

JPanel southp,northp;

Calendar cal;

public MainView() {

setTitle("MainView");

Object [][]rowData = new Object[0][4];

//[0]행 : 생성될 행

//생성될 행을 0으로 해야 앞으로 addRow()가 0인덱스부터 추가됨.

String []columnNames = {"번호","이름","나이","직업"};

dtm=new DefaultTableModel(rowData, columnNames);

table = new JTable(dtm);

scroll_table = new JScrollPane(table);

bt_insert = new JButton("입력");

bt_update = new JButton("수정");

bt_del = new JButton("삭제");

bt_exit = new JButton("종료");

la_time = new JLabel();

southp = new JPanel();

southp.add(bt_insert);

southp.add(bt_update);

southp.add(bt_del);

southp.add(bt_exit);

northp = new JPanel();

northp.add(la_time);

add("Center",scroll_table);

add("South",southp);

add("North",northp);

Thread t = new Thread(this);

t.start();

setBounds(300,200,350,300);

setVisible(true);

setDefaultCloseOperation(EXIT_ON_CLOSE);

}//생성자

@Override

public void run() {

try {

while(true) {

cal = Calendar.getInstance();//시스템 날짜정보를 얻어 cal저장!!

String timeStr=cal.get(Calendar.YEAR)+"년 "

+ (cal.get(Calendar.MONTH)+1)+"월 "

+cal.get(Calendar.DATE)+"일 "

+cal.get(Calendar.HOUR)+"시 "

+cal.get(Calendar.MINUTE)+"분 "

+cal.get(Calendar.SECOND)+"초";

la_time.setText(timeStr);

Thread.sleep(1000);

}

} catch (InterruptedException e) {

e.printStackTrace();

}

}

public void displayTable(Vector<Object[]> v) {

dtm.setRowCount(0);//출력될 포인트 행을 0으로 셋팅

//dtm.addRow(Object[] rowData);

for(int i=0; i<v.size(); i++) {

Object [] rowData = v.get(i);

dtm.addRow(rowData);

}

}//displayTable

}//MainView


package com.encore.person.view;

import javax.swing.JButton;

import javax.swing.JFrame;

import javax.swing.JLabel;

import javax.swing.JTextField;

public class UpForm extends JFrame{

JLabel la_name,la_age,la_job;

public JTextField tf_name,tf_age,tf_job;

public JButton bt_submit, bt_cancel;

public UpForm() {

setTitle("수정폼");

la_name = new JLabel("이름");

la_age = new JLabel("나이");

la_job = new JLabel("직업");

tf_name = new JTextField();

tf_name.setEnabled(false);

tf_age = new JTextField();

tf_job = new JTextField();

bt_submit = new JButton("수정");

bt_cancel = new JButton("취소");

la_name.setBounds(50,30, 30,30);

la_age.setBounds(50,80, 30,30);

la_job.setBounds(50,130, 30,30);

tf_name.setBounds(90,30, 130,30);

tf_age.setBounds(90,80, 130,30);

tf_job.setBounds(90,130, 130,30);

bt_submit.setBounds(60,180, 70,30);

bt_cancel.setBounds(140,180, 70,30);

setLayout(null);

add(la_name);

add(la_age);

add(la_job);

add(tf_name);

add(tf_age);

add(tf_job);

add(bt_submit);

add(bt_cancel);

setBounds(500,200,280,280);

//setVisible(true);

//setDefaultCloseOperation(EXIT_ON_CLOSE);

}//생성자

}//UpForm


<스레드> Thread

- 프로세스내에서 순차적으로 동작하는 문장들의 단일 집합.

- 경량(light weight)의 프로세스

- 하나의 프로세스내에 다수개의 스레드를 정의할 수 있으며

다수개의 스레드는 동시에 수행 될 수 있다 (다중스레드)

- 자바에서는 클래스(Thread)와 인터페이스(Runnable)지원

class My extends Thread{

//스레드 특성 메소드

public void run(){

//동시 실행 코드

}

}

※스레드 객체 생성

Thread t = new Thread();

My m = new My();

t.start();

m.start();

//t,m ===> 스레드 객체!!


class My2 extends JFrame implements Runnable{

//스레드 특성 메소드!!

public void run(){

//동시 실행 코드

}

}

My2 m2 = new My2();

//m2는 스레드객체? (X)

----> Runnable객체!! (O)

----> 별도의 Thread객체 생성이 필요.

---> Thread t2 = new Thread(run()메소드의 위치);

---> Thread t2 = new Thread(m2);

---->스레드 시작: t2.start();

<Test>

TVContribution.java -----> 방송국

Customer.java -----> 경쟁적인 성금자 (스레드)

Account.java -----> 모금함 (저금통)

public class Account {//모금함 (저금통)

private int total;

//지불 메소드

public synchronized void deposit(int account) {

/*

동기화(synchronized)

---> 메소드 동기화 (메소드에 진입한 스레드가 있을 경우

다른 스레드들은 대기(LOCK)하게 하는 역할)

synchronized 리턴형 메소드명(){}

---> 블럭동기화, 특정영역 동기화

synchronized(동기화 객체){}

*/

total += account; //total = total+account;

}//deposit

public int getTotal() {

return total;

}

}

public class Customer extends Thread{//경쟁적인 성금자 (스레드)

//목표액: 50만원!!

Account account;//null

public Customer(Account account) {

this.account = account;//new Account();

}

@Override

public void run() {

try {

for(int i=1; i<=200; i++) {

Thread.sleep(50);//0.05초 간격

account.deposit(1000);//모금

System.out.println(getName()+" : "+ i +"회");//자막효과

if(account.getTotal() >= 500000) {//목표액(오십만원) 달성

break;

}

}

} catch (InterruptedException e) {

e.printStackTrace();

}

}//run

}

public class TVContribution {//방송국

public static void main(String[] args) {

//성금자(Thread) 5명을 모집

/*

Customer c1 = new Customer();

Customer c2 = new Customer();

Customer c3 = new Customer();

Customer c4 = new Customer();

Customer c5 = new Customer();

//c1~c5: Thread객체!!

c1.start();

c2.start();

c3.start();

c4.start();

c5.start();

*/

//1차원 배열 객체생성: 자료형[] 배열명 = new 자료형[사이즈];

Customer[] customers = new Customer[5];

//customers[]={null,null,null,null,null};

Account account = new Account();

for (int i = 0; i < customers.length; i++) {

customers[i] = new Customer(account);//스레드 객체 5개 생성

}

for (int i = 0; i < customers.length; i++) {

customers[i].start(); //모금시작(스레드 시작)

}

try {

for (int i = 0; i < customers.length; i++) {

customers[i].join();//메인 스레드가 다른 스레드 종료까지 기다려라!!

}

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("총 모금액: "+ customers[0].account.getTotal());

}//main

}

<Test2>

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import javax.swing.ImageIcon;

import javax.swing.JButton;

import javax.swing.JFrame;

import javax.swing.JLabel;

public class MoveThread extends JFrame implements Runnable, ActionListener{

JLabel la;

JButton bt;

int x,y;

public MoveThread() {

setTitle("MoveThread");

ImageIcon icon = new ImageIcon("image/right.gif");

la = new JLabel(icon);

la.setBounds(x,y,55,55);//x,y,가로,세로

bt = new JButton("시작");

bt.setBounds(20,420, 80,30);

setLayout(null);

add(la);

add(bt);

setBounds(200,200, 500,500);

setVisible(true);

setDefaultCloseOperation(EXIT_ON_CLOSE);

bt.addActionListener(this);

}//생성자

@Override

public void actionPerformed(ActionEvent e) {

//버튼이 클릭되었을때 스레드 호출!!

//A a = new A(); a.hello(); ===> new A().hello();

//Thread t = new Thread(this);

//t.start();

new Thread(this).start();

}

@Override

public void run() {

try {

while(true) {

Thread.sleep(50);

if(x<=425) {

x+=5;

}else if(y<=400){

y+=5;

}

//la.setLocation(x, y);

la.setLocation(x, y);

}

} catch (InterruptedException e) {

e.printStackTrace();

}

}//run

public static void main(String[] args) {

new MoveThread();

}

}

<Test3>

class YouThread extends Thread{

public YouThread(String name) {

super(name);//상위클래스 생성자 호출

}

//스레드 특징 메소드 ---> run : start()메소드를 통해 호출해야 동시 실행이 가능!!

public void run() {

try {

for(int i=1; i<11; i++) {

Thread.sleep(500);//0.5초 대기

System.out.println(getName()+" : "+ i);

}

} catch (InterruptedException e) {

e.printStackTrace();

}

}//run

}

public class ThreadTest2 {

public static void main(String[] args) {

//YouThread = Thread클래스!!

//스레드에 이름 부여하기 new Thread(String name)

YouThread t1 = new YouThread("길동스레드");

YouThread t2 = new YouThread("라임스레드");

YouThread t3 = new YouThread("주원스레드");

//스레드 우선순위 부여(1~10) 10:우선순위 가장 높음, 5 ---> 기본값

t1.setPriority(Thread.MAX_PRIORITY);//(10);

t2.setPriority(Thread.MIN_PRIORITY);//(1);

t3.setPriority(Thread.NORM_PRIORITY);//(5);

//스레드 실행

t1.start();

t2.start();

t3.start();

}

}