스프링부트+jsp로 배달사이트 만들기-14 주문완료

2021. 12. 8. 16:52스프링부트

주문 시 db에 저장 할 주문 정보는 order테이블에 메뉴정보는 order_detail테이블에 json으로 저장합니다

json을 편하게 변환하기 위해 gson라이브러리를 사용하겠습니다

		<!-- json 변환 -->
		<dependency>
			<groupId>com.google.code.gson</groupId>
			<artifactId>gson</artifactId>
		</dependency>

저장 후 maven 업데이트를 해도 에러가 뜰때가 있는데 이럴땐 서버를 완전히 종료 후 재실행하면 적용됩니다

 

https://sumin2.tistory.com/7

 

JSON 변환하기 (Gson , json-simple)

1. Gson 라이브러리로 변환하기 2. json-simple 라이브러리로 변환하기 1. Gson maven 라이브러리 추가 com.google.code.gson gson 변환할 클래스 class Student { String name; int age; public Student(String n..

sumin2.tistory.com

 

메뉴 정보를 담을 클래스를 생성합니다

@Getter
@Setter
@ToString
@AllArgsConstructor
public class OrderDetail {
	private String orderNum;
	private String foodInfoJSON;
}

 

OrderController  payment메서드의 주문처리 부분을 주석 해제하고 service, dao를 추가합니다

 

orderService

public String order(CartList cart, OrderInfo info, LoginService user, HttpSession session);

 

orderServiceImp

	@Transactional
	@Override
	public String order(CartList cart, OrderInfo info, LoginService user, HttpSession session) {
		Gson gson = new Gson();
		
		System.out.println("info = " + info);
		
		int total = cart.getCartTotal();
		
		info.setStoreId(cart.getStoreId());
		info.setTotalPrice(total);
		
		long userId = 0;
		if (user != null) {
			userId = user.getUser().getId();
			info.setUserId(userId);
		}
		
		List<Cart> cartList = cart.getCart();
		
		OrderDetail[] detail = new OrderDetail[cartList.size()];
		
		
		for(int i=0;i<detail.length;i++) {
			String cartJSON = gson.toJson(cartList.get(i));
			detail[i] = new OrderDetail(info.getOrderNum(), cartJSON);
		}
		
		orderDAO.order(info);
		orderDAO.orderDetail(detail, userId);
		
		
		
		return null;
	}

주문정보와 메뉴정보를 db에 입력하다 에러가 날 경우 전부 취소하기 위해 @Transactional를 붙여줍니다

 

orderDAO

	// 주문 정보 입력
	void order(OrderInfo info);
	
	// 주문 상세정보 입력
	void orderDetail(OrderDetail[] detail, long userId);

 

orderDAOImp

	@Override
	public void order(OrderInfo info) {
		sql.insert("order.order", info);
	}

	@Override
	public void orderDetail(OrderDetail[] detail, long userId) {
		Map<String, Object> map = new HashMap<>();
		map.put("userId", userId);
		map.put("detail", detail);
		sql.insert("order.orderDetail", map);
	}

 

 

orderMappler.xml

<insert id="order">
		<if test="userId == 0">
			INSERT INTO BM_ORDER_NON_USER (
			    ORDER_NUM
			    ,STORE_ID 
			    ,USER_ID 
			    ,PAY_METHOD 
			    ,PHONE
			    ,DELEVERY_ADDRESS1
			    ,DELEVERY_ADDRESS2
			    ,DELEVERY_ADDRESS3
			    ,TOTAL_PRICE 
			    ,USED_POINT 
			    ,REQUEST 
		    ) VALUES (
			    ${orderNum }
			    ,#{storeId }
			    ,#{userId }
			    ,#{payMethod }
			    ,#{phone }  
			    ,#{deleveryAddress1 }
			    ,#{deleveryAddress2 }
			    ,#{deleveryAddress3 } 
			    ,#{totalPrice } 
			    ,#{usedPoint } 
			    ,#{request } 
		    )
		</if>
		
		
		<if test="userId != 0">
			INSERT INTO BM_ORDER_USER (
			     ORDER_NUM
			    ,STORE_ID 
			    ,USER_ID 
			    ,PAY_METHOD 
			    ,PHONE
			    ,DELEVERY_ADDRESS1
			    ,DELEVERY_ADDRESS2
			    ,DELEVERY_ADDRESS3
			    ,TOTAL_PRICE 
			    ,USED_POINT 
			    ,REQUEST 
		    ) VALUES (
			    ${orderNum }
			    ,#{storeId }
			    ,#{userId }
			    ,#{payMethod }
			    ,#{phone }  
			    ,#{deleveryAddress1 }
			    ,#{deleveryAddress2 }
			    ,#{deleveryAddress3 } 
			    ,#{totalPrice } 
			    ,#{usedPoint } 
			    ,#{request } 
		    )
		</if>
	</insert>

insert all문은 하나의 쿼리로 insert를 여러번 할 수 있는데 select문의 들어가야 하기 때문에 SELECT * FROM DUAL을 붙여 주었습니다

 

실행 결과

 

 

로그인 이용자는 주문 완료 시 포인트 적립이 되야 합니다

OrderServiceImp의 order메서드 아래에 코드를 추가합니다

// 회원 포인트 적립
if (user != null) {
    String storeName = cart.getStoreName();
    int point = (int)(total * 0.01); 
    int result = adminDAO.pointUpdate(userId, storeName, point);
    if(result == 1) {
        UserInfoSessionUpdate.sessionUpdate(point+"", "point", user, session);
    }
}

 

포인트 업데이트 관련 메서드는 adminDAO를 따로 만들어서 추가하겠습니다

OrderServiceImp에 의존성을 추가하고 adminDAO를 생성합니다

@Autowired
private AdminDAO adminDAO;

 

public interface AdminDAO {
	
	int pointUpdate(long userId, String info, int point);

}

 

@Repository
public class AdminDAOImp implements AdminDAO {

	@Autowired
	private SqlSession sql;
	
	@Override
	public int pointUpdate(long userId, String info, int point) {
		Map<String, Object> map = new HashMap<>();
		map.put("userId", userId);
		map.put("info", info);
		map.put("point", point);
		
		return sql.insert("admin.pointUpdate", map); 
	}
}

 

adminMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="admin">

	<insert id="pointUpdate" >
		INSERT INTO BM_POINT (
			USER_ID
			,INFO
			,POINT
		) VALUES (
			#{userId }
			,#{info }
			,#{point }
		)
	</insert>
	
</mapper>

이제 db에는 포인트가 업데이트 되지만 아직 세션이 업데이트되지 않아 재로그인 하기 전까진 포인트사용을 할 수 없습니다

세션 업데이트를 위해 util패키지에 클래스를 추가합니다

public class UserInfoSessionUpdate {

	public static void sessionUpdate(String value, String valueType, LoginService user, HttpSession session) {

		LoginService loginService = (LoginService) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
		
		if(valueType.equals("nickname")) {
			loginService.getUser().setNickname(value);
		} 
		else  if(valueType.equals("password")) {
			loginService.getUser().setPassword(value);
		}
		else if(valueType.equals("point")) {
			int point = loginService.getUser().getPoint() + Integer.parseInt(value);
			loginService.getUser().setPoint(point);
		}

		SecurityContext sc = SecurityContextHolder.getContext();

		sc.setAuthentication(new UsernamePasswordAuthenticationToken(loginService, null, user.getAuthorities()));
		
		session.setAttribute("SPRING_SECURITY_CONTEXT", sc);
	}
}

나중에 구현할 닉네임, 비밀번호 업데이트 코드를 미리 추가했습니다

 

이제 주문시 포인트가 적립되는 걸 볼 수 있습니다

-- 그런데 이 기능은 주문 시가 아니라 가게에서 주문을 수락하고 배달 완료가 될 때 적립되도록 변경 하는게 좋을거같습니다 

 

 

마찬가지로 포인트를 사용하면 포인트가 차감되야 합니다

OrderServiceImp의 order메서드 아래에 코드를 추가합니다

// 로그인 사용자가 포인트 사용했을때
if(info.getUsedPoint() != 0 ) {
    String storeName =  cart.getStoreName();
    int usedPoint =  -info.getUsedPoint();
    int result = adminDAO.pointUpdate(userId, storeName, usedPoint);
    
    if(result == 1) {
        UserInfoSessionUpdate.sessionUpdate(usedPoint+"", "point", user, session);
    }
}

 

실행 결과

 

 

 

 


주문 완료후 주문 목록을 보기 위해 Controller에 추가합니다

@GetMapping("/orderList")
public String orderList(@AuthenticationPrincipal LoginService user, Model model) {
    if (user == null) {
        System.out.println("비로그인");
    } else {
        System.out.println("로그인");
        long userId = user.getUser().getId();

        List<OrderList> orderList = orderService.orderList(userId);

        if (orderList.size() == 0) {
            return "order/orderList";
        }

        List<List<Cart>> cartList = new ArrayList<>();

        for (int i=0;i<orderList.size();i++) {
            cartList.add(FoodInfoFromJson.foodInfoFromJson(orderList.get(i).getFoodInfo()));
        }
        
        model.addAttribute("user", user.getUser());
        model.addAttribute("cartList", cartList);
        model.addAttribute("orderList", orderList);
    }

    return "order/orderList";
}

 

 

 

service, dao를 추가합니다

orderService

// 주문목록
List<OrderList> orderList(long userId);

 

orderServiceImp

@Override
public List<OrderList> orderList(long userId) {
	return orderDAO.orderList(userId);
}

 

orderDAO

List<OrderList> orderList(long userId);

 

orderDAOImp

@Override
public List<OrderList> orderList(long userId) {
	return sql.selectList("order.orderList", userId);
}

 

orderMapper.xml

	<select id="orderList" resultType="OrderList">
	SELECT * FROM (
    	SELECT	ROWNUM R
    			,O.* 
    	FROM 	(SELECT	count(*) over() list_count,
				    	o.order_num,
				    	o.user_id,
				    	o.order_date,
				    	o.pay_method,
				    	o.delevery_status,
				    	o.delevery_address1,
				    	o.delevery_address2,
				    	o.delevery_address3,
				    	o.store_id,
				    	o.total_price,
				    	o.used_point,
                        o.request,
                        d.food_info,
				    	s.store_name,
					    s.store_img,
					    s.store_thumb,
					    s.delevery_tip,
			            r.review_content,
			            r.score,
			            r.review_img
			FROM		bm_order_user o
			LEFT JOIN   (SELECT  ORDER_NUM, 
                                 LISTAGG(FOOD_INFO, '/') food_info
                        FROM     BM_ORDER_DETAIL_USER 
                        GROUP BY ORDER_NUM) d
			ON		  	o.order_num = d.order_num
			LEFT JOIN	bm_store s
			ON		 	o.store_id = s.id 
	        LEFT JOIN	bm_review r
	        ON			o.order_num = r.order_num
			WHERE		o.user_id = #{userId }
			ORDER BY	o.order_date desc  
	        ) O
		) 
	</select>

listagg는 첫번 째 인자의 결과가 여러개가 있을 때 두번 째 인자의 구분자로 합쳐서 하나의 컬럼으로 보여줍니다

 

listagg 사용x

 

listagg 사용o

 

 

불러온 json형태의 메뉴 정보를 오브젝트로 변환하기 위해 util패키지에 추가합니다 

public class FoodInfoFromJson {

	public static List<Cart> foodInfoFromJson(String foodInfoJSON) {
		Map<String, Object>  map = new HashMap<>();
		String[] arr = foodInfoJSON.split("/");
		Gson gson = new Gson();
		
		List<Cart> cartList = new ArrayList<>();
		for(int i=0;i<arr.length;i++) {
			cartList.add(gson.fromJson(arr[i], Cart.class));
		}
		return cartList;
	}
}

 

이제 화면을 보여줄 jsp,css와 js를 추가합니다

주문.zip
0.00MB

 

리뷰 모달에서 이미지 첨부시 미리보기 기능을 위해 util.js에 코드를 추가합니다

function imgPreview(e,target){
	const previewBox = target.siblings("div");
	const preview = previewBox.find(".preview");
	const fileReader = new FileReader();

	fileReader.readAsDataURL(e.target.files[0]);

	fileReader.onload = function() {
		preview.attr("src", fileReader.result);
		previewBox.css("display", "block");
	}
}
	
	
function imgClose() {
	$(".preview").attr("src", "");
	$(".img").val("");
	$(".img_box div").css("display", "none");
}

 

실행 결과