网上商城项目(购物车下单、支付)

目录

一、购物车结算前端功能实现

1.购物车页面实现结算功能,主要是拿到传入后台的gids 

二、购物车结算后端功能实现 

1.跳转订单页后台,主要是拿到订单页展示数据  

2.订单页前台展示 

三、生成订单

1.结算页的下单前端

 2.结算下单后台实现

 四、沙箱支付简介

1.配置沙箱支付

 五、沙箱支付应用

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

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


一、购物车结算前端功能实现

 实现思路

1.购物车页面实现结算功能,主要是拿到传入后台的gids

2.跳转订单页后台,主要是拿到订单页展示数据

3.订单页前台数据展示

1.购物车页面实现结算功能,主要是拿到传入后台的gids 

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

测试效果如下:

关于结算按钮的绑定事件

//计算总共几件商品
function zg(){
	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{
		index.each(function(){
			zsl+=parseInt($(this).text());
			$("#sl").text(zsl);
		})
	}
	if($("#sl").text()>0){
		$(".count").css("background","#c10000");
	//	TODO	绑定结算事件
		$(".count").bind("click",function () {
			alert("绑定结算事件");
		})
	}else{
		$(".count").css("background","#8e8e8e");
		$(".count").unbind("click");
	}
}

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 () {
				//拿到gids
			     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
		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();
			console.log(gids);

			$('.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();

				//TODO 先获取所有即将被删除的商品ID
				let gidarr = new Array();
				$(".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='<span class="edit">修改</span>';
//		$(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');
}

测试结果如下:

二、购物车结算后端功能实现 

 在点击结算的事件下,添加上跳转地址:

if($("#sl").text()>0){
   $(".count").css("background","#c10000");
   $(".count").bind("click",function () {
      //拿到gids
       location.href='/order/toOrder?gids='+gids
   });
}else{
   $(".count").css("background","#8e8e8e");
   $(".count").unbind("click");
}

先生成订单表,订单信息表 t_order 、t_order_item

打开CodeGenerator.java运行里面的main方法

package com.jwj.spbootpro.generator;

import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class CodeGenerator {

    /**
     * <p>
     * 读取控制台内容
     * </p>
     */
    public static String scanner(String tip) {
        Scanner scanner = new Scanner(System.in);
        StringBuilder help = new StringBuilder();
        help.append("请输入" + tip + ":");
        System.out.println(help.toString());
        if (scanner.hasNext()) {
            String ipt = scanner.next();
            if (StringUtils.isNotBlank(ipt)) {
                return ipt;
            }
        }
        throw new MybatisPlusException("请输入正确的" + tip + "!");
    }

    public static void main(String[] args) {
        // 代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir") + "/spbootpro";
        gc.setOutputDir(projectPath + "/src/main/java");
        gc.setAuthor("jwj");
        gc.setOpen(false);
        gc.setBaseColumnList(true);
        gc.setBaseResultMap(true);
        // gc.setSwagger2(true); 实体属性 Swagger2 注解
        mpg.setGlobalConfig(gc);

        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/spbootpro?useUnicode=true&useSSL=false&characterEncoding=utf8");
        // dsc.setSchemaName("public");
        dsc.setDriverName("com.mysql.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("123456");
        mpg.setDataSource(dsc);

        // 包配置
        PackageConfig pc = new PackageConfig();
        //pc.setModuleName(scanner("模块名"));
        pc.setParent("com.jwj.spbootpro");
        //设置包名
        pc.setEntity("model");
        mpg.setPackageInfo(pc);

        // 自定义配置
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                // to do nothing
            }
        };

        // 如果模板引擎是 freemarker
        String templatePath = "/templates/mybatis-generator/mapper2.xml.ftl";
        // 如果模板引擎是 velocity
        // String templatePath = "/templates/mapper.xml.vm";

        // 自定义输出配置
        List<FileOutConfig> focList = new ArrayList<>();
        // 自定义配置会被优先输出
        focList.add(new FileOutConfig(templatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
                return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
                        + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
            }
        });
        /*
        cfg.setFileCreate(new IFileCreate() {
            @Override
            public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {
                // 判断自定义文件夹是否需要创建
                checkDir("调用默认方法创建的目录,自定义目录用");
                if (fileType == FileType.MAPPER) {
                    // 已经生成 mapper 文件判断存在,不想重新生成返回 false
                    return !new File(filePath).exists();
                }
                // 允许生成模板文件
                return true;
            }
        });
        */
        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);

        // 配置模板
        TemplateConfig templateConfig = new TemplateConfig();

        // 配置自定义输出模板
        //指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
        templateConfig.setMapper("templates/mybatis-generator/mapper2.java");
        templateConfig.setEntity("templates/mybatis-generator/entity2.java");
        templateConfig.setService("templates/mybatis-generator/service2.java");
        templateConfig.setServiceImpl("templates/mybatis-generator/serviceImpl2.java");
        templateConfig.setController("templates/mybatis-generator/controller2.java");
        templateConfig.setXml(null);
        mpg.setTemplate(templateConfig);

        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        //strategy.setSuperEntityClass("你自己的父类实体,没有就不用设置!");
        strategy.setEntityLombokModel(true);
        strategy.setRestControllerStyle(true);
        strategy.setEntitySerialVersionUID(false);
        // 公共父类
        //strategy.setSuperControllerClass("你自己的父类控制器,没有就不用设置!");
        // 写于父类中的公共字段
        strategy.setSuperEntityColumns("id");
        strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
        strategy.setControllerMappingHyphenStyle(true);
        strategy.setTablePrefix("t_");
        mpg.setStrategy(strategy);
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
        mpg.execute();
    }
}

