springboot项目之沙箱支付&订单生成

发布于:2022-11-09 ⋅ 阅读:(1890) ⋅ 点赞:(2)

目录

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

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

三、结算页的下单前端、后端

 四、沙箱支付简介及初步接入

简介:

 设置支付宝公钥

 设置应用密钥

 设置appId

 五、支付宝支付回调


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

 cart.js

	//计算总共几件商品
	function zg(){
		var zsl = 0;
		var index = $(".th input[type='checkbox']:checked").parents(".th").find(".num span");
		var len =index.length;
		let gids="";
		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");
			//	TODO	绑定结算事件
			$(".count").bind("click",function () {
				// alert("绑定结算事件");
				location.href='/order/toOrder?gids='+gids
			})
		}else{
			$(".count").css("background","#8e8e8e");
			$(".count").unbind("click");
		}
	}

 生成代码:

package com.zking.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("zking");
        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.zking.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();
    }
}

 

实现可跳转功能

 


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

 OrderCotroller 后台代码

package com.zking.spbootpro.Controller;

import com.zking.spbootpro.model.Goods;
import com.zking.spbootpro.model.User;
import com.zking.spbootpro.model.vo.ShopCar;
import com.zking.spbootpro.model.vo.ShopCarItem;
import com.zking.spbootpro.utils.JsonResponseBody;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author 锦鲤
 * @site www.lucy.com
 * @company xxx公司
 * @create  2022-11-08 15:21
 */
@Controller
@RequestMapping("/order")
public class OrderCotroller {


    /**
     * 根据勾选结算的商品跳转到订单页面
     * @param user
     * @param req
     * @param gids
     * @return
     */
    @RequestMapping("/toOrder")
    public ModelAndView toOrder(User user,
                                HttpServletRequest req,
                                String gids){
        ModelAndView mv=new ModelAndView();
        //根据用户ID获取session中对应的购物车
        ShopCar shopCar = getShopCar(user, req);
        //从购物车中获取勾选结算的商品集合
        List<ShopCarItem> list=getgoods(shopCar,gids);
        mv.addObject("goods",list);
        mv.setViewName("order.html");
        return mv;
    }
//筛选指定商品
    private List<ShopCarItem> getgoods(ShopCar shopCar, String gids) {
      List<String> gidlist= Arrays.asList(gids.split(","));
        List<Goods> goods=new ArrayList<>();
        List<ShopCarItem> items=shopCar.getItems();//购物车全部商品
        List<ShopCarItem> itemsnew=new ArrayList<>();//购物车中选中要买的商品
        for (ShopCarItem item : items) {
            if(gidlist.contains(item.getGid()+"")){
                itemsnew.add(item);
            }
        }
        return itemsnew;

    }

    //    从session中获取购物车对象
    private ShopCar getShopCar(User user, HttpServletRequest request) {
        HttpSession session = request.getSession();
        ShopCar shopCar = (ShopCar) session.getAttribute(user.getId() + "_shopCar");
        if (shopCar == null) {
            shopCar = new ShopCar();
            session.setAttribute(user.getId() + "_shopCar", shopCar);
        }
        return shopCar;
    }


}

 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</p>
						<span class="default">[默认地址]</span>
						<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>
				<#assign total=0>
				<#--判断结算商品集合是否为空-->
				<#if goods??>
				<#--循环遍历结算商品-->
					<#list goods.items as g>
					<#--在循环里累加小计的和就是总价-->
						<#assign total=total+g.smalltotal()>
						<ul class="clearfix">
							<li class="fl">
								<img style="width: 87px;height: 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">¥${total}</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">¥${total}</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/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>
<script src="js/user/order.js" type="text/javascript" charset="utf-8"></script>
</body>
</html>

 订单效果图


三、结算页的下单前端、后端

前端:js

