irpas技术客

网上商城项目(购物车下单、支付)_商城支付功能实现_敢敢130

网络 1884

目录

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

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 · * @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; } }

测试如下:

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


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #商城支付功能实现 #支付宝