当前位置: 首页 - 编程技术 - 文章正文

电商项目day17(跨域&订单)

xiaoqihv
今日目标:

掌握跨域请求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框架获得用户的idString userId = SecurityContextHolder.getContext().getAuthentication().getName();return addressService.findAddressListByUserId(userId);}

service层

/** * 通过用户的id查询所对应的地址列表 * @param userId * @return */@Overridepublic 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;/** * 增加 */@Overridepublic 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());}

最后实现订单的添加

 

文章地址:https://wenmayi.cn/post/410.html