$(function(){
    $('.pay').click(function(){
        //获取收货地址、联系人、联系电话
        let name=$('.addres').find('div.on div:eq(0)>p:eq(0)').text().trim();
        let address=$('.addres').find('div.on div:eq(1)>p:eq(0)').text();
        let phone=$('.addres').find('div.on div:eq(1)>p:eq(1)').text();
        console.log("name=%s,address=%s,phone=%s",name,address,phone);
        //获取支付方式
        let pay=$('.way').find('img.on').attr('value');
        console.log(pay);
        //获取快递方式
        let dis=$('.dis').find('span.on').text();
        console.log(dis);
        //获取勾选结算的商品ID
        let gids=$('#gids').val();
        //拼接请求参数
        let params={
            gids:gids,
            address:address,
            person:name,
            telephone:phone,
            pay:pay,
            mail:dis
        };
        console.log(params);

        $.post('/order/addOrder',params,function(rs){
            if(rs.code==200){
                location.href='/page/ok.html';
            }else{
                alert(rs.msg);
            }
        },'json');
    });
});

后端

 SnowFlake  雪花id

package com.zking.spbootpro.utils;
/*
*
* 雪花id特点;可以排序
* uuid特点:随机id,不可排序
*
* */
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);


    }
}

OrderServiceImpl 

package com.zking.spbootpro.service.impl;

import com.zking.spbootpro.model.Dto.OrderDto;
import com.zking.spbootpro.model.Order;
import com.zking.spbootpro.mapper.OrderMapper;
import com.zking.spbootpro.model.OrderItem;
import com.zking.spbootpro.model.vo.ShopCarItem;
import com.zking.spbootpro.service.IOrderItemService;
import com.zking.spbootpro.service.IOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zking.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 zking
 * @since 2022-11-08
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {


    @Autowired
    private  OrderMapper orderMapper;
    @Autowired
    private IOrderItemService iOrderItemService;



    @Transactional
    @Override
    public void addOrder(OrderDto orderDto, List<ShopCarItem> shopCarItems) {

        //1) 生成订单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.保存订单对应的订单项
        iOrderItemService.saveBatch(orderItems);
    }
}

 OrderDto-->获得gid

package com.zking.spbootpro.model.Dto;

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

/**
 * @author 锦鲤
 * @site www.lucy.com
 * @company xxx公司
 * @create  2022-11-08 18:43
 */
@Data
public class OrderDto  extends Order {

private  String gids;



}



IOrderItemService

package com.zking.spbootpro.service;

import com.zking.spbootpro.model.OrderItem;
import com.baomidou.mybatisplus.extension.service.IService;
import org.springframework.stereotype.Repository;

/**
 * <p>
 *  服务类
 * </p>
 *
 * @author zking
 * @since 2022-11-08
 */

public interface IOrderItemService extends IService<OrderItem> {

}

OrderMapper

package com.zking.spbootpro.mapper;

import com.zking.spbootpro.model.Order;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springframework.stereotype.Repository;

/**
 * <p>
 * 订单信息表 Mapper 接口
 * </p>
 *
 * @author zking
 * @since 2022-11-08
 */
@Repository
public interface OrderMapper extends BaseMapper<Order> {

}

 OrderItemMapper

package com.zking.spbootpro.mapper;

import com.zking.spbootpro.model.OrderItem;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springframework.stereotype.Repository;

/**
 * <p>
 *  Mapper 接口
 * </p>
 *
 * @author zking
 * @since 2022-11-08
 */
@Repository
public interface OrderItemMapper extends BaseMapper<OrderItem> {

}


 四、沙箱支付简介及初步接入

简介:

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

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

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

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

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

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

 手机支付宝扫码注册账户

 

 电脑安装密钥工具

作用:生成密钥

 下载沙箱支付宝(只支持安卓)

手机安卓版安装沙箱版支付宝

手机登录后清除清(支付宝开放平台)缓存

随之充值(最高限额1000000元)

设置密钥

 设置支付宝公钥

 

 再将公钥放到 代码里

 //支付宝公钥

config.alipayPublicKey="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmUifAAtXclpNk2ezFnuM/Em1nYyBD2yEnHaanfUwh6TFyhqcQKbcHxYpurlyFyjHsBcBFhYmtUkpVWrNDqsIL4AmxKpNHQ5HGW7pKDOy+4ovoI3JcCzYeXuxti4L4yyd5Afuf3xUDcfRacriOf5FXlH6dSE6NvkShF0f7mPMOhtiVDnKyvuHcxH/qwjcqxZ6WilsaPNcOkOua3NEVlaqFll2wDxezukmtMqntUDqlJZ5U5CpOSXUOwAbvo9L+0nAReFE7N1z0huHtTDODyacIHaOATo5UTB8BQZm/niRqRKeTTduxSy6Udd6mTZkwO5KznZGVOuFdZ6F02zqrM9/1wIDAQAB";

 设置应用密钥

 设置appId

 

 AlipayConfig 