如下图所示:

生成成功后如果有时间问题都改为Date,因为我们上一次的错误就又出现这样的情况,凡是有带时间的都改过来,就比如生成这个Order.java

1.跳转订单页后台,主要是拿到订单页展示数据  

思路

1.从session中获取购物车对象

2.筛选出要结算的订单项列表集合

OrderController.java

package com.jwj.spbootpro.controller;


import com.jwj.spbootpro.model.Goods;
import com.jwj.spbootpro.model.User;
import com.jwj.spbootpro.model.vo.ShopCar;
import com.jwj.spbootpro.model.vo.ShopCarItem;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

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;

/**
 * <p>
 * 订单信息表 前端控制器
 * </p>
 *
 * @author jwj
 * @since 2022-11-10
 *
 * @Controller:因为我们最终是要跳转到页面
 */
@Controller
@RequestMapping("/order")
public class OrderController {

    /**
     * 根据勾选结算的商品跳转到订单页面
     * @param user
     * @param gids
     * @param request
     * @return
     */
    @RequestMapping("/toOrder")
    public ModelAndView toOrder(User user,String gids, HttpServletRequest request){
        ModelAndView mv = new ModelAndView();
//        拿到购物车中的所有商品
        ShopCar shopCar = getShopCar(user, request);
//        通过gids从购物车中筛选出指定的商品
        List<ShopCarItem> list = getGoods(shopCar,gids);
        mv.addObject("goods",list);
        mv.setViewName("order.html");
        return mv;
    }

    /**
     * 由于用户结算商品时,不一定是将购物车中所有商品进行结算,有可能只有部分商品
     * 必须根据前端页面用户勾选的商品ID从购物车中找到对应需要结算的商品并存入
     * @param shopCar
     * @param gids
     * @return
     */
//    通过gids从购物车中筛选出指定的商品
    private List<ShopCarItem> getGoods(ShopCar shopCar, String gids) {
        //根据逗号分割商品gids
        List<String> gidList = Arrays.asList(gids.split(","));
        //代表购物车中已有的商品集合
        List<ShopCarItem> items = shopCar.getItems();   //3个    购物车里的商品
        //定义结算商品集合
        List<ShopCarItem> itemsNew = new ArrayList<>();//2个    购物车要结算的商品
        //循环遍历购物车中的商品并与勾选结算的商品ID进行比较
        for (ShopCarItem item : items) {
            //判断购物车中的商品与勾选结算的商品ID是否一致
            if(gidList.contains(item.getGid()+"")){
                itemsNew.add(item);
            }
        }
        return itemsNew;
    }

    //    从session中获取购物车对象
    private ShopCar getShopCar(User user, HttpServletRequest request){
        //获取session
        HttpSession session = request.getSession();
        //从session中获取购物车对象
        ShopCar shopCar = (ShopCar)session.getAttribute(user.getId() + "_shopCar");
        //判断shopCar是否为空
        if(shopCar == null){
            //初始化购物车对象
            shopCar = new ShopCar();
            //将初始化完成的购物车对象根据用户id报错到session中
            session.setAttribute(user.getId()+"_shopCar",shopCar);
        }
        return shopCar;
    }

}

2.订单页前台展示 

order.html

