購物車業務
購物車業務概要分析
購物車對象封裝分析
購物車實體
public class BuyerCart implements Serializable {
private String sellerId;//商家ID
private String sellerName;//商家名稱
private List<OrderItem> orderItemList;//購物車明細
//..getset
}
購物項實體(在這裏也是訂單項)
public class OrderItem implements Serializable {
private Long id;
/**
* 商品id
*/
private Long itemId;
/**
* SPU_ID
*/
private Long goodsId;
/**
* 訂單id
*/
private Long orderId;
/**
* 商品標題
*/
private String title;
/**
* 商品單價
*/
private BigDecimal price;
/**
* 商品購買數量
*/
private Integer num;
/**
* 商品總金額
*/
private BigDecimal totalFee;
/**
* 商品圖片地址
*/
private String picPath;
private String sellerId;
//...getset
}
購物車詳細流程分析
一、添加購物車
二、總體業務流程
跨域訪問問題
當controller中的方法進行簡單地完成之後,進行測試,發現點擊加入購物車按鈕沒有反應
原因:跨域請求被阻止
什麼是跨域請求:
瀏覽器廠商在開發瀏覽器時,設置了同源策略。
同源策略:要求發送請求的url地址和返回響應的url地址必須保證協議,ip地址,端口號不能夠發生改變,只要有一個發生變化,瀏覽器就會認爲這個響應不安全,會拒絕接收響應數據,這就是跨域請求訪問。
注意:如果前端window.location.href
進行跳轉,跳轉到不同服務器頁面,不會觸發跨域訪問問題,只是頁面跳轉,不會有數據返回
解決方案
jsonp
:jquery如果發生ajax請求,可以將數據類型設置爲jsonp,原理是jquery在發送數據的同時,會在數據中生產一個令牌,controller接收到數據後,進行處理,返回響應時,將令牌原樣返回,jquery會判斷令牌是否是當初發送的,如果是,則接收響應;反之,拒絕接收。cors
:是w3c支持的解決方法,原理是在響應體設置信息Access-Control-Allow-Origin
,如果使用SpringMVC4.2以上版本,可以使用@Cross
註解,就相當於設置了響應頭信息
使用cors解決跨域問題
/**
* 添加商品到購物車
* @CrossOrigin註解,相當於設置了響應體信息,是w3c支持的一種跨域解決方案
* origins屬性,設置的地址是返回響應給靜態頁面,靜態頁面所在服務器的地址
* @param itemId 商品庫存id
* @param num 購買數量
* @return
*/
@RequestMapping("/addGoodsToCartList")
@CrossOrigin(origins = "http://localhost:8086", allowCredentials = "true")
public Result addGoodsToCartList(Long itemId, Integer num){
return new Result(true,"添加成功!");
}
//添加商品到購物車
$scope.addToCart=function(){
//alert('SKUID:'+$scope.sku.id );
$http.get('http://localhost:8080/cart/addGoodsToCartList.do?itemId='
+$scope.sku.id+'&num='+$scope.num ,{'withCredentials':true} ).success(
function(response){
if(response.success){
location.href='http://localhost:8080/cart.html';
}else{
alert(response.message);
}
}
);
}
購物車的controller方法
一、點擊加入購物車按鈕,將商品添加到購物車
二、返回給前端購物車列表
/**
* 購物車業務
*/
@RestController
@RequestMapping("/cart")
public class BuyerCartController {
@Reference
private CartService cartService;
@Autowired
private HttpServletRequest request;
@Autowired
private HttpServletResponse response;
/**
* 添加商品到購物車
* @CrossOrigin註解,相當於設置了響應體信息,是w3c支持的一種跨域解決方案
* origins屬性,設置的地址是返回響應給靜態頁面,靜態頁面所在服務器的地址
* @param itemId 商品庫存id
* @param num 購買數量
* @return
*/
@RequestMapping("/addGoodsToCartList")
@CrossOrigin(origins = "http://localhost:8086", allowCredentials = "true")
public Result addGoodsToCartList(Long itemId, Integer num){
try {
//1. 獲取當前登錄用戶名稱
String username = SecurityContextHolder.getContext().getAuthentication().getName();
//2. 獲取購物車列表
List<BuyerCart> cartList = findCartList();
//3. 將當前商品加入到購物車列表
cartList = cartService.addItemToCartList(cartList,itemId,num);
//4. 判斷當前用戶是否登錄, 未登錄用戶名爲"anonymousUser"
if ("anonymousUser".equals(username)){
//4.a.如果未登錄, 則將購物車列表存入cookie中
CookieUtil.setCookie(request, response, Constants.CART_LIST_COOKIE, JSON.toJSONString(cartList), 60 * 60 * 24 * 30, "utf-8");
//4.b.如果已登錄, 則將購物車列表存入redis中
cartService.setCartListToRedis(username, cartList);
}
return new Result(true,"添加成功!");
} catch (Exception e) {
e.printStackTrace();
return new Result(false, "添加失敗!");
}
}
/**
* 獲取購物車列表數據
* @return
*/
@RequestMapping("/findCartList")
public List<BuyerCart> findCartList(){
//1. 獲取當前登錄用戶名稱
String username = SecurityContextHolder.getContext().getAuthentication().getName();
//2. 從cookie中獲取購物車列表json格式字符串
String cookieCartJson = CookieUtil.getCookieValue(request, Constants.CART_LIST_COOKIE, "utf-8");
//3. 如果購物車列表json串爲空則返回"[]"
if (cookieCartJson==null || "".equals(cookieCartJson)){
cookieCartJson = "[]";
}
//4. 將購物車列表json轉換爲對象
List<BuyerCart> cookieCartList = JSON.parseArray(cookieCartJson, BuyerCart.class);
//5. 判斷用戶是否登錄, 未登錄用戶爲"anonymousUser"
if (!"anonymousUser".equals(username)){
//5.a. 未登錄, 返回cookie中的購物車列表對象
return cookieCartList;
}else {
//5.b.1.已登錄, 從redis中獲取購物車列表對象
List<BuyerCart> redisCartList = cartService.getCartListToRedis(username);
//5.b.2.判斷cookie中是否存在購物車列表
if (cookieCartList.size()>0){
//如果cookie中存在購物車列表則和redis中的購物車列表合併成一個對象
cartService.mergeCookieCartListAndRedisCartList(cookieCartList,redisCartList);
//刪除cookie中購物車列表
CookieUtil.deleteCookie(request,response,Constants.CART_LIST_COOKIE);
//將合併後的購物車列表存入redis中
cartService.setCartListToRedis(username,redisCartList);
}
//5.b.3.返回購物車列表對象
return redisCartList;
}
}
}
購物車的service方法
package cn.itcast.core.service;
import cn.itcast.core.dao.item.ItemDao;
import cn.itcast.core.pojo.entity.BuyerCart;
import cn.itcast.core.pojo.item.Item;
import cn.itcast.core.pojo.order.OrderItem;
import cn.itcast.core.util.Constants;
import com.alibaba.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
@Service
public class CartServiceImpl implements CartService {
@Autowired
private ItemDao itemDao;
@Autowired
private RedisTemplate redisTemplate;
@Override
public List<BuyerCart> addItemToCartList(List<BuyerCart> cartList, Long itemId, Integer num) {
//1. 根據商品SKU ID查詢SKU商品信息
Item item = itemDao.selectByPrimaryKey(itemId);
//2. 判斷商品是否存在不存在, 拋異常
if (item == null){
throw new RuntimeException("該商品不存在!");
}
//3. 判斷商品狀態是否爲1已審覈, 狀態不對拋異常
if (!"1".equals(item.getStatus())){
throw new RuntimeException("該商品未審覈!");
}
//4.獲取當前商品的商家ID
String sellerId = item.getSellerId();
//5.根據商家ID查詢購物車列表中是否存在該商家的購物車
BuyerCart buyerCart = findBuyerCartBySellerId(cartList, sellerId);
//6.判斷如果購物車列表中不存在該商家的購物車
if (buyerCart == null) {
//6.a.1 新建購物車對象
buyerCart = new BuyerCart();
//設置新創建的購物車對象的賣家id
buyerCart.setSellerId(sellerId);
//設置新創建的購物車對象的賣家名稱
buyerCart.setSellerName(item.getSeller());
//創建購物項集合
List<OrderItem> orderItemList = new ArrayList<>();
//創建購物項
OrderItem orderItem = createOrderItem(item, num);
//將購物項添加到購物項集合
orderItemList.add(orderItem);
//將購物項集合添加到購物車
buyerCart.setOrderItemList(orderItemList);
//6.a.2 將新建的購物車對象添加到購物車列表
cartList.add(buyerCart);
}else {
//6.b.1如果購物車列表中存在該商家的購物車 (查詢購物車明細列表中是否存在該商品)
List<OrderItem> orderItemList = buyerCart.getOrderItemList();
OrderItem orderItem = findOrderItemByItemId(orderItemList, itemId);
//6.b.2判斷購物車明細是否爲空
if (orderItem == null){
//6.b.3爲空,新增購物車明細
orderItem= createOrderItem(item, num);
//將新增購物項加入到購物項集合
orderItemList.add(orderItem);
}else {
//6.b.4不爲空,在原購物車明細上添加數量,更改金額
orderItem.setNum(orderItem.getNum() + num);
//設置總價格
orderItem.setTotalFee(orderItem.getPrice().multiply(new BigDecimal(orderItem.getNum())));
}
//6.b.5如果購物車明細中數量操作後小於等於0,則移除
if (orderItem.getNum() <= 0){
orderItemList.remove(orderItem);
}
//6.b.6如果購物車中購物車明細列表爲空,則移除
if (orderItemList.size() <= 0){
cartList.remove(buyerCart);
}
}
//7. 返回購物車列表對象
return cartList;
}
/**
* 判斷當前購物項中是否存在這個商品
* @param orderItemList
* @param itemId
* @return
*/
private OrderItem findOrderItemByItemId(List<OrderItem> orderItemList, Long itemId){
if (orderItemList != null){
for (OrderItem orderItem : orderItemList) {
if (orderItem.getItemId().equals(itemId)){
return orderItem;
}
}
}
return null;
}
/**
* 創建購物項對象
* @param item
* @param num
* @return
*/
private OrderItem createOrderItem(Item item, Integer num){
if (num <= 0){
throw new RuntimeException("購買數量非法!");
}
OrderItem orderItem = new OrderItem();
orderItem.setNum(num);
orderItem.setGoodsId(item.getGoodsId());
orderItem.setItemId(item.getId());
orderItem.setPicPath(item.getImage());
orderItem.setPrice(item.getPrice());
orderItem.setSellerId(item.getSellerId());
orderItem.setTitle(item.getTitle());
orderItem.setTotalFee(item.getPrice().multiply(new BigDecimal(num)));
return orderItem;
}
/**
* 判斷購物車中,是否有該商家的購物車
* @param cartList
* @param sellerId
* @return
*/
private BuyerCart findBuyerCartBySellerId(List<BuyerCart> cartList, String sellerId){
if (cartList != null){
for (BuyerCart buyerCart : cartList) {
if (buyerCart.getSellerId().equals(sellerId)){
return buyerCart;
}
}
}
return null;
}
@Override
public void setCartListToRedis(String username, List<BuyerCart> cartList) {
redisTemplate.boundHashOps(Constants.CART_LIST_REDIS).put(username,cartList);
}
@Override
public List<BuyerCart> getCartListToRedis(String username) {
List<BuyerCart> cartList = (List<BuyerCart>)redisTemplate.boundHashOps(Constants.CART_LIST_REDIS).get(username);
if (cartList == null){
cartList = new ArrayList<>();
}
return cartList;
}
@Override
public List<BuyerCart> mergeCookieCartListAndRedisCartList(List<BuyerCart> cookieCartList, List<BuyerCart> redisCartList) {
if (cookieCartList != null){
//遍歷cookie購物車集合
for (BuyerCart cookieCart : cookieCartList) {
//遍歷cookie購物車中的購物項集合
for (OrderItem cookieOrderItem : cookieCart.getOrderItemList()) {
//將cookie中的購物項加入到redis的購物車集合中
redisCartList = addItemToCartList(redisCartList,cookieOrderItem.getItemId(),cookieOrderItem.getNum());
}
}
}
return redisCartList;
}
}