package com.zking.spbootpro.config;

import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.Config;
import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
import com.zking.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="2021000121689396";
        //支付宝公钥
        config.alipayPublicKey="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmUifAAtXclpNk2ezFnuM/Em1nYyBD2yEnHaanfUwh6TFyhqcQKbcHxYpurlyFyjHsBcBFhYmtUkpVWrNDqsIL4AmxKpNHQ5HGW7pKDOy+4ovoI3JcCzYeXuxti4L4yyd5Afuf3xUDcfRacriOf5FXlH6dSE6NvkShF0f7mPMOhtiVDnKyvuHcxH/qwjcqxZ6WilsaPNcOkOua3NEVlaqFll2wDxezukmtMqntUDqlJZ5U5CpOSXUOwAbvo9L+0nAReFE7N1z0huHtTDODyacIHaOATo5UTB8BQZm/niRqRKeTTduxSy6Udd6mTZkwO5KznZGVOuFdZ6F02zqrM9/1wIDAQAB";
        //签名方式
        config.signType="RSA2";
        //商户私钥(应用私钥),您的PKCS8格式RSA2私钥
        config.merchantPrivateKey="自己的应用私钥";
        return config;
    }
}

实现支付功能

order.js

$(function(){
    $('.pay').click(function(){
        //获取收货地址、联系人、联系电话
        let name=$('.addres').find('div.on div:eq(0)>p:eq(0)').text().trim();
        let address=$('.addres').find('div.on div:eq(1)>p:eq(0)').text();
        let phone=$('.addres').find('div.on div:eq(1)>p:eq(1)').text();
        console.log("name=%s,address=%s,phone=%s",name,address,phone);
        //获取支付方式
        let pay=$('.way').find('img.on').attr('value');
        console.log(pay);
        //获取快递方式
        let dis=$('.dis').find('span.on').text();
        console.log(dis);
        //获取勾选结算的商品ID
        let gids=$('#gids').val();
        //拼接请求参数
        let params={
            gids:gids,
            address:address,
            person:name,
            telephone:phone,
            pay:pay,
            mail:dis
        };
        console.log(params);

        // $.post('/order/addOrder',params,function(rs){
        //     if(rs.code==200){
        //         location.href='/page/ok.html';
        //     }else{
        //         alert(rs.msg);
        //     }
        // },'json');
        location.href='/order/addOrder?'+parseParams(params);
    });
});

/**
 * JSON转URL参数
 * @param data
 * @returns {string}
 */
function parseParams(data) {
    try {
        var tempArr = [];
        for (var i in data) {
            var key = encodeURIComponent(i);
            var value = encodeURIComponent(data[i]);
            tempArr.push(key + '=' + value);
        }
        var urlParamsStr = tempArr.join('&');
        return urlParamsStr;
    } catch (err) {
        return '';
    }
}

 OrderCotroller

package com.zking.spbootpro.Controller;

import com.zking.spbootpro.config.AlipayConfig;
import com.zking.spbootpro.model.Dto.OrderDto;
import com.zking.spbootpro.model.Goods;
import com.zking.spbootpro.model.User;
import com.zking.spbootpro.model.vo.ShopCar;
import com.zking.spbootpro.model.vo.ShopCarItem;
import com.zking.spbootpro.service.IOrderService;
import com.zking.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.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author 锦鲤
 * @site www.lucy.com
 * @company xxx公司
 * @create  2022-11-08 15:21
 */
@Controller
@RequestMapping("/order")
public class OrderCotroller {