<!DOCTYPE html>
<html>
   <head lang="en">
      <#include "common/head.html">
      <link rel="stylesheet" type="text/css" href="css/public.css"/>
      <link rel="stylesheet" type="text/css" href="css/proList.css" />
      <link rel="stylesheet" type="text/css" href="css/mygxin.css" />
   </head>
   <body>
      <!----------------------------------------order------------------>
      <div class="head ding">
         <div class="wrapper clearfix">
            <div class="clearfix" id="top">
               <h1 class="fl"><a href="${ctx}/"><img src="img/logo.png"/></a></h1>
               <div class="fr clearfix" id="top1">
                  <form action="#" method="get" class="fl">
                     <input type="text" placeholder="搜索" />
                     <input type="button" />
                  </form>
               </div>
            </div>
         </div>
      </div>
      <!-----------------site------------------->
      <div class="order cart mt">
      <div class="site">
            <p class="wrapper clearfix">
               <span class="fl">订单确认</span>
               <img class="top" src="img/temp/cartTop02.png">
            </p>
         </div>
         <!-----------------orderCon------------------->
         <div class="orderCon wrapper clearfix">
            <div class="orderL fl">
               <!--------h3---------------->
               <h3>收件信息<a href="#" class="fr">新增地址</a></h3>
               <!--------addres---------------->
               <div class="addres clearfix">
                  <div class="addre fl on">
                     <div class="tit clearfix">
                        <p class="fl">张三1
                           <span class="default">[默认地址]</span>
                        </p>
                        <p class="fr">
                           <a href="#">删除</a>
                           <span>|</span>
                           <a href="#" class="edit">编辑</a>
                        </p>
                     </div>
                     <div class="addCon">
                        <p>河北省&nbsp;唐山市&nbsp;路北区&nbsp;大学生公寓村</p>
                        <p>15732570937</p>
                     </div>
                  </div>
                  <div class="addre fl">
                     <div class="tit clearfix">
                        <p class="fl">张三2
                        </p>
                        <p class="fr">
                           <a href="#" class="setDefault">设为默认</a>
                           <span>|</span>
                           <a href="#">删除</a>
                           <span>|</span>
                           <a href="#" class="edit">编辑</a>
                        </p>
                     </div>
                     <div class="addCon">
                        <p>河北省&nbsp;唐山市&nbsp;路北区&nbsp;大学生公寓村</p>
                        <p>15732570937</p>
                     </div>
                  </div>
                  <div class="addre fl">
                     <div class="tit clearfix">
                        <p class="fl">张三3
                        </p>
                        <p class="fr">
                           <a href="#" class="setDefault">设为默认</a>
                           <span>|</span>
                           <a href="#">删除</a>
                           <span>|</span>
                           <a href="#" class="edit">编辑</a>
                        </p>
                     </div>
                     <div class="addCon">
                        <p>河北省&nbsp;唐山市&nbsp;路北区&nbsp;大学生公寓村</p>
                        <p>15732570937</p>
                     </div>
                  </div>
               </div>
               <h3>支付方式</h3>
               <!--------way---------------->
               <div class="way clearfix">
                  <img class="on" value="0" src="img/temp/way01.jpg">
                  <img value="1" src="img/temp/way02.jpg">
                  <img value="2" src="img/temp/way03.jpg">
                  <img value="3" src="img/temp/way04.jpg">
               </div>
               <h3>选择快递</h3>
               <!--------dis---------------->
               <div class="dis clearfix">
                  <span class="on">顺风快递</span>
                  <span>百世汇通</span>
                  <span>圆通快递</span>
                  <span>中通快递</span>
               </div>
            </div>
            <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>
               <!--------tips---------------->
               <div class="tips">
                  <p><span class="fl">商品金额:</span><span class="fr">¥139.8</span></p>
                  <p><span class="fl">优惠金额:</span><span class="fr">¥0.00</span></p>
                  <p><span class="fl">运费:</span><span class="fr">免运费</span></p>
               </div>
               <!--------tips count---------------->
               <div class="count tips">
                  <p><span class="fl">合计:</span><span class="fr">¥139.8</span></p>

               </div>
               <!--<input type="button" name="" value="去支付"> -->
               <a href="javascript:void(0);" class="pay">去支付</a>
            </div>
         </div>
      </div>
      <!--编辑弹框-->
      <!--遮罩-->
      <div class="mask"></div>
      <div class="adddz editAddre">
         <form action="#" method="get">
            <input type="text" placeholder="姓名" class="on" />
            <input type="text" placeholder="手机号" />
            <div class="city">
               <select name="">
                  <option value="省份/自治区">省份/自治区</option>
               </select>
               <select>
                  <option value="城市/地区">城市/地区</option>
               </select>
               <select>
                  <option value="区/县">区/县</option>
               </select>
               <select>
                  <option value="配送区域">配送区域</option>
               </select>
            </div>
            <textarea name="" rows="" cols="" placeholder="详细地址"></textarea>
            <input type="text" placeholder="邮政编码" />
            <div class="bc">
               <input type="button" value="保存" />
               <input type="button" value="取消" />
            </div>
         </form>
      </div>
      <!--返回顶部-->
      <input type="hidden" id="gids" value="${RequestParameters['gids']!}"/>
      <#include "common/footer.html">
      <script src="js/others/order.js" type="text/javascript" charset="utf-8"></script>
      <script src="js/public.js" type="text/javascript" charset="utf-8"></script>
      <script src="js/pro.js" type="text/javascript" charset="utf-8"></script>
      <script src="js/user.js" type="text/javascript" charset="utf-8"></script>
   </body>
