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

目录

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

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) gid="$(".th").eq(index).find('div:eq(0)" input[type="hidden]').val();" update(num,gid); } }); $(".num .add").click(function(){ num="parseInt($(this).siblings("span").text());" if(num>=5){
            confirm("&#x9650;&#x8D2D;5&#x4EF6;");
        }else{
            num++;
            $(this).siblings("span").text(num);
            var price = $(this).parents(".number").prev().text().substring(1);
            $(this).parents(".th").find(".sAll").text('&#xFFE5;'+(num*price).toFixed(2));
            jisuan();
            zg();

            //TODO &#x83B7;&#x53D6;&#x5F53;&#x524D;&#x884C;&#x7684;&#x884C;&#x7D22;&#x5F15;
            let index = $(this).parents(".th").index()-1;
            //&#x83B7;&#x53D6;&#x5F53;&#x524D;&#x7684;checkbox&#x4E2D;&#x8BBE;&#x7F6E;&#x7684;&#x9690;&#x85CF;&#x57DF;&#xFF08;&#x5305;&#x542B;&#x4E86;&#x5546;&#x54C1;ID&#xFF09;
            let gid=$(".th").eq(index).find('div:eq(0) input[type=hidden]').val();
            update(num,gid);
        }
    });
    //&#x8BA1;&#x7B97;&#x603B;&#x4EF7;
    function jisuan(){
        var all=0;
        var len =$(".th input[type='checkbox']:checked").length;
        if(len==0){
             $("#all").text('&#xFFE5;'+parseFloat(0).toFixed(2));
        }else{
             $(".th input[type='checkbox']:checked").each(function(){
                //&#x83B7;&#x53D6;&#x5C0F;&#x8BA1;&#x91CC;&#x7684;&#x6570;&#x503C;
                var sAll = $(this).parents(".pro").siblings('.sAll').text().substring(1);
                //&#x7D2F;&#x52A0;
                all+=parseFloat(sAll);
                //&#x8D4B;&#x503C;
                $("#all").text('&#xFFE5;'+all.toFixed(2));
            })
        }

    }
    //&#x8BA1;&#x7B97;&#x603B;&#x5171;&#x51E0;&#x4EF6;&#x5546;&#x54C1;
    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  &#x83B7;&#x53D6;&#x5F53;&#x524D;&#x884C;&#x7684;&#x7D22;&#x5F15;
                let idx = $(this).parents(".th").index()-1;
                console.log(idx);
                //&#x5728;&#x8FD9;&#x91CC;&#x9700;&#x8981;&#x83B7;&#x53D6;&#x5F53;&#x524D;&#x884C;&#x5546;&#x54C1;&#x7684;&#x5546;&#x54C1;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 () {
                //&#x62FF;&#x5230;gids
                 location.href='/order/toOrder?gids='+gids
            });
        }else{
            $(".count").css("background","#8e8e8e");
            $(".count").unbind("click");
        }
    }
    /*****************&#x5546;&#x54C1;&#x5168;&#x9009;***********************/
    $("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()); num1="parseInt($(".goCart" $(".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) 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 ]:checked").length="=0){" $(".pleasec").show(); else{ 先获取所有即将被删除的商品id gidarr="new" array(); $(".th ]:checked").each(function(j){ gidarr.push($(".th").eq(index).find('div:eq(0) +="$(".th").eq(index).find('div:eq(0)" 很容易报数据下标越界异常 $('.cancel').click(function(){ 改变商品规格 $(".pro dd").hover(function(){ 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(); $(".changebtn .buy").attr("data-id",i); },function(){ $(this).removeclass("on"); .buy").click(function(){ result="$(".smallImg" .on").find("img").attr("alt"); $("#edit"+index).prev().text(result); $(".prodets").hide(); $("#edit"+index).parent("dd").removeclass("on").find(".edit").remove(); 删除商品 function del(gids) { $.post(' shopcar delete',{ 'gids':gids },function(rs){ if(rs.code!="200)" alert(rs.msg); else location.href="/shopCar/queryShopCar" },'json'); 修改商品数量 update(num,gid){ update',{ 'gid':gid, 'quantity':num < code></len1){></=1){>

测试结果如下:

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

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

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

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>
     * &#x8BFB;&#x53D6;&#x63A7;&#x5236;&#x53F0;&#x5185;&#x5BB9;
     * </p>
     */
    public static String scanner(String tip) {
        Scanner scanner = new Scanner(System.in);
        StringBuilder help = new StringBuilder();
        help.append("&#x8BF7;&#x8F93;&#x5165;" + tip + "&#xFF1A;");
        System.out.println(help.toString());
        if (scanner.hasNext()) {
            String ipt = scanner.next();
            if (StringUtils.isNotBlank(ipt)) {
                return ipt;
            }
        }
        throw new MybatisPlusException("&#x8BF7;&#x8F93;&#x5165;&#x6B63;&#x786E;&#x7684;" + tip + "&#xFF01;");
    }

    public static void main(String[] args) {
        // &#x4EE3;&#x7801;&#x751F;&#x6210;&#x5668;
        AutoGenerator mpg = new AutoGenerator();

        // &#x5168;&#x5C40;&#x914D;&#x7F6E;
        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); &#x5B9E;&#x4F53;&#x5C5E;&#x6027; Swagger2 &#x6CE8;&#x89E3;
        mpg.setGlobalConfig(gc);

        // &#x6570;&#x636E;&#x6E90;&#x914D;&#x7F6E;
        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);

        // &#x5305;&#x914D;&#x7F6E;
        PackageConfig pc = new PackageConfig();
        //pc.setModuleName(scanner("&#x6A21;&#x5757;&#x540D;"));
        pc.setParent("com.jwj.spbootpro");
        //&#x8BBE;&#x7F6E;&#x5305;&#x540D;
        pc.setEntity("model");
        mpg.setPackageInfo(pc);

        // &#x81EA;&#x5B9A;&#x4E49;&#x914D;&#x7F6E;
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                // to do nothing
            }
        };

        // &#x5982;&#x679C;&#x6A21;&#x677F;&#x5F15;&#x64CE;&#x662F; freemarker
        String templatePath = "/templates/mybatis-generator/mapper2.xml.ftl";
        // &#x5982;&#x679C;&#x6A21;&#x677F;&#x5F15;&#x64CE;&#x662F; velocity
        // String templatePath = "/templates/mapper.xml.vm";

        // &#x81EA;&#x5B9A;&#x4E49;&#x8F93;&#x51FA;&#x914D;&#x7F6E;
        List<fileoutconfig> focList = new ArrayList<>();
        // &#x81EA;&#x5B9A;&#x4E49;&#x914D;&#x7F6E;&#x4F1A;&#x88AB;&#x4F18;&#x5148;&#x8F93;&#x51FA;
        focList.add(new FileOutConfig(templatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // &#x81EA;&#x5B9A;&#x4E49;&#x8F93;&#x51FA;&#x6587;&#x4EF6;&#x540D; &#xFF0C; &#x5982;&#x679C;&#x4F60; Entity &#x8BBE;&#x7F6E;&#x4E86;&#x524D;&#x540E;&#x7F00;&#x3001;&#x6B64;&#x5904;&#x6CE8;&#x610F; xml &#x7684;&#x540D;&#x79F0;&#x4F1A;&#x8DDF;&#x7740;&#x53D1;&#x751F;&#x53D8;&#x5316;&#xFF01;&#xFF01;
                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) {
                // &#x5224;&#x65AD;&#x81EA;&#x5B9A;&#x4E49;&#x6587;&#x4EF6;&#x5939;&#x662F;&#x5426;&#x9700;&#x8981;&#x521B;&#x5EFA;
                checkDir("&#x8C03;&#x7528;&#x9ED8;&#x8BA4;&#x65B9;&#x6CD5;&#x521B;&#x5EFA;&#x7684;&#x76EE;&#x5F55;&#xFF0C;&#x81EA;&#x5B9A;&#x4E49;&#x76EE;&#x5F55;&#x7528;");
                if (fileType == FileType.MAPPER) {
                    // &#x5DF2;&#x7ECF;&#x751F;&#x6210; mapper &#x6587;&#x4EF6;&#x5224;&#x65AD;&#x5B58;&#x5728;&#xFF0C;&#x4E0D;&#x60F3;&#x91CD;&#x65B0;&#x751F;&#x6210;&#x8FD4;&#x56DE; false
                    return !new File(filePath).exists();
                }
                // &#x5141;&#x8BB8;&#x751F;&#x6210;&#x6A21;&#x677F;&#x6587;&#x4EF6;
                return true;
            }
        });
        */
        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);

        // &#x914D;&#x7F6E;&#x6A21;&#x677F;
        TemplateConfig templateConfig = new TemplateConfig();

        // &#x914D;&#x7F6E;&#x81EA;&#x5B9A;&#x4E49;&#x8F93;&#x51FA;&#x6A21;&#x677F;
        //&#x6307;&#x5B9A;&#x81EA;&#x5B9A;&#x4E49;&#x6A21;&#x677F;&#x8DEF;&#x5F84;&#xFF0C;&#x6CE8;&#x610F;&#x4E0D;&#x8981;&#x5E26;&#x4E0A;.ftl/.vm, &#x4F1A;&#x6839;&#x636E;&#x4F7F;&#x7528;&#x7684;&#x6A21;&#x677F;&#x5F15;&#x64CE;&#x81EA;&#x52A8;&#x8BC6;&#x522B;
        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);

        // &#x7B56;&#x7565;&#x914D;&#x7F6E;
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        //strategy.setSuperEntityClass("&#x4F60;&#x81EA;&#x5DF1;&#x7684;&#x7236;&#x7C7B;&#x5B9E;&#x4F53;,&#x6CA1;&#x6709;&#x5C31;&#x4E0D;&#x7528;&#x8BBE;&#x7F6E;!");
        strategy.setEntityLombokModel(true);
        strategy.setRestControllerStyle(true);
        strategy.setEntitySerialVersionUID(false);
        // &#x516C;&#x5171;&#x7236;&#x7C7B;
        //strategy.setSuperControllerClass("&#x4F60;&#x81EA;&#x5DF1;&#x7684;&#x7236;&#x7C7B;&#x63A7;&#x5236;&#x5668;,&#x6CA1;&#x6709;&#x5C31;&#x4E0D;&#x7528;&#x8BBE;&#x7F6E;!");
        // &#x5199;&#x4E8E;&#x7236;&#x7C7B;&#x4E2D;&#x7684;&#x516C;&#x5171;&#x5B57;&#x6BB5;
        strategy.setSuperEntityColumns("id");
        strategy.setInclude(scanner("&#x8868;&#x540D;&#xFF0C;&#x591A;&#x4E2A;&#x82F1;&#x6587;&#x9017;&#x53F7;&#x5206;&#x5272;").split(","));
        strategy.setControllerMappingHyphenStyle(true);
        strategy.setTablePrefix("t_");
        mpg.setStrategy(strategy);
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
        mpg.execute();
    }
}
</fileoutconfig>

如下图所示:

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

生成成功后如果有时间问题都改为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>
 * &#x8BA2;&#x5355;&#x4FE1;&#x606F;&#x8868; &#x524D;&#x7AEF;&#x63A7;&#x5236;&#x5668;
 * </p>
 *
 * @author jwj
 * @since 2022-11-10
 *
 * @Controller:&#x56E0;&#x4E3A;&#x6211;&#x4EEC;&#x6700;&#x7EC8;&#x662F;&#x8981;&#x8DF3;&#x8F6C;&#x5230;&#x9875;&#x9762;
 */
@Controller
@RequestMapping("/order")
public class OrderController {

    /**
     * &#x6839;&#x636E;&#x52FE;&#x9009;&#x7ED3;&#x7B97;&#x7684;&#x5546;&#x54C1;&#x8DF3;&#x8F6C;&#x5230;&#x8BA2;&#x5355;&#x9875;&#x9762;
     * @param user
     * @param gids
     * @param request
     * @return
     */
    @RequestMapping("/toOrder")
    public ModelAndView toOrder(User user,String gids, HttpServletRequest request){
        ModelAndView mv = new ModelAndView();
//        &#x62FF;&#x5230;&#x8D2D;&#x7269;&#x8F66;&#x4E2D;&#x7684;&#x6240;&#x6709;&#x5546;&#x54C1;
        ShopCar shopCar = getShopCar(user, request);
//        &#x901A;&#x8FC7;gids&#x4ECE;&#x8D2D;&#x7269;&#x8F66;&#x4E2D;&#x7B5B;&#x9009;&#x51FA;&#x6307;&#x5B9A;&#x7684;&#x5546;&#x54C1;
        List<shopcaritem> list = getGoods(shopCar,gids);
        mv.addObject("goods",list);
        mv.setViewName("order.html");
        return mv;
    }

    /**
     * &#x7531;&#x4E8E;&#x7528;&#x6237;&#x7ED3;&#x7B97;&#x5546;&#x54C1;&#x65F6;&#xFF0C;&#x4E0D;&#x4E00;&#x5B9A;&#x662F;&#x5C06;&#x8D2D;&#x7269;&#x8F66;&#x4E2D;&#x6240;&#x6709;&#x5546;&#x54C1;&#x8FDB;&#x884C;&#x7ED3;&#x7B97;&#xFF0C;&#x6709;&#x53EF;&#x80FD;&#x53EA;&#x6709;&#x90E8;&#x5206;&#x5546;&#x54C1;
     * &#x5FC5;&#x987B;&#x6839;&#x636E;&#x524D;&#x7AEF;&#x9875;&#x9762;&#x7528;&#x6237;&#x52FE;&#x9009;&#x7684;&#x5546;&#x54C1;ID&#x4ECE;&#x8D2D;&#x7269;&#x8F66;&#x4E2D;&#x627E;&#x5230;&#x5BF9;&#x5E94;&#x9700;&#x8981;&#x7ED3;&#x7B97;&#x7684;&#x5546;&#x54C1;&#x5E76;&#x5B58;&#x5165;
     * @param shopCar
     * @param gids
     * @return
     */
//    &#x901A;&#x8FC7;gids&#x4ECE;&#x8D2D;&#x7269;&#x8F66;&#x4E2D;&#x7B5B;&#x9009;&#x51FA;&#x6307;&#x5B9A;&#x7684;&#x5546;&#x54C1;
    private List<shopcaritem> getGoods(ShopCar shopCar, String gids) {
        //&#x6839;&#x636E;&#x9017;&#x53F7;&#x5206;&#x5272;&#x5546;&#x54C1;gids
        List<string> gidList = Arrays.asList(gids.split(","));
        //&#x4EE3;&#x8868;&#x8D2D;&#x7269;&#x8F66;&#x4E2D;&#x5DF2;&#x6709;&#x7684;&#x5546;&#x54C1;&#x96C6;&#x5408;
        List<shopcaritem> items = shopCar.getItems();   //3&#x4E2A;    &#x8D2D;&#x7269;&#x8F66;&#x91CC;&#x7684;&#x5546;&#x54C1;
        //&#x5B9A;&#x4E49;&#x7ED3;&#x7B97;&#x5546;&#x54C1;&#x96C6;&#x5408;
        List<shopcaritem> itemsNew = new ArrayList<>();//2&#x4E2A;    &#x8D2D;&#x7269;&#x8F66;&#x8981;&#x7ED3;&#x7B97;&#x7684;&#x5546;&#x54C1;
        //&#x5FAA;&#x73AF;&#x904D;&#x5386;&#x8D2D;&#x7269;&#x8F66;&#x4E2D;&#x7684;&#x5546;&#x54C1;&#x5E76;&#x4E0E;&#x52FE;&#x9009;&#x7ED3;&#x7B97;&#x7684;&#x5546;&#x54C1;ID&#x8FDB;&#x884C;&#x6BD4;&#x8F83;
        for (ShopCarItem item : items) {
            //&#x5224;&#x65AD;&#x8D2D;&#x7269;&#x8F66;&#x4E2D;&#x7684;&#x5546;&#x54C1;&#x4E0E;&#x52FE;&#x9009;&#x7ED3;&#x7B97;&#x7684;&#x5546;&#x54C1;ID&#x662F;&#x5426;&#x4E00;&#x81F4;
            if(gidList.contains(item.getGid()+"")){
                itemsNew.add(item);
            }
        }
        return itemsNew;
    }

    //    &#x4ECE;session&#x4E2D;&#x83B7;&#x53D6;&#x8D2D;&#x7269;&#x8F66;&#x5BF9;&#x8C61;
    private ShopCar getShopCar(User user, HttpServletRequest request){
        //&#x83B7;&#x53D6;session
        HttpSession session = request.getSession();
        //&#x4ECE;session&#x4E2D;&#x83B7;&#x53D6;&#x8D2D;&#x7269;&#x8F66;&#x5BF9;&#x8C61;
        ShopCar shopCar = (ShopCar)session.getAttribute(user.getId() + "_shopCar");
        //&#x5224;&#x65AD;shopCar&#x662F;&#x5426;&#x4E3A;&#x7A7A;
        if(shopCar == null){
            //&#x521D;&#x59CB;&#x5316;&#x8D2D;&#x7269;&#x8F66;&#x5BF9;&#x8C61;
            shopCar = new ShopCar();
            //&#x5C06;&#x521D;&#x59CB;&#x5316;&#x5B8C;&#x6210;&#x7684;&#x8D2D;&#x7269;&#x8F66;&#x5BF9;&#x8C61;&#x6839;&#x636E;&#x7528;&#x6237;id&#x62A5;&#x9519;&#x5230;session&#x4E2D;
            session.setAttribute(user.getId()+"_shopCar",shopCar);
        }
        return shopCar;
    }

}
</shopcaritem></shopcaritem></string></shopcaritem></shopcaritem>

2.订单页前台展示

order.html

订单确认

               收件信息新增地址

                        张三1
                           [默认地址]

                           删除
                           |
                           编辑

                        河北省 唐山市 路北区 大学生公寓村
                        15732570937

                        张三2

                           设为默认
                           |
                           删除
                           |
                           编辑

                        河北省 唐山市 路北区 大学生公寓村
                        15732570937

                        张三3

                           设为默认
                           |
                           删除
                           |
                           编辑

                        河北省 唐山市 路北区 大学生公寓村
                        15732570937

               支付方式

               选择快递

                  顺风快递
                  百世汇通
                  圆通快递
                  中通快递

                  订单内容返回购物车

                           ${g.goodsName}
                           颜色分类:烟灰色玻璃瓶
                           数量:${g.quantity}

                        ¥${g.goodsPrice}

                  商品金额:¥139.8
                  优惠金额:¥0.00
                  运费:免运费

                  合计:¥139.8

               去支付

                  省份/自治区

                  城市/地区

                  区/县

                  配送区域

展示结果如下:

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

结算如下所示:

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

三、生成订单

实现思路

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 &#x6562;&#x6562;
 * @site www.javajwj.com
 * @company xxx&#x516C;&#x53F8;
 * @create&#xA0; 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;

/**
 *
 * 订单信息表 前端控制器
 *
 *
 * @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 list = getGoods(shopCar,gids);
        mv.addObject("goods",list);
        mv.setViewName("order.html");
        return mv;
    }

    /**
     * 由于用户结算商品时,不一定是将购物车中所有商品进行结算,有可能只有部分商品
     * 必须根据前端页面用户勾选的商品ID从购物车中找到对应需要结算的商品并存入
     * @param shopCar
     * @param gids
     * @return
     */
//    通过gids从购物车中筛选出指定的商品
    private List getGoods(ShopCar shopCar, String gids) {
        //根据逗号分割商品gids
        List gidList = Arrays.asList(gids.split(","));
        //代表购物车中已有的商品集合
        List items = shopCar.getItems();   //3个    购物车里的商品
        //定义结算商品集合
        List 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 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>
 * &#x8BA2;&#x5355;&#x4FE1;&#x606F;&#x8868; &#x670D;&#x52A1;&#x7C7B;
 * </p>
 *
 * @author jwj
 * @since 2022-11-10
 */
public interface IOrderService extends IService<order> {

    void addOrder(OrderDto orderDto, List<shopcaritem> shopCarItems);
}
</shopcaritem></order>

在我们的实现类也要实现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>
 * &#x8BA2;&#x5355;&#x4FE1;&#x606F;&#x8868; &#x670D;&#x52A1;&#x5B9E;&#x73B0;&#x7C7B;
 * </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&#x6CE8;&#x89E3;&#xFF1A;&#x4EE5;&#x4E0B;&#x7684;&#x65B9;&#x6CD5;&#x56E0;&#x4E3A;&#x540C;&#x65F6;&#x8BBE;&#x7F6E;&#x5230;&#x4E24;&#x5F20;&#x8868;&#x7684;&#x589E;&#x5220;&#x6539;&#x7684;&#x64CD;&#x4F5C;&#xFF0C;&#x8981;&#x4E48;&#x540C;&#x65F6;&#x6210;&#x529F;&#xFF0C;&#x8981;&#x4E48;&#x540C;&#x65F6;&#x5931;&#x8D25;
    @Transactional
    @Override
    public void addOrder(OrderDto orderDto, List<shopcaritem> shopCarItems) {
//        &#x8BA2;&#x5355;&#x8868;&#x4EE5;&#x53CA;&#x8BA2;&#x5355;&#x9879;&#x8868;&#x7684;&#x6570;&#x636E;&#x5F55;&#x5165;
        //1) &#x751F;&#x6210;&#x8BA2;&#x5355;ID     SnowFlake&#x751F;&#x6210;&#x96EA;&#x82B1;ID&#xFF0C;&#x5B83;&#x7684;&#x4F5C;&#x7528;&#xFF0C;&#x751F;&#x6210;&#x4E00;&#x4E2A;&#x968F;&#x673A;&#x7684;long&#x7C7B;&#x578B;&#x7684;&#x6570;&#x5B57;&#xFF1B;
//        &#x76F8;&#x6BD4;&#x8F83;&#x4E8E;UUID&#x7684;&#x4F18;&#x70B9;&#x5728;&#x4E8E;&#xFF0C;&#x96EA;&#x82B1;ID&#x53EF;&#x4EE5;&#x6392;&#x5E8F;
        SnowFlake snowFlake = new SnowFlake(2, 3);
        Long orderId=snowFlake.nextId();
        orderDto.setOid(orderId);
        //2) &#x5FAA;&#x73AF;&#x52FE;&#x9009;&#x7684;&#x5546;&#x54C1;&#x96C6;&#x5408;&#x8BA1;&#x7B97;&#x5546;&#x54C1;&#x603B;&#x4EF7;&#x3001;&#x83B7;&#x53D6;&#x5546;&#x54C1;&#x8BE6;&#x60C5;&#x96C6;&#x5408;
        //&#x603B;&#x4EF7;
        BigDecimal total=BigDecimal.valueOf(0);
        //&#x5B9A;&#x4E49;&#x5546;&#x54C1;&#x8BE6;&#x60C5;&#x96C6;&#x5408;
        List<orderitem> orderItems=new ArrayList<>();
        OrderItem it=null;
        for (ShopCarItem shopCarItem : shopCarItems) {
            //&#x7D2F;&#x52A0;&#x5C0F;&#x8BA1;&#x7B49;&#x4E8E;&#x603B;&#x4EF7;
            total=total.add(shopCarItem.smalltotal());
            //&#x521D;&#x59CB;&#x5316;OrderItem&#x5546;&#x54C1;&#x8BE6;&#x60C5;&#x5BF9;&#x8C61;
            it=new OrderItem();
//          &#x8BA2;&#x5355;&#x9879;&#x8868;&#x7684;ooid&#x4E3A;&#x81EA;&#x589E;&#xFF0C;&#x6240;&#x4EE5;&#x4E0D;&#x9700;&#x8981;&#x8BBE;&#x7F6E;
            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.&#x4FDD;&#x5B58;&#x8BA2;&#x5355;
        orderMapper.insert(orderDto);
        //2.&#x4FDD;&#x5B58;&#x8BA2;&#x5355;&#x5BF9;&#x5E94;&#x7684;&#x8BA2;&#x5355;&#x9879;
        orderItemService.saveBatch(orderItems);

    }
}
</orderitem></shopcaritem></ordermapper,>

给我们OrderMapper添加注解@repository,

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

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

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

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

package com.jwj.spbootpro.utils;

public class SnowFlake {

    /**
     * &#x8D77;&#x59CB;&#x7684;&#x65F6;&#x95F4;&#x6233;
     */
    private final static long START_STMP = 1480166465631L;

    /**
     * &#x6BCF;&#x4E00;&#x90E8;&#x5206;&#x5360;&#x7528;&#x7684;&#x4F4D;&#x6570;
     */
    private final static long SEQUENCE_BIT = 12; //&#x5E8F;&#x5217;&#x53F7;&#x5360;&#x7528;&#x7684;&#x4F4D;&#x6570;
    private final static long MACHINE_BIT = 5;   //&#x673A;&#x5668;&#x6807;&#x8BC6;&#x5360;&#x7528;&#x7684;&#x4F4D;&#x6570;
    private final static long DATACENTER_BIT = 5;//&#x6570;&#x636E;&#x4E2D;&#x5FC3;&#x5360;&#x7528;&#x7684;&#x4F4D;&#x6570;

    /**
     * &#x6BCF;&#x4E00;&#x90E8;&#x5206;&#x7684;&#x6700;&#x5927;&#x503C;
     */
    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);

    /**
     * &#x6BCF;&#x4E00;&#x90E8;&#x5206;&#x5411;&#x5DE6;&#x7684;&#x4F4D;&#x79FB;
     */
    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;  //&#x6570;&#x636E;&#x4E2D;&#x5FC3;
    private long machineId;     //&#x673A;&#x5668;&#x6807;&#x8BC6;
    private long sequence = 0L; //&#x5E8F;&#x5217;&#x53F7;
    private long lastStmp = -1L;//&#x4E0A;&#x4E00;&#x6B21;&#x65F6;&#x95F4;&#x6233;

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

    /**
     * &#x4EA7;&#x751F;&#x4E0B;&#x4E00;&#x4E2A;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) {
            //&#x76F8;&#x540C;&#x6BEB;&#x79D2;&#x5185;&#xFF0C;&#x5E8F;&#x5217;&#x53F7;&#x81EA;&#x589E;
            sequence = (sequence + 1) & MAX_SEQUENCE;
            //&#x540C;&#x4E00;&#x6BEB;&#x79D2;&#x7684;&#x5E8F;&#x5217;&#x6570;&#x5DF2;&#x7ECF;&#x8FBE;&#x5230;&#x6700;&#x5927;
            if (sequence == 0L) {
                currStmp = getNextMill();
            }
        } else {
            //&#x4E0D;&#x540C;&#x6BEB;&#x79D2;&#x5185;&#xFF0C;&#x5E8F;&#x5217;&#x53F7;&#x7F6E;&#x4E3A;0
            sequence = 0L;
        }

        lastStmp = currStmp;

        return (currStmp - START_STMP) << TIMESTMP_LEFT //&#x65F6;&#x95F4;&#x6233;&#x90E8;&#x5206;
                | datacenterId << DATACENTER_LEFT       //&#x6570;&#x636E;&#x4E2D;&#x5FC3;&#x90E8;&#x5206;
                | machineId << MACHINE_LEFT             //&#x673A;&#x5668;&#x6807;&#x8BC6;&#x90E8;&#x5206;
                | sequence;                             //&#x5E8F;&#x5217;&#x53F7;&#x90E8;&#x5206;
    }

    private long getNextMill() {
        long mill = getNewstmp();
        while (mill <= laststmp) { mill="getNewstmp();" } return mill; private long getnewstmp() system.currenttimemillis(); public static void main(string[] args) snowflake snowflake(2, 3); start="System.currentTimeMillis();" for (int i="0;" < 1000000; i++) system.out.println(snowflake.nextid()); system.out.println(system.currenttimemillis() - start); }< code></=>

测试效果如下图所示:

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

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

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

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

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

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

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

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

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

四、沙箱支付简介

1.配置沙箱支付

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

网上商城项目(购物车下单、支付)
点击登录:扫码登录
2)首页找到进入管理中心 —》开发工具推荐选择【沙箱】

3)下载安装支付宝开放平台开发助手:
密钥工具简介 | 开放平台

网上商城项目(购物车下单、支付)
下载好之后就是这样的,我下载的安卓的
网上商城项目(购物车下单、支付)
4)打开本地支付宝开放平台助手—》密钥工具—》生成密钥—》以默认的方式(RSA2和KCS8)生成应用私钥和应用公钥
网上商城项目(购物车下单、支付)
网上商城项目(购物车下单、支付)

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;

/**
 * &#x652F;&#x4ED8;&#x5B9D;&#x6C99;&#x7BB1;&#x652F;&#x4ED8;
 */
public class AlipayConfig {

    public String goAlipay(OrderDto orderDto){
        try {
            // 1. &#x8BBE;&#x7F6E;&#x53C2;&#x6570;&#xFF08;&#x5168;&#x5C40;&#x53EA;&#x9700;&#x8BBE;&#x7F6E;&#x4E00;&#x6B21;&#xFF09;
            Factory.setOptions(aliconfig());
            // 2. &#x53D1;&#x8D77;API&#x8C03;&#x7528;&#xFF08;subject&#x5546;&#x54C1;&#x6807;&#x9898;&#x3001;outTradeNo&#x8BA2;&#x5355;&#x7F16;&#x53F7;&#x3001;totalAmount&#x603B;&#x91D1;&#x989D;&#x3001;returnUrl&#x5F02;&#x6B65;&#x901A;&#x77E5;&#x5730;&#x5740;&#xFF09;
            AlipayTradePagePayResponse response = Factory.Payment.Page()
                    .pay(orderDto.getOid()+"",
                            orderDto.getOid()+"",
                            orderDto.getTotal().toString(),
                            "http://localhost:8081/page/ok.html");  //&#x652F;&#x4ED8;&#x6210;&#x529F;&#x4E4B;&#x540E;&#x7684;&#x5F02;&#x6B65;&#x901A;&#x77E5;&#xFF08;&#x8DF3;&#x51FA;&#x5230;&#x81EA;&#x5DF1;&#x7CFB;&#x7EDF;&#x7684;&#x54EA;&#x4E2A;&#x4F4D;&#x7F6E;&#xFF09;
            System.out.println(response.body);
            return response.body;
        }  catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    private Config aliconfig(){
        Config config=new Config();
        //&#x6C99;&#x7BB1;&#x652F;&#x4ED8;&#x5B9D;&#x5730;&#x5740;
        config.gatewayHost="openapi.alipaydev.com";
        //&#x534F;&#x8BAE;https
        config.protocol="https";
        //&#x5E94;&#x7528;ID,&#x60A8;&#x7684;APPID&#xFF0C;&#x6536;&#x6B3E;&#x8D26;&#x53F7;&#x65E2;&#x662F;&#x60A8;&#x7684;APPID&#x5BF9;&#x5E94;&#x652F;&#x4ED8;&#x5B9D;&#x8D26;&#x53F7;
        config.appId="2021000121687583";
        //&#x652F;&#x4ED8;&#x5B9D;&#x516C;&#x94A5;
        config.alipayPublicKey="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsc74PulHrpMlGXt53c1CYfBziNjY9W299fXA5aU3f+eKKNnjc9fmUXYusGms0MgSSYgji4SuAfl1LxtRJEwqz8L7zxOxq0JB6Y5+XFXiSpdys4f6wMJXoaRWamEzfaSkpgoJ6vO+VqJa+j77Brc//mxRtHjrcS3xW5doUBOsAAdofjwaaWgcT2cmzb3r/QEXu4vfrOdV4uuXD5GWJ7bIYTDuRsRBL8iBPtqv1OkB6184f2t0Qch0g6Pyti/cg10BB5s/i9uUCqHCtHl5CQrpubQc6hYb4mmp8ZXLvqfPAmq0fgABDQklCPdww7qML6cATsv+WZF+f5NsxVPOgYPeQwIDAQAB";
        //&#x7B7E;&#x540D;&#x65B9;&#x5F0F;
        config.signType="RSA2";
        //&#x5546;&#x6237;&#x79C1;&#x94A5;&#xFF08;&#x5E94;&#x7528;&#x79C1;&#x94A5;&#xFF09;&#xFF0C;&#x60A8;&#x7684;PKCS8&#x683C;&#x5F0F;RSA2&#x79C1;&#x94A5;
        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 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 代码新增如下:

/**
 * &#x652F;&#x4ED8;&#x6210;&#x529F;&#x540E;&#x56DE;&#x8C03;&#x5904;&#x7406;&#x8BA2;&#x5355;&#x72B6;&#x6001;&#xFF0C;&#x5B8C;&#x6210;&#x6574;&#x4E2A;&#x4E0B;&#x5355;&#x6D41;&#x7A0B;&#x7684;&#x94FE;&#x8DEF;
 * @param param
 * @return
 */
@RequestMapping("/orderFinish")
public String orderFinish(@RequestParam Map<string, string> param){
    System.out.println("&#x5F02;&#x6B65;&#x56DE;&#x8C03;&#x5F00;&#x59CB;&#x3002;&#x3002;&#x3002;&#x3002;&#x3002;&#x3002;");
    Boolean signVerified=false;

    try {
        System.out.println(param);
        signVerified = Factory.Payment.Common().verifyNotify(param);
        System.out.println(signVerified);
        System.out.println("out_trade_no&#xFF1A;"+param.get("out_trade_no"));
        System.out.println("total_amount&#xFF1A;"+param.get("total_amount"));
        System.out.println("trade_no&#xFF1A;"+param.get("trade_no"));
        if(signVerified){
            //&#x652F;&#x4ED8;&#x6210;&#x529F;
            //&#x6839;&#x636E;&#x8BA2;&#x5355;&#x7F16;&#x53F7;&#x4FEE;&#x6539;&#x8BA2;&#x5355;&#x72B6;&#x6001;
            //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")));
            //&#x8DF3;&#x8F6C;&#x5230;&#x652F;&#x4ED8;&#x6210;&#x529F;&#x9875;&#x9762;
        }else{
            //&#x652F;&#x4ED8;&#x5931;&#x8D25;
        }

    } catch (Exception e) {
        e.printStackTrace();
    }
    return "ok.html";
}</order></string,>

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

测试如下:

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

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

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

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

Original: https://blog.csdn.net/weixin_67465673/article/details/127775386
Author: 敢敢130
Title: 网上商城项目(购物车下单、支付)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/659364/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球