1. 程式人生 > >品優購專案記錄:day17

品優購專案記錄:day17

今日目標:

(1)掌握跨域請求CORS解決方案

(2)完成結算頁收貨人地址選擇功能

(3)完成結算頁支付方式選擇

(4)完成結算頁商品清單功能

(5)完成儲存訂單功能

目錄

3.2 前端

1、商品詳細頁跨域請求(購物車對接商品詳細頁)

1.1 需求分析

從商品詳細頁點選“加入購物車”按鈕,將當前商品加入購物車,並跳轉到購物車頁面。

1.2 跨域呼叫測試

(1)修改freemarker靜態資源中的itemController.js中的addToCart方法

	// 加入商品到購物車
	$scope.addToCart = function() {
		// alert("SKU:" + $scope.sku.id + "加入購物車成功,購買數量為:" + $scope.num);
		$http.get('http://localhost:9106/cart/addGoodsToCartList.do?itemId=' + $scope.sku.id + '&num=' + $scope.num).success(
			function(rtn) {
				if (rtn.success) {
					// 新增購物車成功,跳轉到購物車頁面
					location.href = 'http://localhost:9106/cart.html';
				} else {
					// 列印提示資訊
					alert(rtn.message);
				}
			}
		);
	}

(2)呼叫測試

1.3 跨域解決方案CORS

(1)什麼是CORS?

CORS是一個W3C標準,全稱是"跨域資源共享"(Cross-origin resource sharing)。CORS需要瀏覽器和伺服器同時支援。目前,所有瀏覽器都支援該功能,IE瀏覽器不能低於IE10。

它允許瀏覽器向跨源伺服器,發出XMLHttpRequest請求,從而克服了AJAX只能同源使用的限制。整個CORS通訊過程,都是瀏覽器自動完成,不需要使用者參與。對於開發者來說,CORS通訊與同源的AJAX通訊沒有差別,程式碼完全一樣。瀏覽器一旦發現AJAX請求跨源,就會自動新增一些附加的頭資訊,有時還會多出一次附加的請求,但使用者不會有感覺。因此,實現CORS通訊的關鍵是伺服器。只要伺服器實現了CORS介面,就可以跨源通訊。

(2)請求過程

Preflight Request

然後伺服器端給我們返回一個Preflight Response

(3)實現跨域

控制層(cart-web),在addGoodsToCartList新增設定頭資訊程式碼(實現跨域)

        response.setHeader("Access-Control-Allow-Origin", "http://localhost");
        response.setHeader("Access-Control-Allow-Credentials", "true");

控制層(cart-web),在addGoodsToCartList方法上加入註解

@CrossOrigin(origins = "http://localhost",allowCredentials = "true")

注意:請求引數也需要修改,在itemController的addToCart提交請求的引數列表中加入:{'withCredentials':true},用逗號和前面的引數分隔

2、結算頁-收件人地址選擇

2.1 需求分析

在結算頁實現收件人地址選擇功能

2.2 工程搭建

(1)複製程式碼生成器生成的服務層程式碼到 user 模組中,複製控制層程式碼以及靜態頁面到 cart 模組中

2.3 展示收貨地址列表

(1)後端:服務層介面(address-interface),在AddressService新增方法

	/**
	 * 獲取指定使用者的收貨地址列表
	 *
	 * @param userId 使用者ID
	 * @return java.util.List<com.pinyougou.pojo.TbAddress>
	 */
	List<TbAddress> findListByLoginUser(String userId);

(2)後端:服務層實現(address-service),在AddressServiceImpl新增實現

	@Override
	public List<TbAddress> findListByLoginUser(String userId) {
		// 建立查詢條件物件
		TbAddressExample example = new TbAddressExample();
		example.createCriteria().andUserIdEqualTo(userId);
		// 執行查詢
		return addressMapper.selectByExample(example);
	}

(3)後端:控制層(cart-web),在AddressController中新增方法

    /**
     * 獲取當前使用者的收貨地址列表
     * 
     * @return java.util.List<com.pinyougou.pojo.TbAddress>
     */
    @RequestMapping("/findListByLoginUser")
    public List<TbAddress> findListByLoginUser() {
        // 獲取當前登入使用者
        String loginUser = SecurityContextHolder.getContext().getAuthentication().getName();
        return addressService.findListByLoginUser(loginUser);
    }

(4)前端:在cartService.js中新增方法

    // 獲取當前登入使用者的收貨地址列表
    this.findListByLoginUser = function () {
        return $http.get('address/findListByLoginUser.do');
    }

(5)前端:在cartController.js中新增方法

    // 獲取當前使用者的收貨地址列表
    $scope.findListByLoginUser = function () {
        cartService.findListByLoginUser().success(
            function (rtn) {
                $scope.addressList = rtn;
            }
        );
    }

(6)前端:頁面引入JS檔案和基礎指令

(7)頁面迴圈展示收貨地址列表

2.4 選中收貨地址

(1)前端:在cartController.js中新增方法

    // 選擇收貨地址
    $scope.selectAddress = function (address) {
        $scope.address = address;
    }

    // 判斷當前收貨地址是否是被選中地址
    $scope.isSelectedAddress = function (address) {
        if ($scope.address == address) {
            return true;
        }
        return false;
    }

(2)前端:頁面繫結方法

(3)展示預設選中的地址,在findListByLoginUser新增邏輯

3、支付方式選擇

3.1 需求分析

