掌握跨域请求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());}最后实现订单的添加
上一篇:电脑快捷操作方式大全
下一篇:电商中,订单号的生成方法