Paper.Yellow
Service 실습 본문
고객, 상품, 주문 세가지 DB를 통해 Service 구현
1.Object 테이블 생성
고객 - customer
ID | USERNAME | PASSWORD | |
1 | COS | 1234 | (null) |
상품 - product
ID | NAME | PRICE | QTY |
1 | 샴푸 | 3000 | 99 |
두개의 테이블을 생성해서 각각의 임의의 값을 입력
각각의 테이블의 ID는 각자의 Primary_Key로 등록
customer.USERNAME 과 product.NAME은 고유할 수 있게 Unique로 등록
CREATE TABLE customer(
id number(9,0),
username varchar2(12) not null,
password varchar2(20) not null,
email varchar2(50),
CONSTRAINT customer_pk PRIMARY KEY(id),
CONSTRAINT customer_username_uk UNIQUE(username)
);
SELECT * FROM product;
CREATE TABLE product(
id number(9,0),
name varchar2(50) not null,
price number(9,0) not null,
qty number(9,0) not null,
CONSTRAINT product_pk PRIMARY KEY(id),
CONSTRAINT product_name_uk UNIQUE(name)
);
2.관계를 정의할 수 있는 테이블 생성
테이블 사이의 관계를 확인하고 '주문' 테이블을 만든다.
주문 - orders
ID | CUSTOMERID | PRODUCTID |
1 | 1 | 1 |
orders에는 customer.ID / product.ID 를 Foreign_key로 등록
CREATE TABLE orders (
id number(9,0),
customerId number(9,0),
productId number(9,0),
CONSTRAINT orders_pk PRIMARY KEY(id),
CONSTRAINT orders_customer_fk foreign key(customerId) references customer(id),
CONSTRAINT orders_product_fk foreign key(productId) references product(id)
);
3.시퀀스 등록
==========================나중에 시퀀스 포스팅 완료 후 링크 달기
CREATE SEQUENCE CUSTOMER_SEQ
INCREMENT BY 1
START WITH 1;
CREATE SEQUENCE product_seq
START WITH 1
INCREMENT BY 1;
CREATE SEQUENCE orders_seq
START WITH 1
INCREMENT BY 1;
4.DB 연결
package product.db;
import java.sql.Connection;
import java.sql.DriverManager;
public class DBConnection {
public static Connection connection() {
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection conn = DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:xe",
"SCOTT",
"TIGER"
);
conn.setAutoCommit(false);
return conn;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
5.엔티티(Entity) - ex) Customer
3개 테이블 모두 같은 방식으로 생성되어 예시는 하나만 기록
package product.domain.customer;
public class Customer {
private int id;
private String username;
private String password;
private String email;
public Customer() {
}
public Customer(int id, String username, String password, String email) {
this.id = id;
this.username = username;
this.password = password;
this.email = email;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
6.DAO - ex) Customer
package product.domain.customer;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
public class CustomerDao {
private Connection conn;
public CustomerDao(Connection conn) {
this.conn = conn;
}
public int insert(Customer customer) {
int result = -1;
try {
StringBuilder sql = new StringBuilder();
sql.append("INSERT INTO customer ");
sql.append("VALUES(customer_seq.nextval, ?, ?, ?)");
PreparedStatement pstmt = conn.prepareStatement(sql.toString());
pstmt.setString(1, customer.getUsername());
pstmt.setString(2, customer.getPassword());
pstmt.setString(3, customer.getEmail());
result = pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
public Customer findById(int id) {
Customer customer = new Customer();
try {
PreparedStatement pstmt =
conn.prepareStatement("SELECT * FROM customer WHERE id = ?");
pstmt.setInt(1, id);
ResultSet rs = pstmt.executeQuery();
if(rs.next()) {
customer.setId(rs.getInt("id"));
customer.setUsername(rs.getString("username"));
customer.setPassword(rs.getString("password"));
customer.setEmail(rs.getString("email"));
}
} catch (Exception e) {
e.printStackTrace();
}
return customer;
}
public ArrayList<Customer> findAll() {
ArrayList<Customer> customerList = new ArrayList<>();
try {
PreparedStatement pstmt =
conn.prepareStatement("SELECT * FROM customer ORDER BY id DESC");
ResultSet rs = pstmt.executeQuery();
while(rs.next()) {
Customer customer = new Customer();
customer.setId(rs.getInt("id"));
customer.setUsername(rs.getString("username"));
customer.setPassword(rs.getString("password"));
customer.setEmail(rs.getString("email"));
customerList.add(customer);
}
} catch (Exception e) {
e.printStackTrace();
}
return customerList;
}
public int updateById(int id, Customer customer) {
int result = -1;
try {
StringBuilder sql = new StringBuilder();
sql.append("UPDATE customer SET username = ?, password = ?, email = ? ");
sql.append("WHERE id = ?");
PreparedStatement pstmt = conn.prepareStatement(sql.toString());
pstmt.setString(1, customer.getUsername());
pstmt.setString(2, customer.getPassword());
pstmt.setString(3, customer.getEmail());
pstmt.setInt(4, id);
result = pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
public int deleteById(int id) {
int result = -1;
try {
StringBuilder sql = new StringBuilder();
sql.append("DELETE FROM customer WHERE id = ?");
PreparedStatement pstmt = conn.prepareStatement(sql.toString());
pstmt.setInt(1, id);
result = pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
insert - 추가
findById - 한건보기
findAll - 목록보기
updateById - 수정
deleteById - 삭제
위 내용으로 3개의 테이블에 대한 DAO를 동일하게 작성
7. DTO
필요한 서비스 내용
고객서비스 | 상품서비스 | 주문서비스 |
-고객등록 -고객상세보기 -고객목록보기 -고객수정 -고객삭제 |
-상품등록 -상품상세보기 -상품목록보기 -상품수정 -상품삭제 |
-주문하기 -주문취소하기 -고객별주문목록보기 <<==!! |
고객별 주문 목록보기는 하나의 테이블 값으로는 구현 불가.
세개의 테이블 값을 INNER JOIN으로 쿼리를 짰다.
DTO 생성
package product.dto;
public class OrderRespDto {
private int id;
private String username;
private String name;
private int price;
public OrderRespDto() {
}
public OrderRespDto(int id, String username, String name, int price) {
this.id = id;
this.username = username;
this.name = name;
this.price = price;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
OrdersDAO에 추가로 구현
public ArrayList<OrderRespDto> findByIdToOrderList(int customerId) {
ArrayList<OrderRespDto> dtoList = new ArrayList<>();
try {
StringBuilder sql = new StringBuilder();
sql.append("select o.id, c.username, p.name, p.price ");
sql.append("from orders o ");
sql.append("INNER JOIN customer c ");
sql.append("ON o.customerId = c.id ");
sql.append("INNER JOIN product p ");
sql.append("ON o.productId = p.id ");
sql.append("WHERE c.id = ?");
PreparedStatement pstmt =
conn.prepareStatement(sql.toString());
pstmt.setInt(1, customerId);
ResultSet rs = pstmt.executeQuery();
while(rs.next()) {
OrderRespDto dto = new OrderRespDto();
dto.setId(rs.getInt("id"));
dto.setUsername(rs.getString("username"));
dto.setName(rs.getString("name"));
dto.setPrice(rs.getInt("price"));
dtoList.add(dto);
}
} catch (Exception e) {
e.printStackTrace();
}
return dtoList;
}
8.Service
마음데로 짤 수도 있지만 실수를 할 수 있기에,
실무에서 신입으로 지시를 받을때 상사에게 지시를 받을때 예시처럼 Service 목록을 받았다.
package product.service;
import java.util.ArrayList;
import product.dto.OrderRespDto;
public interface OrderService {
public void 주문하기(int customerId, int productId);
public void 주문취소하기(int id);
public ArrayList<OrderRespDto> 고객별주문목록보기(int customerId);
}
interface는 하나의 키로 여러개의 메서드를 실행하는 방법도 있지만, 여기서는 메서드에 강제성을 부여하기 위해 사용됐다.
9.ServiceImpl
사실 이전까지는 엔티티/DAO 모두 처음 받은 예시를 따라치고 값만 대입해서 바꾸면 되는거라 어떻게든 따라했는데,
응용된 요구사항을 받으니 어떻게 실행해야하는지 너무 막막했다.
심지어 제일 첫번째. 재고확인 ( 재고가 0보다 큰가? product findById) 조건마저도 어떻게해야할지 상상이 가지 않았다.
그래서 조건을 쪼개서 보려고 했다.
주문하기
1) 재고확인
>재고가 0보다 큰걸 확인하려면 상품을 하나 검색한 후 그 상품에 대한 재고 값을 알아야 한다. 그리고 그 값이 0보다 크다면 재고가 있음
>productDao의 findById로 값을 조회하고, .getQty의 값을 가져와서 if문으로 0보다 크면 실행 0이라면 실행하지 않도록하기
2) 주문하기
조회(read)가 아닌 수정/추가/삭제(write)에서 result = -1; 이 포함되어 있는걸 사실 이해하지 못하고 코드만 따라쳤는데 App 클래스들에서 result의 값이 1인지 검증을 하는 부분이 보였다.
result의 값이 왜 필요한지 이해가 안 됐다.
이걸 보고 낫보고 기억자도 모른다고 하는걸까. 1이 정상 실행인건 알겠는데 그래서 그게 왜?? 라는 생각 밖에 안 들었다.
거기다가 코드를 비슷하게 쳤는데 오류가 나는거다. 도대체 뭘 입력해야할지 떠오르지 않았다.
포기하고 3. 재고 -1하기를 시도했다.그런데 왜 int로 받아야 하는지 이해가 가지 않았다.
한참 고민하다가 주문취소하기가 더 쉬워보여서 시도했다.
그러다가 문득 쿼리를 작성하고 정상적으로 실행된 것을 확인 한 후에야 최종 실행에서 1(정상실행)의 값을 확인 한 후 commit 한다는걸 깨달은거다.
하나라도 실행이 되지 않으면 안되니까 if문 조건에 and를 넣었다.
이걸 깨달으니 주문하기는 쉬운 응용이지.
최종코드
package product.service;
import java.sql.Connection;
import java.util.ArrayList;
import product.domain.orders.Orders;
import product.domain.orders.OrdersDao;
import product.domain.product.Product;
import product.domain.product.ProductDao;
import product.dto.OrderRespDto;
public class OrderServiceImpl implements OrderService{
private Connection connection;
private ProductDao productDao;
private OrdersDao orderDao;
private Orders orders;
public OrderServiceImpl(Connection connection, ProductDao productDao, OrdersDao orderDao) {
this.connection = connection;
this.productDao = productDao;
this.orderDao = orderDao;
}
@Override
public void 주문하기(int customerId, int productId) {
// 1. 재고확인 ( 재고가 0보다 큰가? product findById)
Product o = productDao.findById(productId);
if(o.getQty() >0) {
// 2. 주문하기 ( order insert)
int result1 = orderDao.insert(orders);
// 3. 재고 -1 하기 ( product updateByIdToQty)
int result2 = productDao.updateByIdToQty(productId);
try {
if(result1==1 && result2 ==1) {
connection.commit();
}else {
connection.rollback();
}
} catch (Exception e) {
e.printStackTrace();
}
}else {
System.out.println("재고없음");
}
}
@Override
public void 주문취소하기(int id) {
// 1. order deleteById
int result1 = orderDao.deleteById(id);
// 2. product qty + 1 하기
int result2 = productDao.updateByIdToQty2(id);
try {
if(result1==1 && result2 ==1) {
connection.commit();
}else {
connection.rollback();
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public ArrayList<OrderRespDto> 고객별주문목록보기(int customerId) {
return orderDao.findByIdToOrderList(customerId);
}
}
10.MainApp
package product;
import java.sql.Connection;
import java.util.ArrayList;
import product.db.DBConnection;
import product.domain.customer.CustomerDao;
import product.domain.orders.OrdersDao;
import product.domain.product.ProductDao;
import product.dto.OrderRespDto;
import product.service.OrderService;
import product.service.OrderServiceImpl;
public class MainApp {
public static void main(String[] args) {
Connection conn = DBConnection.connection();
CustomerDao customerDao = new CustomerDao(conn);
ProductDao productDao = new ProductDao(conn);
OrdersDao orderDao = new OrdersDao(conn);
OrderService orderService = new OrderServiceImpl(conn, productDao, orderDao);
// given
int customerId = 1;
ArrayList<OrderRespDto> orderRespDtoList =
orderService.고객별주문목록보기(customerId);
for (int i = 0; i < orderRespDtoList.size(); i++) {
System.out.println(orderRespDtoList.get(0).getId());
System.out.println(orderRespDtoList.get(0).getUsername());
System.out.println(orderRespDtoList.get(0).getName());
System.out.println(orderRespDtoList.get(0).getPrice());
}
orderService.주문하기(customerId, customerId);
orderService.주문취소하기(customerId);
}
}
고객별주문목록보기 풀이와 주문하기, 주문취소하기에 대한 주석힌트를 받은 상태로 구현한거라 온전히 내 힘으로 푼건 아니지만 몇시간동안 머리 굴려서 혼자 풀어냈다는게 뿌듯하다.
주말과제
Board [id, title, content + memberId], Member [id, username, password], Comment[id, content, boardId, memberId]
세개의 테이블로 엔티티 / DAO / DTO (Board id, title, username, 댓글수) 구현
힌트 OUTER JOIN 사용.
'데이터베이스 > 실습' 카테고리의 다른 글
주말 과제 (0) | 2022.08.22 |
---|---|
데이터베이스 CRUD 생성 (0) | 2022.08.16 |