일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 쿠버네티스
- 리눅스
- IT
- springboot
- 스프링부트
- Linux
- Java
- 자바
- 운영체제
- Python
- 카카오
- 스프링
- 프로그래머스 #카카오 #IT #코딩테스트
- 백엔드
- 도커
- 프로그래머스
- programmers
- 파이썬
- Elasticsearch
- Spring
- DPDK
- 캐시
- Kakao
- 개발자
- docker
- C
- 네트워크
- 엘라스틱서치
- 알고리즘
- 코딩테스트
- Today
- Total
저고데
[쇼핑몰만들기] 5. 주문 기능을 추가해보자 본문
주문 테이블 생성하기
장바구니의 친구인 주문 기능을 만들어보도록 하자.
우선 Order라는 이름을 가진 테이블을 아래와 같이 생성해주었다.
@Getter
@Setter
@Entity
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
@ManyToOne
@JoinColumn(name = "item_id")
private Item item;
private Long count;
}
하지만 바로 문제가 발생했다 !
JPA에서 구체적으로 테이블명을 선언하지 않으면 class명으로 테이블이 생성된다.
따라서 Order라는 테이블이 생성되어야 정상이지만, Order는 MySQL에서 사용하는 예약어이기 때문에 발생한 문제였다.
그러므로 @Table 어노테이션을 사용하여 구체적인 테이블명을 선언해주었다.
@Getter
@Setter
@Entity
@Table(name = "orders") // 추가된 부분
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
@ManyToOne
@JoinColumn(name = "item_id")
private Item item;
private Long count;
}
소셜 로그인 문제 해결하기
그리고 상품을 눌렀을 때, '구매하기'와 '장바구니 추가' 기능을 볼 수 있게 화면을 만들어주었다.
<div th:if="${item}" style="margin-top: 1%; margin-left: 1%; width: 50%;">
<p th:text="${item.name}" style="font-size: 1.5em; font-weight: bold;"></p>
<p th:text="${item.price}" style="font-size: 1.2em; color: #000000; margin-bottom: 10px;"></p>
<label for="quantity" style="font-size: 1.2em; margin-right: 10px;">수량:</label>
<input type="number" id="quantity" name="quantity" value="1" min="1" style="padding: 5px; width: 50px;">
<form action="/purchase" method="post" id="purchaseForm" style="display: inline-block; margin-right: 10px;">
<input type="hidden" name="quantity" th:valued="${quantity}" />
<input type="hidden" name="id" th:value="${item.id}" />
<button type="submit" style="padding: 8px; background-color: #000000; color: white; border: none; border-radius: 5px; cursor: pointer;">구매</button>
</form>
<form action="/cart/add" method="post" id="cartForm" style="display: inline-block;">
<input type="hidden" name="quantity" th:value="${quantity}" />
<button type="submit" style="padding: 8px; background-color: #3c4e54; color: white; border: none; border-radius: 5px; cursor: pointer;">장바구니에 담기</button>
</form>
</div>
하지만 여기서 가장 큰 문제가 발생하였다.
SecurityConfig에서 상품을 주문하고 장바구니에 추가하는 경로를 모두 허용했음에도 불구하고 소셜 로그인 화면으로 이동하는 문제가 계속 발생하였다.
문제 해결 과정 1 : Get 요청이 아닌 Post 요청은 따로 설정을 해야하는 걸까?
.requestMatchers("/login", "/register", "/login", "/upload", "/mypage", "/cart/**", "/item/**").permitAll()
이전의 경로들은 모두 Get 요청이여서, Post 요청은 다르게 해야하나 생각했었다.
심지어 해당 메서드에는 .requestMatchers(Http 호출 종류, 경로 ...) 형태도 가능하였기 때문에, Post 요청은 별도로 표시해야하나 싶었다.
따라서 Post 요청을 따로 추가하여 다시 실행해보았다.
하지만 이 역시도 해결하지 못하였다.
문득, 회원가입 화면에서 정보를 입력한 후에 submit을 누르면 post 요청으로 "/register" 경로에 접근하는 것이 생각났다.
<form action="/register" method="post">
<label for="name">이름</label>
<input type="text" id="name" name="name" required>
<label for="username">아이디</label>
<input type="text" id="username" name="username" required>
<label for="password">비밀번호</label>
<input type="password" id="password" name="password" required>
<input type="submit" value="회원가입">
</form>
그렇다는 것은 ... SecurityConfig에서 요청의 종류는 관계가 없다는 것이다.
문제 해결 과정 2 : 우선 소셜 로그인으로 접근을 해보자.
도저히 원인을 알 수가 없어서, 소셜 로그인으로 "주문하기"와 "장바구니 추가"를 했을 때, 이상이 없는지 확인하였다.
그런데 이 역시도 문제가 발생하였다.
접근 경로가 스프링 부트 내에서 설정한 경로가 아니기 때문에 화면을 보여줄 수 없다는 내용이었다.
그렇다 !!
이건 html에서의 문제라고 판단했다.
<div th:if="${item}" style="margin-top: 1%; margin-left: 1%; width: 50%;">
<p th:text="${item.name}" style="font-size: 1.5em; font-weight: bold;"></p>
<p th:text="${item.price}" style="font-size: 1.2em; color: #000000; margin-bottom: 10px;"></p>
<label for="quantity" style="font-size: 1.2em; margin-right: 10px;">수량:</label>
<input type="number" id="quantity" name="quantity" value="1" min="1" style="padding: 5px; width: 50px;">
<form action="/purchase" method="post" id="purchaseForm" style="display: inline-block; margin-right: 10px;">
<input type="hidden" name="quantity" th:valued="${quantity}" />
<input type="hidden" name="id" th:value="${item.id}" />
<button type="submit" style="padding: 8px; background-color: #000000; color: white; border: none; border-radius: 5px; cursor: pointer;">구매</button>
</form>
<form action="/cart/add" method="post" id="cartForm" style="display: inline-block;">
<input type="hidden" name="quantity" th:value="${quantity}" />
<button type="submit" style="padding: 8px; background-color: #3c4e54; color: white; border: none; border-radius: 5px; cursor: pointer;">장바구니에 담기</button>
</form>
</div>
기존의 form을 통해서는 하나의 경로만 접근이 가능하다.
하지만, 필자는 기존의 쇼핑몰 화면처럼 "주문하기" 옆에 "장바구니 추가" 기능을 한 화면에 보여주고 싶었기 때문에 form을 세 개를 두었다.
먼저, 실질적으로 사용자의 눈에 보여서 수량을 선택할 수 있는 form과
두번째로, "주문하기" 경로에 post 요청으로 선택된 수량과 상품의 아이디를 전달하는 form,
마지막으로 "장바구니 추가" 경로에 post 요청으로 선택된 수량과 상품의 아이디를 전달하는 form 이렇게 세 개 말이다.
첫번째 form에서 수량을 선택하면 두, 세번째 form에서 th 기능을 통해서 자동으로 이를 받아올 수 있을 줄 알았다.
하지만 그러지 못해서 오류가 발생한 것이였다. (어쩐지, th:value="${quantity}" 부분에 계속 노란색 밑줄이 있었다.)
따라서, 첫번째 form에서 수량을 선택할 시에 자동으로 해당 값을 배껴오는 형태의 함수를 JavaScript로 작성하여 문제를 해결하였다.
<div th:if="${item}" style="margin-top: 1%; margin-left: 1%; width: 50%;">
<p th:text="${item.name}" style="font-size: 1.5em; font-weight: bold;"></p>
<p th:text="${item.price}" style="font-size: 1.2em; color: #000000; margin-bottom: 10px;"></p>
<label for="quantity" style="font-size: 1.2em; margin-right: 10px;">수량:</label>
<input type="number" id="quantity" name="quantity" value="1" min="1" style="padding: 5px; width: 50px;">
<form action="/purchase" method="post" id="purchaseForm" style="display: inline-block; margin-right: 10px;">
<input type="hidden" name="quantity" id="hiddenQuantity" />
<input type="hidden" name="id" th:value="${item.id}" />
<button type="submit" style="padding: 8px; background-color: #000000; color: white; border: none; border-radius: 5px; cursor: pointer;">구매</button>
</form>
<form action="/cart/add" method="post" id="cartForm" style="display: inline-block;">
<input type="hidden" name="quantity" id="hiddenCartQuantity" />
<button type="submit" style="padding: 8px; background-color: #3c4e54; color: white; border: none; border-radius: 5px; cursor: pointer;">장바구니에 담기</button>
</form>
<script>
document.getElementById('quantity').addEventListener('input', function () {
var quantity = this.value;
document.getElementById('hiddenQuantity').value = quantity;
document.getElementById('hiddenCartQuantity').value = quantity;
});
</script>
</div>
해당 문제를 해결하는데만 3시간 정도가 소요되었다. (진심으로 할 맛이 안났어요 ㅠㅠ)
드디어 소셜 로그인 화면으로 이동하지 않고 수량과 상품의 아이디를 잘 반환하는 것을 확인할 수 있었다.
@PostMapping("/purchase")
public String create(ItemForm itemForm) {
SessionUser sessionUser = (SessionUser) httpSession.getAttribute("user");
if (sessionUser == null) {
return "redirect:/login";
}
System.out.println(itemForm.getQuantity());
System.out.println(itemForm.getId());
return "redirect:/";
}
마치며
오늘은 이렇게 주문하기 기능을 추가해보았다. (50%도 안되지만 ...)
개발 과정에서 오류도 많이 발생하고 마음대로 작성이 되지 않아서 사진도 많이 못찍고 설명만 글로 줄줄히 적은 것 같다. (그래도 누군가에게 큰 힘이 되었으면 합니다.)
간단한 쇼핑몰을 만드는 것도 이렇게 어려운데, 조금 더 수련이 필요해보인다.
다음 시간에는 주문하기 기능을 마저 완성해보도록 하겠다.
'쇼핑몰만들기' 카테고리의 다른 글
[쇼핑몰만들기] 6. 주문과 장바구니 정복하기. (0) | 2024.03.13 |
---|---|
[쇼핑몰만들기] 4. 장바구니 기능을 만들어보자 (0) | 2024.03.11 |
[쇼핑몰만들기] 3. 로그인 기능을 다듬고 상품 등록 기능을 추가하자 (0) | 2024.03.08 |
[쇼핑몰만들기] 2. 자체 로그인을 만들어보자 (1) | 2024.03.03 |
[쇼핑몰만들기] 1. 구글 로그인 구현 (0) | 2024.03.02 |