자바 프로그래밍

게시판 클래스다이어그램

그림을 클릭하면 원래 크기로 볼 수 있습니다.

게시판 테이블 물리설계

-- 게시판 테이블 생성
DROP TABLE IF EXISTS board_data;
CREATE TABLE board_data (
    no SERIAL,
    title VARCHAR(100) NOT NULL,
    article VARCHAR(800) NOT NULL,
    writer VARCHAR(50) NOT NULL DEFAULT '아무개',
    wdate TIMESTAMP,
    hitcnt SMALLINT UNSIGNED NOT NULL DEFAULT '0',
    PRIMARY KEY (no)
    ) ENGINE = MyISAM
    COLLATE utf8_general_ci;

-- list()
-- 페이징 계산 필요 offset = (pageNum - 1) * rows
SELECT no, title, article, writer, wdate, hitcnt
FROM board_data
ORDER BY no DESC
LIMIT 0, 10;

-- write()
INSERT INTO board_data (title, article, writer)
VALUES ('제목1', '안녕하세요.', '홍길동');

-- delete()
DELETE FROM board_data
WHERE no = ?;

-- edit()
UPDATE board_data
SET title = '제목1', article = '안녕하세요', writer = '홍길동', hitcnt = hitcnt + 1;

-- view()
SELECT no, title, article, writer, wdate, hitcnt
FROM board_data
WHERE no = ?;

-- search()
SELECT no, title, article, writer, wdate, hitcnt
FROM board_data
WHERE ? LIKE ?;

게시판 row를 담을 빈 설계

package net.jeongsam.board;

import java.sql.Timestamp;

/**
 * 게시판 row 데이터 저장 빈
 * 2009. 9. 18
 * @author 정승용
 *
 */
public class BoardData {
	private Long no;
	private String title;
	private String article;
	private String writer;
	private Timestamp wDate;
	private Integer hitCnt;
	
	public Long getNo() {
		return no;
	}
	public void setNo(Long no) {
		this.no = no;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getArticle() {
		return article;
	}
	public void setArticle(String article) {
		this.article = article;
	}
	public String getWriter() {
		return writer;
	}
	public void setWriter(String writer) {
		this.writer = writer;
	}
	public Timestamp getwDate() {
		return wDate;
	}
	public void setwDate(Timestamp wDate) {
		this.wDate = wDate;
	}
	public Integer getHitCnt() {
		return hitCnt;
	}
	public void setHitCnt(Integer hitCnt) {
		this.hitCnt = hitCnt;
	}
}

정렬 데이터를 담을 빈 설계

package net.jeongsam.board;

/**
 * 정렬 기준 필드 이름과 정렬 방법을 저장할 자바빈
 * @author 정승용
 *
 */
public class SortData {
	private String fieldName; // 컬럼 이름
	private String order; // 정렬 방식 "ASC"와 "DESC" 중 선택
	
	public String getFieldName() {
		return fieldName;
	}
	public void setFieldName(String fieldName) {
		this.fieldName = fieldName;
	}
	public String getOrder() {
		return order;
	}
	public void setOrder(String order) {
		this.order = order;
	}
}

게시판 관리 클래스

package net.jeongsam.board;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;

/**
 * 게시판 관리
 * 2009. 9. 18
 * @author 정승용
 *
 */
public class BoardMgr {
	/**
	 *  게시판 표시 기본 행 수
	 */
	public static int DEFAULT_ROW = 10;
	
	/**
	 * DB 연결 정보
	 */
	private String url = "jdbc:mysql://127.0.0.1/example";
	private String user = "root";
	private String password = "1234";
	
	private Connection conn = null;
	
