跨域解决方案与提交订单

Posted chenjiaji

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了跨域解决方案与提交订单相关的知识,希望对你有一定的参考价值。

跨域解决方案与提交订单 

 

课程目标 

目标 1:掌握跨域请求 CORS 解决方案目标 2:完成结算页收货人地址选择功能目标 3:完成结算页支付方式选择目标 4:完成结算页商品清单功能目标 5:完成保存订单功能 

1.商品详细页跨域请求 

1.1 需求分析 

从商品详细页点击“加入购物车”按钮,将当前商品加入购物车,并跳转到购物车页面。 

1.2 JS 跨域请求 

这里说的 js 跨域是指通过 js 在不同的域之间进行数据传输或通信,比如用 ajax 向一个不同的域请求数据,或者通过 js 获取页面中不同域的框架中(iframe)的数据。只要协议、域名、端口有任何一个不同,都被当作是不同的域。 

1.3 跨域调用测试 

修改 pinyougou-page-web itemController.js ,引入$http 服务,修改 addToCart 方法 

//添加商品到购物车 

  $scope.addToCart=function() 

    $http.get(‘http://localhost:9107/cart/addGoodsToCartList.do?itemId=‘ 

        + $scope.sku.id +‘&num=‘+$scope.num).success( 

         function(response) 

           if(response.success) 

       

 

   location.href=‘http://localhost:9107/cart.html‘;//跳转到购

物车页面 

       

       

       

 

 

 

 el

 

 

se 

 alert(response.message); 

          

       

    );  

   

 

 

 

 

     

 

测试后发现无法跨域调用 

XMLHttpRequest cannot  load  http://localhost:9107/cart/addGoodsToCartList.do?itemId=112344&num=1.  

No ‘Access-Control-Allow-Origin‘ header is present on the requested resource. Origin ‘http://localhost:9100‘ is therefore not allowed access. The response had HTTP status code 400.

1.4 跨域解决方案 CORS

CORS 是一个 W3C 标准,全称是"跨域资源共享"Cross-origin resource sharing)。CORS

需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE 浏览器不能低于 IE10 

它允许浏览器向跨源服务器,发出 XMLHttpRequest 请求,从而克服了 AJAX 只能同源使用的限制。整个 CORS 通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS 通信与同源的 AJAX 通信没有差别,代码完全一样。浏览器一旦发现 AJAX 请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。因此,实现 CORS 通信的关键是服务器。只要服务器实现了 CORS 接口,就可以跨源通信。 

请求过程如下图:

 

Preflight Request 

 

然后服务器端给我们返回一个 Preflight Response 

 

下面我们就开始动手,让我们的购物车工程能够接收跨域请求 

1)首先修改 pinyougou-cart-web CartController.java addGoodsToCartList 方法,添加下面两句代码 

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 

也可以设置为 * 表示该资源谁都可以用 

2)修改 pinyougou-item-web itemController.js  

//添加商品到购物车 

$scope.addToCart=function()

  $http.get(‘http://localhost:9107/cart/addGoodsToCartList.do?itemId=‘   + $scope.sku.id +‘&num=‘+$scope.num,‘withCredentials‘:true).success(

      function(response)

        .......         

             

  );    

 

调用测试,可以实现跨域了。 

CORS 请求默认不发送 Cookie HTTP 认证信息。如果要把 Cookie 发到服务器,一方面要服务器同意,指定 Access-Control-Allow-Credentials 字段。另一方面,开发者必须在 AJAX 请求中打开 withCredentials 属性。否则,即使服务器同意发送 Cookie,浏览器也不会发送。或者,服务器要求设置 Cookie,浏览器也不会处理。 

1.5 SpringMVC 跨域注解 

springMVC 的版本在 4.2 或以上版本,可以使用注解实现跨域, 我们只需要在需要跨域的方

法上添加注解@CrossOrigin 即可 

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

allowCredentials="true"  可以缺省 

2.结算页-收件人地址选择 

2.1 需求与数据库分析 

2.1.1 需求描述 

在结算页实现收件人地址选择功能 

2.1.2 数据库结构分析 

Tb_address 为地址表 

 

2.2 准备工作 

2.2.1 生成代码 

使用《黑马程序员代码生成器》生成代码,并拷贝到工程 

