- 자바 스윙을 이용한 중고 상품 거래 시스템 만들기 -

 

Domain

Sale.java

package domain;

public class Sale {
	
	/*
	 * Field
	 */
	private int saleId;
	private int sellerId;
	private int productId;
	private String saleStatus;
	

	/*
	 * Method - getter, setter
	 */
	public int getSaleId() {
		return saleId;
	}
	public void setSaleId(int saleId) {
		this.saleId = saleId;
	}
	public int getSellerId() {
		return sellerId;
	}
	public void setSellerId(int sellerId) {
		this.sellerId = sellerId;
	}
	public int getProductId() {
		return productId;
	}
	public void setProductId(int productId) {
		this.productId = productId;
	}
	public String getSaleStatus() {
		return saleStatus;
	}
	public void setSaleStatus(String saleStatus) {
		this.saleStatus = saleStatus;
	}
	@Override
	public String toString() {
		return "Sale [saleId=" + saleId + ", sellerId=" + sellerId + ", productId=" + productId + ", saleStatus="
				+ saleStatus + "]";
	}
}

 

Product.java

package domain;

import exception.NotEnoughStockException;

public class Product {
	
	/*
	 * Field
	 */
	private int productId;
	private String name;
	private int quantity;
	private int price;
	private String description;
	private String image;

	
	/*
	 * Method - getter, setter
	 */
	public int getProductId() {
		return productId;
	}
	public void setProductId(int productId) {
		this.productId = productId;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getQuantity() {
		return quantity;
	}
	public void setQuantity(int quantity) {
		this.quantity = quantity;
	}
	public int getPrice() {
		return price;
	}
	public void setPrice(int price) {
		this.price = price;
	}
	public String getDescription() {
		return description;
	}
	public void setDescription(String description) {
		this.description = description;
	}
	public String getImage() {
		return image;
	}
	public void setImage(String image) {
		this.image = image;
	}
	@Override
	public String toString() {
		return "Product [productId=" + productId + ", name=" + name + ", quantity=" + quantity + ", price=" + price
				+ ", description=" + description + "]";
	}
	
	// -- 비즈니스 로직 -- // 
	public void removeQuantity(int orderQuantity, Product product) {
		int restQuantity = product.getQuantity() - orderQuantity;
		
		if (restQuantity < 0) {
			throw new NotEnoughStockException("상품수량이 부족합니다.");
		}
		product.setQuantity(restQuantity);
	}
}

Product.java 인 엔티티에 직접 비즈니스 로직을 추가

상품의 주문이 발생할 시 상품수량의 변동이 발생하게 된다.

이를 orderService 에서 product 엔티티를 직접 컨트롤 하기 위함이다.

 

Repository

JdbcSaleRepository.java

package repository.jdbc;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import domain.Sale;
import domain.SaleInfo;
import repository.inerface.SaleRepository;

public class JdbcSaleRepository extends DAO implements SaleRepository{
	
	/*
	 * Field
	 */
	// 싱글톤
	private static SaleRepository saleRepository = null;
		

	/*
	 * Constructor
	 */
	// 싱글톤
	private JdbcSaleRepository() {}

	
	/*
	 * Method
	 */
	// 싱글톤 -> 메서드로 인스턴스 생성
	public static SaleRepository getSaleRepository() {
		if (saleRepository == null) {
			saleRepository = new JdbcSaleRepository();
		}
		return saleRepository;
	}