	/**
	 *  목록 표시 원형
	 *  @param pageNum 표시할 페이지
	 *  @param rows 한 페이지 당 표시할 행 수
	 *  @param sort 정렬 기준 컬럼 이름과 정렬 순서 값을 저장할 자바빈
	 *  @return 결과 테이블 구조를 저장할 컬렉션 
	 * @throws SQLException 
	 * @throws ClassNotFoundException 
	 */
	public Collection<BoardData> list(int pageNum, int rows, SortData sort)
			throws ClassNotFoundException, SQLException {
		Statement stmt = null;
		ResultSet rs = null;
		ArrayList<BoardData> table = new ArrayList();
		// Limit offset, row_count
		// offset = (페이지 번호 - 1) * 페이지당 행 수
		int offset = (pageNum - 1) * rows;
		
		String sql = "SELECT no, title, article, writer, wdate, hitcnt ";
		sql += "FROM board_data ";
		sql += "ORDER BY " + sort.getFieldName() + " " + sort.getOrder() + " ";
		sql += "LIMIT " + offset + ", " + rows;
		
		conn = getConnection();
		stmt = conn.createStatement();
		rs = stmt.executeQuery(sql);
		
		if (rs == null) {
			System.out.println("글이 없습니다."); // 사용자 정의 예외 처리가 원칙
		} else {
			while (rs.next()) {
				BoardData rec = new BoardData();
				rec.setNo(rs.getLong(1));
				rec.setTitle(rs.getString(2));
				rec.setArticle(rs.getString(3));
				rec.setWriter(rs.getString(4));
				rec.setwDate(rs.getTimestamp(5));
				rec.setHitCnt(rs.getInt(6));
				
				table.add(rec);
			}
		}	
		return table;
	}
	
	/**
	 * 필드별 정렬하여 목록 표시
	 * @param pageNum 표시할 페이지
	 * @param sort 정렬 기준 컬럼 이름과 정렬 순서 값을 저장할 자바빈
	 * @return 결과 테이블 구조를 저장할 컬렉션 
	 * @throws SQLException 
	 * @throws ClassNotFoundException 
	 */
	public Collection<BoardData> list(int pageNum, SortData sort)
			throws ClassNotFoundException, SQLException {
		return list(pageNum, DEFAULT_ROW, sort);
	}
	
	/**
	 *  기본 목록 표시
	 * @param pageNum 표시할 페이지
	 * @return 결과 테이블 구조를 저장할 컬렉션
	 * @throws SQLException 
	 * @throws ClassNotFoundException 
	 */
	public Collection<BoardData> list(int pageNum)
			throws ClassNotFoundException, SQLException {
		SortData sort = new SortData();
		
		sort.setFieldName("no");
		sort.setOrder("DESC");
		
		return list(pageNum, DEFAULT_ROW, sort);
	}
	
	/**
	 *  글 올리기
	 * @param article 게시물을 저장할 자바빈
	 * @throws SQLException JDBC 드라이버 로딩 오류
	 * @throws ClassNotFoundException MySQL DBMS 연결 오류
	 */
	public void write(BoardData article) throws ClassNotFoundException, SQLException {
		Statement stmt = null;
		String sql = "INSERT INTO board_data (title, article, writer) ";
		sql += "VALUES ('" + article.getTitle() + "', '" 
				+ article.getArticle() + "', '" + article.getWriter() + "')";
		// Debug 코드
		System.out.println("write() : " + sql);
		try {
			conn = getConnection();
			stmt = conn.createStatement();
			stmt.executeUpdate(sql);
		} finally {
			if (stmt != null) {
				stmt.close();
				stmt = null;
			}
			if (conn != null) {
				conn.close();
				conn = null;
			}
		}
	}
	
	/**
	 * 글 삭제
	 * @param articleNo 삭제할 글 번호
	 * @throws ClassNotFoundException JDBC 드라이버 로딩 오류
	 * @throws SQLException MySQL DBMS 연결 오류
	 */
	public void delete(long articleNo) throws ClassNotFoundException, SQLException {
		Statement stmt = null;
		String sql = "DELETE FROM board_data WHERE no = " + articleNo;
		// Debug 코드
		System.out.println("delete() : " + sql);
		try {
			conn = getConnection();
			stmt = conn.createStatement();
			stmt.executeUpdate(sql);
		} finally {
			if (stmt != null) {
				stmt.close();
				stmt = null;
			}
			if (conn != null) {
				conn.close();
				conn = null;
			}
		}
	}
	