實現支付方式的選擇,品優購支援兩種支付方式:微信支付和貨到付款

3.2 前端

(1)在cartController.js 中新增方法

    // 選擇付款方式
    $scope.order = {paymentType:'1'};
    $scope.selectPayment = function (type) {
        $scope.order.paymentType = type;
    }

(2)頁面繫結單擊事件(其中1為線上支付,2為貨到付款)

4、送貨清單與金額顯示

4.1 需求分析

顯示購物車中的商品清單以及合計數量、金額

4.2 顯示商品清單

(1)初始化呼叫findCartList方法

(2)頁面迴圈展示購物車列表

4.3 顯示總金額

(1)繫結變數即可

5、儲存訂單

5.1 需求分析

(1)需求

點選訂單結算頁的提交訂單 ,將購物車儲存到訂單表和訂單明細表中,並將購物車資料清除.

(2)工程搭建

參看其他的服務層工程,注意web層還是在cart-web中,需要將order的控制層程式碼複製到cart-web的controller包下

5.2 分散式ID生成演算法

我們採用的是開源的twitter(  非官方中文慣稱:推特.是國外的一個網站,是一個社交網路及微部落格服務)  的snowflake演算法。

結構(64位2進位制數):

時間戳(41bit):精確到毫秒

工作機器id(10bit):5位 資料中心ID  5位 機器ID

5.3 儲存訂單

(1)後端:在spring的配置檔案中配置雪花演算法的工具類bean(order-service)

	<!-- 配置雪花演算法的工具類bean -->
	<bean class="util.IdWorker">
		<constructor-arg name="datacenterId" value="0"/>
		<constructor-arg name="workerId" value="0"/>
	</bean>

(2)後端:服務層實現(order-service),修改OrderServiceImpl中的add方法的邏輯

	/**
	 * 增加
	 */
	@Override
	public void add(TbOrder order) {
		// 1.從redis中提取購物車列表
		List<Cart> cartList = (List<Cart>) redisTemplate.boundHashOps("cartList").get(order.getUserId());

		// 2.迴圈購物車儲存訂單
		for (Cart cart : cartList) {
			// 生成訂單物件
			TbOrder tbOrder = buildOrder(order);
			// 設定商家ID
			tbOrder.setSellerId(cart.getSellerId());
			// 合計金額
			double money = 0;

			// 迴圈購物車明細
			for (TbOrderItem orderItem : cart.getOrderItemList()) {
				// 補全訂單明細資料
				orderItem.setOrderId(tbOrder.getOrderId());
				orderItem.setSellerId(cart.getSellerId());
				orderItem.setId(idWorker.nextId());
				// 儲存
				orderItemMapper.insert(orderItem);

				// 累加合計金額
				money += orderItem.getTotalFee().doubleValue();
			}
			// 設定合計金額到訂單
			tbOrder.setPayment(BigDecimal.valueOf(money));
			// 儲存
			orderMapper.insert(tbOrder);
		}

		// 3.清除購物車中的資料
		redisTemplate.boundHashOps("cartList").delete(order.getUserId());
	}

	/**
	 * 構建訂單物件
	 *
	 * @param order 訂單部分資料
	 * @return com.pinyougou.pojo.TbOrder
	 */
	private TbOrder buildOrder(TbOrder order) {
		TbOrder tbOrder = new TbOrder();
		tbOrder.setOrderId(idWorker.nextId());
		tbOrder.setPaymentType(order.getPaymentType());
		tbOrder.setStatus(TbOrder.STATUS_NOT_PAY);
		tbOrder.setCreateTime(new Date());
		tbOrder.setUpdateTime(new Date());
		tbOrder.setUserId(order.getUserId());
		tbOrder.setReceiverAreaName(order.getReceiverAreaName());
		tbOrder.setReceiverMobile(order.getReceiverMobile());
		tbOrder.setReceiver(order.getReceiver());
		tbOrder.setSourceType(order.getSourceType());

		return tbOrder;
	}

(3)後端:控制層新增方法

	/**
	 * 增加
	 * @param order
	 * @return
	 */
	@RequestMapping("/add")
	public Result add(@RequestBody TbOrder order){
		try {
			order.setUserId(SecurityContextHolder.getContext().getAuthentication().getName());
			// 設定訂單來源:PC端
			order.setSourceType("2");
			orderService.add(order);
			return new Result(true, "增加成功");
		} catch (Exception e) {
			e.printStackTrace();
			return new Result(false, "增加失敗");
		}
	}

(4)前端:在cartService.js中新增方法

    // 提交訂單
    this.submitOrder = function (order) {
        return $http.post('order/add.do', order);
    }

(5)前端:在cartController.js中新增方法

    // 提交訂單
    $scope.submitOrder = function () {
        // 封裝資料
        $scope.order.receiverAreaName = $scope.address.address;// 地址
        $scope.order.receiverMobile = $scope.address.mobile;// 手機
        $scope.order.receiver = $scope.address.contact;// 聯絡人

        cartService.submitOrder($scope.order).success(
            function (rtn) {
                if (rtn.success) {
                    // 提交訂單成功,跳轉到支付頁面
                    if ($scope.order.paymentType == "1") {// 微信支付 跳轉到支付頁面
                        location.href = 'pay.html';
                    } else {// 貨到付款 跳轉到提示頁面
                        location.href = 'paysuccess.html';
                    }
                } else {
                    alert(rtn.message);
                }
            }
        );
    }

(6)前端:提交訂單按鈕繫結單擊事件