品優購專案記錄:day17
今日目標:
(1)掌握跨域請求CORS解決方案
(2)完成結算頁收貨人地址選擇功能
(3)完成結算頁支付方式選擇
(4)完成結算頁商品清單功能
(5)完成儲存訂單功能
目錄
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)前端:提交訂單按鈕繫結單擊事件