	/**
	 * 글 편집
	 * @param article 편집 내용을 담은 자바빈
	 * @throws SQLException JDBC 드라이버 로딩 오류
	 * @throws ClassNotFoundException MySQL DBMS 연결 오류
	 */
	public void edit(BoardData article) throws ClassNotFoundException, SQLException {
		Statement stmt = null;
		String sql = "UPDATE board_data ";
		sql += "SET title = '" + article.getTitle() + "', article = '";
		sql += article.getArticle() + "', writer = '" + article.getWriter() + "', hitcnt = hitcnt + 1";
		// Debug 코드
		System.out.println("edit() : " + sql);
		try {
			conn = getConnection();
			stmt = conn.createStatement();
			stmt.executeUpdate(sql);
		} finally {
			if (stmt != null) {
				stmt.close();
				stmt = null;
			}
			if (conn != null) {
				conn.close();
				conn = null;
			}
		}
	}
	
	/**
	 * 글 보기
	 * @param articleNo 화면에 표시할 글 번호
	 * @return 화면에 표시될 내용을 담은 자바빈
	 */
	public BoardData view(long articleNo) {
		return null;
	}
	
	/**
	 * 찾기
	 * @param fieldName 검색할 컬럼 이름
	 * @param value 검색할 데이터
	 * @return 검색 결과로 표시된 테이블을 담을 컬렉션
	 */
	public Collection<BoardData> search(String fieldName, String value) {
		return null;
	}
	
	/**
	 * MySQL DBMS에 연결하여 Connection 객체 생성
	 * @return Connection 인스턴스
	 * @throws ClassNotFoundException JDBC 드라이버 로딩 오류
	 * @throws SQLException MySQL DBMS 연결 오류
	 */
	private Connection getConnection() throws ClassNotFoundException, SQLException {
		Class.forName("com.mysql.jdbc.Driver");
		return DriverManager.getConnection(url, user, password);
	}
}

우편번호 저장 빈

package net.jeongsam.zipfinder;

public class ZipData {
	private Integer seq;
	private String zipcode;
	private String sido;
	private String gugun;
	private String dong;
	private String bunji;
	
	public Integer getSeq() {
		return seq;
	}
	public void setSeq(Integer seq) {
		this.seq = seq;
	}
	public String getZipcode() {
		return zipcode;
	}
	public void setZipcode(String zipcode) {
		this.zipcode = zipcode;
	}
	public String getSido() {
		return sido;
	}
	public void setSido(String sido) {
		this.sido = sido;
	}
	public String getGugun() {
		return gugun;
	}
	public void setGugun(String gugun) {
		this.gugun = gugun;
	}
	public String getDong() {
		return dong;
	}
	public void setDong(String dong) {
		this.dong = dong;
	}
	public String getBunji() {
		return bunji;
	}
	public void setBunji(String bunji) {
		this.bunji = bunji;
	}
}

우편번호 매니저

package net.jeongsam.zipfinder;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;

public class ZipManager {
	private Collection<ZipData>zipTable = new ArrayList<ZipData>();
	