</html>

 展示结果如下:

结算如下所示:

三、生成订单

实现思路

1.前台订单相关数据获取

2.后台进行下单操作 

1.结算页的下单前端

前端相关处理

1.获取收货地址、收货人以及联系电话

2.获取支付方式

获取快递方式

 


在Order.html添加Order.js 

Order.js代码如下:

$(function () {
    $(".pay").click(function () {
        // 1)获取收货地址、收货人以及联系电话
        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);
        // 2)获取支付方式
        let pay=$('.way').find('img.on').attr('value');
        console.log(pay);
        // 3)获取快递方式
        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');
    });
});

 2.结算下单后台实现

建一个OrderDto.java为了处理在order.js里去写大量的js代码

OrderDto.java

package com.jwj.spbootpro.model.dto;

import com.jwj.spbootpro.model.Order;
import lombok.Data;

/**
 * @author 敢敢
 * @site www.javajwj.com
 * @company xxx公司
 * @create  2022-11-10 18:23
 */
@Data
public class OrderDto extends Order {
    private String gids;
}

OrderController.java   

package com.jwj.spbootpro.controller;


import com.jwj.spbootpro.model.Goods;
import com.jwj.spbootpro.model.User;
import com.jwj.spbootpro.model.dto.OrderDto;
import com.jwj.spbootpro.model.vo.ShopCar;
import com.jwj.spbootpro.model.vo.ShopCarItem;
import com.jwj.spbootpro.service.IOrderService;
import com.jwj.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.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;

/**
 * <p>
 * 订单信息表 前端控制器
 * </p>
 *
 * @author jwj
 * @since 2022-11-10
 *
 * @Controller:因为我们最终是要跳转到页面
 */
@Controller
@RequestMapping("/order")
public class OrderController {

    /**
     * 根据勾选结算的商品跳转到订单页面
     * @param user
     * @param gids
     * @param request
     * @return
     */
    @RequestMapping("/toOrder")
    public ModelAndView toOrder(User user,String gids, HttpServletRequest request){
        ModelAndView mv = new ModelAndView();
//        拿到购物车中的所有商品
        ShopCar shopCar = getShopCar(user, request);
//        通过gids从购物车中筛选出指定的商品
        List<ShopCarItem> list = getGoods(shopCar,gids);
        mv.addObject("goods",list);
        mv.setViewName("order.html");
        return mv;
    }

    /**
     * 由于用户结算商品时,不一定是将购物车中所有商品进行结算,有可能只有部分商品
     * 必须根据前端页面用户勾选的商品ID从购物车中找到对应需要结算的商品并存入
     * @param shopCar
     * @param gids
     * @return
     */
//    通过gids从购物车中筛选出指定的商品
    private List<ShopCarItem> getGoods(ShopCar shopCar, String gids) {
        //根据逗号分割商品gids
        List<String> gidList = Arrays.asList(gids.split(","));
        //代表购物车中已有的商品集合
        List<ShopCarItem> items = shopCar.getItems();   //3个    购物车里的商品
        //定义结算商品集合
        List<ShopCarItem> itemsNew = new ArrayList<>();//2个    购物车要结算的商品
        //循环遍历购物车中的商品并与勾选结算的商品ID进行比较
        for (ShopCarItem item : items) {
            //判断购物车中的商品与勾选结算的商品ID是否一致
            if(gidList.contains(item.getGid()+"")){
                itemsNew.add(item);
            }
        }
        return itemsNew;
    }

    //    从session中获取购物车对象
    private ShopCar getShopCar(User user, HttpServletRequest request){
        //获取session
        HttpSession session = request.getSession();
        //从session中获取购物车对象
        ShopCar shopCar = (ShopCar)session.getAttribute(user.getId() + "_shopCar");
        //判断shopCar是否为空
        if(shopCar == null){
            //初始化购物车对象
            shopCar = new ShopCar();
            //将初始化完成的购物车对象根据用户id报错到session中
            session.setAttribute(user.getId()+"_shopCar",shopCar);
        }
        return shopCar;
    }

    @Autowired
    private IOrderService orderService;

