1. 程式人生 > >電商專案day17(跨域&訂單)

電商專案day17(跨域&訂單)

今日目標:

掌握跨域請求CORS
    完成結算頁收貨人地址選擇功能
    完成結算頁支付方式選擇
    完成結算頁商品清單功能
    儲存訂單功能

一.商品詳情頁跨域請求

1.購物車詳情頁面功能的對接

首先我們在模板中配置新增購物車的點選按鈕,我們主要獲得兩個引數   itemId   和    num  

通過我們通過插值替換,獲得商品的id   

我們在本地的靜態工程中的controller中的js  中pageController.js編寫方法新增購車車的方法,通過請求cart_web的工程

//新增商品到購物車
	$scope.addItemToCartList=function(){
		$http.get("http://localhost:8087/cart/addItemToCartList.do?itemId="+itemId+"&num="+$scope.num).success(function(response){
			if (response.success)
			{
				//新增購物車成功
				location.href="http://localhost:8087/cart.html";
			}else{
				alert(response.message);
			}
		})
	}

我們重新啟動購物車相關服務   通過商品詳情頁面訪問,點選新增購物車按鈕,出現如下問題:

無法進行跨域訪問

No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin

域:包含;協議、域名、埠號  三種任意一個不同,就是涉及瀏覽器跨域問題。    
        http://www.demo.com/a.html
        https://www.demo.com/a.html    

        http://www.demo.com/a.html
        http://www.test.com/a.html        

        http://www.demo.com:8000/a.html
        http://www.demo.com/a.html            
        
    跨域大前提:請求方式是非同步請求。ajax。 angularjs的$http發起的請求,全部是非同步請求。

同步請求:
    location.href  <a href="">  form表單提交。

2.跨域請求的解決方案(三種解決方案)

   第一種:  jQuery:提供跨域解決方案,jsonp  原理:動態的生成<script>發起同步請求。
        
   第二種: CORS:w3c提供的“跨域資源共享”Cross-origin resource sharing

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

又上圖我們可以看到,會進行兩次請求和兩次相應,主要方法是通過設定一些頭資訊

我們在controller層的新增購物車列表中編寫兩行程式碼:

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

Access-Control-Allow-Origin
Access-Control-Allow-Origin 是 HTML5 中定義的一種解決資源跨域的策略。
他是通過伺服器端返回帶有 Access-Control-Allow-Origin 標識的 Response header,用來解決資源的跨域許可權問題。
使用方法,在 response 新增 Access-Control-Allow-Origin,例如
Access-Control-Allow-Origin:www.google.com
也可以設定為 * 表示該資源誰都可以用

      第三種方案:  springMVC跨域註解

我們只需要新增一個註解:   @CrossOrigin即可

注意:版本一定要高   4.2以上

我們伺服器端允許了跨域的請求,我們必須客戶端也開啟跨域

如果我們不寫上面的配置的話,瀏覽器則不發cookie

重新測試:

則跳轉到購物車頁面

二.訂單結算頁收件人功能展示

1.首先構建訂單的模組   order_web   order_interface   order_service

複製address地址的相關檔案

2.注意我們沒有寫order_web工程,直接在cart_web中編寫,這樣我們就不用重新建立工程,新增spring-security的安全框架

需求分析:

我們必須在AddressControlelr中編寫通過使用者id找對應的地址列表

/**
	 * 通過使用者id查詢使用者對應的所有的地址
	 */
	@RequestMapping("findAddressListByUserId")
	public List<TbAddress> findAddressListByUserId(){
		//通過spring-security框架獲得使用者的id
		String userId = SecurityContextHolder.getContext().getAuthentication().getName();
		return addressService.findAddressListByUserId(userId);
	}

service層

/**
	 * 通過使用者的id查詢所對應的地址列表
	 * @param userId
	 * @return
	 */
	@Override
	public List<TbAddress> findAddressListByUserId(String userId) {
		//通過條件查詢獲得地址的列表
		TbAddressExample example = new TbAddressExample();
		Criteria criteria = example.createCriteria();
		criteria.andUserIdEqualTo(userId);
		List<TbAddress> addressList = addressMapper.selectByExample(example);
		return addressList;
	}

前臺頁面:

//通過使用者的id查詢使用者的地址列表
    this.findAddressListByUserId=function(){
        return $http.get('address/findAddressListByUserId.do');
    }

orderController.js

 //傳送請求,獲得使用者對應的地址資訊
	$scope.findAddressListByUserId=function () {
		addressService.findAddressListByUserId().success(function (response) {
			$scope.addressList=response;
        })
    }

頁面點選的,聯動底層的寄送地址