	public Collection<ZipData> search(String dong)
			throws ClassNotFoundException, SQLException {
		Connection conn = null;
		Statement stmt = null;
		ResultSet rs = null;
		
		// DB 접속 정보 (URL 형식)
		String url = "jdbc:mysql://127.0.0.1/example";
		// DB에 전달할 SQL문
		StringBuilder sql = new StringBuilder();
		
		sql.append("SELECT seq, zipcode, sido, gugun, dong, bunji ");
		sql.append("FROM ziptable ");
		sql.append("WHERE dong LIKE '%" + dong + "%'");
		
//		System.out.println(sql.toString());
		try {
			// JDBC 드라이버 로딩
			Class.forName("com.mysql.jdbc.Driver");
			// DBMS에 연결 : Connection 인스턴스 생성
			conn = DriverManager.getConnection(url, "root", "암호");
			// Query 객체 생성 : SQL문 DB로 전달
			stmt = conn.createStatement();
			// SQL 문 DB로 전달 실행하여 ResultSet으로 결과 받음
			rs = stmt.executeQuery(sql.toString());
			// ResultSet에 담긴 데이터를 JavaBean 컬렉션으로 복사
			while (rs.next()) {
				// 행(row)를 담을 JavaBean 인스턴스 생성
				ZipData zipRecord = new ZipData();
				// JavaBean에 ResultSet 행(row)를 복사
				zipRecord.setSeq(rs.getInt(1));
				zipRecord.setZipcode(rs.getString(2));
				zipRecord.setSido(rs.getString(3));
				zipRecord.setGugun(rs.getString(4));
				zipRecord.setDong(rs.getString(5));
				zipRecord.setBunji(rs.getString(6));
				// JavaBean을 컬렉션에 추가
				zipTable.add(zipRecord);
			}
		} finally {
			
		}
		return zipTable;
	}
}

우편번호 찾기 메인 클래스

package net.jeongsam.zipfinder;

import java.sql.SQLException;
import java.util.Collection;
import java.util.Iterator;

public class ZipFinder {