    @ResponseBody
    @RequestMapping("/addOrder")
    //非ajax返回的ModelAndView,ajax返回的是JsonResponseBody
    public JsonResponseBody addOrder(User user, OrderDto orderDto,HttpServletRequest request){
        // 1.拿到购物车 2.通过orderDto拿到gids,再拿到要结算的商品 3.数据要入订单表 4.数据要入订单项表
        //获取购物车
        ShopCar shopCar = this.getShopCar(user, request);
        //获取结算商品集合
        List<ShopCarItem> shopCarItems = this.getGoods(shopCar, orderDto.getGids());
        //生成订单及订单项
        orderDto.setUserId(user.getId());
        orderService.addOrder(orderDto,shopCarItems);
        //从购物车中删除已结算的商品
        shopCar.delete(orderDto.getGids());
        //跳转支付页面
        return new JsonResponseBody();
    }
}

 IOrderService.java创建addOrder方法

package com.jwj.spbootpro.service;

import com.jwj.spbootpro.model.Order;
import com.baomidou.mybatisplus.extension.service.IService;
import com.jwj.spbootpro.model.dto.OrderDto;
import com.jwj.spbootpro.model.vo.ShopCarItem;

import java.util.List;

/**
 * <p>
 * 订单信息表 服务类
 * </p>
 *
 * @author jwj
 * @since 2022-11-10
 */
public interface IOrderService extends IService<Order> {

    void addOrder(OrderDto orderDto, List<ShopCarItem> shopCarItems);
}

 在我们的实现类也要实现addOrder方法

OrderServiceImpl.java

package com.jwj.spbootpro.service.impl;

import com.jwj.spbootpro.model.Order;
import com.jwj.spbootpro.mapper.OrderMapper;
import com.jwj.spbootpro.model.OrderItem;
import com.jwj.spbootpro.model.dto.OrderDto;
import com.jwj.spbootpro.model.vo.ShopCarItem;
import com.jwj.spbootpro.service.IOrderItemService;
import com.jwj.spbootpro.service.IOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jwj.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;

/**
 * <p>
 * 订单信息表 服务实现类
 * </p>
 *
 * @author jwj
 * @since 2022-11-10
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {
    @Autowired
    private OrderMapper orderMapper;

    @Autowired
   private IOrderItemService orderItemService;


//    @Transactional注解:以下的方法因为同时设置到两张表的增删改的操作,要么同时成功,要么同时失败
    @Transactional
    @Override
    public void addOrder(OrderDto orderDto, List<ShopCarItem> shopCarItems) {
//        订单表以及订单项表的数据录入
        //1) 生成订单ID     SnowFlake生成雪花ID,它的作用,生成一个随机的long类型的数字;
//        相比较于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);

    }
}

给我们OrderMapper添加注解@repository,

同时还要OrderItemMapper也要添加注解@repository

SnowFlake.java 放到我们的util里面去

这是我们的雪花算法,把我们的id转成一个long类型的随机的一个数字

想比较于UUID的优点在于,雪花ID可以排序 

package com.jwj.spbootpro.utils;

public class SnowFlake {

    /**
     * 起始的时间戳
     */
    private final static long START_STMP = 1480166465631L;

    /**
     * 每一部分占用的位数
     */
    private final static long SEQUENCE_BIT = 12; //序列号占用的位数
    private final static long MACHINE_BIT = 5;   //机器标识占用的位数
    private final static long DATACENTER_BIT = 5;//数据中心占用的位数

    /**
     * 每一部分的最大值
     */
    private final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT);
    private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);
    private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);

    /**
     * 每一部分向左的位移
     */
    private final static long MACHINE_LEFT = SEQUENCE_BIT;
    private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
    private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT;

    private long datacenterId;  //数据中心
    private long machineId;     //机器标识
    private long sequence = 0L; //序列号
    private long lastStmp = -1L;//上一次时间戳

    public SnowFlake(long datacenterId, long machineId) {
        if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) {
            throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0");
        }
        if (machineId > MAX_MACHINE_NUM || machineId < 0) {
            throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0");
        }
        this.datacenterId = datacenterId;
        this.machineId = machineId;
    }

    /**
     * 产生下一个ID
     *
     * @return
     */
    public synchronized long nextId() {
        long currStmp = getNewstmp();
        if (currStmp < lastStmp) {
            throw new RuntimeException("Clock moved backwards.  Refusing to generate id");
        }

        if (currStmp == lastStmp) {
            //相同毫秒内,序列号自增
            sequence = (sequence + 1) & MAX_SEQUENCE;
            //同一毫秒的序列数已经达到最大
            if (sequence == 0L) {
                currStmp = getNextMill();
            }
        } else {
            //不同毫秒内,序列号置为0
            sequence = 0L;
        }

        lastStmp = currStmp;

        return (currStmp - START_STMP) << TIMESTMP_LEFT //时间戳部分
                | datacenterId << DATACENTER_LEFT       //数据中心部分
                | machineId << MACHINE_LEFT             //机器标识部分
                | sequence;                             //序列号部分
    }

    private long getNextMill() {
        long mill = getNewstmp();
        while (mill <= lastStmp) {
            mill = getNewstmp();
        }
        return mill;
    }

    private long getNewstmp() {
        return System.currentTimeMillis();
    }

    public static void main(String[] args) {
        SnowFlake snowFlake = new SnowFlake(2, 3);

        long start = System.currentTimeMillis();
        for (int i = 0; i < 1000000; i++) {
            System.out.println(snowFlake.nextId());
        }

        System.out.println(System.currentTimeMillis() - start);


    }
}

