当前位置:   article > 正文

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

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号