Java

Java List component

승모근뭉치 2023. 2. 9. 22:49

프로젝트 내 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