测试效果如下图所示:

我们数据库里目前是没有数据的,如下所示:

注意:这里的数据库里面要自动增长,如果没有很可能会出错。 

最终跳转到结算成功页面,5s后自动跳转到订单展示页面,如下图所示:

在看一下我们数据库有没有数据,如下所示:

 四、沙箱支付简介

1.配置沙箱支付

第一步:

1)登陆支付宝:https://open.alipay.com/

点击登录:扫码登录

2)首页找到进入管理中心 ---》开发工具推荐选择【沙箱】

3)下载安装支付宝开放平台开发助手:

密钥工具简介 | 开放平台

下载好之后就是这样的,我下载的安卓的

4)打开本地支付宝开放平台助手---》密钥工具---》生成密钥---》以默认的方式(RSA2和KCS8)生成应用私钥和应用公钥

注意:密钥是留给自己用的 ,公钥是copy出去的

5)在沙箱应用的开发信息中选择自定义密钥生成支付宝公钥(基于应用公钥生成支付宝公钥)

第二步:配置沙箱账号(买家)并完成手动充值

登录 - 支付宝

第三步:下载沙箱支付宝(只支持安卓)

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

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

通过这个扫码它就会自动下载,下载沙箱支付宝APP的安装包,下载好了之后,这里面默认会有100万块钱或者其他,可以通过下面这种方式,进行充值。

 五、沙箱支付应用

实现思路

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

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

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

根据官方网站开发文档进行支付宝接入

Easy 版 | 开放平台

先在支付宝开放平台密钥工具,生成密钥,把我们的 应用公钥复制到

注意:上面的支付宝公钥复制了之后要记得点击确定。 

 把我们的支付宝公钥复制到我们的代码里面AlipayConfig类里的支付宝公钥

那么下面这里我封装了一版,封装类版,配置类 

AlipayConfig.java

package com.jwj.spbootpro.config;

import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.Config;
import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
import com.jwj.spbootpro.model.dto.OrderDto;