前臺實現:

 //展示收件人地址列表
    $scope.findAddressListByUserId=function () {
        addressService.findAddressListByUserId().success(function (response) {
            //收件人地址列表
            $scope.addressList=response;

            for(var i=0;i< $scope.addressList.length;i++){
                if($scope.addressList[i].isDefault=='1'){//預設收件人地址
                    $scope.address=$scope.addressList[i];
                    break;
                }
            }

            //如果沒有設定預設收件人地址,取第一個地址為預設地址
            if($scope.address==null){
                $scope.address=$scope.addressList[0];
            }

        })
    }

    //定義寄送至的收件人地址物件
    $scope.address=null;

    //勾選預設收件人地址
    $scope.isSelected=function (addr) {
        if($scope.address==addr){
            return true;
        }else {
            return false;
        }
    }
    //跟改點選選中的狀態然後我們,動態給address賦值
    $scope.updateSelected=function (addr) {
        $scope.address=addr;
    }

頁面:

三.支付方式選擇

思路分析:我們通過分析該專案由兩種支付方式,分別是線上是否,通過傳過來的值,我們通過傳過來的值1或者2判斷時那種支付方式

需求分析:

 //支付方式,
    //定義一個實體類
    $scope.entity={paymentType:"1"};
    $scope.updatePaymentType=function (type) {
        $scope.entity.paymentType=type;
    }

 

四.商品清單與金額顯示

思路分析:其實這個功能我們在購物車詳情頁面已經實現了,findCartList()  所有我們直接用就可以了

六.儲存清單

思路分析:

分散式id生成器,IDwork   這個是基於推特公司的開源演算法,雪花演算法

訂單與商家關聯:

          購物車結算時,如果有多個商家的商品,根據商家生成多個訂單,

資料庫表的分析:

注意:我們設計金錢的相關資料時,我們不能頁面傳遞資料,只能後臺組裝.

隨著訂單的與日俱增,一臺資料庫無法滿足訂單,資料的儲存,需要,搭建叢集的方式,儲存資料,主要考慮訂單主鍵生成策略

四種方法:

第一種:UUID   缺點無法基於UUID生成主鍵,完成排序

第二種:oracle 的sequence (序列)

第三種:可以基於redis實現數字加一

第四種:開源框架,技術,分散式id生成器    twitter   基於雪花演算法生成id

資料庫表結構分析:

    tb_order 訂單表
      `expire` datetime DEFAULT NULL COMMENT '過期時間,定期清理',  //基於定時任務框架定期清理無效訂單 spring task  quartz
    
    後端組裝資料
         `order_id` bigint(20) NOT NULL COMMENT '訂單id',  //不是主鍵自增
         `payment` decimal(20,2) DEFAULT NULL COMMENT '實付金額。精確到2位小數;單位:元。如:200.07,表示:200元7分',
         `status` varchar(1) COLLATE utf8_bin DEFAULT NULL COMMENT '狀態:1、未付款,2、已付款,3、未發貨,4、已發貨,5、交易成功,6、交易關閉,7、待評價',
         `create_time` datetime DEFAULT NULL COMMENT '訂單建立時間',
         `update_time` datetime DEFAULT NULL COMMENT '訂單更新時間',
         `user_id` varchar(50) COLLATE utf8_bin DEFAULT NULL COMMENT '使用者id',
         `source_type` varchar(1) COLLATE utf8_bin DEFAULT NULL COMMENT '訂單來源:1:app端,2:pc端,3:M端,4:微信端,5:手機qq端',
         `seller_id` varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '商家ID',  //來著購物車
    頁面提交資料
     `payment_type` varchar(1) COLLATE utf8_bin DEFAULT NULL COMMENT '支付型別,1、線上支付,2、貨到付款',
      `receiver_area_name` varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '收貨人地區名稱(省,市,縣)街道',
      `receiver_mobile` varchar(12) COLLATE utf8_bin DEFAULT NULL COMMENT '收貨人手機',
      `receiver` varchar(50) COLLATE utf8_bin DEFAULT NULL COMMENT '收貨人',
    
tb_order_item  訂單項表
     
          `id` bigint(20) NOT NULL,    //不是主鍵自增
          
          `order_id` bigint(20) NOT NULL COMMENT '訂單id',    

儲存訂單實現流程:
        1、構建訂單模組
        2、將程式碼生成器生成的訂單相關程式碼拷貝到專案中
        3、組裝訂單資料
            1、根據使用者名稱從redis中獲取購物車列表
            
            2、構建訂單資料(後臺組裝資料、前臺頁面傳遞資料)
        4、儲存組裝好的資料到資料庫中

後臺程式碼實現:

controller層,我們通過spring-cecurity獲得使用者id  

service層:

