• SpringBoot电商项目之购物车下单(沙箱支付)


    目录

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

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

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

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

    3.订单页前台展示

    三、结算页的下单前端

    生成订单

    1.前端相关处理

    四、结算页的下单后端

    2.后台进行下单操作

    五、支付宝支付简介、初步接入以及支付宝支付回调

    1、配置沙箱支付

    沙箱支付应用

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

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


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

    实现思路

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

    购物车页面实现结算功能

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

     
    

    cart.js进行整改:关于结算按钮的绑定事件

    1. //计算总共几件商品
    2. function zg(){
    3. let gids="";
    4. var zsl = 0;
    5. var index = $(".th input[type='checkbox']:checked").parents(".th").find(".num span");
    6. var len =index.length;
    7. if(len==0){
    8. $("#sl").text(0);
    9. }else{
    10. let gidarr=new Array();
    11. index.each(function(){
    12. zsl+=parseInt($(this).text());
    13. $("#sl").text(zsl);
    14. //TODO 获取当前行的索引
    15. let idx = $(this).parents(".th").index()-1;
    16. console.log(idx);
    17. gidarr.push($(".th").eq(index).find('div:eq(0) input[type=hidden]').val());
    18. });
    19. gids=gidarr.join(",");
    20. }
    21. if($("#sl").text()>0){
    22. $(".count").css("background","#c10000");
    23. $(".count").bind("click",function () {
    24. // 拿到gids
    25. location.href='/order/toOrder?gids='+gids
    26. });
    27. }else{
    28. $(".count").css("background","#8e8e8e");
    29. $(".count").unbind("click");
    30. }
    31. }

    测试结果,当点击结算,会跳转访问地址http://localhost:8080/order/toOrder?gids=2,22

    说明gids的值是已经拿到了;

    然后再次去生成订单、订单项的代码:

     记得在Order类修改时间的类型:

     

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

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


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

    OrderController .java:

    1. package com.ycx.spbootpro.controller;
    2. import com.ycx.spbootpro.model.Goods;
    3. import com.ycx.spbootpro.model.User;
    4. import com.ycx.spbootpro.model.vo.ShopCar;
    5. import com.ycx.spbootpro.model.vo.ShopCarItem;
    6. import org.springframework.stereotype.Controller;
    7. import org.springframework.web.bind.annotation.RequestMapping;
    8. import org.springframework.web.bind.annotation.RestController;
    9. import org.springframework.web.servlet.ModelAndView;
    10. import javax.servlet.http.HttpServletRequest;
    11. import javax.servlet.http.HttpSession;
    12. import java.util.ArrayList;
    13. import java.util.Arrays;
    14. import java.util.List;
    15. /**
    16. *

    17. * 订单信息表 前端控制器
    18. *

    19. *
    20. * @author yangzong
    21. * @since 2022-11-08
    22. */
    23. @Controller
    24. @RequestMapping("/order")
    25. public class OrderController {
    26. @RequestMapping("/toOrder")
    27. public ModelAndView toOrder(User user,
    28. String gids,
    29. HttpServletRequest request){
    30. ModelAndView mv=new ModelAndView();
    31. // 拿到购物车中的所有商品
    32. ShopCar shopCar = getShopCar(user, request);
    33. // 通过gids从购物车中筛选出指定的商品
    34. List<ShopCarItem> list=getGoods(shopCar,gids);
    35. mv.addObject("goods",list);
    36. mv.setViewName("order.html");
    37. return mv;
    38. }
    39. //通过gids从购物车中筛选出指定的商品
    40. private List<ShopCarItem> getGoods(ShopCar shopCar, String gids) {
    41. List<String> gidList = Arrays.asList(gids.split(","));
    42. List<ShopCarItem> items=shopCar.getItems();//购物车里的商品
    43. List<ShopCarItem> itemsNew=new ArrayList<>();//购物车中要结算的商品
    44. for (ShopCarItem item:items){
    45. if(gidList.contains(item.getGid()+"")){
    46. itemsNew.add(item);
    47. }
    48. }
    49. return itemsNew;
    50. }
    51. // 从session中获取购物车对象
    52. private ShopCar getShopCar(User user,
    53. HttpServletRequest request) {
    54. HttpSession session = request.getSession();
    55. ShopCar shopCar = (ShopCar) session.getAttribute(user.getId() + "_shopCar");
    56. if (shopCar == null) {
    57. shopCar = new ShopCar();
    58. session.setAttribute(user.getId() + "_shopCar", shopCar);
    59. }
    60. return shopCar;
    61. }
    62. }

    3.订单页前台展示

    order.html:

    1. html>
    2. <html>
    3. <head lang="en">
    4. <#include "common/head.html">
    5. <link rel="stylesheet" type="text/css" href="css/public.css"/>
    6. <link rel="stylesheet" type="text/css" href="css/proList.css" />
    7. <link rel="stylesheet" type="text/css" href="css/mygxin.css" />
    8. head>
    9. <body>
    10. <div class="head ding">
    11. <div class="wrapper clearfix">
    12. <div class="clearfix" id="top">
    13. <h1 class="fl"><a href="${ctx}/"><img src="img/logo.png"/>a>h1>
    14. <div class="fr clearfix" id="top1">
    15. <form action="#" method="get" class="fl">
    16. <input type="text" placeholder="搜索" />
    17. <input type="button" />
    18. form>
    19. div>
    20. div>
    21. div>
    22. div>
    23. <div class="order cart mt">
    24. <div class="site">
    25. <p class="wrapper clearfix">
    26. <span class="fl">订单确认span>
    27. <img class="top" src="img/temp/cartTop02.png">
    28. p>
    29. div>
    30. <div class="orderCon wrapper clearfix">
    31. <div class="orderL fl">
    32. <h3>收件信息<a href="#" class="fr">新增地址a>h3>
    33. <div class="addres clearfix">
    34. <div class="addre fl on">
    35. <div class="tit clearfix">
    36. <p class="fl">张三1p>
    37. <span class="default">[默认地址]span>
    38. <p class="fr">
    39. <a href="#">删除a>
    40. <span>|span>
    41. <a href="#" class="edit">编辑a>
    42. p>
    43. div>
    44. <div class="addCon">
    45. <p>河北省 唐山市 路北区 大学生公寓村p>
    46. <p>15732570937p>
    47. div>
    48. div>
    49. <div class="addre fl">
    50. <div class="tit clearfix">
    51. <p class="fl">张三2
    52. p>
    53. <p class="fr">
    54. <a href="#" class="setDefault">设为默认a>
    55. <span>|span>
    56. <a href="#">删除a>
    57. <span>|span>
    58. <a href="#" class="edit">编辑a>
    59. p>
    60. div>
    61. <div class="addCon">
    62. <p>河北省 唐山市 路北区 大学生公寓村p>
    63. <p>15732570937p>
    64. div>
    65. div>
    66. <div class="addre fl">
    67. <div class="tit clearfix">
    68. <p class="fl">张三3
    69. p>
    70. <p class="fr">
    71. <a href="#" class="setDefault">设为默认a>
    72. <span>|span>
    73. <a href="#">删除a>
    74. <span>|span>
    75. <a href="#" class="edit">编辑a>
    76. p>
    77. div>
    78. <div class="addCon">
    79. <p>河北省 唐山市 路北区 大学生公寓村p>
    80. <p>15732570937p>
    81. div>
    82. div>
    83. div>
    84. <h3>支付方式h3>
    85. <div class="way clearfix">
    86. <img class="on" value="0" src="img/temp/way01.jpg">
    87. <img value="1" src="img/temp/way02.jpg">
    88. <img value="2" src="img/temp/way03.jpg">
    89. <img value="3" src="img/temp/way04.jpg">
    90. div>
    91. <h3>选择快递h3>
    92. <div class="dis clearfix">
    93. <span class="on">顺风快递span>
    94. <span>百世汇通span>
    95. <span>圆通快递span>
    96. <span>中通快递span>
    97. div>
    98. div>
    99. <div class="orderR fr">
    100. <div class="msg">
    101. <h3>订单内容<a href="${ctx}/shopCar/queryShopCar" class="fr">返回购物车a>h3>
    102. <#if goods??>
    103. <#list goods as g>
    104. <ul class="clearfix">
    105. <li class="fl">
    106. <img style="height: 87px; width: 87px;" src="${g.goodsImg}">
    107. li>
    108. <li class="fl">
    109. <p>${g.goodsName}p>
    110. <p>颜色分类:烟灰色玻璃瓶p>
    111. <p>数量:${g.quantity}p>
    112. li>
    113. <li class="fr">¥ ${g.goodsPrice}li>
    114. ul>
    115. div>
    116. <div class="tips">
    117. <p><span class="fl">商品金额:span><span class="fr">¥139.8span>p>
    118. <p><span class="fl">优惠金额:span><span class="fr">¥0.00span>p>
    119. <p><span class="fl">运费:span><span class="fr">免运费span>p>
    120. div>
    121. <div class="count tips">
    122. <p><span class="fl">合计:span><span class="fr">¥139.8span>p>
    123. div>
    124. <a href="javascript:void(0);" class="pay">去支付a>
    125. div>
    126. div>
    127. div>
    128. <div class="mask">div>
    129. <div class="adddz editAddre">
    130. <form action="#" method="get">
    131. <input type="text" placeholder="姓名" class="on" />
    132. <input type="text" placeholder="手机号" />
    133. <div class="city">
    134. <select name="">
    135. <option value="省份/自治区">省份/自治区option>
    136. select>
    137. <select>
    138. <option value="城市/地区">城市/地区option>
    139. select>
    140. <select>
    141. <option value="区/县">区/县option>
    142. select>
    143. <select>
    144. <option value="配送区域">配送区域option>
    145. select>
    146. div>
    147. <textarea name="" rows="" cols="" placeholder="详细地址">textarea>
    148. <input type="text" placeholder="邮政编码" />
    149. <div class="bc">
    150. <input type="button" value="保存" />
    151. <input type="button" value="取消" />
    152. div>
    153. form>
    154. div>
    155. <input type="hidden" id="gids" value="${RequestParameters['gids']!}"/>
    156. <#include "common/footer.html">
    157. <script src="js/others/order.js" type="text/javascript" charset="utf-8">script>
    158. <script src="js/public.js" type="text/javascript" charset="utf-8">script>
    159. <script src="js/pro.js" type="text/javascript" charset="utf-8">script>
    160. <script src="js/user.js" type="text/javascript" charset="utf-8">script>
    161. body>
    162. html>

    展示结果如下:

     

    三、结算页的下单前端

    生成订单

    实现思路

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

    1.前端相关处理

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

    在Order.html添加order.js,

    order.js代码如下

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

    四、结算页的下单后端

    2.后台进行下单操作

    OrderDto :

    1. package com.ycx.spbootpro.model.dto;
    2. import com.ycx.spbootpro.model.Order;
    3. import lombok.Data;
    4. /**
    5. * @author 杨总
    6. * @create 2022-11-08 21:36
    7. */
    8. @Data
    9. public class OrderDto extends Order{
    10. private String gids;
    11. }

    OrderController.java:

    1. package com.ycx.spbootpro.controller;
    2. import com.ycx.spbootpro.model.Goods;
    3. import com.ycx.spbootpro.model.User;
    4. import com.ycx.spbootpro.model.dto.OrderDto;
    5. import com.ycx.spbootpro.model.vo.ShopCar;
    6. import com.ycx.spbootpro.model.vo.ShopCarItem;
    7. import com.ycx.spbootpro.service.IOrderService;
    8. import com.ycx.spbootpro.utils.JsonResponseBody;
    9. import org.springframework.beans.factory.annotation.Autowired;
    10. import org.springframework.stereotype.Controller;
    11. import org.springframework.web.bind.annotation.RequestMapping;
    12. import org.springframework.web.bind.annotation.ResponseBody;
    13. import org.springframework.web.bind.annotation.RestController;
    14. import org.springframework.web.servlet.ModelAndView;
    15. import javax.servlet.http.HttpServletRequest;
    16. import javax.servlet.http.HttpSession;
    17. import java.util.ArrayList;
    18. import java.util.Arrays;
    19. import java.util.List;
    20. /**
    21. *

    22. * 订单信息表 前端控制器
    23. *

    24. *
    25. * @author yangzong
    26. * @since 2022-11-08
    27. */
    28. @Controller
    29. @RequestMapping("/order")
    30. public class OrderController {
    31. @RequestMapping("/toOrder")
    32. public ModelAndView toOrder(User user,
    33. String gids,
    34. HttpServletRequest request){
    35. ModelAndView mv=new ModelAndView();
    36. // 拿到购物车中的所有商品
    37. ShopCar shopCar = getShopCar(user, request);
    38. // 通过gids从购物车中筛选出指定的商品
    39. List<ShopCarItem> list=getGoods(shopCar,gids);
    40. mv.addObject("goods",list);
    41. mv.setViewName("order.html");
    42. return mv;
    43. }
    44. //通过gids从购物车中筛选出指定的商品
    45. private List<ShopCarItem> getGoods(ShopCar shopCar, String gids) {
    46. List<String> gidList = Arrays.asList(gids.split(","));
    47. List<ShopCarItem> items=shopCar.getItems();//购物车里的商品
    48. List<ShopCarItem> itemsNew=new ArrayList<>();//购物车中要结算的商品
    49. for (ShopCarItem item:items){
    50. if(gidList.contains(item.getGid()+"")){
    51. itemsNew.add(item);
    52. }
    53. }
    54. return itemsNew;
    55. }
    56. // 从session中获取购物车对象
    57. private ShopCar getShopCar(User user,
    58. HttpServletRequest request) {
    59. HttpSession session = request.getSession();
    60. ShopCar shopCar = (ShopCar) session.getAttribute(user.getId() + "_shopCar");
    61. if (shopCar == null) {
    62. shopCar = new ShopCar();
    63. session.setAttribute(user.getId() + "_shopCar", shopCar);
    64. }
    65. return shopCar;
    66. }
    67. @Autowired
    68. private IOrderService orderService;
    69. @RequestMapping("/addOrder")
    70. @ResponseBody
    71. public JsonResponseBody addOrder(User user,
    72. HttpServletRequest req,
    73. OrderDto orderDto){
    74. //获取购物车
    75. ShopCar shopCar = this.getShopCar(user, req);
    76. //获取结算商品集合
    77. List<ShopCarItem> shopCarItems = this.getGoods(shopCar, orderDto.getGids());
    78. //生成订单及订单项
    79. orderDto.setUserId(user.getId());
    80. orderService.addOrder(orderDto,shopCarItems);
    81. //从购物车中删除已结算的商品
    82. shopCar.delete(orderDto.getGids());
    83. //跳转支付页面(下节课内容)
    84. return new JsonResponseBody();
    85. }
    86. }

    OrderServiceImpl.java:

    1. package com.ycx.spbootpro.service.impl;
    2. import com.ycx.spbootpro.model.Order;
    3. import com.ycx.spbootpro.mapper.OrderMapper;
    4. import com.ycx.spbootpro.model.OrderItem;
    5. import com.ycx.spbootpro.model.dto.OrderDto;
    6. import com.ycx.spbootpro.model.vo.ShopCarItem;
    7. import com.ycx.spbootpro.service.IOrderItemService;
    8. import com.ycx.spbootpro.service.IOrderService;
    9. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    10. import com.ycx.spbootpro.utils.SnowFlake;
    11. import org.springframework.beans.factory.annotation.Autowired;
    12. import org.springframework.stereotype.Service;
    13. import org.springframework.transaction.annotation.Transactional;
    14. import java.math.BigDecimal;
    15. import java.util.ArrayList;
    16. import java.util.List;
    17. /**
    18. *

    19. * 订单信息表 服务实现类
    20. *

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

    SnowFlake :

    (SnowFlake生成雪花ID,它的作用:生成一个随机的long类型的数字;相较于UUID的优点在于雪花ID可以排序)
    1. package com.ycx.spbootpro.utils;
    2. public class SnowFlake {
    3. /**
    4. * 起始的时间戳
    5. */
    6. private final static long START_STMP = 1480166465631L;
    7. /**
    8. * 每一部分占用的位数
    9. */
    10. private final static long SEQUENCE_BIT = 12; //序列号占用的位数
    11. private final static long MACHINE_BIT = 5; //机器标识占用的位数
    12. private final static long DATACENTER_BIT = 5;//数据中心占用的位数
    13. /**
    14. * 每一部分的最大值
    15. */
    16. private final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT);
    17. private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);
    18. private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);
    19. /**
    20. * 每一部分向左的位移
    21. */
    22. private final static long MACHINE_LEFT = SEQUENCE_BIT;
    23. private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
    24. private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT;
    25. private long datacenterId; //数据中心
    26. private long machineId; //机器标识
    27. private long sequence = 0L; //序列号
    28. private long lastStmp = -1L;//上一次时间戳
    29. public SnowFlake(long datacenterId, long machineId) {
    30. if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) {
    31. throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0");
    32. }
    33. if (machineId > MAX_MACHINE_NUM || machineId < 0) {
    34. throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0");
    35. }
    36. this.datacenterId = datacenterId;
    37. this.machineId = machineId;
    38. }
    39. /**
    40. * 产生下一个ID
    41. *
    42. * @return
    43. */
    44. public synchronized long nextId() {
    45. long currStmp = getNewstmp();
    46. if (currStmp < lastStmp) {
    47. throw new RuntimeException("Clock moved backwards. Refusing to generate id");
    48. }
    49. if (currStmp == lastStmp) {
    50. //相同毫秒内,序列号自增
    51. sequence = (sequence + 1) & MAX_SEQUENCE;
    52. //同一毫秒的序列数已经达到最大
    53. if (sequence == 0L) {
    54. currStmp = getNextMill();
    55. }
    56. } else {
    57. //不同毫秒内,序列号置为0
    58. sequence = 0L;
    59. }
    60. lastStmp = currStmp;
    61. return (currStmp - START_STMP) << TIMESTMP_LEFT //时间戳部分
    62. | datacenterId << DATACENTER_LEFT //数据中心部分
    63. | machineId << MACHINE_LEFT //机器标识部分
    64. | sequence; //序列号部分
    65. }
    66. private long getNextMill() {
    67. long mill = getNewstmp();
    68. while (mill <= lastStmp) {
    69. mill = getNewstmp();
    70. }
    71. return mill;
    72. }
    73. private long getNewstmp() {
    74. return System.currentTimeMillis();
    75. }
    76. public static void main(String[] args) {
    77. SnowFlake snowFlake = new SnowFlake(2, 3);
    78. long start = System.currentTimeMillis();
    79. for (int i = 0; i < 1000000; i++) {
    80. System.out.println(snowFlake.nextId());
    81. }
    82. System.out.println(System.currentTimeMillis() - start);
    83. }
    84. }

    IOrderService : 

    1. package com.ycx.spbootpro.service;
    2. import com.ycx.spbootpro.model.Order;
    3. import com.baomidou.mybatisplus.extension.service.IService;
    4. import com.ycx.spbootpro.model.dto.OrderDto;
    5. import com.ycx.spbootpro.model.vo.ShopCarItem;
    6. import java.util.List;
    7. /**
    8. *

    9. * 订单信息表 服务类
    10. *

    11. *
    12. * @author yangzong
    13. * @since 2022-11-08
    14. */
    15. public interface IOrderService extends IService<Order> {
    16. void addOrder(OrderDto orderDto, List<ShopCarItem> shopCarItems);
    17. }

    OrderMapper :

    1. package com.ycx.spbootpro.mapper;
    2. import com.ycx.spbootpro.model.Order;
    3. import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    4. import org.springframework.stereotype.Repository;
    5. /**
    6. *

    7. * 订单信息表 Mapper 接口
    8. *

    9. *
    10. * @author yangzong
    11. * @since 2022-11-08
    12. */
    13. @Repository
    14. public interface OrderMapper extends BaseMapper<Order> {
    15. }

    OrderItemMapper :

    1. package com.ycx.spbootpro.mapper;
    2. import com.ycx.spbootpro.model.OrderItem;
    3. import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    4. import org.springframework.stereotype.Repository;
    5. /**
    6. *

    7. * Mapper 接口
    8. *

    9. *
    10. * @author yangzong
    11. * @since 2022-11-08
    12. */
    13. @Repository
    14. public interface OrderItemMapper extends BaseMapper<OrderItem> {
    15. }

     

     

     数据插入了表中即可。

    五、支付宝支付简介、初步接入以及支付宝支付回调

    1、配置沙箱支付

    第一步:
    1)登陆支付宝:https://open.alipay.com/
    打开自己的支付宝扫一扫:
    
    2)首页找到进入管理中心 -> 开发工具推荐选择【沙箱】
    3)下载安装支付宝开放平台开发助手:
    https://opendocs.alipay.com/common/02kipk
    
    4)打开本地支付宝开放平台助手 -> 密钥工具 -> 生成密钥 -> 以默认方式(RSA2和PKCS8)生成应用私钥和应用公钥
    5)在沙箱应用的开发信息中选择自定义密钥生成支付宝公钥(基于应用公钥生成支付宝公钥)
    ​
    第二步:配置沙箱账号(买家)并完成手动充值
    https://open.alipay.com/develop/sandbox/account
    ​
    第三步:下载沙箱支付宝(只支持安卓)
    https://open.alipay.com/develop/sandbox/tool/alipayclint
    ​
    沙箱工具 -> 支付宝客户端沙箱版 -> 请使用浏览器中的扫码功能扫描下载
    ​
    注:请使用Android手机扫码下载支付宝客户端沙箱版;如需登录,请访问沙箱账号,在商家信息中获取帐密

    沙箱支付应用

    实现思路

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

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

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

    https://opendocs.alipay.com/common/02kg69

    AlipayConfig.java

    1. package com.ycx.spbootpro.config;
    2. import com.ycx.spbootpro.model.dto.OrderDto;
    3. /**
    4. * 支付宝沙箱支付
    5. */
    6. public class AlipayConfig {
    7. public String goAlipay(OrderDto orderDto){
    8. try {
    9. // 1. 设置参数(全局只需设置一次)
    10. Factory.setOptions(aliconfig());
    11. // 2. 发起API调用(subject商品标题、outTradeNo订单编号、totalAmount总金额、returnUrl异步通知地址)
    12. AlipayTradePagePayResponse response = Factory.Payment.Page()
    13. .pay(orderDto.getOid()+"",
    14. orderDto.getOid()+"",
    15. orderDto.getTotal().toString(),
    16. "http://localhost:8081/page/ok.html"); //支付成功之后的异步通知(跳出到自己系统的哪个位置)
    17. System.out.println(response.body);
    18. return response.body;
    19. } catch (Exception e) {
    20. e.printStackTrace();
    21. throw new RuntimeException(e);
    22. }
    23. }
    24. private Config aliconfig(){
    25. Config config=new Config();
    26. //沙箱支付宝地址
    27. config.gatewayHost="openapi.alipaydev.com";
    28. //协议https
    29. config.protocol="https";
    30. //应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号
    31. config.appId="2016093000634935";
    32. //支付宝公钥
    33. config.alipayPublicKey="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy/NfwxWr2SfktLUekBR+3w/MUjz1mnW7/wzTOkN1WWIx4i4Ak2m7XDl+evV76FPCcj40HfqgLXxxSVW5a1cCwJ8Z9EgEd7dd1J0EW6slx0v1XMHoPQgOkEVijSWZLLjVhw9x88IWtPTr93YGHYWgR7T9S0M58ABrXPO5eoRxjDdkPCdzyDSmeVixzXZcrhCBHsUMJqipEr8NQA6Iz8QYRYBvQxtkv8j7NZcu+tFfWZ0EPswbsYp/ie+LFjFxTKsov27aduM466Q9ECOYRhCJvB0IbTyY/KYc/VT8TvZIyBA3JP1w2KYoUnKgc5sAGt7ifVXjH3jc8rrC4rWeUIGVFQIDAQAB";
    34. //签名方式
    35. config.signType="RSA2";
    36. //商户私钥(应用私钥),您的PKCS8格式RSA2私钥
    37. config.merchantPrivateKey="MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC06LM7m2P2svS9/2W6GwhP9WwcuwmA4ASjsIx6y1llPdrDfPU/79tnWpZXnaA+JcVhUv1iZ0JfEBCMCSPXISuIbvYWsRk+UJ5JqFhutuOSKgG2Xr5UFoHpsEZxehgOa7sPsy109XtQS0Nk/0FiyyoDYzgubPrvneEyqT4vnvMD3xDTILI8hqyTt+DD8HAKDR0D/5vMXi5JuSJfizIRkOQCT6zdx5QkOm40nk4xaJdlV2FmknYiJdy8TpEwTtmk6v8cSt9o6GcmydiqqmMfWZ1pFoeeoHw0zep6cdhhTVhnEWu4lTnUtS2W1kCtU1uDzAkDUygGVCNB2TaW9L1dme5TAgMBAAECggEAY6R7/AvVnm7pELFYVY5IIMpbtuNqE5rP010NsyDH51SPZvcvmfzBywaBIlcGiNSDB90PBSE81GFjy83I+NgjQy1izBLVhZYf6RAZTTnc1Ifgk5NRn70Z5x4ZXq1SDLdXvAkDs5T2S754q2tQl1qxlFYU/rU17b7259GCF/ajgXBwDGIeq+gaGvyWI7ZQAlIJttTisPJfEq9BujZ2NiKabTuyztqGTB2/3woX3pCDwRyYdjmw65obMwzh4CpXJ1ku5eTorwdI/wVX/FY2+4ZfeB632vTJcCWqJilwTwGhlLF0ZQfFgkBaABCLUOGVCIqL4V9JcZaTBYHbsRjfeDZ3WQKBgQDxjk8d4tFRqJWwyhxF9TddIbnR6LydUIOH9dvpoxGTSLQwFY/OYRA2aOfgch0Xturti/iGtu3MNQX1KTA5+WvHKPspYZrHkDpk6K9iXylIQo0+9L1bn73HAYuH/PqGoxewVstlegu5wk9u/BAh9bmGm1T0NOQZ7AafpplhxIGnNwKBgQC/ugUYbLIAI+Zt5rD7oaHUKSyYGPD2DFzP2tYUjKWQy5sh7fzNK0D/X49RI/ozbHctvl/CLUb6/vtbWTGe9LDstflY/v+q/WnLKW4alrgmztIwlq1x8wRkYSbG6QeMPYZsJ17SUY6JWfkVLxqS9oTqImmDRx13kM7CLdyepSxHxQKBgAoDqVoG1kC5aYNLzcJEuUfeJxMBwBgRh3Jyiex0uzzM7dN0gWK/+WkYDkzqzjP2fGTewa3sFY26wQV58KrmoUY/d7Iufrk5TIJ0dxjv8wkw4SQ0B0muJLMEaGF55nUAe/Hulz4cwjGwUZS7VHvj8Q4YkHwTWUWN2HRz9rXr7KgfAoGBALhHRISAXOozl1SEyhFh/phcZudd+aSUp1SFIwUnVi+A83++LiDJdTS/lZHIwcBRfY9zDrklKbcwA0p+xWniCHfMRHjcx8KCxf+mt5RIz4FFgtN+0ADZMpyEoG/JJR8PN7eWc9Y024p69yT8XE9rML+WCdJLNTBp98C9sfKuEYx9AoGBAN6RslNXhkGmAZEeZD9nUpfdJJz+55uXv6vlMSp9SHw0ZZH5Ndu0YfWLP3AhhrhP+u/2LVggAE50x12LVJjDWhr9eGUsCvuKLrekfZvUC7OGSmBcrLLkY0BbYGo9+S3FYxTe/rRd23jM4UEA0X/49gK0NMN1yrkhvYvQZBfn4PaJ";
    38. return config;
    39. }
    40. }

    order.js变更如下:

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

     OrderController.java代码变更如下:

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

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

    OrderController.java代码新增如下:

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

    AlipayConfig.java变更如下:

    1. package com.ycx.spbootpro.config;
    2. import com.alipay.easysdk.factory.Factory;
    3. import com.alipay.easysdk.kernel.Config;
    4. import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
    5. import com.ycx.spbootpro.model.dto.OrderDto;
    6. /**
    7. * 支付宝沙箱支付
    8. */
    9. public class AlipayConfig {
    10. public String goAlipay(OrderDto orderDto){
    11. try {
    12. // 1. 设置参数(全局只需设置一次)
    13. Factory.setOptions(aliconfig());
    14. // 2. 发起API调用(subject商品标题、outTradeNo订单编号、totalAmount总金额、returnUrl异步通知地址)
    15. AlipayTradePagePayResponse response = Factory.Payment.Page()
    16. .pay(orderDto.getOid()+"",
    17. orderDto.getOid()+"",
    18. orderDto.getTotal().toString(),
    19. // "http://localhost:8080/page/ok.html");
    20. "http://localhost:8080/order/orderFinish");
    21. //支付成功之后的异步通知(跳出到自己系统的哪个位置)
    22. System.out.println(response.body);
    23. return response.body;
    24. } catch (Exception e) {
    25. e.printStackTrace();
    26. throw new RuntimeException(e);
    27. }
    28. }
    29. private Config aliconfig(){
    30. Config config=new Config();
    31. //沙箱支付宝地址
    32. config.gatewayHost="openapi.alipaydev.com";
    33. //协议https
    34. config.protocol="https";
    35. //应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号
    36. config.appId="2021000120601533";
    37. //支付宝公钥
    38. config.alipayPublicKey="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6rbyoXBc0GLKuVQAAQsvimxWKKJr/0a93yqadDalqIfrWeXlg6tFoQT+DtRazaJSBb3DwQuq3GUpUHA5RaAkhpLId6fRFiufhIwiL1mt+urs82u2wpDRq0mw7eNdSSCN+SP03Gi15fuS94twPYCmHv9F/lecSs27vEIZkGUHN6ueeGm7I/9JeoxKXIu6D9agKZzMR2jY6ThVOmGnpkV95PxuI3XSG+nvkZoCSB2UJ7A7/P5xHiDw3sk8JEjpCDcwcUCq1Mbems3MrQLwS9rn2uqXFTwfS1Wl9aT3XCyMUKciSrO7mGm608S0swVFf52otLaEnd/44QVOD/vGdK05qwIDAQAB";
    39. //签名方式
    40. config.signType="RSA2";
    41. //商户私钥(应用私钥),您的PKCS8格式RSA2私钥
    42. config.merchantPrivateKey="MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDAlDU9aEj69WZluzXp912ACjjlrlJ+h9x5cr/bp/fq5CQapDIqgriW9dWAMS9VVUFsoiA7lU/5UGuvjgTTGlY/4+PRnlbxyk4LF8dM/4czAB7G8TTiZNmemijL8xdO/ifYXskZJ+epbbqZGGaf3GKIuvhAbfNRBoNJBG2pUxlPkpjuY1w4oox2h4fd9+ERknWpQClOArAKnmg9qsMjZMwHpUh561jyOSjWGeNUg+bpRVwfbhDp4Js/QC1vXBcR5lsADuyrC7He3apHF3uoTQBkC1NbL7RinpoSIom6ZUB3T9lmpJ2VBxvYTGIHM8GVebDc2c9UNj0tU0StHC/hIu/VAgMBAAECggEBAIs9XbU1prbVIiFiF9w/v3npajQfM4RLBU1Ge5P9QZKzO6uLlr4H4CE+RA05AslHKFO8cWPDVJyl2gaHv9NG0p/FTR5txt1x8bWxjqeMhhuI9bfQBPXAB1zWh7LW4754oySde/dVU/m73dP9wY3KUfAch4xGM0wdUmVD72ojLETMLOpiUweuVb+WNWX/mP5JtLEWI8M8usWMYN/0PaAfy0ayZrsLif3Tep21lf9wXAICgMWI/dtTgNAfmfU1WDdSC0ENKsV1/DYvqjlEmFDOQccRGjBWoGgXxamCukppTAtpWfqFHdsY9z/WGhB+XxVaKRklUuw51XwVGhlo0cKipCECgYEA/sEr8hxMl1m2X7VjsdD9PHXDsXrdEX+gyQCJHNlP8KEJQjEWV8znWGsNS3LvkA9/mC1JMDV/FVK/7CSPR0tHrr/Mv48DEUA+zukz4SBGqI+NlXg3CeoRrbJOj95zRp7na7jsw1UyxwIoXXWzthuqOZ7TPn4fQyZSNEsIQ/qL3v0CgYEAwYU5BxIwE+3dGLpKiBetKCg9LvE7KiYY4uzzlvR4aGC3jx4y9GYw31QEWyEbLHy8373nE2lIlCwhSdyWGQD+NWDLuebti9MCf9erRJ+ImdTPgg0Kwqui1P72qrjIP+QaMSNlZZBW2CsRIu7ST9HSdNTCkD6TkmmIYtxzlWXjZ7kCgYBt/uhDpHZpjyHQl1hRaaQ927dARYV4TbwVrbaGD0qV4mJGAz3bcSyen7Jg1mKbuCVmhn8oYqDZix41DuASb22nBUeZml0/sJat7kEpPi9kDn+afwp8rGUvs2J6ehkZ7/iKKZGJEZtYFBVrrSuIQM+yC2K4g+ppqv0peRA7kc2c3QKBgC2ai3nTG2lW4Id3PyEbEz8nXGO3jU29dJflZvHn4ogWYqtjXnahrlqyneQrxQ+SxZ+kTNQSN3xTefTB+s0hosZJbTj95nTQ4QHnfQDK55H4yH3JPQPrFpBDFTXeHbKQumth//8TKKQAYiVtSjptI79MdB0x4eza2b0SXlqSjChhAoGBAIl91/O6TiAX9SjUj0ItJtaPc3PyoAWh19ZlTHLlN6NQ8XevEHVUEtVkK2mKgXr7PUUNRw3meDGoB0fpYwiCW5s2R2x8xQAATo+SIQMyBwtAr610+vkhyjQSZ/u0JhIazDrI6RJZmvzeLMgLQwQKTXnKwHTUgxNUqRSE4F3eet46";
    43. return config;
    44. }
    45. }

    测试:

     

     

     

     随后便自动调回商品首页,下单已完成!

    关于SpringBoot电商项目就到此告一段落啦~感谢收看。

  • 相关阅读:
    深度学习DeepLearning多元线性回归 学习笔记
    225. 用队列实现栈-C语言
    【一周聚焦】 联邦学习 arxiv 2.16-3.10
    图形用户界面和游戏开发
    被视为“救世主”的架构师,普遍缺失了哪些基础能力?
    初始多线程
    使用 Webmin+bind9快速搭建私有DNS服务器
    AI目标分割能力,无需绿幕即可实现快速视频抠图
    工业设计的特点和流程
    微服务中远程调用Dubbo与Feign对比
  • 原文地址:https://blog.csdn.net/weixin_65808248/article/details/127749745