/**
 * 支付宝沙箱支付
 */
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");  //支付成功之后的异步通知(跳出到自己系统的哪个位置)
            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="2021000121687583";
        //支付宝公钥
        config.alipayPublicKey="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsc74PulHrpMlGXt53c1CYfBziNjY9W299fXA5aU3f+eKKNnjc9fmUXYusGms0MgSSYgji4SuAfl1LxtRJEwqz8L7zxOxq0JB6Y5+XFXiSpdys4f6wMJXoaRWamEzfaSkpgoJ6vO+VqJa+j77Brc//mxRtHjrcS3xW5doUBOsAAdofjwaaWgcT2cmzb3r/QEXu4vfrOdV4uuXD5GWJ7bIYTDuRsRBL8iBPtqv1OkB6184f2t0Qch0g6Pyti/cg10BB5s/i9uUCqHCtHl5CQrpubQc6hYb4mmp8ZXLvqfPAmq0fgABDQklCPdww7qML6cATsv+WZF+f5NsxVPOgYPeQwIDAQAB";
        //签名方式
        config.signType="RSA2";
        //商户私钥(应用私钥),您的PKCS8格式RSA2私钥
        config.merchantPrivateKey="MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCG0psRs7/OH5gLmjpvlINXDMPOMIlLk8oqP1KdeKBHTOejsk01PyN6zqS0rzqmYHRNMCFsZnX1JvpqvZ8F0Vcw8FSzTGXGLyvAufqic5dIASb91qcF/4QSnoFzNVhIp6KSUsWlpY87bHkRZlLY3sseHu8M4HWOJmr1XidvIFpozxDmc5EgA0tHqogcth6ncW3uGXtNtKg840hejawhpEryCXNPbPK0pq1P95iWpmV+YtxTUWSfFTgjc88JPCaNSfhpPx11Up3oDHsMa+RlsKD1xaetLzjfPwoU73ymPVo0ii88z/KrzdNKfTE0Mkm4GQbID31GJ4yhYW/jsLNUQs+vAgMBAAECggEAN8TEOjVVQMkW1q3MQD15eregAxlWoXmXpZQd819jRTsNkkv93empHnJ99POK2imJ0if3m2RipK6j5SVcs0Zdv7OaBbSzYKBAg+8qOqp/yFwZqeRxoGyKUD1apLJLO3qEJ+yvLw7lyZncFpNx751w/ZukHHp4hf1kPuzceP40B6gH8h8BIJTpYItP3fVYrECjJ94Yr68OAQZ1pvlwK68b1HD68MIInHZIeZ9QYpzfMoCk/6wNYE31yYuoUpkmoENuCrA2r/G2xOQBVwgIO8pPyJ7WQCC5/jtFu8pbob8HBb2QHAUfvYj+MXtxglC8cHZmXECW7+mc61YRFCS7AlnmkQKBgQD0prghOEQdp1zCw0y2yfhmLhwfARyZUFZbOe4yuKuWitsuG3c7t8JCPiT3ifXzRnyoG3ticQxctFtfsBmGFzNxk+Y7fyexzN5EMcwD6wGIstemxumF76ts4Ycj4iiuotxbqJ/gw/xPHcL03AZTMokO1+HR78xjHLXjl0LshgK9pwKBgQCNE6arORAsnvJnC5scDsE2IYcbB13+eRKed2I5KAIMfEnXYRIscI413dujU3vR85s6ed91+vifh6wchwtdngX/eJ7V5Diz7m46hvGDH7YAe9RbSD9QaedDf2z/kotKV6m16Wlwy64DCEUlyVkaw3I7qOjrezfATQLWqbsimCZuuQKBgGvEyRVxGKhLYhQ1PaTDYVV5eE+8CKIMfo3e/et/563/6r7rwGEg+ER/5X7ZWetZIG5Y9MgPblej5yBGjWfA7ptYgDGzOIQc78fwe6M6MUnLJi3EL3gddFEZI5ON+0e6XAFQTWUQUCN1w7xi87JQb4mHVWVKEamTKxhfOE7CVZC/AoGAHA2UTugB912EBkmghmvIr+Lq4s0MO9YHhctnlMYH4kO0y0daPcwD+2Iqkse/D3jJnU8uyF8noVFxQBr6f5s0xiBONWo0fFMlSC4dSF2960q0Z5JuRKdKfXmRSyDw4c+cx7eqZ+uYprG2TlVDirbiuEpWRr0x0ON/dQA7Xh2zRsECgYEAj4iagNb8hBqJOPLBLzca3qLbUmdrGMVSEbXxyJaR6RP9C4SFeuJTh09LqVcFuss+jw7GaCJ74j1a2xQuKDF1xlfO7krb32EV0KGnrMtVwTCyT7LVcugPw+rsd97pros85jZhigARiSUA3vKpQf0bA7BEfq2RFSVKZ9fdHVsUSAM=";
        return config;
    }
}

我们支付成功之后就要跳转到最终的那个页面了,然而我们之前是直接跳转到最终页面了,现在就不可以了。

order.js 就要变更如下:        支付会引发页面跳转,所以要经ajax请求换成页面跳转的方式

$(function(){
    $('.pay').click(function(){
        alert("11");
        //获取收货地址、联系人、联系电话
        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');
        //一般的支付成功网址都是很长就列如:http://localhost:8080/order/addOrder?gids=sjdksjljfdsjw&djfsj&name=jssjdj
        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 '';
    }
}

OrderController.java代码也要变更如下:

@Autowired
private IOrderService orderService;

@RequestMapping("/addOrder")
@ResponseBody
//非ajax返回的ModelAndView,ajax返回的是JsonResponseBody
public String addOrder(User user, OrderDto orderDto,HttpServletRequest request){
    // 1.拿到购物车 2.通过orderDto拿到gids,再拿到要结算的商品 3.数据要入订单表 4.数据要入订单项表
    //获取购物车
    ShopCar shopCar = this.getShopCar(user, request);
    //获取结算商品集合
    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);
}

测试如下:为了方便我们测试,我又把数据清空掉了


成功了 

来看一下我们买家的金额 

看一下我们的数据库里有没有数据

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

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";
}

 AlipayConfig.java 变更如下:

package com.jwj.spbootpro.config;

import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.Config;
import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
import com.jwj.spbootpro.model.dto.OrderDto;