    /**
     * 根据勾选结算的商品跳转到订单页面
     * @param user
     * @param req
     * @param gids
     * @return
     */
    @RequestMapping("/toOrder")
    public ModelAndView toOrder(User user,
                                HttpServletRequest req,
                                String gids){
        ModelAndView mv=new ModelAndView();
        //根据用户ID获取session中对应的购物车
        ShopCar shopCar = getShopCar(user, req);
        //从购物车中获取勾选结算的商品集合
        List<ShopCarItem> list=getgoods(shopCar,gids);
        mv.addObject("goods",list);
        mv.setViewName("order.html");
        return mv;
    }
//筛选指定商品
    private List<ShopCarItem> getgoods(ShopCar shopCar, String gids) {
      List<String> gidlist= Arrays.asList(gids.split(","));
        List<Goods> goods=new ArrayList<>();
        List<ShopCarItem> items=shopCar.getItems();//购物车全部商品
        List<ShopCarItem> itemsnew=new ArrayList<>();//购物车中选中要买的商品
        for (ShopCarItem item : items) {
            if(gidlist.contains(item.getGid()+"")){
                itemsnew.add(item);
            }
        }
        return itemsnew;

    }

    //    从session中获取购物车对象
    private ShopCar getShopCar(User user, HttpServletRequest request) {
        HttpSession session = request.getSession();
        ShopCar shopCar = (ShopCar) session.getAttribute(user.getId() + "_shopCar");
        if (shopCar == null) {
            shopCar = new ShopCar();
            session.setAttribute(user.getId() + "_shopCar", shopCar);
        }
        return shopCar;
    }

    /**
     *
     * @param user 拿到商品信息
     * @param request 拿到session
     * @param orderDto 拿到gids
     * @return
     */

    @Autowired
    private IOrderService orderService;

            @ResponseBody
            @RequestMapping("/addOrder")
            public  String addOrder(User user, HttpServletRequest request, OrderDto orderDto){

                //获取购物车
                ShopCar shopCar = this.getShopCar(user, request);
                //获取结算商品集合
                List<ShopCarItem> shopCarItems = getgoods(shopCar, orderDto.getGids());
                //生成订单及订单项
//                orderDto.setUserId(Long.parseLong(user.getId()));
                orderDto.setUserId(user.getId());
                orderService.addOrder(orderDto,shopCarItems);
                //从购物车中删除已结算的商品
                shopCar.delete(orderDto.getGids());
                //跳转支付页面
                AlipayConfig alipayConfig= new AlipayConfig();

                return alipayConfig.goAlipay(orderDto);
            }


}

报错了!

 拿到自己的app_id

 询问客服

解决:

 


 五、支付宝支付回调

 代码源于

 OrderCotroller更新

package com.zking.spbootpro.Controller;

import com.alipay.easysdk.factory.Factory;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.zking.spbootpro.config.AlipayConfig;
import com.zking.spbootpro.model.Dto.OrderDto;
import com.zking.spbootpro.model.Goods;
import com.zking.spbootpro.model.Order;
import com.zking.spbootpro.model.User;
import com.zking.spbootpro.model.vo.ShopCar;
import com.zking.spbootpro.model.vo.ShopCarItem;
import com.zking.spbootpro.service.IOrderService;
import com.zking.spbootpro.utils.JsonResponseBody;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * @author 锦鲤
 * @site www.lucy.com
 * @company xxx公司
 * @create  2022-11-08 15:21
 */
@Controller
@RequestMapping("/order")
public class OrderCotroller {


    /**
     * 根据勾选结算的商品跳转到订单页面
     * @param user
     * @param req
     * @param gids
     * @return
     */
    @RequestMapping("/toOrder")
    public ModelAndView toOrder(User user,
                                HttpServletRequest req,
                                String gids){
        ModelAndView mv=new ModelAndView();
        //根据用户ID获取session中对应的购物车
        ShopCar shopCar = getShopCar(user, req);
        //从购物车中获取勾选结算的商品集合
        List<ShopCarItem> list=getgoods(shopCar,gids);
        mv.addObject("goods",list);
        mv.setViewName("order.html");
        return mv;
    }
//筛选指定商品
    private List<ShopCarItem> getgoods(ShopCar shopCar, String gids) {
      List<String> gidlist= Arrays.asList(gids.split(","));
        List<Goods> goods=new ArrayList<>();
        List<ShopCarItem> items=shopCar.getItems();//购物车全部商品
        List<ShopCarItem> itemsnew=new ArrayList<>();//购物车中选中要买的商品
        for (ShopCarItem item : items) {
            if(gidlist.contains(item.getGid()+"")){
                itemsnew.add(item);
            }
        }
        return itemsnew;

    }