	public static void main(String[] args) {
		ZipManager zipMgr = new ZipManager();
		Collection<ZipData> result = null;
		try {
			if (args.length != 1) {
				System.out.println("Usage: ZipFinder 동이름");
			} else {
				result = zipMgr.search(args[0]);
				if (result == null) {
					System.out.println("찾는 주소가 없습니다.");
				} else {
					Iterator<ZipData> itZipTable = result.iterator();
					while (itZipTable.hasNext()) {
						ZipData zipRec = itZipTable.next();
						System.out.print(zipRec.getZipcode() + " ");
						System.out.print(zipRec.getSido() + " ");
						System.out.print(zipRec.getGugun() + " ");
						System.out.print(zipRec.getDong() + " ");
						System.out.println(zipRec.getBunji() + " ");
					}
				}
			}
		} catch (ClassNotFoundException e) {
			System.err.println("JDBC 드라이버 로딩 에러!!");
		} catch (SQLException e) {
			System.err.println("DB 연결 에러!!");
			e.printStackTrace();
		}
	}

}

JDBC를 이용한 데이터베이스 연결

1. JDBC 소개

JDBC는 자바 언어를 이용하여 데이터베이스에 접근할 수 있는 프로그래밍 API입니다. 데이터베이스에 접근해서 작업을 하기위해 SQL(Structured Query Language)를 사용합니다. JDBC는 이 자바 언어를 이용하여 SQL로 작성된 쿼리 객체를 데이터베이스에 전달하여 데이터베이스 안의 테이블을 대상으로 작업을 할 수 있도록 해줍니다.

JDBC는 실제로는 Interface로 정의되어 있기 때문에 각 데이터베이스 제조사들은 각자 자신들의 데이터베이스에 접속해서 작업할 수 있도록 Interface를 구현하여 드라이버 클래스를 만들어서 프로그래머들에게 제공하고 있습니다. 그러므로 프로그래머는 어떤 데이터베이스의 JDBC를 사용하더라도 통일된 메서드의 사용을 통해 작업을 할 수 있으므로 개별 데이터베이스에 접근하는 방법을 일일이 배울 필요없이 표준적인 JDBC의 사용법만을 익히면 JDBC를 제공하는 모든 데이터베이스에 대해 프로그래밍을 할 수 있는 장점을 얻게 됩니다.

JDBC의 역사를 거슬러 올라가면 Microsoft社의 ODBC(Open Database Connectivity)의 영향을 받아 만들어졌습니다. 그래서 자바는 필요하다면 ODBC를 직접 이용할 수도 있습니다. 하지만 C언어로 제작된 ODBC를 이용하려면 여러가지 복잡한 작업이 필요하며 무엇보다 자바의 객체지향적인 언어적 장점을 살릴 수 없게 됩니다. 그래서 순수 자바 기술이 적용된 JDBC를 만들게 된 것입니다.

JDBC는 이미 설명한 바와 같이 프로그래머가 이용하기 위한 API 명세인 Interface 외에 실제 데이터베이스와 연결을 책임지는 드라이버의 2중 구조로 되어 있습니다. JDBC Interface의 핵심부는 DirverManager라는 클래스로 이 클래스는 다양한 드라이버를 자바 응용 프로그램과 연결시켜 주는 역할을 합니다. JDBC 드라아버는 다양한 단체와 업체에서 만들어지기 때문에 다양한 방식으로 제작되는데 4가지 타입이 있습니다.

TYPE1. JDBC-ODBC 브리지 드라이버

Sun社에서 기본적으로 제공하는 JDBC 드라이버로써 윈도우 운영체제에서 제공되는 ODBC를 사용할 수 있도록 해줍니다. sun.jdbc.odbc 패키지를 통해 해당 클래스들이 제공됩니다.

TYPE 2. 네이티브 JDBC 드라이버

DBMS의 C 언어나 C++ 언어용 API를 호출하는 자바 언어로 작성된 메서드입니다. 오라클의 OCI 드라이버가 이 타입에 속합니다.

TYPE 3. JDBC 네트워크 연결 드라이버

JDBC 메서드 호출을 DBMS에 독립적인 네트워크 프로토콜로 바꾸어 미들웨어에게 전달하고 이 미들웨어가 DBMS와 통신을 하는 형태의 순수 자바로 작성된 드라이버입니다.

TYPE-4. DBMS 프로토콜 준수 드라이버

가장 일반적으로 사용되는 드라이버로 DBMS를 직접 접속하여 사용합니다. DBMS 프로토콜을 직접 사용하므로 DBMS에 종속되어 DBMS마다 별도로 만들어집니다. 대부분 DBMS 제작사에서 제공하며 순수 자바로 작성되어 있습니다. 이번 시간에 사용하게 될 MySQL용 JDBC 드라이버 역시 타입4에 해당하는 드라이버입니다.

2. MySQL용 JDBC의 설치

http://www.mysql.com로 접속하여 Developer Zone-Downloads-Connectors-Connector/J 순으로 선택하여 mysql-connector-java-5.1.8.zip 파일을 내려받습니다. 내려받은 파일의 압축을 풀고 mysql-connector-java-5.1.8-bin.jar 파일을 JDK가 설치된 디렉터리에 있는 jre/lib/ext 디렉터리에 복사해 넣습니다. 이 디렉터리는 JVM(자바 가상 머신)이 실행될 때 자동으로 읽어들이는 실행경로(PATH)이므로 별도의 환경변수 설정없이 사용할 수 있습니다.

이클립스의 경우 기본적으로 JDK가 아닌 JRE를 이용하여 실행되므로 JRE가 설치된 경로의 lib/ext 디렉터리에 복사해 넣어야 제대로 사용할 수 있습니다.

3. 연결테스트 하기

일반적으로 JDBC 응용프로그램은 2가지 방식으로 데이터베이스에 연결됩니다.