(1) AddressService 接口拷入 pinyougou-user-interface  

(2) AddressServiceImpl 类拷入到 pinyougou-user-service  

(3) pinyougou-cart-web 引入 pinyougou-user-interface 依赖 AddressController 类拷入到 pinyougou-cart-web   

2.2.2 拷贝页面资源 

getOrderInfo.html 拷贝至 pinyougou-cart-web webapp  

2.3 实现地址列表 

2.3.1 后端代码 

(1) 修改 pinyougou-user-interface AddressService.java,新增方法定义 

  /** 

根据用户查询地址 

@param userId 

@return 

   */ 

  public List<TbAddress> findListByUserId(String userId ); 

(2) 修改 pinyougou-user-service AddressServiceImpl.java

  /** 

根据用户查询地址 

@param userId 

@return    */ 

  public List<TbAddress> findListByUserId(String userId )        

    TbAddressExample example=new TbAddressExample(); 

    Criteria criteria = example.createCriteria(); 

   

   

   

criteria.andUserIdEqualTo(userId);    

return addressMapper.selectByExample(example); 

(3) 修改 pinyougou-cart-web AddressController.java

  @RequestMapping("/findListByLoginUser") 

  public List<TbAddress> findListByLoginUser() 

    String userId =

SecurityContextHolder.getContext().getAuthentication().getName(); 

    return addressService.findListByUserId(userId); 

   

2.3.2 前端代码 

(1) pinyougou-cart-web cartService.js

  //获取地址列表 

  this.findAddressList=function() 

    return $http.get(‘address/findListByLoginUser.do‘);  

   

(2) pinyougou-cart-web cartController.js

  //获取地址列表 

  $scope.findAddressList=function() 

    cartService.findAddressList().success( 

      function(response) 

        $scope.addressList=response; 

         

   

   

);    

(3) 修改 getOrderInfo.html 引入 js

<script type="text/javascript" src="plugins/angularjs/angular.min.js">  </script> 

<script type="text/javascript" src="js/base.js">  </script> 

<script type="text/javascript" src="js/service/cartService.js">  </script> 

<script type="text/javascript" src="js/controller/cartController.js">  </script> 

指令 

<

body

 ng-app="pinyougou" ng-controller="

cartController" ng-init="findAddressList()"

 

循环列表 

<

<

<

<

<

 

 

<

<

<

div

 ng-repeat="address in addressList" > 

 class="con name">

href="javascript:;" >address.contact<span title="点击取消选择"> </a>

 class="con address"   >address.address<span>address.mobile</span>  

<span class="base" ng-if="address.isDefault==‘1‘">默认地址</span> 

<span class="edittext"><a data-toggle="modal" data-target=".edit" 

-keyboard="false" >编辑</a>  <a href="javascript:;">删除</a></span> 

 class="clearfix"></div> 

div

a /div

div

data

/div

div

div /

显示效果如下: 

 

2.4 地址选择 

(1)  orderInfoController.js 增加代码 

  //选择地址 

  $scope.selectAddress=function(address) 

    $scope.address=address;    

   

   

  //判断是否是当前选中的地址 

  $scope.isSelectedAddress=function(address) 

    if(address==$scope.address) 

      return true;     else 

      return false

       

   

(2) 修改页面-点击选择 

<

<

<

 

 

<

<

<

div

 ng-repeat="address in addressList" >

div class="con name isSelectedAddress(address)?‘selected‘:‘‘" ><a

"javascript:;" ng-click="selectAddress(address)">address.contact<span 

"点击取消选择"> </a></div>

div class="con address"   >address.address<span>address.mobile</span>  

<span class="base" ng-if="address.isDefault==‘1‘">默认地址</span>

<span class="edittext"><a data-toggle="modal" data-target=".edit" 

-keyboard="false" >编辑</a>  <a href="javascript:;">删除</a></span>

>

div class="clearfix"></div>

href= title=

data

/div

div

/

(3) 修改页面,显示选择的地址 

<

div

 class="fc-receiverInfo">寄送至:address.address 收货人:address.contact

 

 

address.mobile</

div

 

2.5 默认地址显示 

修改 orderInfoController.js

  //查询当前登录人的地址列表 

  $scope.findAddressList=function()

    addressService.findListByLoginUser().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;

         

   

   

 

 

 

 

       

   

   

);  

 

 

 

