
✅ Model-View-Controller
대규모 프로그램이나 유지보수가 필요한 애플리케이션에서 주로 사용하는 설계 원칙(디자인 패턴)
“데이터 처리(로직)와 화면표시(View)를 분리시켜라”
| 구성 요소 | 역할 | 설명 |
|---|---|---|
| Model | 데이터, 로직 처리 | DB 처리, 계산 등 실제 데이터를 다룸 (데이터와 기능) |
| View | 사용자 UI | 사용자에게 보여지는 부분 (HTML, 화면, 디자인 등) |
| Controller | 중간 제어자 | 사용자의 입력을 받아서 Model과 View 사이를 연결함 |
JTable table = new JTable(데이터처리객체: TableModel);
TableModel : 데이터 처리 역할 (Model) 담당 JTable : 사용자에게 보여주는 View + 이벤트 처리 컨트롤러 역할JTable은 MVC를 부분적으로 반영한 컴포넌트
➡ 데이터(Model)와 UI(View + Controller)가 어느 정도 분리돼 있음
Spring Framework 전용 IDE
(Eclipse 기반의 통합 개발 환경)
Spring 개발을 위한 도구와 설정이 사전 탑재된 도구
JTable은 MVC 패턴 기반의 컴포넌트
MyModel)JTable이 동시에 수행⭐JTable은 단순히 UI이고, 실제 데이터를 다루는 것은 TableModel임
핵심: 데이터(Model)와 테이블(JTable)을 분리하여 유지보수가 쉬운 구조로 만듦
import java.awt.*;
import java.sql.*;
import javax.swing.*;
public class MemberRegist extends JFrame implements ActionListener, WindowListener {
// 서쪽 입력 폼 구성 요소
JPanel p_west;
JTextField t_id, t_name, t_tel;
JButton bt;
// 센터 테이블 구성 요소
JPanel p_center;
JTable table;
JScrollPane scroll;
TableModel model;
Connection con = null; // DB 연결 객체
/*접속은 윈도우 창 생성 시 한 번 시도 후,
닫을 때 접속해제해야하므로 멤버변수로 빼기*/
public MemberRegist() {
// GUI 요소 생성
p_west = new JPanel();
t_id = new JTextField();
t_name = new JTextField();
t_tel = new JTextField();
bt = new JButton("가입");
p_center = new JPanel();
table = new JTable(model = new MyModel());
// ⭐JTable은 모델 기반으로 데이터를 표현⭐
scroll = new JScrollPane(table);
// 스타일 설정
p_west.setBackground(Color.ORANGE);
p_west.setPreferredSize(new Dimension(150, 500));
Dimension d = new Dimension(146, 35);
t_id.setPreferredSize(d);
t_name.setPreferredSize(d);
t_tel.setPreferredSize(d);
scroll.setPreferredSize(new Dimension(420, 490));
bt.addActionListener(this); // 버튼 이벤트
this.addWindowListener(this); // 창 이벤트
// 컴포넌트 조립
p_west.add(t_id);
p_west.add(t_name);
p_west.add(t_tel);
p_west.add(bt);
add(p_west, BorderLayout.WEST);
p_center.add(scroll);
add(p_center);
// 창 설정
setBounds(100, 300, 600, 500);
setVisible(true);
// ✅ DB 연결 및 초기 데이터 조회
connect();
selectAll();
}
프로그램이 실행될 때(윈도우창 띄우자마자)
바로 DB 연결하고 데이터를 불러오려면 UI구성 끝나고 connect(), selectAll() 호출
public void connect() {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/dev";
String id = "java";
String pwd = "****";
con = DriverManager.getConnection(url, id, pwd);
if (con != null) setTitle("접속성공");
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
}
use dev; create table member4( member4_id int primary key auto_increment, id varchar(20), name varchar(16), tel varchar(20), regdate timestamp default now() );INSERT하기 전, member4 테이블 생성하기
public void regist() {
String sql = "INSERT INTO member4(id, name, tel) VALUES('"
+ t_id.getText() + "', '" + t_name.getText() + "', '" + t_tel.getText() + "')";
PreparedStatement pstmt = null;
try {
pstmt = con.prepareStatement(sql);
int result = pstmt.executeUpdate();
// ✅ executeUpdate : DML(insert, update, delete)수행
if (result > 0) {
JOptionPane.showMessageDialog(this, "등록 성공");
// GUI 팝업창
selectAll();
} else {
JOptionPane.showMessageDialog(this, "등록 실패");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (pstmt != null) pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public void selectAll() {
String sql = "SELECT * FROM member4";
PreparedStatement pstmt = null; // finally에서 닫아야해서 지역변수로 빼기
ResultSet rs = null;
try {
pstmt = con.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
// ✅ SELECT문이니까 executeQuery사용
rs = pstmt.executeQuery();
rs.last(); // 마지막 행으로 이동
int total = rs.getRow(); // 전체 행 수
((MyModel) model).rows = new String[total][3]; // 모델의 데이터 공간 재구성
rs.beforeFirst(); // 처음 위치로 이동
int index = 0;
while (rs.next()) {
String[] record = {
rs.getString("id"),
rs.getString("name"),
rs.getString("tel")
};
((MyModel) model).rows[index++] = record;
}
table.updateUI(); // 테이블 새로고침
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (rs != null) rs.close();
if (pstmt != null) pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new MemberRegist();
}
// Button 이벤트 메서드 (필수 구현)
@Override
public void actionPerformed(ActionEvent e) {
regist(); // 가입 버튼 클릭 시 회원 등록
}
// Window 이벤트 메서드 (필수 구현)
@Override public void windowOpened(WindowEvent e) { }
/*윈도우 창을 닫는 순간 호출되는 메서드
연결되어있던 자원을 해제하는 용도로 적합*/
@Override public void windowClosing(WindowEvent e) {
System.out.println("windowClosing()");
try {
if (con != null) con.close(); // DB 연결 해제
} catch (SQLException ex) {
ex.printStackTrace();
}
}
@Override public void windowClosed(WindowEvent e) { }
@Override public void windowIconified(WindowEvent e) { }
@Override public void windowDeiconified(WindowEvent e) { }
@Override public void windowActivated(WindowEvent e) { }
@Override public void windowDeactivated(WindowEvent e) { }
}
JTable에 표시할 데이터를 관리하기 위해 AbstractTableModel을 상속해서 만든 사용자 정의 모델 클래스
import javax.swing.table.AbstractTableModel;
public class MyModel extends AbstractTableModel {
// 테이블에 보여줄 데이터 (2차원 배열: 행 x 열)
String[][] rows = new String[0][3];
// 테이블 컬럼 이름들
String[] columns = { "ID", "Name", "Tel" };
// 행 개수 반환 (레코드 수)
@Override
public int getRowCount() {
return rows.length;
}
// 열 개수 반환 (컬럼 수)
@Override
public int getColumnCount() {
return columns.length;
}
// 각 컬럼의 이름 반환
@Override
public String getColumnName(int col) {
return columns[col];
}
// 각 셀의 값 반환 (표시할 데이터)
@Override
public Object getValueAt(int row, int col) {
return rows[row][col];
}
// 셀 수정 가능 여부 (기본적으로 true로 설정)
@Override
public boolean isCellEditable(int row, int col) {
System.out.println(row + "행, " + col + "열 수정 가능");
return true;
}
}