  • DriverManager : 해당 DBMS용 드라이버가 필요하며 DBMS 연결에 필요한 정보는 URL 형식으로 응용프로그램의 소스내에 직접 코딩됩니다.
  • DataSource : DataSource 객체를 통해 Data Source(접근하고하는 DB 대상)에 투명하게 접근할 수 있습니다. 연결에 필요한 정보는 DataSource 객체의 속성으로 숨겨지지 때문에 응용프로그램 소스에는 연결 정보가 감춰집니다.

연결은 JDBC 드라이버를 로딩하고 연결을 만드는 2단계로 이뤄집니다.

드라이버 로딩하기

Class.forName() 메서드를 이용하여 JDBC 드라이버 클래스를 로딩하면 자동으로 해당 클래스의 인스턴스가 만들어져서 드라이버를 사용할 수 있게 됩니다.

(사용예)

package net.jeongsam.excise;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

/**
 * JDBC 사용 예제1
 * MySQL과 연결 테스트
 * @author 정승용
 *
 */
class JdbcEx01 {

	public static void main(String[] args) {
		Connection conn = null;
		String url = "jdbc:mysql://127.0.0.1/example?user=root&password=1234";
		
		try {
			// MySQL jdbc 드라이버 로드
			Class.forName("com.mysql.jdbc.Driver");
			
			// DriverMangar을 이용하여 Connection 인스턴스 생성
			conn = DriverManager.getConnection(url);
			
			if (conn != null)
				System.out.println("데이터베이스 연결을 성공했습니다.");
			else
				System.out.println("데이터베이스 연결이 실패했습니다.");
			
			// Connection 반납하여 데이터베이스와 연결 해제
			if (conn != null) {
				conn.close();
				conn = null;
			}
		} catch (ClassNotFoundException e) {
			// Class.forName()
			e.printStackTrace();
		} catch (SQLException e) {
			// DriverManager.getConnection()
			e.printStackTrace();
		}
	}

}

연결 생성

DriverManager 클래스를 이용

(사용예)

String url = "jdbc:mysql://127.0.0.1/example?user=root&password=1234";
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(url);

DriverManager 클래스는 사용 가능한 JDBC 드라이버들 중 선택하여 DBMS와 Driver interface를 연결하여 사용할 수 있도록 합니다. 프로그래머는 Driver interace에서 정의된 메서드를 사용하여 DBMS를 대상으로 프로그래밍을 할 수 있게 됩니다. DBMS 연결에 필요한 로그인 정보는 URL 형식으로 직접 코딩됩니다.

DataSource 객체를 이용

(사용예)

InitialContext ic = new InitialContext();
 
DataSource ds = ic.lookup("java:comp/env/jdbc/myDB");
Connection con = ds.getConnection();
DataSource ds = (DataSource) org.apache.derby.jdbc.ClientDataSource()
ds.setPort(1527);
ds.setHost("localhost");
ds.setUser("APP")
ds.setPassword("APP");

DataSource 객체는 속성(property)들 사용하기 위해 getter와 setter가 구현되어 제공되어야 합니다. 보통 이 속성들은 DataSource 객체가 사용될 때 초기화됩니다.

4. 간단한 질의어 결과 얻기

(사용예)

package net.jeongsam.excise;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * JDBC 예제2
 * 간단한 질의 처리
 * @author 정승용
 *
 */
public class JdbcEx02 {