/**
 * 支付宝沙箱支付
 */
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="2021000121687583";
        //支付宝公钥
        config.alipayPublicKey="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsc74PulHrpMlGXt53c1CYfBziNjY9W299fXA5aU3f+eKKNnjc9fmUXYusGms0MgSSYgji4SuAfl1LxtRJEwqz8L7zxOxq0JB6Y5+XFXiSpdys4f6wMJXoaRWamEzfaSkpgoJ6vO+VqJa+j77Brc//mxRtHjrcS3xW5doUBOsAAdofjwaaWgcT2cmzb3r/QEXu4vfrOdV4uuXD5GWJ7bIYTDuRsRBL8iBPtqv1OkB6184f2t0Qch0g6Pyti/cg10BB5s/i9uUCqHCtHl5CQrpubQc6hYb4mmp8ZXLvqfPAmq0fgABDQklCPdww7qML6cATsv+WZF+f5NsxVPOgYPeQwIDAQAB";
        //签名方式
        config.signType="RSA2";
        //商户私钥(应用私钥),您的PKCS8格式RSA2私钥
        config.merchantPrivateKey="MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCG0psRs7/OH5gLmjpvlINXDMPOMIlLk8oqP1KdeKBHTOejsk01PyN6zqS0rzqmYHRNMCFsZnX1JvpqvZ8F0Vcw8FSzTGXGLyvAufqic5dIASb91qcF/4QSnoFzNVhIp6KSUsWlpY87bHkRZlLY3sseHu8M4HWOJmr1XidvIFpozxDmc5EgA0tHqogcth6ncW3uGXtNtKg840hejawhpEryCXNPbPK0pq1P95iWpmV+YtxTUWSfFTgjc88JPCaNSfhpPx11Up3oDHsMa+RlsKD1xaetLzjfPwoU73ymPVo0ii88z/KrzdNKfTE0Mkm4GQbID31GJ4yhYW/jsLNUQs+vAgMBAAECggEAN8TEOjVVQMkW1q3MQD15eregAxlWoXmXpZQd819jRTsNkkv93empHnJ99POK2imJ0if3m2RipK6j5SVcs0Zdv7OaBbSzYKBAg+8qOqp/yFwZqeRxoGyKUD1apLJLO3qEJ+yvLw7lyZncFpNx751w/ZukHHp4hf1kPuzceP40B6gH8h8BIJTpYItP3fVYrECjJ94Yr68OAQZ1pvlwK68b1HD68MIInHZIeZ9QYpzfMoCk/6wNYE31yYuoUpkmoENuCrA2r/G2xOQBVwgIO8pPyJ7WQCC5/jtFu8pbob8HBb2QHAUfvYj+MXtxglC8cHZmXECW7+mc61YRFCS7AlnmkQKBgQD0prghOEQdp1zCw0y2yfhmLhwfARyZUFZbOe4yuKuWitsuG3c7t8JCPiT3ifXzRnyoG3ticQxctFtfsBmGFzNxk+Y7fyexzN5EMcwD6wGIstemxumF76ts4Ycj4iiuotxbqJ/gw/xPHcL03AZTMokO1+HR78xjHLXjl0LshgK9pwKBgQCNE6arORAsnvJnC5scDsE2IYcbB13+eRKed2I5KAIMfEnXYRIscI413dujU3vR85s6ed91+vifh6wchwtdngX/eJ7V5Diz7m46hvGDH7YAe9RbSD9QaedDf2z/kotKV6m16Wlwy64DCEUlyVkaw3I7qOjrezfATQLWqbsimCZuuQKBgGvEyRVxGKhLYhQ1PaTDYVV5eE+8CKIMfo3e/et/563/6r7rwGEg+ER/5X7ZWetZIG5Y9MgPblej5yBGjWfA7ptYgDGzOIQc78fwe6M6MUnLJi3EL3gddFEZI5ON+0e6XAFQTWUQUCN1w7xi87JQb4mHVWVKEamTKxhfOE7CVZC/AoGAHA2UTugB912EBkmghmvIr+Lq4s0MO9YHhctnlMYH4kO0y0daPcwD+2Iqkse/D3jJnU8uyF8noVFxQBr6f5s0xiBONWo0fFMlSC4dSF2960q0Z5JuRKdKfXmRSyDw4c+cx7eqZ+uYprG2TlVDirbiuEpWRr0x0ON/dQA7Xh2zRsECgYEAj4iagNb8hBqJOPLBLzca3qLbUmdrGMVSEbXxyJaR6RP9C4SFeuJTh09LqVcFuss+jw7GaCJ74j1a2xQuKDF1xlfO7krb32EV0KGnrMtVwTCyT7LVcugPw+rsd97pros85jZhigARiSUA3vKpQf0bA7BEfq2RFSVKZ9fdHVsUSAM=";
        return config;
    }
}

测试如下:

看看我们的数据库时间有没有,状态发生改变没有如下:

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值