2.6 收件人地址增加、修改与删除 

学员实现 

3.结算页-支付方式选择 

3.1 需求分析 

实现支付方式的选择,品优购支持两种支付方式:微信支付和货到付款 

3.2 支付方式选择 

3.2.1 前端控制层 

cartController.js

$scope.order=paymentType:‘1‘;  

//选择支付方式 

  $scope.selectPayType=function(type) 

    $scope.order.paymentType= type; 

   

3.2.2 页面 

getOrderInfo.html

<

"

<

li

 class="selected" ng-click="selectPayType(‘1‘)">微信付款<span title="点击取消选择

/span></li> 

 ng-click="selectPayType(‘2‘)">货到付款<span title="点击取消选择"></span></li> 

><

li

 

4.结算页-商品清单与金额显示 

4.1 需求分析 

显示购物车中的商品清单以及合计数量、金额 

4.2 显示商品清单 

(1) 页面 getOrderInfo.html 上初始化调用 

<body ng-app="pinyougou" 

ng-init="findAddressList();findCartList()"

ng-controller="cartController" 

(2) 循环显示商品清单 

<

 

 

 

 

 

 

 

div

 ng-repeat="cart in cartList"

<ul class="yui3-g" ng-repeat="orderItem in cart.orderItemList"

  <li class="yui3-u-1-6"

    <span><img src="orderItem.picPath"/></span> 

  </li> 

  <li class="yui3-u-7-12"

    <div class="desc">orderItem.title</div> 

    <div class="seven">7天无理由退货</div> 

 

    </li> 

    <li class="yui3-u-1-12"

      <div class="price">¥orderItem.price</div> 

    </li> 

    <li class="yui3-u-1-12"

      <div class="num">XorderItem.num</div> 

    </li> 

    <li class="yui3-u-1-12"

      <div class="exit">有货</div> 

    </li> 

  </ul> 

div

</ > 

4.3 显示合计金额 

修改 getOrderInfo.html

<

 

 

<

<

<

div

 class="list"

<span><i class="number">totalValue.totalNum</i>件商品,总商品金额</span> 

<em class="allprice">¥totalValue.totalMoney.toFixed(2)</em> 

>  

 class="fc-price">应付金额:

div

 class="price">¥totalValue.totalMoney.toFixed(2)</span></ >

div

/

......

div

span

 

5.保存订单 

5.1 需求分析 

5.1.1 需求描述 

点击订单结算页的提交订单 ,将购物车保存到订单表和订单明细表中,并将购物车数据清除.

5.1.2 数据库结构分析 

Tb_order 为订单主表 

 

 

 

5.2 准备工作 

5.2.1 搭建框架 

(1) 创建 pinyougou-order-interface  引入依赖 pinyougou-pojo

(2) 创建 pinyougou-order-service  WAR 参照其它服务工程引入依赖,添加 web.xml  spring 配置文件  dubbox 端口 20888  tomcat7 运行端口 9008

(3) pinyougou-cart-web 引入依赖 pinyougou-order-interface    

5.2.2 生成代码 

生成 tb_order 表相关代码,并拷贝到工程中 

 

 

 

5.2.3 分布式 ID 生成器 

我们采用的是开源的 twitter(  非官方中文惯称:推特.是国外的一个网站,是一个社交网络及微博客服务)   snowflake 算法。 

 

(1) “配置文件/工具类”下的 IdWorker.java 拷贝到 common 工程 

(2)  pinyougou-order-service 工程的 spring 配置文件中添加配置 

<bean id="idWorker" class="util.IdWorker"

     <!-- 进程ID --> 

     <constructor-arg index="0" value="0"></constructor-arg> 

     <!-- 数据中心ID --> 

     <constructor-arg index="1" value="0"></constructor-arg> 

 </bean> 

5.3 后端代码 

5.3.1 服务实现层 