	public static void main(String[] args) {
		Connection conn = null;
		Statement stmt = null;
		ResultSet rs = null;
		
		// DB 접속 문자열 URL 형식
		String url = "jdbc:mysql://127.0.0.1/example?user=root&password=1234";
		// DB에 전송할 SQL Query 준비
		String query = "SELECT DISTINCT sido FROM ziptable";
		
		try {
			// 1. JDBC 드라이버 로드
			Class.forName("com.mysql.jdbc.Driver");
			// 2. DriverManager.getConnection()를 이용하여 Connection 인스턴스 생성
			conn = DriverManager.getConnection(url);
			// 3. Connection 인스턴스를 이용하여 Statement 인스턴스 생성
			stmt = conn.createStatement();
			// 4. Query 실행후 결과를 ResultSet으로 참조
			rs = stmt.executeQuery(query);
			// 5. ResultSet이 참조하는 인스턴스로부터 next() 메서드를 이용하여 데이터 추출
			while (rs.next()) {
				// 5-1. next() 메서드를 이용하여 추출한 데이터를 getter()를 이용하여 다운캐스팅
				System.out.println(rs.getString(1));
			}
		} catch (ClassNotFoundException e) {
			// Class.forName() : 지정한 클래스가 없을 경우
			e.printStackTrace();
		} catch (SQLException e) {
			// DriverManager.getConnection() : DB 접속 오류일 경우
			e.printStackTrace();
		} finally {
			// 6. 사용이 끝난 ResultSet 인스턴스 반납
			if (rs != null)
				try {
					rs.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
				rs = null;
			// 7. 사용이 끝난 Statement 인스턴스 반납
			if (stmt != null)
				try {
					stmt.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
				stmt = null;
			// 8. 사용이 끝난 Connection 객체 반납
			if (conn != null)
				try {
					conn.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
				conn = null;
		}
	}

}

애완동물

package net.jeongsam.collection;

public class Pet {
	private String name;
	public int age;
	
	public Pet(String name) {
		this.name = name;
	}
	
	public Pet(String name, int age) {
		this(name);
		this.age = age;
	}
	
	public Pet() { }

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((name == null || age == 0) ? 0 : name.hashCode() + age);
		return result;
	}

	@Override
	public boolean equals(Object o) {
		boolean isEqual = false;
		if ((o instanceof Pet) && ((Pet)o).name.equals(name) &&
				((Pet)o).age == age) {
			isEqual = true;
		}
		
		return isEqual;
	}

	@Override
	public String toString() {
		return "[" + name + " : " + age + "]";
	}
}

Comparator를 구현한 클래스 선언

package net.jeongsam.collection;

import java.util.Comparator;

public class AgeComp<T> implements Comparator<T> {

	@Override
	public int compare(T o1, T o2) {
		Pet p1 = (Pet)o1;
		Pet p2 = (Pet)o2;
		int result = 0;
		
		if ((p1.age - p2.age) > 0) result = 1;
		if ((p1.age - p2.age) < 0) result = -1;
		
		return result;
	}

}

TreeSet에 적용

package net.jeongsam.collection;

import java.util.*;

class SortedEx04 {

	public static void main(String[] args) {
		TreeSet<Pet> sortedPetSet = new TreeSet<Pet>(new AgeComp<Pet>());
		
		Collections.addAll(sortedPetSet,
				new Pet("치와와", 4), new Pet("누렁이", 3),
				new Pet("손오공", 5), new Pet("저팔계", 2));
		
		System.out.println(sortedPetSet);
	}
}

View

package net.jeongsam.minieditor;

import java.util.ArrayList;
import java.util.Collections;
import java.awt.*;

@SuppressWarnings("serial")
public class View extends Frame {
	ArrayList<MenuItem> lstMnuFile = new ArrayList<MenuItem>();
	ArrayList<MenuItem> lstMnuEdit = new ArrayList<MenuItem>();
	ArrayList<MenuItem> lstMnuHelp = new ArrayList<MenuItem>();
	ArrayList<Menu> lstMenu = new ArrayList<Menu>();
	MenuBar menuBar = new MenuBar();
	Menu menu = new Menu();
	TextArea taEdit = new TextArea();
	
	public View() {
		Collections.addAll(lstMnuFile,
				new MenuItem("새 파일..."), new MenuItem("열기..."),
				new MenuItem("저장"), new MenuItem("종료"));
		Collections.addAll(lstMnuEdit,
				new MenuItem("복사하기"), new MenuItem("잘라내기"),
				new MenuItem("붙여넣기"));
		Collections.addAll(lstMnuHelp, new MenuItem("이 프로그램은..."));
		Collections.addAll(lstMenu,
				new Menu("파일"), new Menu("편집"), new Menu("도움말"));
		
		for (MenuItem m : lstMnuFile) {
			m.addActionListener(new ActionModel());
			lstMenu.get(0).add(m);
		}
		for (MenuItem m : lstMnuEdit) {
			m.addActionListener(new ActionModel());
			m.setEnabled(false);
			lstMenu.get(1).add(m);
		}
		for (MenuItem m : lstMnuHelp) {
			m.addActionListener(new ActionModel());
			lstMenu.get(2).add(m);
		}
		
		for (Menu m : lstMenu)
			menuBar.add(m);
		
		add(taEdit);
		setMenuBar(menuBar);
		setSize(400, 300);
		setVisible(true);
	}
	
	public static void main(String[] args) {
		new View();
	}
}
// 다른 방법
package net.jeongsam.minieditor;

import java.util.*;
import java.awt.*;

@SuppressWarnings("serial")
public class View extends Frame {
	ArrayList<ArrayList<MenuItem>> menuItems = new ArrayList<ArrayList<MenuItem>>();
	ArrayList<MenuItem> lstMnuFile = new ArrayList<MenuItem>();
	ArrayList<MenuItem> lstMnuEdit = new ArrayList<MenuItem>();
	ArrayList<MenuItem> lstMnuHelp = new ArrayList<MenuItem>();
	ArrayList<Menu> lstMenu = new ArrayList<Menu>();
	MenuBar menuBar = new MenuBar();
	Menu menu = new Menu();
	TextArea taEdit = new TextArea();
	
	@SuppressWarnings("unchecked")
	public View() {
		Collections.addAll(lstMnuFile,
				new MenuItem("새 파일..."), new MenuItem("열기..."),
				new MenuItem("저장"), new MenuItem(),
				new MenuItem("종료"));
		Collections.addAll(lstMnuEdit,
				new MenuItem("복사하기"), new MenuItem("잘라내기"),
				new MenuItem("붙여넣기"));
		Collections.addAll(lstMnuHelp, new MenuItem("이 프로그램은..."));
		Collections.addAll(menuItems, lstMnuFile, lstMnuEdit, lstMnuHelp);
		Collections.addAll(lstMenu,
				new Menu("파일"), new Menu("편집"), new Menu("도움말"));
		
		for (int i = 0; i < menuItems.size(); i++) {
			for (MenuItem m : menuItems.get(i)) {
				if (m.getLabel().length() == 0) {
					lstMenu.get(i).addSeparator();
				} else {
					m.addActionListener(new ActionModel());
					lstMenu.get(i).add(m);
				}
			}
		}
		
		for (Menu m : lstMenu)
			menuBar.add(m);
		
		add(taEdit);
		setMenuBar(menuBar);
		setSize(400, 300);
		setVisible(true);
	}
	
	public static void main(String[] args) {
		new View();
	}
}

Controller : Command Pattern 사용

package net.jeongsam.minieditor;

import java.util.*;
import java.awt.*;
import java.awt.event.*;

public class ActionModel implements ActionListener {
	HashMap<String, Object> actions =
		new HashMap<String, Object>();
	public ActionModel() {
		actions.put("새 파일...", new NewFileAction());
		// Action을 여기에 추가하세요.
	}
	
	private void command(String command) {
		CommandProcess comm = (CommandProcess)actions.get(command);
		comm.doAction();
	}

	@Override
	public void actionPerformed(ActionEvent event) {
		if (event.getSource() instanceof MenuItem) {
			MenuItem m = (MenuItem)event.getSource();
			command(m.getLabel());
		}
	}
}

Model

/* 공통 인터페이스 */
package net.jeongsam.minieditor;

public interface CommandProcess {
	public void doAction();
}
/* 개별 Action */
package net.jeongsam.minieditor;

public class NewFileAction implements CommandProcess {

	@Override
	public void doAction() {
		System.out.println(getClass() + ": 새파일 명령을 실행합니다.");
	}

}

+ Recent posts