	@Override
	public void insert(Sale sale) {
		try {
			connect();

			String sql = "INSERT INTO sales VALUES (sales_seq.nextval ,?, ?, ?)";
			ps = conn.prepareStatement(sql);
			ps.setInt(1, sale.getSellerId());
			ps.setInt(2, sale.getProductId());
			ps.setString(3, sale.getSaleStatus());

			int result = ps.executeUpdate();

			if (result > 0) {
				System.out.println(result + "행 삽입에 성공했습니다.");
			} else {
				System.out.println("삽입에 실패했습니다.");
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			disconnect();
		}
	}

	@Override
	public void update(Sale sale) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void delete(int saleId) {
		try {
			connect();

			String sql = "DELETE FROM sales WHERE sale_id = ?";
			ps = conn.prepareStatement(sql);
			ps.setInt(1, saleId);

			int result = ps.executeUpdate();

			if (result > 0) {
				System.out.println(result + "행 삭제에 성공했습니다.");
			} else {
				System.out.println("삭제에 실패했습니다.");
			}

		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			disconnect();
		}
		
	}

	@Override
	public Sale selectOne(int saleId) {
		Sale sale = null;

		try {
			connect();

			String sql = "SELECT * FROM sales WHERE sale_id = ?";
			ps = conn.prepareStatement(sql);
			ps.setInt(1, saleId);

			rs = ps.executeQuery();

			if (rs.next()) {
				sale = new Sale();
				sale.setSaleId(rs.getInt(1));
				sale.setSellerId(rs.getInt(2));
				sale.setProductId(rs.getInt(3));
				sale.setSaleStatus(rs.getString(4));
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			disconnect();
		}
		return sale;
	}

	// 상품 전체 검색
	@Override
	public List<SaleInfo> selectAll(int loginMemberId) {
		List<SaleInfo> list = new ArrayList<SaleInfo>();

		try {
			connect();

			String sql = "SELECT s.sale_id, s.seller_id, m.identification, s.sale_status, p.name, p.quantity, p.price, p.description, m.address, s.product_id, p.image "
						+ "FROM sales s "
						+ "JOIN products p ON (s.product_id = p.product_id) "
						+ "JOIN members m ON (s.seller_id = m.member_id) "
						+ "WHERE p.quantity > 0 AND s.seller_id <> ? "
						+ "ORDER BY s.product_id desc";
			ps = conn.prepareStatement(sql);
			ps.setInt(1, loginMemberId);

			rs = ps.executeQuery();

			while (rs.next()) {
				SaleInfo saleInfo = new SaleInfo();
				saleInfo.setSaleId(rs.getInt(1));
				saleInfo.setSellerId(rs.getInt(2));
				saleInfo.setIdentification(rs.getString(3));
				saleInfo.setSaleStatus(rs.getString(4));
				saleInfo.setProductName(rs.getString(5));
				saleInfo.setProductQuantity(rs.getInt(6));
				saleInfo.setProductPrice(rs.getInt(7));
				saleInfo.setProductDescription(rs.getString(8));
				saleInfo.setAddress(rs.getString(9));
				saleInfo.setProduct_id(rs.getInt(10));
				saleInfo.setProductImage(rs.getString(11));
				
				
				list.add(saleInfo);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			disconnect();
		}
		return list;
	}
	
	// 상품 키워드로 검색
	@Override
	public List<SaleInfo> selectAllByKeyword(int loginMemberId, String keyword) {
		List<SaleInfo> list = new ArrayList<SaleInfo>();

		try {
			connect();

			String sql = "SELECT s.sale_id, s.seller_id, m.identification, s.sale_status, p.name, p.quantity, p.price, p.description, m.address, s.product_id, p.image  "
						+ "FROM sales s "
						+ "JOIN products p ON (s.product_id = p.product_id) "
						+ "JOIN members m ON (s.seller_id = m.member_id) "
						+ "WHERE p.quantity > 0 "
						+ "AND s.seller_id <> ? "
						+ "AND p.name like '%'||?||'%'"
						+ "ORDER BY s.product_id desc";
			ps = conn.prepareStatement(sql);
			ps.setInt(1, loginMemberId);
			ps.setString(2, keyword);

			rs = ps.executeQuery();

			while (rs.next()) {
				SaleInfo saleInfo = new SaleInfo();
				
				saleInfo.setSaleId(rs.getInt(1));
				saleInfo.setSellerId(rs.getInt(2));
				saleInfo.setIdentification(rs.getString(3));
				saleInfo.setSaleStatus(rs.getString(4));
				saleInfo.setProductName(rs.getString(5));
				saleInfo.setProductQuantity(rs.getInt(6));
				saleInfo.setProductPrice(rs.getInt(7));
				saleInfo.setProductDescription(rs.getString(8));
				saleInfo.setAddress(rs.getString(9));
				saleInfo.setProduct_id(rs.getInt(10));
				saleInfo.setProductImage(rs.getString(11));
				
				
				list.add(saleInfo);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			disconnect();
		}
		return list;
	}
	
	// 상품 주변지역으로 검색
	@Override
	public List<SaleInfo> selectAllByNeighbor(int loginMemberId, int prevEmdCd, int nextEmdCd) {
		List<SaleInfo> list = new ArrayList<SaleInfo>();

		try {
			connect();

			String sql = "SELECT s.sale_id, s.seller_id, m.identification, s.sale_status, p.name, p.quantity, p.price, p.description, m.address, s.product_id, o.emd_cd, p.image  "
						+ "FROM sales s "
						+ "JOIN products p ON (s.product_id = p.product_id) "
						+ "JOIN members m ON (s.seller_id = m.member_id) "
						+ "JOIN suseong_map o ON (m.address = o.emd_nn) "
						+ "WHERE p.quantity > 0 AND s.seller_id <> ? "
						+ "AND o.emd_cd BETWEEN ? AND ?"
						+ "ORDER BY s.product_id desc";
			ps = conn.prepareStatement(sql);
			ps.setInt(1, loginMemberId);
			ps.setInt(2, prevEmdCd);
			ps.setInt(3, nextEmdCd);

			rs = ps.executeQuery();

			while (rs.next()) {
				SaleInfo saleInfo = new SaleInfo();
				saleInfo.setSaleId(rs.getInt(1));
				saleInfo.setSellerId(rs.getInt(2));
				saleInfo.setIdentification(rs.getString(3));
				saleInfo.setSaleStatus(rs.getString(4));
				saleInfo.setProductName(rs.getString(5));
				saleInfo.setProductQuantity(rs.getInt(6));
				saleInfo.setProductPrice(rs.getInt(7));
				saleInfo.setProductDescription(rs.getString(8));
				saleInfo.setAddress(rs.getString(9));
				saleInfo.setProduct_id(rs.getInt(10));
				saleInfo.setEmdCd(rs.getInt(11));
				saleInfo.setProductImage(rs.getString(12));
				
				
				list.add(saleInfo);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			disconnect();
		}
		return list;
	}
}

 

JdbcProductRepository.java

package repository.jdbc;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import domain.Product;
import repository.inerface.ProductRepository;

public class JdbcProductRepository extends DAO implements ProductRepository {

	/*
	 * Field
	 */
	// 싱글톤
	private static ProductRepository productRepository = null;
	

	/*
	 * Constructor
	 */
	// 싱글톤
	private JdbcProductRepository() {}

	/*
	 * Method
	 */
	// 싱글톤 -> 메서드로 인스턴스 생성
	public static ProductRepository getProductRepository() {
		if (productRepository == null) {
			productRepository = new JdbcProductRepository();
		}
		return productRepository;
	}

	@Override
	public void insert(Product product) {
		try {
			connect();
			
			String sql = "INSERT INTO products "
						+ "VALUES (products_seq.nextval ,?, ?, ?, ?, ?)";
			ps = conn.prepareStatement(sql);
			ps.setString(1, product.getName());
			ps.setInt(2, product.getQuantity());
			ps.setInt(3, product.getPrice());
			ps.setString(4, product.getDescription());
			ps.setString(5, product.getImage());
			
			int result = ps.executeUpdate();
			
			if (result > 0) {
				System.out.println(result + "행 삽입에 성공했습니다.");
			}
			else {
				System.out.println("삽입에 실패했습니다.");
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			disconnect();
		}
	}

	@Override
	public void update(int productId, int productQuantity) {
		try {
			connect();
			
			String sql = "UPDATE products SET quantity = ? WHERE product_id = ?";
			ps = conn.prepareStatement(sql);
			ps.setInt(1, productQuantity);
			ps.setInt(2, productId);
			
			
			int result = ps.executeUpdate();
			
			if (result > 0) {
				System.out.println(result + "행 수정에 성공했습니다.");
			}
			else {
				System.out.println("수정에 실패했습니다.");
			}
			
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			disconnect();
		}
	}

	@Override
	public void delete(int productId) {
		try {
			connect();
			
			String sql = "DELETE FROM products WHERE product_id = ?";
			ps = conn.prepareStatement(sql);
			ps.setInt(1, productId);
			
			int result = ps.executeUpdate();
			
			if (result > 0) {
				System.out.println(result + "행 삭제에 성공했습니다.");
			}
			else {
				System.out.println("삭제에 실패했습니다.");
			}
			
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			disconnect();
		}
	}

	@Override
	public Product selectOne(int productId) {
		Product product = null;
		
		try {
			connect();
			
			String sql = "SELECT * FROM products WHERE product_id = ?";
			ps = conn.prepareStatement(sql);
			ps.setInt(1, productId);
			
			rs = ps.executeQuery();
			
			if (rs.next()) {
				product = new Product();
				
				product.setProductId(rs.getInt(1));
				product.setName(rs.getString(2));
				product.setQuantity(rs.getInt(3));
				product.setPrice(rs.getInt(4));
				product.setDescription(rs.getString(5));
				product.setImage(rs.getString(6));
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			disconnect();
		}
		return product;
	}

	@Override
	public Product selectOne(String name) {
		Product product = null;
		
		try {
			connect();
			
			String sql = "SELECT * FROM products WHERE name = ?";
			ps = conn.prepareStatement(sql);
			ps.setString(1, name);
			
			rs = ps.executeQuery();
			
			if (rs.next()) {
				product = new Product();
				product.setProductId(rs.getInt(1));
				product.setName(rs.getString(2));
				product.setQuantity(rs.getInt(3));
				product.setPrice(rs.getInt(4));
				product.setDescription(rs.getString(5));
				product.setImage(rs.getString(6));
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			disconnect();
		}
		return product;
	}

	@Override
	public List<Product> selectAll() {
		List<Product> list = new ArrayList<Product>();
		
		try {
			connect();
			
			String sql = "SELECT * FROM products";
			ps = conn.prepareStatement(sql);
			
			rs = ps.executeQuery();
			
			while (rs.next()) {
				Product product = new Product();
				product.setProductId(rs.getInt(1));
				product.setName(rs.getString(2));
				product.setQuantity(rs.getInt(3));
				product.setPrice(rs.getInt(4));
				product.setDescription(rs.getString(5));
				product.setImage(rs.getString(6));
				
				list.add(product);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			disconnect();
		}
		return list;
	}
}

 

Service

SaleService.java

package service;

import java.util.List;

import domain.Sale;
import domain.SaleInfo;
import repository.inerface.SaleRepository;

public class SaleService {

	/*
	 * Field
	 */
	private final SaleRepository saleRepository;

	/*
	 * Constructor
	 */
	public SaleService(SaleRepository saleRepository) {
		this.saleRepository = saleRepository;
	}

	/*
	 * Method
	 */
	// 판매 등록
	public void createSale(Sale sale) {
		saleRepository.insert(sale);
	}

	// 판매 수정 - 판매상태 수정?
	public void updateSale(Sale sale) {
		saleRepository.update(sale);
	}

	// 판매 삭제
	public void deleteSale(int saleId) {
		saleRepository.delete(saleId);
	}

	// 판매 단건조회
	public Sale findOneSale(int saleId) {
		return saleRepository.selectOne(saleId);
	}

	// 판매 전체조회
	public List<SaleInfo> findAllSales(int loginMemberId) {
		return saleRepository.selectAll(loginMemberId);
	}

	// 판매 키워드조회
	public List<SaleInfo> findAllSalesByKeyword(int loginMemberId, String keyword) {
		return saleRepository.selectAllByKeyword(loginMemberId, keyword);
	}

	// 판매 키워드조회
	public List<SaleInfo> findAllSalesByNeighbor(int loginMemberId, int prevEmdCd, int nextEmdCd) {
		return saleRepository.selectAllByNeighbor(loginMemberId, prevEmdCd, nextEmdCd);
	}
}

 

ProductService.java

package service;

import java.util.List;

import domain.Product;
import repository.inerface.ProductRepository;

public class ProductService {

	/*
	 * Field
	 */
	private final ProductRepository productRepository;

	/*
	 * Constructor
	 */
	public ProductService(ProductRepository productRepository) {
		this.productRepository = productRepository;
	}

	/*
	 * Method
	 */
	// 상품 등록
	public void saveProduct(Product product) {
		productRepository.insert(product);
	}

	// 상품 수정
	public void modifyProduct(int productId, int productQuantity) {
		productRepository.update(productId, productQuantity);
	}

	// 상품 삭제
	public void deleteProduct(int productId) {
		productRepository.delete(productId);
	}

	// 상품 단건조회 - 상품번호
	public Product findOneProductById(int productId) {
		return productRepository.selectOne(productId);
	}

	// 상품 단건조회 - 상품이름
	public Product findOneProductById(String name) {
		return productRepository.selectOne(name);
	}
	
	// 전체 상품조회
	public List<Product> findAllProducts() {
		return productRepository.selectAll();
	}
}

 

View

ShopFrame.java

	// 판매등록 버튼
	private RoundedButton postSaleButton() {
		RoundedButton saleRegBtn = new RoundedButton("REGISTER");
		saleRegBtn.setBounds(565, 20, 70, 40);
		saleRegBtn.setBackground(Color.pink);

		// 판매등록 버튼 클릭시 상품등록 폼 팝업
		saleRegBtn.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {

				// 상품 등록 폼
				JFrame jf = new JFrame("SALE REG");
				jf.setLayout(null);
				jf.setBackground(Color.BLACK);
				jf.setBounds(850, 90, 500, 700);
				jf.setVisible(true);

				JPanel panel = new JPanel();
				panel.setBounds(0, 0, 500, 700);
				panel.setLayout(null);

				JLabel lblNewLabe2 = new JLabel("# Register your product #");
				lblNewLabe2.setBounds(120, 20, 300, 35);
				lblNewLabe2.setFont(new Font("휴먼둥근헤드라인", Font.BOLD, 20));
				panel.add(lblNewLabe2);
				
				// 입력 란 시작 위치 및 간격
				int yGap = 49;
				int labelStartY = 260;
				int textStartY = 287;
				int lableStartX = 30;
				int textStartX = 180;

				// 상품 이름 입력
				JLabel lblNewLabel2_1 = new JLabel("NAME");
				lblNewLabel2_1.setBounds(lableStartX, labelStartY, 100, 80);
				lblNewLabel2_1.setFont(new Font("굴림", Font.BOLD, 18));
				panel.add(lblNewLabel2_1);

				JTextField textCreateName = new JTextField();
				textCreateName.setBounds(textStartX, textStartY, 231, 25);
				panel.add(textCreateName);
				textCreateName.setColumns(10);

				// 상품 가격 입력
				JLabel lblNewLabel2_2 = new JLabel("PRICE");
				lblNewLabel2_2.setBounds(lableStartX, labelStartY + yGap, 100, 80);
				lblNewLabel2_2.setFont(new Font("굴림", Font.BOLD, 18));
				panel.add(lblNewLabel2_2);

				JTextField textCreatePrice = new JTextField();
				textCreatePrice.setBounds(textStartX, textStartY + yGap, 231, 25);
				panel.add(textCreatePrice);
				textCreatePrice.setColumns(10);

				// 상품 수량 입력
				JLabel lblNewLabel2_3 = new JLabel("QUANTITY");
				lblNewLabel2_3.setBounds(lableStartX, labelStartY + 2 * yGap, 100, 80);
				lblNewLabel2_3.setFont(new Font("굴림", Font.BOLD, 18));
				panel.add(lblNewLabel2_3);

				JTextField textCreateQuantity = new JTextField();
				textCreateQuantity.setBounds(textStartX, textStartY + 2 * yGap, 231, 25);
				panel.add(textCreateQuantity);
				textCreateQuantity.setColumns(10);

				// 이미지 입력
				JLabel lblNewLabel2_4 = new JLabel("IMAGE");
				lblNewLabel2_4.setBounds(lableStartX, labelStartY + 3 * yGap, 100, 80);
				lblNewLabel2_4.setFont(new Font("굴림", Font.BOLD, 18));
				panel.add(lblNewLabel2_4);

				JTextField textCreateImage = new JTextField();
				textCreateImage.setBounds(textStartX, textStartY + 3 * yGap, 231, 25);
				panel.add(textCreateImage);
				textCreateImage.setColumns(10);
				
				// 상품 이름에서 이름 입력 후 엔터 치면 이미지 이름 자동 완성
				textCreateName.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent e) {					
						textCreateImage.setText(textCreateName.getText() + ".jpg");
					}
				});

				// 상품 설명 입력 - text area
				JLabel lblNewLabel2_5 = new JLabel("DISCRIPTION");
				lblNewLabel2_5.setBounds(lableStartX, labelStartY + 4 * yGap, 120, 80);
				lblNewLabel2_5.setFont(new Font("굴림", Font.BOLD, 18));
				panel.add(lblNewLabel2_5);

				JTextArea textCreateDiscription = new JTextArea();
				textCreateDiscription.setBounds(textStartX, textStartY + 4 * yGap, 231, 100);
				textCreateDiscription.setLineWrap(true); // 자동 줄바꿈
				panel.add(textCreateDiscription);
				textCreateDiscription.setColumns(10);

				// 뒤로가기
				RoundedButton backBtn = new RoundedButton("BACK");
				backBtn.setBounds(290, 600, 60, 40);
				backBtn.setBackground(Color.pink);
				jf.add(backBtn);

				// 뒤로가기 클릭
				backBtn.addMouseListener(new MouseAdapter() {
					public void mouseClicked(MouseEvent e) {
						jf.dispose();
					}
				});

				// 등록버튼
				RoundedButton postBtn = new RoundedButton("POST");
				postBtn.setBounds(390, 600, 60, 40);
				postBtn.setBackground(Color.pink);
				jf.add(postBtn);

				// 등록 버튼 클릭시 DB에 product, sale 저장
				postBtn.addMouseListener(new MouseAdapter() {
					public void mouseClicked(MouseEvent e) {

						// 상품정보 미기입 예외처리
						if (textCreateName.getText().length() != 0 && textCreatePrice.getText().length() != 0
								&& textCreateQuantity.getText().length() != 0
								&& textCreateDiscription.getText().length() != 0) {
							// 상품 등록
							Product product = new Product();
							product.setName(textCreateName.getText());
							product.setPrice(Integer.parseInt(textCreatePrice.getText()));
							product.setQuantity(Integer.parseInt(textCreateQuantity.getText()));
							product.setImage(textCreateImage.getText());
							product.setDescription(textCreateDiscription.getText());

							JOptionPane.showMessageDialog(frame, "Product resistration successfully",
									"Congratulations !", JOptionPane.INFORMATION_MESSAGE);
							productService.saveProduct(product);
							
							// 상품 고유 번호(시퀀스) 받아서 Sales 테이블에 저장 
							int productId = productService.findOneProductById(textCreateName.getText()).getProductId();
							// 판매 등록
							Sale sale = new Sale();
							sale.setSellerId(HomeFrame.logInMember.getMemberId());
							sale.setProductId(productId);
							sale.setSaleStatus("판매중");
							
							// 판매 내역 DB에 저장
							saleService.createSale(sale);

							jf.dispose();
							searchFrame.dispose();
							
						// 상품 정보 한 개라도 미기입 
						} else {
							JOptionPane.showMessageDialog(frame, "Please fill product Info.",
									"Product resistration failed !", JOptionPane.INFORMATION_MESSAGE);
							return;
						}
					}
				});
				jf.add(panel);
			}
		});
		return saleRegBtn;
	}

상품 등록 시 Product 테이블과 Sales 테이블에 동시 저장

판매와 상품이 가진 엔티티를 분리하기 위함 

 

실행 화면

상품 등록 페이지

 

- Just Do It -

 

반응형
복사했습니다!