我們大多的資料從資料庫中獲得的,我們通過遍歷購物車列表,每個購物車就是一個訂單,我們自己建立訂單,賦值,最後新增完後我們必須要刪除redis資料庫中的的購物車資料

 @Autowired
    private RedisTemplate redisTemplate;
	@Autowired
    private TbOrderItemMapper tbOrderItemMapper;
	/**
	 * 增加
	 */
	@Override
	public void add(TbOrder order) {
		//我們必須自己組裝資料,很多的資料我們只能從購物車列表中獲得,可能購物車中有兩個商家,那麼我麼
		//要通過迴圈購物車列表來生成訂單 ,從redis中獲得購物車資料
        //訂單與商家關聯,訂單資料有很多是來自購物車列表資料
        List<Cart> cartList = (List<Cart>) redisTemplate.boundValueOps(order.getUserId()).get();
        //迴圈購物車   ,組裝訂單  ,每個購物車列表就是一個訂單
        for (Cart cart : cartList) {
            //構建訂單物件
            TbOrder tbOrder = new TbOrder();
            /*
            `order_id` bigint(20) NOT NULL COMMENT '訂單id',  //不是主鍵自增
		 `payment` decimal(20,2) DEFAULT NULL COMMENT '實付金額。精確到2位小數;單位:元。如:200.07,表示:200元7分',
		 `status` varchar(1) COLLATE utf8_bin DEFAULT NULL COMMENT '狀態:1、未付款,2、已付款,3、未發貨,4、已發貨,5、交易成功,6、交易關閉,7、待評價',
		 `create_time` datetime DEFAULT NULL COMMENT '訂單建立時間',
		 `update_time` datetime DEFAULT NULL COMMENT '訂單更新時間',
		 `user_id` varchar(50) COLLATE utf8_bin DEFAULT NULL COMMENT '使用者id',
		 `source_type` varchar(1) COLLATE utf8_bin DEFAULT NULL COMMENT '訂單來源:1:app端,2:pc端,3:M端,4:微信端,5:手機qq端',
		 `seller_id` varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '商家ID',  //來著購物車
             */
            //訂單id的封裝
            long orderId = idWorker.nextId();
            tbOrder.setOrderId(orderId);
            //訂單狀態封裝
            tbOrder.setStatus("1");
            //建立訂單時間
            tbOrder.setCreateTime(new Date());
            //建立跟新訂單時間
            tbOrder.setUpdateTime(new Date());
            //使用者id,因為我們在controller層已經封裝 了,所以我們自己獲得就行
            tbOrder.setUserId(order.getUserId());
            //訂單來源
            tbOrder.setSourceType("2");
            //商家id
            tbOrder.setSellerId(cart.getSellerId());
            /*
            頁面提交資料
	 `payment_type` varchar(1) COLLATE utf8_bin DEFAULT NULL COMMENT '支付型別,1、線上支付,2、貨到付款',
	  `receiver_area_name` varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '收貨人地區名稱(省,市,縣)街道',
	  `receiver_mobile` varchar(12) COLLATE utf8_bin DEFAULT NULL COMMENT '收貨人手機',
	  `receiver` varchar(50) COLLATE utf8_bin DEFAULT NULL COMMENT '收貨人',
             */
            //支付型別的封裝
            tbOrder.setPaymentType(order.getPaymentType());
            //收貨人地址
            tbOrder.setReceiverAreaName(order.getReceiverAreaName());
            //收貨人手機
            tbOrder.setReceiverMobile(order.getReceiverMobile());
            //收貨人
            tbOrder.setReceiver(order.getReceiver());

            //遍歷購物車明細資料,組裝訂單詳情資料
            //我們主要後臺組裝資料   連個資料  其他的度,在購物車新增資料的時候已經組裝好了
            List<TbOrderItem> orderItemList = cart.getOrderItemList();
            //定義一個費用統計的變數
            double payment = 0.00;
            for (TbOrderItem orderItem : orderItemList) {
                //  `id` bigint(20) NOT NULL,    //不是主鍵自增
              	    orderItem.setId(idWorker.nextId());
                //		  `order_id` bigint(20) NOT NULL COMMENT '訂單id',
                    orderItem.setOrderId(orderId);
                    //獲得費用
                    payment+=orderItem.getTotalFee().doubleValue();
                    //儲存到orderItem中
                tbOrderItemMapper.insert(orderItem);

            }
            //payment  實付金額 我們不是前天傳的,我們從後臺算的
            tbOrder.setPayment(new BigDecimal(payment));
            //新增到訂單表中
             orderMapper.insert(tbOrder);
        }
        //新增完,我們把redis中的購物車資料列表刪除
        redisTemplate.boundHashOps("cartList").delete(order.getUserId());
	}

最後實現訂單的新增