修改 pinyougou-order-service OrderServiceImpl.java

  @Autowired 

  private RedisTemplate<String, Object> redisTemplate; 

   

  @Autowired 

  private TbOrderItemMapper orderItemMapper; 

   

  @Autowired 

  private IdWorker idWorker; 

   

  /** 

   * 增加 

   */ 

  @Override 

  public void add(TbOrder order)  

 

    //得到购物车数据 

    List<Cart> cartList = (List<Cart>)  

    redisTemplate.boundHashOps("cartList").get( order.getUserId() )

    for(Cart cart:cartList) 

      long orderId = idWorker.nextId(); 

      System.out.println("sellerId:"+cart.getSellerId());       TbOrder tborder=new TbOrder();//新创建订单对象 

      tborder.setOrderId(orderId);//订单ID 

      tborder.setUserId(order.getUserId());//用户名 

      tborder.setPaymentType(order.getPaymentType());//支付类型 

      tborder.setStatus("1");//状态:未付款 

      tborder.setCreateTime(new Date());//订单创建日期 

      tborder.setUpdateTime(new Date());//订单更新日期 

      tborder.setReceiverAreaName(order.getReceiverAreaName());//地址 

      tborder.setReceiverMobile(order.getReceiverMobile());//手机号 

      tborder.setReceiver(order.getReceiver());//收货人 

tbOrder.setSourceType(order.getSourceType());//订单来源 

      tborder.setSellerId(cart.getSellerId());//商家ID        

      //循环购物车明细 

      double money=0; 

      for(TbOrderItem orderItem :cart.getOrderItemList())    

        orderItem.setId(idWorker.nextId()); 

        orderItem.setOrderId( orderId  );//订单ID  

   

   

   

 

 

 

  orderItem.setSellerId(cart.getSellerId()); 

  money+=orderItem.getTotalFee().doubleValue();//金额累加 

  orderItemMapper.insert(orderItem);        

   

   

   

 

 

 

 

tborder.setPayment(new BigDecimal(money));      

orderMapper.insert(tborder);  

   

   

   

 

redisTemplate.boundHashOps("cartList").delete(order.getUserId()); 

5.3.3 控制层 

修改 pinyougou-cart-web OrderController.java  

  /**

增加 

@param order

@return 

   */

  @RequestMapping("/add")

  public Result add(@RequestBody TbOrder order)

    //获取当前登录人账号 

    String username =

SecurityContextHolder.getContext().getAuthentication().getName();

    order.setUserId(username);

    order.setSourceType("2");//订单来源  PC

   

   

   

   

   

   

   

   

try 

  orderService.add(order);

  return new Result(true, "增加成功");

catch (Exception e)

  e.printStackTrace();

  return new Result(false, "增加失败");

5.4 前端代码 

5.4.1 服务层 

修改 pinyougou-cart-web cartService.js

  //保存订单 

  this.submitOrder=function(order) 

    return $http.post(‘order/add.do‘,order);    

   

5.4.2 控制层 

修改 cartController.js

  //保存订单 

  $scope.submitOrder=function() 

    $scope.order.receiverAreaName=$scope.address.address;//地址 

    $scope.order.receiverMobile=$scope.address.mobile;//手机 

   

   

   

   

   

   

   

   

   

   

   

   

   

  function

   

   

   

   

   

   

   

   

   

   

$scope.order.receiver=$scope.address.contact;//联系人 

cartService.submitOrder( $scope.order ).success( 

(response) 

if(response.success) 

  //页面跳转 

  if($scope.order.paymentType==‘1‘)//如果是微信支付,跳转到支付页面 

    location.href="pay.html"; 

  else//如果货到付款,跳转到提示页面 

    location.href="paysuccess.html"; 

           

else 

  alert(response.message); //也可以跳转到提示页面        

       

   

   

   

 

);  

 

 

     

5.4.3 页面 

修改 getOrderInfo.html

<a

 class="sui-btn btn-danger btn-xlarge" ng-click="submitOrder()" >提交订单</a

 

将静态原型中的 pay.html  paysuccess.html  payfail.html 拷贝到 pinyougou-cart-web  

 

以上是关于跨域解决方案与提交订单的主要内容,如果未能解决你的问题,请参考以下文章

HTTP(“跨域问题”和“防止表单重复提交”)

允许浏览器跨域访问web服务端的解决方案

JavaScript学习--Item33 跨域总结与解决办法

JSONP解决跨域问题,防止表单重复提交,防止XSS攻击

你不知道的JavaScript--Item33 跨域总结与解决办法

跨域是指啥,因为啥引起的?都有哪些解决方案?web前端知识