Servlet/JSP - SubwayStore
# 서브웨이 주문하기
0. VO만들기 (DB에 맞게)
package com.kh.model.vo;
import java.sql.Date;
public class Order {
private String userName;
private String phone;
private String address;
private String message;
private String sandwich;
private String vegetable;
private String sauce;
private String cookie;
private String payment;
private int price;
private Date orderDate;
public Order() {
super();
}
public Order(String userName, String phone, String address, String message, String sandwich, String vegetable,
String sauce, String cookie, String payment, int price, Date orderDate) {
super();
this.userName = userName;
this.phone = phone;
this.address = address;
this.message = message;
this.sandwich = sandwich;
this.vegetable = vegetable;
this.sauce = sauce;
this.cookie = cookie;
this.payment = payment;
this.price = price;
this.orderDate = orderDate;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getSandwich() {
return sandwich;
}
public void setSandwich(String sandwich) {
this.sandwich = sandwich;
}
public String getVegetable() {
return vegetable;
}
public void setVegetable(String vegetable) {
this.vegetable = vegetable;
}
public String getSauce() {
return sauce;
}
public void setSause(String sauce) {
this.sauce = sauce;
}
public String getCookie() {
return cookie;
}
public void setCookie(String cookie) {
this.cookie = cookie;
}
public String getPayment() {
return payment;
}
public void setPayment(String payment) {
this.payment = payment;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public Date getOrderDate() {
return orderDate;
}
public void setOrderDate(Date orderDate) {
this.orderDate = orderDate;
}
@Override
public String toString() {
return "Order [userName=" + userName + ", phone=" + phone + ", address=" + address + ", message=" + message
+ ", sandwich=" + sandwich + ", vegetable=" + vegetable + ", sauce=" + sauce + ", cookie=" + cookie
+ ", payment=" + payment + ", price=" + price + "]";
}
}
1. 사용자에게 주문을 받을 화면
<index.jsp>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>안녕하세요 서브웨이입니다 ~ </title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@100&family=Roboto+Condensed:wght@300&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css">
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
<style>
body {
margin : 0px;
padding : 0px;
color:blanchedalmond;
}
#img{
display: none;
position: absolute;
top : 250px;
left : 1000px;
}
#title{
text-align:center;
font-size:45px;
}
#title1{
color: #ffce32;
}
#title2{
color: #009223;
}
#header {
background-color: white;
padding-bottom: 10px;
line-height:100px
}
#btn-zone{
text-align:right;
padding-right: 20px;
}
.wrap{
width : 820px;
height : 830px;
margin : auto;
}
.content{
font-family: 'Noto Sans KR', sans-serif;
font-weight: bold;
background-color: #009222;
border-radius: 20px;
}
table {
border-collapse: separate;
border-spacing: 0 5px;
}
input[type=checkbox]{
margin-right: 10px;
margin-left : 5px;
}
th, legend{
padding-left: 20px;
}
a {
text-decoration: none;
color: crimson;
}
</style>
</head>
<body>
<div class="wrap">
<div id="header">
<h1 id="title">
<span id="title1">SUB</span><span id="title2">WAY</span>
</h1>
</div>
<!--
서버를 요청할 때 : 항상 form태그로 넘겼음(submit버튼_
form태그에 항상 있어야하는 것 : action속성(어느 서블릿으로 보낼건지)
method속상(get/post)
-->
<div class="content">
<br><br>
<form action="/3_SubwayStore/order.do" method="get">
<fieldset>
<legend>주문자 정보</legend>
<table>
<tr>
<th width="130">이름</th>
<td><input type="text" name="userName" class="form-control" required></td>
</tr>
<tr>
<th>전화번호</th>
<td><input type="text" name="phone" class="form-control" required></td>
</tr>
<tr>
<th>주소</th>
<td><input type="text" name="address" class="form-control" required></td>
</tr>
<tr>
<th>요청사항</th>
<td><textarea name="message" cols="80" rows="5" class="form-control" style="resize:none"></textarea></td>
</tr>
</table>
</fieldset>
<br>
<fieldset>
<legend>주문 정보</legend>
<table>
<tr>
<th width="130">샌드위치</th>
<td>
<select name="sandwich" class="form-control">
<option>스테이크 & 치즈</option>
<option>로티세리 바비큐 치킨</option>
<option>스파이시 바비큐</option>
<option>K-바비큐</option>
<option>풀드 포크 바비큐</option>
<option>머쉬룸</option>
<option>쉬림프</option>
<option>로스트 치킨</option>
<option>치킨 데리야끼</option>
<option>서브웨이 클럽</option>
<option>치킨 슬라이스</option>
<option>참치</option>
<option>에그마요</option>
<option>이탈리안 비엠티</option>
<option>터키 베이컨 아보카도</option>
</select>
</td>
</tr>
<tr>
<th>채소</th>
<td>
<input type="checkbox" name="vegetable" value="오이" checked><label>오이</label>
<input type="checkbox" name="vegetable" value="양배추" checked>양배추
<input type="checkbox" name="vegetable" value="올리브" checked>올리브
<input type="checkbox" name="vegetable" value="할라피뇨" checked>할라피뇨
<input type="checkbox" name="vegetable" value="적양파" checked>적양파
<input type="checkbox" name="vegetable" value="피망" checked>피망
<input type="checkbox" name="vegetable" value="토마토" checked>토마토
</td>
</tr>
<tr>
<th>소스</th>
<td>
<input type="checkbox" name="sauce" value="랜치">랜치
<input type="checkbox" name="sauce" value="후추">후추
<input type="checkbox" name="sauce" value="스위트 어니언">스위트 어니언
<input type="checkbox" name="sauce" value="스위트 칠리">스위트 칠리
<input type="checkbox" name="sauce" value="핫칠리">핫 칠리
<input type="checkbox" name="sauce" value="마요네즈">마요네즈
<input type="checkbox" name="sauce" value="홀스래디쉬">홀스래디쉬
</td>
</tr>
<tr>
<td></td>
<td>
<input type="checkbox" name="sauce" value="스모크 바비큐">스모크 바비큐
<input type="checkbox" name="sauce" value="허니 머스타드">허니 머스타드
<input type="checkbox" name="sauce" value="사우스웨스트 치폴레">사우스웨스트 치폴레
<input type="checkbox" name="sauce" value="이탈리안 드레싱">이탈리안 드레싱
</td>
</tr>
<tr>
<th>쿠키</th>
<td>
<input type="checkbox" name="cookie" value="라즈베리치즈케잌">라즈베리치즈케잌
<input type="checkbox" name="cookie" value="더블초코칩쿠키">더블초코칩쿠키
<input type="checkbox" name="cookie" value="스모어초코어쩌고">스모어초코어쩌고
</td>
</tr>
<tr>
<th>결제방식</th>
<td>
<input type="radio" name="payment" value="card" checked> 카드결제
<input type="radio" name="payment" value="cash"> 현금결제
</td>
</tr>
</table>
</fieldset>
<br>
<hr>
<div id="btn-zone">
<input type="submit" class="btn btn-info" value="주문하기">
<input type="reset" class="btn btn-warning" value="초기화">
</div>
</form>
<br>
</div>
<br>
</div>
<a href='/3_SubwayStore/orderList.sandwich'>주문내역보기</a>
<br>
<div id="img">
<img id="sandimg" src="">
</div>
<script>
$(function(){
$('select').change(function(){
var sand = $(this).val();
sandwich = {
'스테이크 & 치즈' : 'https://www.subway.co.kr/upload/menu/Steak-&-Cheese_20211231095455613.png',
'스파이시 이탈리안' : 'https://www.subway.co.kr/upload/menu/spicy_italian_20211231095435532.png',
'로티세리 바비큐 치킨' : 'https://www.subway.co.kr/upload/menu/Rotisserie-Barbecue-Chicken_20211231023137878.png',
'스파이시 바비큐' : 'https://www.subway.co.kr/upload/menu/%EC%8A%A4%ED%8C%8C%EC%9D%B4%EC%8B%9C%EB%B0%94%EB%B9%84%ED%81%90_%EC%A0%95%EB%A9%B4_20221031041334845.png',
'K-바비큐' : 'https://www.subway.co.kr/upload/menu/K-BBQ_20211231094930225.png',
'풀드 포크 바비큐' : 'https://www.subway.co.kr/upload/menu/Pulled-Pork+cheese_20211231095012512.png',
'머쉬룸' : 'https://www.subway.co.kr/upload/menu/%EB%A8%B8%EC%89%AC%EB%A3%B8_%EC%83%8C%EB%93%9C%EC%9C%84%EC%B9%98_20220715112921467.png',
'쉬림프' : 'https://www.subway.co.kr/upload/menu/Shrimp_20211231095411189.png',
'로스트 치킨' : 'https://www.subway.co.kr/upload/menu/Roasted-Chicken_20211231095032718.png',
'치킨 데리야끼' : 'https://www.subway.co.kr/upload/menu/Chicken-Teriyaki_20211231094803381.png',
'서브웨이 클럽' : 'https://www.subway.co.kr/upload/menu/Subway-Club%E2%84%A2_20211231095518589.png',
'치킨 슬라이스' : 'https://www.subway.co.kr/upload/menu/%EC%B9%98%ED%82%A8%EC%8A%AC%EB%9D%BC%EC%9D%B4%EC%8A%A4%EC%83%8C%EB%93%9C%EC%9C%84%EC%B9%98_20220804012537491.png',
'참치' : 'https://www.subway.co.kr/upload/menu/Tuna_20211231095535268.png',
'에그마요' : 'https://www.subway.co.kr/upload/menu/Egg-Mayo_20211231094817112.png',
'이탈리안 비엠티' : 'https://www.subway.co.kr/upload/menu/Italian_B.M.T_20211231094910899.png',
'터키 베이컨 아보카도' : 'https://www.subway.co.kr/upload/menu/%EC%B9%98%ED%82%A8%EB%B2%A0%EC%9D%B4%EC%BB%A8%EC%95%84%EB%B3%B4%EC%B9%B4%EB%8F%84%EC%83%8C%EB%93%9C%EC%9C%84%EC%B9%98_20220804012954461.png'
};
for(var key in sandwich){
if(sand == key){
$('#sandimg').attr('src', sandwich[key]);
break;
}
};
$('#img').show(1000);
setTimeout(() => {
$('#img').hide(1000);
}, 4000);
});
});
</script>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
</body>
</html>
서버를 요청할 때 : 항상 form태그로 넘겼음(submit버튼)
form태그에 항상 있어야하는 것 : action속성(어느 서블릿으로 보낼건지), method속성(get/post)
<form action="/3_SubwayStore/order.do" method="get">
2. <com.kh.controller>SubwayOrderController
<요청>
1) POST방식일 때만 => 인코딩
2) 뽑기 => request의 Parameter영역에서 (request.getParameter("키값") / request.getParmeterValues("키값")
뽑아서 변수에 담아야 함
- 주문자정보뽑기
String userName = request.getParameter("userName");
String phone = request.getParameter("phone");
String address = request.getParameter("address");
String message = request.getParameter("message");
- 주문 정보 뽑기
checkbox == request.ParameterValues(); => String[] => 체크된 게 하나도 없을 때 null
String sandwich = request.getParameter("sandwich");
String[] vegetable = request.getParameterValues("vegetable");
String[] sauce = request.getParameterValues("sauce");
String[] cookie = request.getParameterValues("cookie");
String payment = request.getParameter("payment");
3) 가공 => VO클래스 객체 생성해서 거기 담았음
- 가격책정할 변수 초기화(지역변수는 항상 초기화)
int price = 0;
- 샌드위치에 따른 가격
switch(sandwich) {
case "스테이크 & 치즈" : price += 6000; break;
case "로티세리 바비큐 치킨" : price += 7000; break;
case "스파이시 바비큐": price += 6400; break;
case "K-바비큐": price += 6100; break;
case "풀드 포크 바비큐": price += 6700; break;
case "머쉬룸": price += 5000; break;
case "쉬림프": price += 6900; break;
case "로스트 치킨": price += 6800; break;
case "치킨 데리야끼": price += 5500; break;
case "서브웨이 클럽": price += 6500; break;
case "치킨 슬라이스": price += 5600; break;
case "참치": price += 4500; break;
case "에그마요": price += 4500; break;
case "이탈리안 비엠티": price += 6300; break;
case "터키 베이컨 아보카도": price += 6200; break;
}
- 쿠키 종류에 따라서 추가금액 더하기
배열의 경우 체크된 게 없을 때 null이기 때문에
무작정 반복문을 돌리면 NullPointException발생할 가능성이 있음
=> if문으로 애초에 발생 안하게 막는걸 권장
if(cookie != null) {
for(int i = 0; i<cookie.length; i++) {
switch(cookie[i]) {
case "라즈베리치즈케잌" :
case "더블초코칩쿠키" :
case "스모어초코어쩌고" : price += 2300; break;
}
}
}
- VO객체에 담기
Order order = new Order(userName,
phone,
address,
message,
sandwich,
String.join(",", vegetable),
String.join(",", sauce),
String.join(",", cookie),
payment,
price,
null);
order_date는 어차피 default가 sysdate이기 때문에 null값을 전달해줌(따로 값을 전달할 필요가 없기때문에)
<응답>
4) Service단으로 전달하기 => 결과값
int result = new SubwayService().insertOrder(order);
5) request의 Attribute영역에 담기 & 응답화면 지정
request.setAttribute("sandwich", sandwich);
request.setAttribute("vegetable", vegetable);
request.setAttribute("sause", sauce);
request.setAttribute("cookie", cookie);
request.setAttribute("payment", payment );
request.setAttribute("price", price);
- 응답뷰지정 => 응답화면 jsp파일로 하나 만들어서 보내기
WebContent/views/~~~.jsp
포워딩 방식으로
if(result>0) {
RequestDispatcher view = request.getRequestDispatcher("views/result.jsp");
view.forward(request, response);
}
3. <com.kh.service>SubwayService
public int insertOrder(Order order) {
//Servies단의 가장 큰 역할 : Connection객체 만들기
Connection conn = JDBCTemplate.getConnection();
//DAO호출
//=> Connection객체, Controller로부터 전달받은 그 무언가하고 같이 넘겨버리기
int result = new SubwayDao().insertOrder(conn, order);
//insert, update, delete를 하면,
//테이블의 내용물이 바뀜 => 확정(COMMIT)돌아가기(ROLLBACK)
if(result > 0) {
JDBCTemplate.commit(conn);
}else {
JDBCTemplate.rollback(conn);
}
//Connection 자원반납
JDBCTemplate.close(conn);
return result;
}
4. <com.kh.dao>SubwayDao
private Properties prop = new Properties();
public SubwayDao() {
//mapper파일의 경로 담아주기
String fileName = SubwayDao.class.getResource("/sql/subway/subway-mapper.xml").getPath();
try {
prop.loadFromXML(new FileInputStream(fileName));
} catch (IOException e) {
e.printStackTrace();
}
DAO단에서 항상 해야할 것
mapper파일 연결
=> 기본생성자
public int insertOrder(Connection conn, Order order) {
//INSERT => INT
int result = 0;
PreparedStatement pstmt = null;
String sql = prop.getProperty("insertOrder");
try {
//pstmt는 항상 conn객체로 만듬(쿼리문을 미리넘김)
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, order.getUserName());
pstmt.setString(2, order.getPhone());
pstmt.setString(3, order.getAddress());
pstmt.setString(4, order.getMessage());
pstmt.setString(5, order.getSandwich());
pstmt.setString(6, order.getVegetable());
pstmt.setString(7, order.getSauce());
pstmt.setString(8, order.getCookie());
pstmt.setString(9, order.getPayment());
pstmt.setInt(10, order.getPrice());
//DML문은 executeUpdate()호출
result = pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCTemplate.close(pstmt);
}
return result;
}
5. <result.jsp> 주문 결과 화면 jsp
사용자가 결제 요청을 했을 때 모두 다 같은 페이지를 보게 된다면 html 을 보여줘도 되지만,
결제는 사용자가 어떤 메뉴를 주문했냐에 따라 다른 페이지를 보게됨 => JSP를 사용해야하는 이유
스크립틀릿 : 자바코드를 그대로 작성(세미콜론을 포함한 완전한 형태로 작성)
포장풀기-> request의 Attribute영역
request.getAttribute("키값"); => Object타입(모든 형태의 부모)
<%
String sandwich = (String)request.getAttribute("sandwich");
String[] vegetable = (String[])request.getAttribute("vegetable");
String[] sauce = (String[])request.getAttribute("sauce");
String[] cookie = (String[])request.getAttribute("cookie");
String payment = (String)request.getAttribute("payment");
int price = (int)request.getAttribute("price");
%>
= : 출력식, 표현식 => jsp화면에 뿌려주는 역할 => 내가 출력할 변수명, 메소드명(호출) => 세미콜론은 X
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%> <!-- 페이지 지시어 -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>주문내역</h1>
샌드위치 : <%= sandwich %> <br>
<%if(vegetable==null){ %>
선택 안 함 <br>
<%}else{ %>
<!-- String.join(연결자, 배열명) -->
채소 : <%= String.join(",", vegetable) %><br>
<%} %>
소스 :
<%if(sauce==null){ %>
선택 안 함 <br>
<%}else{ %>
<!-- String.join(연결자, 배열명) -->
<%= String.join(",", sauce) %><br>
<%} %>
쿠키 :
<%if(cookie==null){ %>
선택 안 함 <br>
<%}else{ %>
<%= String.join(",", cookie) %><br>
<%} %>
결제 방식 : <%=payment %> <br><br>
위와 같이 주문하시겠습니까? <br>
총가격 : <%= price %>원
</body>
</html>
- String.join(연결자, 배열명) : 배열을 문자열로 변환시켜줌
# 서브웨이 주문조회하기
<a href='/3_SubwayStore/orderList.sandwich'>주문내역보기</a>
index.jsp에서 주문내역보기를 click했을 때,
<com.kh.controller>SubwayOrderListController
Service에 요청(Select)
ArrayList<Order> list = new SubwayService().selectOrderList();
request.setAttribute("list", list);
- 조회결과가 있는지 없는지 판단해서 메시지를 리스트 화면으로 보내기
if(list.isEmpty()) {
request.setAttribute("alertMsg", "조회결과가 없습니다.");
}else {
request.setAttribute("alertMsg", "조회결과가 있습니다.");
}
request.getRequestDispatcher("views/admin.jsp").forward(request, response);
}
<com.kh.model.service> SubwayService
public ArrayList<Order> selectOrderList() {
//Service => Connection객체 만들기
Connection conn = JDBCTemplate.getConnection();
ArrayList<Order> list = new SubwayDao().selectOrderList(conn);
JDBCTemplate.close(conn);
return list;
}
<com.kh.model.dao> SubwayDao
public ArrayList<Order> selectOrderList(Connection conn) {
//SELECT => ResultSet => 여러 행 (ArrayList, while문)
//필요한 변수들 셋팅
ArrayList<Order> list = new ArrayList();
PreparedStatement pstmt = null;
ResultSet rset = null;
String sql = prop.getProperty("selectOrderList");
try {
pstmt = conn.prepareStatement(sql);
rset = pstmt.executeQuery();
while(rset.next()) {
Order o = new Order(rset.getString("USER_NAME"),
rset.getString("PHONE"),
rset.getString("ADDRESS"),
rset.getString("MESSAGE"),
rset.getString("SANDWICH"),
rset.getString("VEGETABLE"),
rset.getString("SAUCE"),
rset.getString("COOKIE"),
rset.getString("PAYMENT"),
rset.getInt("PRICE"),
rset.getDate("ORDER_DATE"));
list.add(o);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCTemplate.close(rset);
JDBCTemplate.close(pstmt);
}
return list;
}
<admin.jsp> 결과화면
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.util.ArrayList, com.kh.model.vo.Order" %>
<%
//.getAttribute("키값") => Object
String alertMsg = (String)request.getAttribute("alertMsg");
ArrayList<Order> list = (ArrayList<Order>)request.getAttribute("list");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>주문내역조회</title>
</head>
<body>
<h3></h3>
<table border="1">
<tr>
<th>주문자명</th>
<th>핸드폰번호</th>
<th>주소</th>
<th>요청사항</th>
<th>샌드위치</th>
<th>채소</th>
<th>소스</th>
<th>쿠키</th>
<th>결제수단</th>
<th>총금액</th>
<th>주문일자</th>
</tr>
<% if(list.isEmpty()){ %>
<tr>
<td colspan="11"><%=alertMsg %></td>
</tr>
<% } else { %>
<%for(Order o : list){ %>
<tr>
<td><%= o.getUserName()%></td>
<td><%= o.getPhone()%></td>
<td><%= o.getAddress()%></td>
<td><%= o.getMessage()%></td>
<td><%= o.getSandwich()%></td>
<td><%= o.getVegetable()%></td>
<td><%= o.getSauce()%></td>
<td><%= o.getCookie()%></td>
<td><%= o.getPayment()%></td>
<td><%= o.getPrice()%></td>
<td><%= o.getOrderDate()%></td>
</tr>
<% } %>
<% } %>
</table>
</body>
</html>