• 购物车下单


    一、商品结算页

    实现思路

    1.购物车页面实现结算功能,主要是拿到传入后台的gids
    2.跳转订单页后台,主要是拿到订单页展示数据
    3.订单页前台数据展示

    1、购物车页面实现结算功能

    注:使用jquery动态实现结算功能,必须勾选购物车中的商品进行结算,没有勾选无法完成结算功能!!!

    cart.js:

    $(function(){
    	/**************数量加减***************/
    	$(".num .sub").click(function(){
    		var num = parseInt($(this).siblings("span").text());
    		if(num<=1){
    			$(this).attr("disabled","disabled");
    		}else{
    			num--;
    			$(this).siblings("span").text(num);
    			//获取除了货币符号以外的数字
    			var price = $(this).parents(".number").prev().text().substring(1);
    			//单价和数量相乘并保留两位小数
    			$(this).parents(".th").find(".sAll").text('¥'+(num*price).toFixed(2));
    			jisuan();
    			zg();
    
    			//TODO 获取当前行的行索引
    			let index = $(this).parents(".th").index()-1;
    			//获取当前的checkbox中设置的隐藏域(包含了商品ID)
    			let gid=$(".th").eq(index).find('div:eq(0) input[type=hidden]').val();
    			update(num,gid);
    		}
    	});
    	$(".num .add").click(function(){
    		var num = parseInt($(this).siblings("span").text());
    		if(num>=5){
    			confirm("限购5件");
    		}else{
    			num++;
    			$(this).siblings("span").text(num);
    			var price = $(this).parents(".number").prev().text().substring(1);
    			$(this).parents(".th").find(".sAll").text('¥'+(num*price).toFixed(2));
    			jisuan();
    			zg();
    
    			//TODO 获取当前行的行索引
    			let index = $(this).parents(".th").index()-1;
    			//获取当前的checkbox中设置的隐藏域(包含了商品ID)
    			let gid=$(".th").eq(index).find('div:eq(0) input[type=hidden]').val();
    			update(num,gid);
    		}
    	});
    	//计算总价
    	function jisuan(){
    		var all=0;
    		var len =$(".th input[type='checkbox']:checked").length;
    		if(len==0){
    			$("#all").text('¥'+parseFloat(0).toFixed(2));
    		}else{
    			$(".th input[type='checkbox']:checked").each(function(){
    				//获取小计里的数值
    				var sAll = $(this).parents(".pro").siblings('.sAll').text().substring(1);
    				//累加
    				all+=parseFloat(sAll);
    				//赋值
    				$("#all").text('¥'+all.toFixed(2));
    			})
    		}
    
    	}
    	//计算总共几件商品
    	function zg(){
    		let gids = "";
    		var zsl = 0;
    		var index = $(".th input[type='checkbox']:checked").parents(".th").find(".num span");
    		var len =index.length;
    		if(len==0){
    			$("#sl").text(0);
    		}else{
    			let gidarr = new Array();
    			index.each(function(){
    				zsl+=parseInt($(this).text());
    				$("#sl").text(zsl);
    
    				//TODO	获取当前行的索引
    				let idx = $(this).parents(".th").index()-1;
    				console.log(idx);
    				//在这里需要获取当前行商品的商品ID
    				gidarr.push($(".th").eq(idx).find("div:eq(0) input[type='hidden']").val());
    			})
    			gids = gidarr.join(",");
    		}
    		if($("#sl").text()>0){
    			$(".count").css("background","#c10000");
    			$(".count").bind("click",function () {
    				location.href='/order/toOrder?gids='+gids
    			})
    		}else{
    			$(".count").css("background","#8e8e8e");
    			$(".count").unbind("click");
    		}
    	}
    	/*****************商品全选***********************/
    	$("input[type='checkbox']").on('click',function(){
    		var sf = $(this).is(":checked");
    		var sc= $(this).hasClass("checkAll");
    		if(sf){
    			if(sc){
    				$("input[type='checkbox']").each(function(){
    					this.checked=true;
    				});
    				zg();
    				jisuan();
    			}else{
    				$(this).checked=true;
    				var len = $("input[type='checkbox']:checked").length;
    				var len1 = $("input").length-1;
    				if(len==len1){
    					$("input[type='checkbox']").each(function(){
    						this.checked=true;
    					});
    				}
    				zg();
    				jisuan();
    			}
    		}else{
    			if(sc){
    				$("input[type='checkbox']").each(function(){
    					this.checked=false;
    				});
    				zg();
    				jisuan();
    			}else{
    				$(this).checked=false;
    				var len = $(".th input[type='checkbox']:checked").length;
    				var len1 = $("input").length-1;
    				if(len<len1){
    					$('.checkAll').attr("checked",false);
    				}
    				zg();
    				jisuan();
    			}
    		}
    
    	});
    	/****************************proDetail 加入购物车*******************************/
    	$(".btns .cart").click(function(){
    		if($(".categ p").hasClass("on")){
    			var num = parseInt($(".num span").text());
    			var num1 = parseInt($(".goCart span").text());
    			$(".goCart span").text(num+num1);
    		}
    	});
    
    	//删除购物车商品
    	$('.del').click(function(){
    		//定义商品id	1,2,3,4,5,6
    		let gids = "";
    		//单个删除
    		if($(this).parent().parent().hasClass("th")){
    			$(".mask").show();
    			$(".tipDel").show();
    			index = $(this).parents(".th").index()-1;
    
    			//TODO 获取当前的checkbox中设置的隐藏域(包含了商品ID)
    			gids=$(".th").eq(index).find('div:eq(0) input[type=hidden]').val();
    
    			$('.cer').click(function(){
    				$(".mask").hide();
    				$(".tipDel").hide();
    				$(".th").eq(index).remove();
    				$('.cer').off('click');
    				if($(".th").length==0){
    					$(".table .goOn").show();
    				}
    
    				del(gids);
    			})
    		}else{
    			//选中多个一起删除
    			if($(".th input[type='checkbox']:checked").length==0){
    				$(".mask").show();
    				$(".pleaseC").show();
    			}
    			else{
    				$(".mask").show();
    				$(".tipDel").show();
    
    				let gidarr = new Array();// {1,2,3,4,5,6}
    				$(".th input[type='checkbox']:checked").each(function(j){
    					gidarr.push($(".th").eq(index).find('div:eq(0) input[type=hidden]').val());
    					// gids += $(".th").eq(index).find('div:eq(0) input[type=hidden]').val() + ",";
    				});
    				gids = gidarr.join(",");
    
    				$('.cer').click(function(){
    					$(".th input[type='checkbox']:checked").each(function(j){
    						index = $(this).parents('.th').index()-1;
    						$(".th").eq(index).remove();
    						if($(".th").length==0){
    							$(".table .goOn").show();
    						}
    					})
    					$(".mask").hide();
    					$(".tipDel").hide();
    					zg();
    					jisuan();
    
    					del(gids);
    				})
    			}
    		}
    	})
    	$('.cancel').click(function(){
    		$(".mask").hide();
    		$(".tipDel").hide();
    	})
    	//改变商品规格
    //	$(".pro dd").hover(function(){
    //		var html='';
    //		html='修改';
    //		$(this).addClass("on").append(html).parents(".th").siblings(".th").find(".pro dd").removeClass("on").find('.edit').remove();
    //		$(".edit").each(function(i){
    //			$(this).attr("id",'edit'+i);
    //			$("#edit"+i).click(function(){
    //				$(".proDets").show();
    //				$(".mask").show();
    //				$(".changeBtn .buy").attr("data-id",i);
    //			})
    //		})
    //	},function(){
    //		$(this).removeClass("on");
    //	})
    //	$(".changeBtn .buy").click(function(){
    //		var index = $(this).attr("data-id");
    //		var result = $(".smallImg .on").find("img").attr("alt");
    //		$("#edit"+index).prev().text(result);
    //		$(".proDets").hide();
    //		$(".mask").hide();
    //		$("#edit"+index).parent("dd").removeClass("on").find(".edit").remove();
    //	});
    //	$(".changeBtn .cart").click(function(){
    //		$(".proDets").hide();
    //		$(".mask").hide();
    //	})
    })
    //删除商品
    function del(gids){
    	$.post('/shopCar/delete',{
    		'gids':gids
    	},function(rs){
    		if(rs.code!=200)
    			alert(rs.msg);
    		else
    			location.href='/shopCar/queryShopCar';
    	},'json');
    }
    
    //更新商品数量
    function update(num,gid){
    	$.post('/shopCar/update',{
    		'gid':gid,
    		'quantity':num
    	},function(rs){
    		if(rs.code!=200)
    			alert(rs.msg);
    		else
    			location.href='/shopCar/queryShopCar';
    	},'json');
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260

    测试结果,当点击结算,会跳转访问地址http://localhost:8081/order/toOrder?gids=2,22;
    说明gids的值是已经拿到了;

    2、跳转订单页后台

    1.从session中获取购物车对象
    2.筛选出要结算的订单项列表集合

    OrderController.java

    package com.xnx.spbootpro.controller;
    
    
    import com.alipay.easysdk.factory.Factory;
    import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
    import com.xnx.spbootpro.config.AlipayConfig;
    import com.xnx.spbootpro.model.Goods;
    import com.xnx.spbootpro.model.Order;
    import com.xnx.spbootpro.model.User;
    import com.xnx.spbootpro.model.dto.OrderDto;
    import com.xnx.spbootpro.model.vo.ShopCar;
    import com.xnx.spbootpro.model.vo.ShopCarItem;
    import com.xnx.spbootpro.service.IOrderService;
    import com.xnx.spbootpro.utils.JsonResponseBody;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpSession;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    import java.util.Map;
    
    /**
     * 

    * 订单信息表 前端控制器 *

    * * @author xnx * @since 2022-11-08 */
    @Controller @RequestMapping("/order") public class OrderController { @RequestMapping("/toOrder") public ModelAndView toOrder(String gids, HttpServletRequest request,User user){ ModelAndView mv = new ModelAndView(); // 拿到购物车中的所有商品 3 ShopCar shopCar = getShopCar(user, request); // 通过gids从购物车中筛选出指定的商品 2 List<ShopCarItem> list = getGoods(shopCar,gids); mv.addObject("goods",list); mv.setViewName("order.html"); return mv; } // 通过gids从购物车中筛选出指定的商品 2 private List<ShopCarItem> getGoods(ShopCar shopCar, String gids) { List<String> gidList = Arrays.asList(gids.split(",")); List<ShopCarItem> items = shopCar.getItems();//3个 购物车里的商品 List<ShopCarItem> itemsNew = new ArrayList<>();//2个 购物车中要结算的商品 for (ShopCarItem item : items) { if (gidList.contains(item.getGid()+"")){ itemsNew.add(item); } } return itemsNew; } // 从session中获取购物车对象 private ShopCar getShopCar(User user, HttpServletRequest request){ HttpSession session = request.getSession(); ShopCar shopCar = (ShopCar)session.getAttribute(user.getId()+"_shopCar"); if (shopCar == null){ shopCar = new ShopCar(); session.setAttribute(user.getId()+"_shopCar",shopCar); } return shopCar; } @Autowired private IOrderService orderService; @RequestMapping("/addOrder") @ResponseBody public String addOrder(User user, HttpServletRequest req, OrderDto orderDto){ //获取购物车 ShopCar shopCar = this.getShopCar(user, req); //获取结算商品集合 List<ShopCarItem> shopCarItems = this.getGoods(shopCar, orderDto.getGids()); //生成订单及订单项 orderDto.setUserId(user.getId()); orderService.addOrder(orderDto,shopCarItems); //从购物车中删除已结算的商品 shopCar.delete(orderDto.getGids()); //跳转支付页面(下节课内容) AlipayConfig alipayConfig = new AlipayConfig(); return alipayConfig.goAlipay(orderDto); } /** * 支付成功后回调处理订单状态,完成整个下单流程的链路 * @param param * @return */ @RequestMapping("/orderFinish") public String orderFinish(@RequestParam Map<String, String> param){ System.out.println("异步回调开始。。。。。。"); Boolean signVerified=false; try { System.out.println(param); signVerified = Factory.Payment.Common().verifyNotify(param); System.out.println(signVerified); System.out.println("out_trade_no:"+param.get("out_trade_no")); System.out.println("total_amount:"+param.get("total_amount")); System.out.println("trade_no:"+param.get("trade_no")); if(signVerified){ //支付成功 //根据订单编号修改订单状态 //update t_xxx set xx=?,tt=? where id=? orderService.update(new UpdateWrapper<Order>() .set("status",1) .setSql("pay_date=now()") .eq("oid",param.get("out_trade_no"))); //跳转到支付成功页面 }else{ //支付失败 } } catch (Exception e) { e.printStackTrace(); } return "ok.html"; } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138

    3、订单页前台展示

    order.html

    <div class="orderR fr">
    					<div class="msg">
    						<h3>订单内容<a href="${ctx}/shopCar/queryShopCar" class="fr">返回购物车a>h3>
    						<#if goods??>
    							<#list goods as g>
    								<ul class="clearfix">
    									<li class="fl">
    										<img style="height: 87px;width: 87px;" src="${g.goodsImg}">
    									li>
    									<li class="fl">
    										<p>${g.goodsName}p>
    										<p>颜色分类:烟灰色玻璃瓶p>
    										<p>数量:${g.quantity}p>
    									li>
    									<li class="fr">¥${g.goodsPrice}li>
    								ul>
    							#list>
    						#if>
    
    					div>
    					
    					<div class="tips">
    						<p><span class="fl">商品金额:span><span class="fr">¥139.8span>p>
    						<p><span class="fl">优惠金额:span><span class="fr">¥0.00span>p>
    						<p><span class="fl">运费:span><span class="fr">免运费span>p>
    					div>
    					
    					<div class="count tips">
    						<p><span class="fl">合计:span><span class="fr">¥${total}span>p>
    
    					div>
    					
    					<a href="javascript:void(0);" class="pay">去支付a>
    				div>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    如下图所示极为成功:
    在这里插入图片描述

    二、生成订单

    实现思路

    1.前台订单相关数据获取
    2.后台进行下单操作

    1、前端相关处理

    1)获取收货地址、收货人以及联系电话
    2)获取支付方式
    3)获取快递方式

    Order.html

    $(function(){
        $('.pay').click(function(){
            //获取收货地址、联系人、联系电话
            let name=$('.addres').find('div.on div:eq(0)>p:eq(0)').text().trim();
            let address=$('.addres').find('div.on div:eq(1)>p:eq(0)').text();
            let phone=$('.addres').find('div.on div:eq(1)>p:eq(1)').text();
            console.log("name=%s,address=%s,phone=%s",name,address,phone);
            //获取支付方式
            let pay=$('.way').find('img.on').attr('value');
            console.log(pay);
            //获取快递方式
            let dis=$('.dis').find('span.on').text();
            console.log(dis);
            //获取勾选结算的商品ID
            let gids=$('#gids').val();
            //拼接请求参数
            let params={
                gids:gids,
                address:address,
                person:name,
                telephone:phone,
                pay:pay,
                mail:dis
            };
            console.log(params);
    
            $.post('/order/addOrder',params,function(rs){
                if(rs.code==200){
                    location.href='/page/ok.html';
                }else{
                    alert(rs.msg);
                }
            },'json');
        });
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    2、后台进行下单操作

    OrderController.java
    同上一点的OrderController.java
    OrderServiceImpl.java:

    package com.xnx.spbootpro.service.impl;
    
    import com.xnx.spbootpro.model.Order;
    import com.xnx.spbootpro.mapper.OrderMapper;
    import com.xnx.spbootpro.model.OrderItem;
    import com.xnx.spbootpro.model.dto.OrderDto;
    import com.xnx.spbootpro.model.vo.ShopCarItem;
    import com.xnx.spbootpro.service.IOrderItemService;
    import com.xnx.spbootpro.service.IOrderService;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import com.xnx.spbootpro.utils.SnowFlake;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    
    import java.math.BigDecimal;
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 

    * 订单信息表 服务实现类 *

    * * @author xnx * @since 2022-11-08 */
    @Service public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService { @Autowired private OrderMapper orderMapper; @Autowired private IOrderItemService orderItemService; @Transactional @Override public void addOrder(OrderDto orderDto, List<ShopCarItem> shopCarItems) { //1) 生成订单ID // 相比较于UUID的优点在于,雪花ID可以排序 SnowFlake snowFlake = new SnowFlake(2, 3); Long orderId=snowFlake.nextId(); orderDto.setOid(orderId); //2) 循环勾选的商品集合计算商品总价、获取商品详情集合 //总价 BigDecimal total=BigDecimal.valueOf(0); //定义商品详情集合 List<OrderItem> orderItems=new ArrayList<>(); OrderItem it=null; for (ShopCarItem shopCarItem : shopCarItems) { //累加小计等于总价 total=total.add(shopCarItem.smalltotal()); //初始化OrderItem商品详情对象 it=new OrderItem(); // 订单项表的ooid为自增,所以不需要设置 it.setOid(orderId); it.setGid(shopCarItem.getGid()); it.setGoodsName(shopCarItem.getGoodsName()); it.setGoodsPrice(shopCarItem.getGoodsPrice()); it.setQuantity(shopCarItem.getQuantity()); orderItems.add(it); } orderDto.setTotal(total); //1.保存订单 orderMapper.insert(orderDto); //2.保存订单对应的订单项 orderItemService.saveBatch(orderItems); } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72

    三、沙箱支付简介

    配置沙箱支付

    第一步:
    1)登陆支付宝:https://open.alipay.com/
    2)首页找到进入管理中心 -> 开发工具推荐选择【沙箱】
    3)下载安装支付宝开放平台开发助手:
    https://opendocs.alipay.com/common/02kipk
    4)打开本地支付宝开放平台助手 -> 密钥工具 -> 生成密钥 -> 以默认方式(RSA2和PKCS8)生成应用私钥和应用公钥
    5)在沙箱应用的开发信息中选择自定义密钥生成支付宝公钥(基于应用公钥生成支付宝公钥)

    第二步:配置沙箱账号(买家)并完成手动充值
    https://open.alipay.com/develop/sandbox/account

    第三步:下载沙箱支付宝(只支持安卓)
    https://open.alipay.com/develop/sandbox/tool/alipayclint

    沙箱工具 -> 支付宝客户端沙箱版 -> 请使用浏览器中的扫码功能扫描下载

    注:请使用Android手机扫码下载支付宝客户端沙箱版;如需登录,请访问沙箱账号,在商家信息中获取帐密

    四、沙箱支付应用

    实现思路

    1.完成支付宝沙箱支付功能接入
    2.支付成功后变更订单状态

    1、完成支付宝沙箱支付功能接入

    根据官方网站开发文档进行支付宝支付接入
    https://opendocs.alipay.com/common/02kg69

    AlipayConfig.java:

    package com.xnx.spbootpro.config;
    
    import com.alipay.easysdk.factory.Factory;
    import com.alipay.easysdk.kernel.Config;
    import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
    import com.xnx.spbootpro.model.dto.OrderDto;
    
    /**
     * 支付宝沙箱支付
     */
    /**
     * @author xnx
     * @create 2022-11-08 16:20
     */
    public class AlipayConfig {
        public String goAlipay(OrderDto orderDto){
            try {
                // 1. 设置参数(全局只需设置一次)
                Factory.setOptions(aliconfig());
                // 2. 发起API调用(subject商品标题、outTradeNo订单编号、totalAmount总金额、returnUrl异步通知地址)
                AlipayTradePagePayResponse response = Factory.Payment.Page()
                        .pay(orderDto.getOid()+"",
                                orderDto.getOid()+"",
                                orderDto.getTotal().toString(),
                                "http://localhost:8081/page/ok.html");  //支付成功之后的异步通知(跳出到自己系统的哪个位置)
    //                            "http://localhost:8081/order/orderFinish");
                System.out.println(response.body);
                return response.body;
            }  catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }
    
        private Config aliconfig(){
            Config config=new Config();
            //沙箱支付宝地址
            config.gatewayHost="openapi.alipaydev.com";
            //协议https
            config.protocol="https";
            //应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号
            config.appId="2021000121688520";
            //支付宝公钥
            config.alipayPublicKey="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvUzm5DQGaq8E9C8SgKFsHru+6reHfQScSLCw3QS0E58IvFT+usscxzWsyuBTbPJndpZdMXZdjM0BLkG9usmIrx61Ot++WBan1qRhuQi0OmAVGMWKYqBcnbe8TuGd7ipplYNq544uYiHoM/pf6JaVaIlssvTolW4TA22bwnpzsVhM4583fBR4C0G42LRIyLDxAeJ504qYZ3bxil4hxxhVjDRrip/PuEvQXhhB/xQiAO52LJFPHFpf34tkzn38fCRhOYATDUSfpeqN0SdyhgEr7XiyZqHOOK/HFnjd4E5+VRpHDw/cbQr4fK07MX10BKnQiWJ7dkXTcIo6C936YifcBQIDAQAB";
            //签名方式
            config.signType="RSA2";
            //商户私钥(应用私钥),您的PKCS8格式RSA2私钥
            config.merchantPrivateKey="MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDOyXz0HJ59v7XUFIJzr8rTUjG/n43AL6lTVEoaJ4su2IRUUoTcgxDCVs21OSokt4zzDCNJDDlvFCeOTNUiJXv3I6VNmk7HtuUw6u92MYOBO9ogc9xcYqDDeZWdG+GO4p+UaqfJmExK3H7QtyC9dzNGk/UCFCqEglKh8hYFXEgPXW6VzZy1H9jwEqwd3HuBwwmRG9J82wwspWL6nDQSPhMfdEa3uWKoHm2SsXPzdxPjm0nnqsE41qYZGCMrocJTbI8tVRZoDapzSRvfoVKPkwACqNWdSyI5emeyPTC3XwDtseuy8GWlPxIBbtm5fxwVQj1XXX8tpje+7LQ/fteQS5NHAgMBAAECggEACohErwJOKEV9c2HgCxhnEkBbfFEaHTHQRAhFBfQBqM8qXkkdr0WVsvBM5fAVb21R5oc1vOC8hCXYpezP5j9Wgw3zu3IilRWBsu4kaDa5ZfmwcHq2PJZhbdNhhXEIGgj868hK53+0UxPL+cF6D2xk1jFvBz4TtFAW+VylNnyuxul56UkMkhIqPwxi4EP5Sb9OooeqYhzdil9RVCdgJcD/aeTY/+gJC7xNkzDEICGS8bLziNWq/Yn1aKc4N7kOAy2M8Dpx3bzH1LLzCVcnBspuCLyodExikU8VirDdJVsoExjdU6EX6Pae34PM0TJxE4agkRMNbP5426QX4L/tNxQukQKBgQDqeLLNE/a3uwiI48IGI5aWEacBO17Iiqdz5fDNEbvf6d7qSFLyBgPxgk/HmuccpuYsLKqvCjI7lQwTfiD5NDUJ5ktHvDyhTCqzssyMw/nS2UqdUB2kq5LF5JRdMU/CNSIZuLAkxaemwNnAZqOmlDgqY1oTW0U1nFRhfjY/OxILZQKBgQDhxg/HQsW2NGCnFpsu1QBmeP24bKTwGKV0GzYKHgYs2iVSQP+ZTEH1H7GjsAPXsg4jbBFqvw7yNv/ghCUU4FzIyLI3kpyccUwi0qBJZ3q+LLB/F5T1hmpniMIluKdLIC2fBAkR7uOp+fk76YnWSurGvluUT9sdRpFN73ev4It3OwKBgDvZAwqFhfvvqYYHXIbknpM/fjk6Rj855PQYRRaS6DmHIHb8bu+HyYnjkSmJyGPv1eCApjB3kcrTiHmRQClbwg380kpFKdSh9GRZxwxHGYVQIVN2F5rokFYiuhvvckRH+6RFF/DK4rgVkX8is7LZMlzfbyZxrYC5nnAkHwSUt05hAoGBAI774Yg/aHlhKIkJTxRUv2EmZQEEhVytLzOd/BZiN2T2bsZt9bH/UpJMFTNmSLi0wjF6wnkJMQ0C+gAVkGptQTXDrOJ3DoohUqeHHw395AVGxixnIeZwzzhsqxA6pnB0m4/mfVwHH9XJQyfHWo0FezSM3/DItisPQvzJmNIg8hJ7AoGAS9epjgLLkkFku1kh2lLuvKs56kV8Gp5ZgjxtoDL2l0qfIQSuPstbQOQFB71Bm+0Y9yB2zeOFvGAFhxCxlnKwSNCUgpqvUwdl3NNyM9o3mAkjnZcCGUBoW0/y+1sdsZpmQVRSas/wbYCqAQyWVzv9aXQqmFDwwanP1/55wZ7Z+ew=";
            return config;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    order.js

    $(function(){
        $('.pay').click(function(){
            //获取收货地址、联系人、联系电话
            let name=$('.addres').find('div.on div:eq(0)>p:eq(0)').text().trim();
            let address=$('.addres').find('div.on div:eq(1)>p:eq(0)').text();
            let phone=$('.addres').find('div.on div:eq(1)>p:eq(1)').text();
            console.log("name=%s,address=%s,phone=%s",name,address,phone);
            //获取支付方式
            let pay=$('.way').find('img.on').attr('value');
            console.log(pay);
            //获取快递方式
            let dis=$('.dis').find('span.on').text();
            console.log(dis);
            //获取勾选结算的商品ID
            let gids=$('#gids').val();
            //拼接请求参数
            let params={
                gids:gids,
                address:address,
                person:name,
                telephone:phone,
                pay:pay,
                mail:dis
            };
            console.log(params);
    
            // $.post('/order/addOrder',params,function(rs){
            //     if(rs.code==200){
            //         location.href='/page/ok.html';
            //     }else{
            //         alert(rs.msg);
            //     }
            // },'json');
    
            location.href='/order/addOrder?'+parseParams(params);
    
        });
    });
    
    /**
     * JSON转URL参数
     * @param data
     * @returns {string}
     */
    function parseParams(data) {
        try {
            var tempArr = [];
            for (var i in data) {
                var key = encodeURIComponent(i);
                var value = encodeURIComponent(data[i]);
                tempArr.push(key + '=' + value);
            }
            var urlParamsStr = tempArr.join('&');
            return urlParamsStr;
        } catch (err) {
            return '';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    OrderController.java

    @RequestMapping("/addOrder")
    @ResponseBody
    public String addOrder(User user,
    								 HttpServletRequest req,
    								 OrderDto orderDto){
    	//获取购物车
    	ShopCar shopCar = this.getShopCar(user.getId(), req);
    	//获取结算商品集合
    	List<ShopCarItem> shopCarItems = this.getShopCarItems(shopCar, orderDto.getGids());
    	//生成订单及订单项
    	orderDto.setUserId(Long.parseLong(user.getId()));
    	orderService.addOrder(orderDto,shopCarItems);
    	//从购物车中删除已结算的商品
    	shopCar.delete(orderDto.getGids());
    	//跳转支付页面(下节课内容)
    	AlipayConfig alipayConfig = new AlipayConfig();
    	return alipayConfig.goAlipay(orderDto);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    2、支付成功后变更订单状态

    OrderController.java代码新增如下

    /**
     * 支付成功后回调处理订单状态,完成整个下单流程的链路
     * @param param
     * @return
     */
    @RequestMapping("/orderFinish")
    public String orderFinish(@RequestParam Map<String, String> param){
    	System.out.println("异步回调开始。。。。。。");
    	Boolean signVerified=false;
    
    	try {
    		System.out.println(param);
    		signVerified = Factory.Payment.Common().verifyNotify(param);
    		System.out.println(signVerified);
    		System.out.println("out_trade_no:"+param.get("out_trade_no"));
    		System.out.println("total_amount:"+param.get("total_amount"));
    		System.out.println("trade_no:"+param.get("trade_no"));
    		if(signVerified){
    			//支付成功
    			//根据订单编号修改订单状态
    			//update t_xxx set xx=?,tt=? where id=?
    			orderService.update(new UpdateWrapper<Order>()
    					.set("status",1)
    					.setSql("pay_date=now()")
    					.eq("oid",param.get("out_trade_no")));
    			//跳转到支付成功页面
    		}else{
    			//支付失败
    		}
    
    
    	} catch (Exception e) {
    		e.printStackTrace();
    	}
    	return "ok.html";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    AlipayConfig.java变更如下

    public String goAlipay(OrderDto orderDto) {
    	try {
    		// 1. 设置参数(全局只需设置一次)
    		Factory.setOptions(aliconfig());
    		// 2. 发起API调用(subject商品标题、outTradeNo订单编号、totalAmount总金额、returnUrl异步通知地址)
    		AlipayTradePagePayResponse response = Factory.Payment.Page()
    				.pay(orderDto.getOid() + "",
    						orderDto.getOid() + "",
    						orderDto.getTotal().toString(),
    //                            "http://localhost:8081/page/ok.html");  //支付成功之后的异步通知(跳出到自己系统的哪个位置)
    						"http://localhost:8081/order/orderFinish");  //支付成功之后的异步通知(跳出到自己系统的哪个位置)
    		System.out.println(response.body);
    		return response.body;
    	} catch (Exception e) {
    		e.printStackTrace();
    		throw new RuntimeException(e);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述

  • 相关阅读:
    【Linux】常用命令汇总
    全栈开发可能需要的环境及工具
    Linux内存管理(十九):slab 分配器概述和初始化
    Spring中常用的请求处理携带参数的注解@RequestBody、@RequestParam和 @PathVariable
    处理Java异常的10个最佳实践
    剑指 Offer 2022/7/2
    前后端分离项目,vue+uni-app+php+mysql在线小说电子书阅读小程序系统设计与实现
    Matlab读写操作
    R语言使用使用as_tibble函数和names函数基于一个dataframe的列名列表创建一个新的dataframe
    深入理解并发和并行
  • 原文地址:https://blog.csdn.net/weixin_67677668/article/details/127756247