Java List component
프로젝트 내 src 내 oracle.db 패키지 내 OracleConnect.java
package oracle.db;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class OracleConnect {
// 다른 클래스에서는 new 로 생성할수 없다
private OracleConnect() {
// 오라클 드라이버 클래스 실행
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
System.out.println("오라클 드라이버가 없어요:" + e.getMessage());
}
}
public static OracleConnect getInstance() {
return new OracleConnect();
}
// db 연결해서 성공한 커넥션 반환하는 메서드
public Connection getConnection() {
Connection conn = null;
String url = "jdbc:oracle:thin:@127.0.0.1:1521:orcl";
try {
conn = DriverManager.getConnection(url, "사용자이름", "a1234");
} catch (SQLException e) {
// TODO Auto-generated catch block
System.out.println("오라클 서버 연결 실패:" + e.getMessage());
}
return conn;
}
// 총 4개의 dbClose 를 만듬
public void dbClose(ResultSet rs, Statement stmt, Connection conn) {
try {
if (rs != null)
rs.close();
if (stmt != null)
stmt.close();
if (conn != null)
conn.close();
} catch (SQLException e) {
}
}
public void dbClose(Statement stmt, Connection conn) {
try {
if (stmt != null)
stmt.close();
if (conn != null)
conn.close();
} catch (SQLException e) {
}
}
public void dbClose(ResultSet rs, PreparedStatement pstmt, Connection conn) {
try {
if (rs != null)
rs.close();
if (pstmt != null)
pstmt.close();
if (conn != null)
conn.close();
} catch (SQLException e) {
}
}
public void dbClose(PreparedStatement pstmt, Connection conn) {
try {
if (pstmt != null)
pstmt.close();
if (conn != null)
conn.close();
} catch (SQLException e) {
}
}
}
프로젝트 내 src 내 javabasic 패키지 내 ShoppingDto.java
package javabasic;
import java.sql.Timestamp;
public class ShoppingDto {
private int num;
private String sangpum;
private String photo;
private int su;
private int dan;
private String color;
private Timestamp ipgoday;
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getSangpum() {
return sangpum;
}
public void setSangpum(String sangpum) {
this.sangpum = sangpum;
}
public String getPhoto() {
return photo;
}
public void setPhoto(String photo) {
this.photo = photo;
}
public int getSu() {
return su;
}
public void setSu(int su) {
this.su = su;
}
public int getDan() {
return dan;
}
public void setDan(int dan) {
this.dan = dan;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public Timestamp getIpgoday() {
return ipgoday;
}
public void setIpgoday(Timestamp ipgoday) {
this.ipgoday = ipgoday;
}
}
ShoppingDto.java 에서 보면
private Timestamp ipgoday; 라고 클래스 멤버 변수 타입이 Timestamp 이다.
java.sql.Timestamp
Timestamp 클래스는 JDBC API 가 Timestamp 클래스의 객체 변수를 SQL TIMESTAMP 값으로 식별하게 만드는 클래스로써 java.util.Date 클래스를 감싸는 간소화되고 간단해진 wrapper(wrapper class) 이다.
wrapper 란 예를 들어서
아이패드는 아이폰을 감싼다 고 볼 수 있다. 크기면에서도 감싸며,
아이패드는 기본적으로 커다란 아이폰이다. 근본적으로는 아이폰이지만 다른 모습을 가져 더 큰 화면을 가진다.
즉, 아이패드는 다른 겉싸개(wrapper) 를 가진다.
이는 문자그대로 객체와 다를것이 없다.
wrapper 는 뒤에 숨은 객체와 비교해서 보다 더 다른 특징들을 노출할지도 모른다.
때때로 wrapper 는 개발자나 사용자가 내부로 접근할 수 있는 것들을 제한할 수 있다. 예를 들어서, 비록 아이폰이
아이패드 안에 박혀있어서 아이패드가 아이폰이 지닌 전화거는 능력이 있다고 해도, 그 아이패드는 사용자가 전화를
걸 수 있는 기능을 못하게 제한할 수 있다.
다음 예로는, 수동차량으 wrapper 로써 주행하는 자동차량 이다.
자동차량과 수동차량을 생각해 보자.
자동차량에서는, 운전자를 위해서 자동적으로 기어를 바꾸어주는 엔지니어링 매커니즘이 있지만,
근본적으로, 보이지 않는 표면 아래를 살펴보면, 그 차는 여전히 수동차량이다.
다시 말해서, 차의 자동기어기능이 수동기어기능을 감싸고 있다.
만약에 운전자가 자동기어차량을 타고서는 운전자스스로 수동적으로 기어를 바꾸기를 바란다면, 당연히 운전자는
그렇게 하지 못한다. 자동기어차량에서는 기어를 변화시킬 수 있는 기능이 노출되지 않는다. 그러나 그 기능은
수동기어차량에서는 노출되어 있다.
wrapper 를 쓰는 목적은 만약에 개발자가 클래스와 그 안의 기능등을 단순화하고 싶을 때 작성한다. 모든 복잡하고 장황하고 자잘한 코드들이 외부로 노출되지 않는 것을 확실하게 하면서 그런 모든 복잡한 자잘한 코드들은 wrapper 안에 남기는 것이다.
Timestamp 클래스는 소숫점 이하 초부터 시작해서 나노초의 정밀도 자릿수까지 상술할 수 있게 함으로써,
SQL TIMESTAMP 의 소숫점 이하 초의 정밀한 값을 가질 수 있는 기능을 추가한다.
자바에서 Timestamp를 이용해 현재 시간을 구할 수 있는데
Date를 이용한 방법과의 차이는
Date는 Millisecond까지 구할 수 있지만
Timestamp는 Millisecond에서 Nanosecond까지 구할 수 있다.
프로젝트 내 src 내 javabasic 패키지 내 ShoppingDao.java
package javabasic;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import oracle.db.OracleConnect;
public class ShoppingDao {
OracleConnect oCdb;
public ShoppingDao() {
oCdb = OracleConnect.getInstance();
}
public void insertSangpum(ShoppingDto dto) {
Connection conn = null;
Statement stmt = null;
String sql = "insert into shopping values (seq2.nextval,'" + dto.getSangpum() + "','" + dto.getPhoto() + "',"
+ dto.getSu() + "," + dto.getDan() + ",'" + dto.getColor() + "',sysdate)";
System.out.println(sql);
conn = oCdb.getConnection();
try {
stmt = conn.createStatement();
stmt.executeUpdate(sql);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
oCdb.dbClose(stmt, conn);
}
}
public void updateSangpum(ShoppingDto dto) {
Connection conn = null;
Statement stmt = null;
String sql = "update shopping set sangpum='" + dto.getSangpum() + "',photo='" + dto.getPhoto() + "',su="
+ dto.getSu() + ",dan=" + dto.getDan() + ",color='" + dto.getColor() + "',ipgoday=sysdate where num="
+ dto.getNum();
System.out.println(sql);
conn = oCdb.getConnection();
try {
stmt = conn.createStatement();
stmt.executeUpdate(sql);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
oCdb.dbClose(stmt, conn);
}
}
public List<ShoppingDto> writeAll() {
List<ShoppingDto> splist = new ArrayList<ShoppingDto>();
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
conn = oCdb.getConnection();
String sql = "select * from shopping order by sangpum";
try {
stmt = conn.createStatement();
rs = stmt.executeQuery(sql);
while (rs.next()) {
ShoppingDto dto = new ShoppingDto();
dto.setNum(rs.getInt("num"));
dto.setSangpum(rs.getString("sangpum"));
dto.setPhoto(rs.getString(3));
dto.setSu(rs.getInt(4));
dto.setDan(rs.getInt(5));
dto.setColor(rs.getString(6));
dto.setIpgoday(rs.getTimestamp(7));
splist.add(dto);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
oCdb.dbClose(rs, stmt, conn);
}
return splist;
}
}
프로젝트 내 src 내 javabasic 패키지 내 AddShop.java
package javabasic;
import java.awt.Color;
import java.awt.FileDialog;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.border.LineBorder;
@SuppressWarnings("serial")
public class AddShop extends JFrame {
JComboBox<String> cbColor;
JLabel lblPhoto;
JButton btnAdd, dbAdd;
JTextField txtSangpum, txtSu, txtDan, txtIpgoday;
public AddShop(String title) {
// TODO Auto-generated constructor stub
super(title);
this.setBounds(700, 100, 505, 420);// 시작위치x,y,크기 w,h
// super로 해도 되고 this로 해도 됨 super는 조상
// this로 해도 상속을 받아서 괜찮음
// this.getContentPane().setBackground(Color.orange);//프레임위에 있는 패널의 색상 변경
this.getContentPane().setBackground(Color.white);// 프레임위에 있는 패널의 색상 변경
this.setDesign();// 디자인 코드
// this.setVisible(true);//보이게 하기
// this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//프로그램을 종료해주는 메서드
}
public void setDesign() {
this.setLayout(null);
String colors[] = { "Red", "Orange", "Yellow", "Green", "Blue", "Indigo", "Violet", "White", "Black" };
cbColor = new JComboBox<String>(colors);
cbColor.setBounds(20, 20, 100, 30);
this.add(cbColor);
lblPhoto = new JLabel();
lblPhoto.setBorder(new LineBorder(Color.gray, 2));
lblPhoto.setBounds(20, 70, 300, 30);
this.add(lblPhoto);
btnAdd = new JButton("이미지 가져오기");
btnAdd.setBounds(340, 70, 130, 30);
btnAdd.addActionListener(new btnaddClick());
this.add(btnAdd);
JLabel lblSangpum = new JLabel("상품명");
lblSangpum.setBounds(20, 120, 100, 30);
this.add(lblSangpum);
txtSangpum = new JTextField();
txtSangpum.setBounds(140, 120, 200, 30);
this.add(txtSangpum);
JLabel lblSu = new JLabel("수량");
lblSu.setBounds(20, 170, 100, 30);
this.add(lblSu);
txtSu = new JTextField();
txtSu.setBounds(140, 170, 200, 30);
this.add(txtSu);
JLabel lblDan = new JLabel("단가");
lblDan.setBounds(20, 220, 100, 30);
this.add(lblDan);
txtDan = new JTextField();
txtDan.setBounds(140, 220, 200, 30);
this.add(txtDan);
JLabel lblIpgoday = new JLabel("쇼핑일");
lblIpgoday.setBounds(20, 270, 100, 30);
this.add(lblIpgoday);
txtIpgoday = new JTextField();
txtIpgoday.setBounds(140, 270, 200, 30);
this.add(txtIpgoday);
dbAdd = new JButton("DB Add");
dbAdd.setBounds(102, 320, 300, 30);
this.add(dbAdd);
}
class btnaddClick implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
FileDialog fd = new FileDialog(AddShop.this, "", FileDialog.LOAD);
fd.setVisible(true);
if (fd.getDirectory() == null)
return;
String fileName = fd.getDirectory() + fd.getFile();
lblPhoto.setText(fileName);
}
}
// public static void main(String[] args) {
// // TODO Auto-generated method stub
// AddShop ex = new AddShop("입력폼");
// }
}
프로젝트 내 src 내 javabasic 패키지 내 UpdateShop.java
package javabasic;
import java.awt.Color;
import java.awt.FileDialog;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.border.LineBorder;
@SuppressWarnings("serial")
public class UpdateShop extends JFrame {
JComboBox<String> cbCol;
String colors[] = { "Red", "Orange", "Yellow", "Green", "Blue", "Indigo", "Violet", "White", "Black" };
JTextField txtProduct, txtSu, txtDan, txtIday;
JLabel lblShowP;
JButton btnPhoto, btnUpdate;
int num = 0;
public UpdateShop(String title) {
// TODO Auto-generated constructor stub
super(title);
this.setBounds(1400, 100, 400, 700);// 시작위치x,y,크기 w,h
// super로 해도 되고 this로 해도 됨 super는 조상
// this로 해도 상속을 받아서 괜찮음
// this.getContentPane().setBackground(Color.orange);//프레임위에 있는 패널의 색상 변경
this.getContentPane().setBackground(Color.white);// 프레임위에 있는 패널의 색상 변경
this.setDesign();// 디자인 코드
// this.setVisible(true);//보이게 하기
// this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//프로그램을 종료해주는 메서드
}
public void setDesign() {
this.setLayout(null);
cbCol = new JComboBox<String>(colors);
cbCol.setBounds(20, 20, 200, 30);
this.add(cbCol);
JLabel lblProduct = new JLabel("상품명");
lblProduct.setBounds(20, 70, 100, 20);
this.add(lblProduct);
txtProduct = new JTextField();
txtProduct.setBounds(20, 110, 300, 20);
this.add(txtProduct);
JLabel lblPhoto = new JLabel("사진");
lblPhoto.setBounds(20, 510, 100, 20);
this.add(lblPhoto);
lblShowP = new JLabel();
lblShowP.setBounds(20, 550, 300, 20);
lblShowP.setBorder(new LineBorder(Color.gray));
this.add(lblShowP);
JLabel lblSu = new JLabel("수량");
lblSu.setBounds(20, 230, 100, 20);
this.add(lblSu);
txtSu = new JTextField();
txtSu.setBounds(20, 270, 300, 20);
this.add(txtSu);
JLabel lblDan = new JLabel("단가");
lblDan.setBounds(20, 310, 100, 20);
this.add(lblDan);
txtDan = new JTextField();
txtDan.setBounds(20, 350, 300, 20);
this.add(txtDan);
JLabel lblShopDay = new JLabel("쇼핑일");
lblShopDay.setBounds(20, 390, 100, 20);
this.add(lblShopDay);
txtIday = new JTextField();
txtIday.setBounds(20, 430, 300, 20);
this.add(txtIday);
btnPhoto = new JButton("상품이미지 가져오기");
btnPhoto.setBounds(20, 470, 300, 20);
btnPhoto.addActionListener(new btnphotoClick());
this.add(btnPhoto);
btnUpdate = new JButton("DB Update");
btnUpdate.setBounds(20, 590, 300, 20);
this.add(btnUpdate);
}
class btnphotoClick implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
FileDialog dlg = new FileDialog(UpdateShop.this, "", FileDialog.LOAD);
dlg.setVisible(true);
if (dlg.getDirectory() == null)
return;
String fileName = dlg.getDirectory() + dlg.getFile();
lblShowP.setText(fileName);
}
}
// public static void main(String[] args) {
// // TODO Auto-generated method stub
// UpdateShop ex = new UpdateShop("수정폼");
// }
}
프로젝트 내 src 내 javabasic 패키지 내 MyShoppingMunje.java
package javabasic;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.List;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.border.LineBorder;
/*
* MyShoppingMunje
* 입력폼 : AddShop
* 수정폼 : UpdateShop
*
* dto : ShoppingDto
* dao : ShoppingDao
*
* 디자인 설계
*
* 입력할때 색상은 combo 로 (색상 여러가지 등록)
* 상품이미지는 이전 예제처럼 버튼 누르면 이미지경로 가져오기
* 상품명 출력시 수량,단가 는 3자리 컴마및 화폐단위
*
*/
@SuppressWarnings("serial")
public class MyShoppingMunje extends JFrame implements ActionListener {
// 경고:The serializable class MyShoppingMunje does not declare a static final serialVersionUID field of type long
// 윗줄과 같은 경고쪽지가 뜨는 이유는 serializable 과 관계가 있다
// serializable 은 직렬화로
// 인스턴스가 파일에 저장되는 과정을 의미한다.
// 그 반대로 파일로부터 인스턴스가 복원되는 과정은 deserializable(역직렬화) 라고 한다.
// serializable 클래스는 Java 에서 java.io.Serializable 이라는
// 인터페이스(규격) 로 구현되어 있다.
// 파일의 입출력 대상이 되는 인스턴스는 java.io.Serializable 인터페이스(규격) 를
// 구현하거나, java.io.Serializable 인터페이스(규격) 를 구현하는 클래스를
// 상속해야 한다.
// 즉,
// 경고:The serializable class MyShoppingMunje does not declare a static final serialVersionUID field of type long
// 윗줄과 같은 경고 메세지를 받는 상황의 대부분은
// Serializable 인터페이스(규격) 를 구현해야만 하는데 하지 않은 상위클래스를 상속받거나
// Serializable 인터페이스(규격) 를 구현해야만 하는 클래스에서 생긴다.
// 직접적이거나 간접적인 Serializable 인터페이스(규격) 의 구현을 해야 한다.
// Java API 에서는 직렬화 대상이 되는 인스턴스에 대해
// 명시적으로 serialVersionUID 를 선언할 것을 적극 권장한다.
// serialVersionUID 는 JVM 이 default(기본) 로 자동으로 생성하지만,
// 이렇게 자동으로 생성한 것은 너무 불완전하다.
// 직렬화는
// 데이타 구조나 오브젝트 상태를 동일하거나 다른 컴퓨터 환경에 저장하고,
// 나중에 재구성할 수 있는 포맷으로 변환하는 과정이다.
// 동일하거나 다른 컴퓨터 환경에 저장한다는 것은
// 파일이나 메모리 버퍼로 저장하거나 네트워크 연결 링크 간 전송하여 저장하는 것을 말한다.
// 즉, 직렬화란 현재 데이타(structure, object, 구조, 객체) 의 상태를
// 영속적으로 저장하거나 다른 환경으로 전달(네트워크 통신 등 으로 전달) 하기 위해서
// 어떤 정해진 포맷으로 변환하는 과정이다.
// 이 변환된 데이타는 다시 원래 데이타로 변환 할 수 있고 이런 과정은
// 역직렬화(deserialization) 이라고 한다.
// 자바 직렬화란
// Java 시스템 내부에서 사용되는 객체 또는 데이타를
// 외부의 Java 시스템에서도 사용할 수 있도록 바이트(byte) 형태로
// 데이타 변환하는 기술과
// 바이트로 변환된 데이타를 다시 객체로 변환하는 기술(역직렬화) 을 아울러 말한다.
// 시스템에서 보면,
// Java Virtual Machine 으 메모리(heap 또는 stack) 에 상주되어 있는
// 객체 데이타를 바이트 형태로 변환하는 기술과
// 직렬화된 바이트 형태의 데이타를 객체로 변환해서
// JVM 으로 상주시키는 형태를 말한다.
// Java 에서는 직렬화 할 때 데이타(object, 객체) 를 바이트(byte)스트림 형태로
// 변환한다.
// 직렬화 방법
// type 이 primitive type(기본형 타입) 이거나
// java.io.Serializable 인터페이스(규격) 를 구현하거나
// java.io.Serializable 인터페이스(규격) 를 구현하지 않은 상위클래스를 상속 받아야 한다.
// Serializable 선언부 는 비어있다.
// package java.io;
// public interface Serializable {}
// 다른 기능 없이 Serializable 인터페이스(규격) 를 구현한 객체는 직렬화 가능하다는
// 것을 알 수 있는 용도로만 사용된다.
// 직렬화를 하려면
// java.io.ByteArrayOutputStream 과
// java.io.ObjectOutputStream 을 이용한다면 된다고 한다.
// 역직렬화를 하려면
// java.io.ByteArrayInputStream 과
// java.io.ObjectInputStream 을 이용하면 된다고 한다.
// transient 키워드
// 비밀번호와 같이 직렬화하는 대상에서 제외하고 싶은 항목이 있다.
// 이 때, transient 키워드를 이용하면, 그 property 는 직렬화 대상에서 제외된다.
// 직렬화 후 역직렬화하면, transient 키워드를 붙여 직렬화 대상에서 제외된 property에는
// null 값이 들어간다고 한다.
// 데이타를 직렬화 하는 방법에는
// 자바 직렬화 뿐만 아니라
// CSV,XML,JSON 으로의 직렬화도 존재한다고 한다.
// 실제로,
// 표 형태의 다량의 데이타를 저장하거나
// 전송할 때
// CSV 를 많이 이용하고,
// 네트워크에서 구조적인 데이타를 송수신할 때(API 시스템) 대부분 JSON 을 많이 사용한다고 한다.
// CSV 로 직렬화 할 때는 Apache Commons CSV, opencsv 등의 라이브러리를 이용하고,
// JSON 으로 직렬화 할 때는 Jackson, GSON 등의 라이브러리를 많이 이용한다고 한다.
// 위의 CSV, JSON 으로의 직렬화를 이용하면 되는데 굳이 Java 직렬화를 사용하는 이유는
// Java 직렬화는
// 같은 Java 시스템에서의 데이타 전송(즉, 다른 JVM 환경의 시스템으로의 전송) 과
// 저장에 최적화 되어 있다고 한다.
// 데이타 구조가 복잡해도 직렬화의 기본 조건만 지키면, 바로 직렬화와 역직렬화가 가능하다고한다.
// 무엇보다도 데이타 타입이 자동으로 맞춰지기 때문에, 역직렬화 시 바로 기존 객체처럼
// 사용가능하다고 한다.
// 개발자가 하나하나 타입을 맞춰 줄(형변환) 필요가 없어서 상당히 편리하다고 한다.
// Java 직렬화가 사용되는 상황
// 1 Servlet Session
// 서블릿 기반의 WAS(톰캣 등) 들은 대부분 session 의 Java 직렬화를 지원한다.
// 단순히 메모리 위에서 운용하는 세션이 아닌(서버 재시작 시 초기화)
// 클러스터링 환경에서 세션 공유를 위해 파일로 저장하거나
// DB 에 저장할 때
// 세션 객체를 자바 직렬화를 사용하여 저장할 수 있다고 한다.
// 2 Cache
// 실시간으로 반복적으로
// DB 에서 조회하는 데이타가 아니라면
// 리소스 절약을 위해 주로 Cache(메모리 데이타베이스) 라이브러리 시스템(Redis 등) 에
// 데이타를 저장해 놓고 사용하게 되는데, 이 때 데이타를 자바 직렬화하여 저장할 수 있다고 한다.
// 3 Java RMI(Remote Method Invocation)
// 지금은 잘 쓰지 않지만, 사실 자바 직렬화는 자바 Remote Method Invocation 에서
// 많이 사용했다고 한다.
// Remote Method Invocation 이란
// 원격 시스템(외부 시스템)
// 에서
// 원격에 있는 시스템 메서드를
// 로컬 시스템의 메서드 인 것 처럼 호출하는 것을 말한다.
// 그런데 메서드의 파라메터로 객체를 전달할 때 그 객체를 자동으로 직렬화시켜서 전달한다고 한다.
// 그렇기 때문에 파라메터로 전달되는 데이타는 Serializable 인터페이스(규격) 를
// 구현해야만 한다.
// 데이타를 전달받은 원격 시스템에서는
// 직렬화 된 데이타를
// 역직렬화하여 사용하게 된다.
// 주의사항 - 구조 변경
// 객체를 자바 직렬화 한 후 객체데이타의 클래스 구조가 변경 될 때 문제가 난다고 한다.
// public class User implements Serializable {
// private String name;
// private int age;
// private String email;
// ...
// }
// User user = User.builder()
// .name("아무개")
// .age(30)
// .email("amoogae@naver.com")
// .build();
// User 클래스를 직렬화 해서 직렬화한 결과 어떤 인코딩된 문자가 나왔다고 하자.
// 이 때, 만약 User 클래스에 address 프로퍼티가 추가된다면, 기존에
// 직렬화된 데이타를 역직렬화하면 문제가 발생한다고 한다.
// public class User implements Serializable {
// private String name;
// private int age;
// private String email;
// //추가
// private String address;
// ...
// }
// 역직렬화 하면 오류가 발생한다고 한다.
// java.io.InvalidClassException: 패키지이름.User; local class incompatible: stream classdesc
// serialVersionUID = -6709885925697981180, local class serialVersionUID = -5519332639680234859
// 위 두줄과 같은 모양으로 오류가 발생한다고 한다.
// serialVersionUID 가 달라서 오류가 발생한다고 한다.
// serialVersionUID 를 선언한 적이 없는데 왜 오류가 날까요?
// 직렬화를 하면 serialVersionUID 는 직접 작성하지 않아도 내부적으로 추가된다고 한다.
// 그리고 그 값은 클래스 구조 정보를 이용해서 생성된 hash값을 이용한다고 한다.
// 그리고 serialVersionUID 를 비교해서 다르다면 역직렬화가 불가능하다고 한다.
// 클래스 구조를 바꾸거나 클래스 구조가 바뀌면 serialVersionUID 도 변경 된다
// 클래스 구조가 변경되었을 때, 역직렬화를 해서 오류를 발생시켜야하는 시스템이 아니라면
// serialVersionUID 를 개발자가 직접 관리할 수 있다고 한다.
// User 클래스에 serialVersionUID 를 추가한다. (address property를 제거한 상태로 돌린다.)
// public class User implements Serializable {
// private static final long serialVersionUID = 1L;
// private String name;
// private int age;
// private String email;
// ...
// }
// User user = User.builder()
// .name("아무개")
// .age(30)
// .email("amoogae.naver.com")
// .build();
// user 객체를 직렬화 한 다음에
// User 클래스에 address property 를 추가해서 역직렬화 하면
// 제대로 역직렬화가 된다고 한다. 그리고 address 는 null 로 설정된다.
// 이렇게 Java 직렬화와 역직렬화는 클래스 구조 변경에 민감하다고 한다.
// serialVersionUID 를 설정했다고 했을 때 클래스 구조를 변경하면
// 문제가 발생한다.
// 1 직렬화 한 후 property 를 추가, 삭제하거나 이름 변경 했을 때는
// 오류가 발생하지 않고 단순히 값이 삭제되거나 null 로 설정된다.
// 2 직렬화 후 property 의 타입을 변경하면 오류가 발생한다 (직렬화는 타입에 엄격하다)
// 요 두가지 이유 때문에 Java 직렬화를 자주 변경되는 클래스의 객체에 사용하는 것을
// 피해야 한다.
// 게다가 외부(데이타베이스, Cache, NoSQL 서버) 에 장기간 저장될 정보에
// 자바 직렬화를 사용하는 것도 피해야 한다.
// 데이타가 저장되어 있는 동안 데이타 구조가 바뀌면, 그 직렬화된 데이타는
// Garbage 쓰레기가 되어 버릴 가능성이 높기 때문이다.
// 그래서 Eclipse IDE 는 경고 쪽지를 통해 개발자에게 직렬화 때문에
// 직접적이거나 간접적인 영향을 받고 있다는 것을 알리는 것이라고 한다.
// 그래서 그에 따른 해결책으로
// serialVersionUID 를 생성하거나
// @SuppressWarnings("serial") 어노테이션 처리를 해주길 바란다고 한다.
// 하지만 대부분의 프로그램에서는
// 요런 직렬화로 인한 버전 불일치에 대한 일이 일어날 일이 거의 없다고 한다.
// 그래서 무시해도 된다.
AddShop addFrame = new AddShop("입력폼");
JButton addButton;
JButton updateButton;
UpdateShop updateFrame = new UpdateShop("수정폼");
ShoppingDao dao = new ShoppingDao();
List spList;
java.util.List<ShoppingDto> list = new ArrayList<ShoppingDto>();
JTextField txtSang;
JTextField txtSu;
JTextField txtDan;
JTextField txtColor;
JLabel lblShoppingDay;
JLabel lblPhoto;
Image photoImage;
drawPhoto dP = new drawPhoto();
public MyShoppingMunje(String title) {
// TODO Auto-generated constructor stub
super(title);
this.setBounds(700, 100, 600, 800);// 시작위치x,y,크기 w,h
// super로 해도 되고 this로 해도 됨 super는 조상
// this로 해도 상속을 받아서 괜찮음
// this.getContentPane().setBackground(Color.orange);//프레임위에 있는 패널의 색상 변경
this.getContentPane().setBackground(new Color(211, 225, 208));// 프레임위에 있는 패널의 색상 변경
this.setDesign();// 디자인 코드
this.setVisible(true);// 보이게 하기
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);// 프로그램을 종료해주는 메서드
}
public void setDesign() {
this.setLayout(null);
addButton = new JButton("상품추가");
addButton.setBounds(20, 20, 200, 20);
addButton.addActionListener(new addbtnclick());
this.add(addButton);
updateButton = new JButton("상품수정");
updateButton.setBounds(20, 60, 200, 20);
updateButton.addActionListener(new udbtnclick());
this.add(updateButton);
spList = new List();
JScrollPane jsp = new JScrollPane(spList);
jsp.setBounds(20, 100, 300, 300);
this.add(jsp);
this.writeList();
spList.addItemListener(new listItemclick());
// addFrame.dbAdd.addActionListener(this);
addFrame.dbAdd.addActionListener(new addFabtnclick());
// updateFrame.btnUpdate.addActionListener(this);
updateFrame.btnUpdate.addActionListener(new udFudbtnclick());
JLabel lblSang = new JLabel("상품명");
lblSang.setBounds(340, 100, 100, 30);
this.add(lblSang);
txtSang = new JTextField();
txtSang.setBounds(340, 140, 200, 30);
this.add(txtSang);
JLabel lblSu = new JLabel("수량");
lblSu.setBounds(340, 180, 100, 30);
this.add(lblSu);
txtSu = new JTextField();
txtSu.setBounds(340, 220, 200, 30);
this.add(txtSu);
JLabel lblDan = new JLabel("단가");
lblDan.setBounds(340, 260, 100, 30);
this.add(lblDan);
txtDan = new JTextField();
txtDan.setBounds(340, 300, 200, 30);
this.add(txtDan);
JLabel lblColor = new JLabel("색상");
lblColor.setBounds(340, 340, 100, 30);
this.add(lblColor);
txtColor = new JTextField();
txtColor.setBounds(340, 380, 200, 30);
this.add(txtColor);
lblShoppingDay = new JLabel("등록일 : xxxx", JLabel.CENTER);
lblShoppingDay.setBounds(240, 20, 300, 60);
lblShoppingDay.setBorder(new LineBorder(Color.gray));
this.add(lblShoppingDay);
// lblPhoto=new JLabel();
// lblPhoto.setBounds(20, 420, 540, 325);
// lblPhoto.setBorder(new LineBorder(Color.gray, 2));
// this.add(lblPhoto);
photoImage = new ImageIcon("C:\\java0901\\image\\귀여운 아이콘\\c1.png").getImage();
dP.setBounds(20, 420, 540, 325);
this.add(dP);
}
public void writeList() {
spList.removeAll();
list = dao.writeAll();
for (int i = 0; i < list.size(); i = i + 1) {
spList.add(list.get(i).getSangpum());
}
}
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
Object ob = e.getSource();
if (ob == addFrame.dbAdd) {
if (addFrame.txtSangpum.getText().length() == 0 || addFrame.lblPhoto.getText().length() == 0
|| addFrame.txtSu.getText().length() == 0 || addFrame.txtDan.getText().length() == 0) {
JOptionPane.showMessageDialog(addFrame, "입력안한 항목이 있습니다. 입력하십시오.");
return;
}
ShoppingDto dto = new ShoppingDto();
dto.setSangpum(addFrame.txtSangpum.getText());
dto.setPhoto(addFrame.lblPhoto.getText());
int num = Integer.parseInt(addFrame.txtSu.getText());
dto.setSu(num);
dto.setDan(Integer.parseInt(addFrame.txtDan.getText()));
dto.setColor(addFrame.cbColor.getSelectedItem().toString());
dao.insertSangpum(dto);
this.writeList();
addFrame.cbColor.setSelectedIndex(0);
addFrame.lblPhoto.setText("");
addFrame.txtSangpum.setText("");
addFrame.txtSu.setText("");
addFrame.txtIpgoday.setText("");
addFrame.setVisible(false);
} else if (ob == updateFrame.btnUpdate) {
ShoppingDto dto = new ShoppingDto();
dto.setNum(updateFrame.num);
dto.setSangpum(updateFrame.txtProduct.getText());
dto.setPhoto(updateFrame.lblShowP.getText());
dto.setSu(Integer.parseInt(updateFrame.txtSu.getText()));
dto.setDan(Integer.parseInt(updateFrame.txtDan.getText()));
dto.setColor(updateFrame.cbCol.getSelectedItem().toString().toLowerCase());
dao.updateSangpum(dto);
updateFrame.setVisible(false);
this.writeList();
}
}
class addbtnclick implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
addFrame.setVisible(true);
}
}
class udbtnclick implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
int idx = spList.getSelectedIndex();
System.out.println(idx);
if (idx == -1) {
JOptionPane.showMessageDialog(MyShoppingMunje.this, "수정할 상품이 선택되지 않았습니다. 수정할 상품을 골라주십시오.");
return;
}
ShoppingDto dto = list.get(idx);
updateFrame.setVisible(true);
updateFrame.num = dto.getNum();
System.out.println(updateFrame.num);
updateFrame.cbCol.setSelectedItem(dto.getColor());
updateFrame.txtProduct.setText(dto.getSangpum());
updateFrame.txtSu.setText(String.valueOf(dto.getSu()));
updateFrame.txtDan.setText(String.valueOf(dto.getDan()));
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date = null;
date = sdf.format(dto.getIpgoday());
updateFrame.txtIday.setText(date);
updateFrame.lblShowP.setText(dto.getPhoto());
}
}
class addFabtnclick implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
if (addFrame.txtSangpum.getText().length() == 0 || addFrame.lblPhoto.getText().length() == 0
|| addFrame.txtSu.getText().length() == 0 || addFrame.txtDan.getText().length() == 0) {
JOptionPane.showMessageDialog(addFrame, "입력안한 항목이 있습니다. 입력하십시오.");
return;
}
ShoppingDto dto = new ShoppingDto();
dto.setSangpum(addFrame.txtSangpum.getText());
dto.setPhoto(addFrame.lblPhoto.getText());
int num = Integer.parseInt(addFrame.txtSu.getText());
dto.setSu(num);
dto.setDan(Integer.parseInt(addFrame.txtDan.getText()));
dto.setColor(addFrame.cbColor.getSelectedItem().toString());
dao.insertSangpum(dto);
MyShoppingMunje.this.writeList();
addFrame.cbColor.setSelectedIndex(0);
addFrame.lblPhoto.setText("");
addFrame.txtSangpum.setText("");
addFrame.txtSu.setText("");
addFrame.txtIpgoday.setText("");
addFrame.setVisible(false);
}
}
class udFudbtnclick implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
ShoppingDto dto = new ShoppingDto();
dto.setNum(updateFrame.num);
dto.setSangpum(updateFrame.txtProduct.getText());
dto.setPhoto(updateFrame.lblShowP.getText());
dto.setSu(Integer.parseInt(updateFrame.txtSu.getText()));
dto.setDan(Integer.parseInt(updateFrame.txtDan.getText()));
dto.setColor(updateFrame.cbCol.getSelectedItem().toString().toLowerCase());
dao.updateSangpum(dto);
MyShoppingMunje.this.writeList();
updateFrame.setVisible(false);
}
}
class listItemclick implements ItemListener {
@Override
public void itemStateChanged(ItemEvent e) {
// TODO Auto-generated method stub
int idx = spList.getSelectedIndex();
ShoppingDto dto = list.get(idx);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date = sdf.format(dto.getIpgoday());
MyShoppingMunje.this.lblShoppingDay.setText("쇼핑일 " + date);
MyShoppingMunje.this.txtSang.setText(dto.getSangpum());
MyShoppingMunje.this.txtSu.setText(String.format("%,d", dto.getSu()));
MyShoppingMunje mS = MyShoppingMunje.this;
NumberFormat nf = NumberFormat.getCurrencyInstance();
mS.txtDan.setText(String.valueOf(nf.format(dto.getDan())));
mS.txtColor.setText(dto.getColor());
photoImage = new ImageIcon(dto.getPhoto()).getImage();
dP.repaint();
}
}
class drawPhoto extends Canvas {
// 경고:The serializable class drawPhoto does not declare a static final serialVersionUID field of type long
@Override
public void paint(Graphics g) {
// TODO Auto-generated method stub
super.paint(g);
g.drawImage(photoImage, 0, 0, 300, 340, this);
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
MyShoppingMunje ex = new MyShoppingMunje("");
}
}
https://blog.naver.com/fochaerim/70105895049
serialVersionUID, @SuppressWarnings("serial") 에 대해서 (작성중..)
자바를 하다보면 흔히 겪는 노란 줄로 표시되는 Warning Message "The serializable class MyFra...
blog.naver.com
https://www.happykoo.net/@happykoo/posts/257
해피쿠 블로그 - [Java] 직렬화(Serialization)에 대해 알아보자
누구나 손쉽게 운영하는 블로그!
www.happykoo.net