    //    从session中获取购物车对象
    private ShopCar getShopCar(User user, HttpServletRequest request) {
        HttpSession session = request.getSession();
        ShopCar shopCar = (ShopCar) session.getAttribute(user.getId() + "_shopCar");
        if (shopCar == null) {
            shopCar = new ShopCar();
            session.setAttribute(user.getId() + "_shopCar", shopCar);
        }
        return shopCar;
    }

    /**
     *
     * @param user 拿到商品信息
     * @param request 拿到session
     * @param orderDto 拿到gids
     * @return
     */

    @Autowired
    private IOrderService orderService;

            @ResponseBody
            @RequestMapping("/addOrder")
            public  String addOrder(User user, HttpServletRequest request, OrderDto orderDto){

                //获取购物车
                ShopCar shopCar = getShopCar(user, request);

                //获取结算商品集合
                List<ShopCarItem> shopCarItems = getgoods(shopCar, orderDto.getGids());
                //生成订单及订单项
                orderDto.setUserId(user.getId());
                orderService.addOrder(orderDto,shopCarItems);
                //从购物车中删除已结算的商品
                shopCar.delete(orderDto.getGids());
                //跳转支付页面(下节课内容)
                AlipayConfig alipayConfig= new AlipayConfig();

                return alipayConfig.goAlipay(orderDto);
            }
    /**
     * 支付成功后回调处理订单状态,完成整个下单流程的链路
     * @param param
     * @return
     */
    @RequestMapping("/orderFinish")
    public String orderFinish(@RequestParam Map<String, String> param){
        System.out.println("异步回调开始。。。。。。");
        Boolean signVerified=false;

        try {
            System.out.println(param);
            signVerified = Factory.Payment.Common().verifyNotify(param);
            System.out.println(signVerified);
            System.out.println("out_trade_no:"+param.get("out_trade_no"));
            System.out.println("total_amount:"+param.get("total_amount"));
            System.out.println("trade_no:"+param.get("trade_no"));
            if(signVerified){
                //支付成功
                //根据订单编号修改订单状态
                //update t_xxx set xx=?,tt=? where id=?
                orderService.update(new UpdateWrapper<Order>()
                        .set("status",1)
                        .setSql("pay_date=now()")
                        .eq("oid",param.get("out_trade_no")));
                //跳转到支付成功页面
            }else{
                //支付失败
            }


        } catch (Exception e) {
            e.printStackTrace();
        }
        return "ok.html";
    }


}

AlipayConfig更新

package com.zking.spbootpro.config;

import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.Config;
import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
import com.zking.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="2021000121689396";
        //支付宝公钥
        config.alipayPublicKey="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmUifAAtXclpNk2ezFnuM/Em1nYyBD2yEnHaanfUwh6TFyhqcQKbcHxYpurlyFyjHsBcBFhYmtUkpVWrNDqsIL4AmxKpNHQ5HGW7pKDOy+4ovoI3JcCzYeXuxti4L4yyd5Afuf3xUDcfRacriOf5FXlH6dSE6NvkShF0f7mPMOhtiVDnKyvuHcxH/qwjcqxZ6WilsaPNcOkOua3NEVlaqFll2wDxezukmtMqntUDqlJZ5U5CpOSXUOwAbvo9L+0nAReFE7N1z0huHtTDODyacIHaOATo5UTB8BQZm/niRqRKeTTduxSy6Udd6mTZkwO5KznZGVOuFdZ6F02zqrM9/1wIDAQAB";
        //签名方式
        config.signType="RSA2";
        //商户私钥(应用私钥),您的PKCS8格式RSA2私钥
        config.merchantPrivateKey="自己的支付宝开放平台私钥";
        return config;
    }
}

 输入沙箱支付宝密码合账户

 

 查看余额

 

 查看数据库数据

 账单状态由0变为1