目录
配置沙箱支付
一、订单生成
购物车结算前端功能实现
cart.js进行整改,给结算按钮增加点击事件
cart.js
$(function(){
/**************数量加减***************/
$(".num .sub").click(function(){
var num = parseInt($(this).siblings("span").text());
if(num<=1){
$(this).attr("disabled","disabled");
}else{
num--;
$(this).siblings("span").text(num);
//获取除了货币符号以外的数字
var price = $(this).parents(".number").prev().text().substring(1);
//单价和数量相乘并保留两位小数
$(this).parents(".th").find(".sAll").text('¥'+(num*price).toFixed(2));
jisuan();
zg();
//TODO 获取当前行的行索引
let index = $(this).parents(".th").index()-1;
//获取当前的checkbox中设置的隐藏域(包含了商品ID)
let gid=$(".th").eq(index).find('div:eq(0) input[type=hidden]').val();
update(num,gid);
}
});
$(".num .add").click(function(){
var num = parseInt($(this).siblings("span").text());
if(num>=5){
confirm("限购5件");
}else{
num++;
$(this).siblings("span").text(num);
var price = $(this).parents(".number").prev().text().substring(1);
$(this).parents(".th").find(".sAll").text('¥'+(num*price).toFixed(2));
jisuan();
zg();
//TODO 获取当前行的行索引
let index = $(this).parents(".th").index()-1;
//获取当前的checkbox中设置的隐藏域(包含了商品ID)
let gid=$(".th").eq(index).find('div:eq(0) input[type=hidden]').val();
update(num,gid);
}
});
//计算总价
function jisuan(){
var all=0;
var len =$(".th input[type='checkbox']:checked").length;
if(len==0){
$("#all").text('¥'+parseFloat(0).toFixed(2));
}else{
$(".th input[type='checkbox']:checked").each(function(){
//获取小计里的数值
var sAll = $(this).parents(".pro").siblings('.sAll').text().substring(1);
//累加
all+=parseFloat(sAll);
//赋值
$("#all").text('¥'+all.toFixed(2));
})
}
}
//计算总共几件商品
function zg(){
var zsl = 0;
var index = $(".th input[type='checkbox']:checked").parents(".th").find(".num span");
var len =index.length;
if(len==0){
$("#sl").text(0);
}else{
// index.each(function(){
// zsl+=parseInt($(this).text());
// $("#sl").text(zsl);
// })
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");
}
}
/*****************商品全选***********************/
$("input[type='checkbox']").on('click',function(){
var sf = $(this).is(":checked");
var sc= $(this).hasClass("checkAll");
if(sf){
if(sc){
$("input[type='checkbox']").each(function(){
this.checked=true;
});
zg();
jisuan();
}else{
$(this).checked=true;
var len = $("input[type='checkbox']:checked").length;
var len1 = $("input").length-1;
if(len==len1){
$("input[type='checkbox']").each(function(){
this.checked=true;
});
}
zg();
jisuan();
}
}else{
if(sc){
$("input[type='checkbox']").each(function(){
this.checked=false;
});
zg();
jisuan();
}else{
$(this).checked=false;
var len = $(".th input[type='checkbox']:checked").length;
var len1 = $("input").length-1;
if(len<len1){
$('.checkAll').attr("checked",false);
}
zg();
jisuan();
}
}
});
/****************************proDetail 加入购物车*******************************/
$(".btns .cart").click(function(){
if($(".categ p").hasClass("on")){
var num = parseInt($(".num span").text());
var num1 = parseInt($(".goCart span").text());
$(".goCart span").text(num+num1);
}
});
//删除购物车商品
$('.del').click(function(){
//定义商品id 1,2,3,4,5,6
let gids = "";
//单个删除
if($(this).parent().parent().hasClass("th")){
$(".mask").show();
$(".tipDel").show();
index = $(this).parents(".th").index()-1;
//TODO 获取当前的checkbox中设置的隐藏域(包含了商品ID)
gids=$(".th").eq(index).find('div:eq(0) input[type=hidden]').val();
$('.cer').click(function(){
$(".mask").hide();
$(".tipDel").hide();
$(".th").eq(index).remove();
$('.cer').off('click');
if($(".th").length==0){
$(".table .goOn").show();
}
del(gids);
})
}else{
//选中多个一起删除
if($(".th input[type='checkbox']:checked").length==0){
$(".mask").show();
$(".pleaseC").show();
}
else{
$(".mask").show();
$(".tipDel").show();
let gidarr = new Array();// {1,2,3,4,5,6}
$(".th input[type='checkbox']:checked").each(function(j){
gidarr.push($(".th").eq(index).find('div:eq(0) input[type=hidden]').val());
// gids += $(".th").eq(index).find('div:eq(0) input[type=hidden]').val() + ",";
});
gids = gidarr.join(",");
$('.cer').click(function(){
$(".th input[type='checkbox']:checked").each(function(j){
index = $(this).parents('.th').index()-1;
$(".th").eq(index).remove();
if($(".th").length==0){
$(".table .goOn").show();
}
})
$(".mask").hide();
$(".tipDel").hide();
zg();
jisuan();
del(gids);
})
}
}
})
$('.cancel').click(function(){
$(".mask").hide();
$(".tipDel").hide();
})
//改变商品规格
// $(".pro dd").hover(function(){
// var html='';
// html='<span class="edit">修改</span>';
// $(this).addClass("on").append(html).parents(".th").siblings(".th").find(".pro dd").removeClass("on").find('.edit').remove();
// $(".edit").each(function(i){
// $(this).attr("id",'edit'+i);
// $("#edit"+i).click(function(){
// $(".proDets").show();
// $(".mask").show();
// $(".changeBtn .buy").attr("data-id",i);
// })
// })
// },function(){
// $(this).removeClass("on");
// })
// $(".changeBtn .buy").click(function(){
// var index = $(this).attr("data-id");
// var result = $(".smallImg .on").find("img").attr("alt");
// $("#edit"+index).prev().text(result);
// $(".proDets").hide();
// $(".mask").hide();
// $("#edit"+index).parent("dd").removeClass("on").find(".edit").remove();
// });
// $(".changeBtn .cart").click(function(){
// $(".proDets").hide();
// $(".mask").hide();
// })
})
//删除商品
function del(gids){
$.post('/shopCar/delete',{
'gids':gids
},function(rs){
if(rs.code!=200)
alert(rs.msg);
else
location.href='/shopCar/queryShopCar';
},'json');
}
//更新商品数量
function update(num,gid){
$.post('/shopCar/update',{
'gid':gid,
'quantity':num
},function(rs){
if(rs.code!=200)
alert(rs.msg);
else
location.href='/shopCar/queryShopCar';
},'json');
}
点击结算
现在购物车结算前端已经完成了
购物车结算后端功能实现
运行mybatisplus的代码生成类
CodeGenerator
package com.cdl.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("cdl");
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.cdl.spbootpro");
//设置包名
pc.setEntity("model");
mpg.setPackageInfo(pc);
// 自定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};
// 如果模板引擎是 freemarker
String templatePath = "/templates/mybatis-generator/mapper2.xml.ftl";
// 如果模板引擎是 velocity
// String templatePath = "/templates/mapper.xml.vm";
// 自定义输出配置
List<FileOutConfig> focList = new ArrayList<>();
// 自定义配置会被优先输出
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
+ "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});
/*
cfg.setFileCreate(new IFileCreate() {
@Override
public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {
// 判断自定义文件夹是否需要创建
checkDir("调用默认方法创建的目录,自定义目录用");
if (fileType == FileType.MAPPER) {
// 已经生成 mapper 文件判断存在,不想重新生成返回 false
return !new File(filePath).exists();
}
// 允许生成模板文件
return true;
}
});
*/
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
// 配置模板
TemplateConfig templateConfig = new TemplateConfig();
// 配置自定义输出模板
//指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
templateConfig.setMapper("templates/mybatis-generator/mapper2.java");
templateConfig.setEntity("templates/mybatis-generator/entity2.java");
templateConfig.setService("templates/mybatis-generator/service2.java");
templateConfig.setServiceImpl("templates/mybatis-generator/serviceImpl2.java");
templateConfig.setController("templates/mybatis-generator/controller2.java");
templateConfig.setXml(null);
mpg.setTemplate(templateConfig);
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
//strategy.setSuperEntityClass("你自己的父类实体,没有就不用设置!");
strategy.setEntityLombokModel(true);
strategy.setRestControllerStyle(true);
strategy.setEntitySerialVersionUID(false);
// 公共父类
//strategy.setSuperControllerClass("你自己的父类控制器,没有就不用设置!");
// 写于父类中的公共字段
strategy.setSuperEntityColumns("id");
strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
strategy.setControllerMappingHyphenStyle(true);
strategy.setTablePrefix("t_");
mpg.setStrategy(strategy);
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
mpg.execute();
}
}
注意实体类有关时间的类型改为Date
点击结算到订单页所需的相关的后台代码
OrderController
package com.cdl.spbootpro.controller;
import com.cdl.spbootpro.model.User;
import com.cdl.spbootpro.model.vo.ShopCar;
import com.cdl.spbootpro.model.vo.ShopCarItem;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* <p>
* 订单信息表 前端控制器
* </p>
*
* @author cdl
* @since 2022-11-08
*/
@Controller
@RequestMapping("/order")
public class OrderController {
/**
* 从session中获取购物车对象
* @param user
* @param req
* @return
*/
private ShopCar getShopCar(User user,HttpServletRequest req){
//获取session
HttpSession session = req.getSession();
//从session中获取购物车对象
ShopCar shopCar= (ShopCar) session.getAttribute(user.getId()+"_shopCar");
//判断shopCar是否为空
if(null==shopCar){
//初始化购物车对象_
shopCar=new ShopCar();
//将初始化完成的购物车对象根据用户Id保存到session中
session.setAttribute(user.getId()+"_shopCar",shopCar);
}
return shopCar;
}
/**
* 由于用户结算商品时,不一定是将购物车中所有商品进行结算,有可能只有部分商品
* 必须根据前端页面用户勾选的商品ID从购物车中找到对应需要结算的商品并存入List<ShopCarItem>
* @param shopCar
* @param gids
* @return
*/
private List<ShopCarItem> getShopCarItems(ShopCar shopCar,String gids){
//根据逗号分割商品gids
List<String> ids= Arrays.asList(gids.split(","));
//定义结算商品集合
List<ShopCarItem> items=new ArrayList<>();
//循环遍历购物车中的商品并与勾选结算的商品ID进行比较
//shopCar.getItems():代表购物车中已有的商品集合
//ids:勾选结算的商品ID集合
for (ShopCarItem item : shopCar.getItems()) {
//判断购物车中的商品与勾选结算的商品ID是否一致
if(ids.contains(item.getGid()+"")){
items.add(item);
}
}
return items;
}
/**
* 根据勾选结算的商品跳转到订单页面
* @param user
* @param req
* @param gids
* @return
*/
@RequestMapping("/toOrder")
public ModelAndView toOrder(User user,
HttpServletRequest req,
String gids){
//根据用户ID获取session中对应的购物车 然后拿到购物车中的所有商品
ShopCar shopCar = getShopCar(user, req);
//从购物车中获取勾选结算的商品集合
List<ShopCarItem> shopCarItems = this.getShopCarItems(shopCar, gids);
ModelAndView mv=new ModelAndView();
mv.addObject("goods",shopCarItems);
mv.setViewName("order.html");
return mv;
}
}
order.html
<!DOCTYPE html>
<html>
<head lang="en">
<#include "common/head.html">
<link rel="stylesheet" type="text/css" href="css/public.css"/>
<link rel="stylesheet" type="text/css" href="css/proList.css" />
<link rel="stylesheet" type="text/css" href="css/mygxin.css" />
</head>
<body>
<!----------------------------------------order------------------>
<div class="head ding">
<div class="wrapper clearfix">
<div class="clearfix" id="top">
<h1 class="fl"><a href="${ctx}/"><img src="img/logo.png"/></a></h1>
<div class="fr clearfix" id="top1">
<form action="#" method="get" class="fl">
<input type="text" placeholder="搜索" />
<input type="button" />
</form>
</div>
</div>
</div>
</div>
<!-----------------site------------------->
<div class="order cart mt">
<div class="site">
<p class="wrapper clearfix">
<span class="fl">订单确认</span>
<img class="top" src="img/temp/cartTop02.png">
</p>
</div>
<!-----------------orderCon------------------->
<div class="orderCon wrapper clearfix">
<div class="orderL fl">
<!--------h3---------------->
<h3>收件信息<a href="#" class="fr">新增地址</a></h3>
<!--------addres---------------->
<div class="addres clearfix">
<div class="addre fl on">
<div class="tit clearfix">
<p class="fl">张三1
<span class="default">[默认地址]</span>
</p>
<p class="fr">
<a href="#">删除</a>
<span>|</span>
<a href="#" class="edit">编辑</a>
</p>
</div>
<div class="addCon">
<p>河北省 唐山市 路北区 大学生公寓村</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>河北省 唐山市 路北区 大学生公寓村</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>河北省 唐山市 路北区 大学生公寓村</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 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.smalltotal())!}</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/others/order.js" type="text/javascript" charset="utf-8"></script>
<script src="js/public.js" type="text/javascript" charset="utf-8"></script>
<script src="js/pro.js" type="text/javascript" charset="utf-8"></script>
<script src="js/user.js" type="text/javascript" charset="utf-8"></script>
</body>
</html>
点击结算
生成订单
实现的思路
1.前台订单相关数据获取
2.后台进行下单操作
在Order.html添加Order.js代码
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>河北省 唐山市 路北区 大学生公寓村</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>河北省 唐山市 路北区 大学生公寓村</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>河北省 唐山市 路北区 大学生公寓村</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 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.smalltotal())!}</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/order/order.js" type="text/javascript" charset="utf-8"></script>
<script src="js/public.js" type="text/javascript" charset="utf-8"></script>
<script src="js/pro.js" type="text/javascript" charset="utf-8"></script>
<script src="js/user.js" type="text/javascript" charset="utf-8"></script>
</body>
</html>
order.js
$(function(){
$('.pay').click(function(){
//获取收货地址、联系人、联系电话
//let name = $(".fl.on").find("div:eq(0) p:eq(0)").html();
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');
});
});
后台进行下单
OrderController
package com.cdl.spbootpro.controller;
import com.cdl.spbootpro.model.User;
import com.cdl.spbootpro.model.dto.OrderDto;
import com.cdl.spbootpro.model.vo.ShopCar;
import com.cdl.spbootpro.model.vo.ShopCarItem;
import com.cdl.spbootpro.service.IOrderService;
import com.cdl.spbootpro.utils.JsonResponseBody;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* <p>
* 订单信息表 前端控制器
* </p>
*
* @author cdl
* @since 2022-11-08
*/
@Controller
@RequestMapping("/order")
public class OrderController {
/**
* 从session中获取购物车对象
* @param user
* @param req
* @return
*/
private ShopCar getShopCar(User user,HttpServletRequest req){
//获取session
HttpSession session = req.getSession();
//从session中获取购物车对象
ShopCar shopCar= (ShopCar) session.getAttribute(user.getId()+"_shopCar");
//判断shopCar是否为空
if(null==shopCar){
//初始化购物车对象_
shopCar=new ShopCar();
//将初始化完成的购物车对象根据用户Id保存到session中
session.setAttribute(user.getId()+"_shopCar",shopCar);
}
return shopCar;
}
/**
* 由于用户结算商品时,不一定是将购物车中所有商品进行结算,有可能只有部分商品
* 必须根据前端页面用户勾选的商品ID从购物车中找到对应需要结算的商品并存入List<ShopCarItem>
* @param shopCar
* @param gids
* @return
*/
private List<ShopCarItem> getShopCarItems(ShopCar shopCar,String gids){
//根据逗号分割商品gids
List<String> ids= Arrays.asList(gids.split(","));
//定义结算商品集合
List<ShopCarItem> items=new ArrayList<>();
//循环遍历购物车中的商品并与勾选结算的商品ID进行比较
//shopCar.getItems():代表购物车中已有的商品集合
//ids:勾选结算的商品ID集合
for (ShopCarItem item : shopCar.getItems()) {
//判断购物车中的商品与勾选结算的商品ID是否一致
if(ids.contains(item.getGid()+"")){
items.add(item);
}
}
return items;
}
/**
* 根据勾选结算的商品跳转到订单页面
* @param user
* @param req
* @param gids
* @return
*/
@RequestMapping("/toOrder")
public ModelAndView toOrder(User user,
HttpServletRequest req,
String gids){
//根据用户ID获取session中对应的购物车 然后拿到购物车中的所有商品
ShopCar shopCar = getShopCar(user, req);
//从购物车中获取勾选结算的商品集合
List<ShopCarItem> shopCarItems = this.getShopCarItems(shopCar, gids);
ModelAndView mv=new ModelAndView();
mv.addObject("goods",shopCarItems);
mv.setViewName("order.html");
return mv;
}
@Autowired
private IOrderService orderService;
@RequestMapping("/addOrder")
@ResponseBody
public JsonResponseBody addOrder(User user,
HttpServletRequest req,
OrderDto orderDto){
//获取购物车
ShopCar shopCar = this.getShopCar(user,req);
//获取结算商品集合
List<ShopCarItem> shopCarItems = this.getShopCarItems(shopCar, orderDto.getGids());
//生成订单及订单项
orderDto.setUserId(user.getId());
orderService.addOrder(orderDto,shopCarItems);
//从购物车中删除已结算的商品
shopCar.delete(orderDto.getGids());
//跳转支付页面(下节课内容)
return new JsonResponseBody();
}
}
OrderServiceImpl
package com.cdl.spbootpro.service.impl;
import com.cdl.spbootpro.model.Order;
import com.cdl.spbootpro.mapper.OrderMapper;
import com.cdl.spbootpro.model.OrderItem;
import com.cdl.spbootpro.model.vo.ShopCarItem;
import com.cdl.spbootpro.service.IOrderItemService;
import com.cdl.spbootpro.service.IOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cdl.spbootpro.utils.SnowFlake;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.jaxb.SpringDataJaxb.OrderDto;
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 cdl
* @since 2022-11-08
*/
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private IOrderItemService orderItemService;
@Transactional
@Override
public void addOrder(com.cdl.spbootpro.model.dto.OrderDto orderDto, List<ShopCarItem> shopCarItems) {
//1) 生成订单ID SnowFlake 生成雪花id作用是生成一个随机的long类型的数字
// 相比较于uuid的优点在于,雪花id可以排序
SnowFlake snowFlake = new SnowFlake(2, 3);
Long orderId=snowFlake.nextId();
orderDto.setOid(orderId);
//2) 循环勾选的商品集合计算商品总价、获取商品详情集合
//总价
BigDecimal total=BigDecimal.valueOf(0);
//定义商品详情集合
List<OrderItem> orderItems=new ArrayList<>();
OrderItem it=null;
for (ShopCarItem shopCarItem : shopCarItems) {
//累加小计等于总价
total=total.add(shopCarItem.smalltotal());
//初始化OrderItem商品详情对象
it=new OrderItem();
// 订单项表的ooid非自增,所以不需要设置
Long ooid = snowFlake.nextId();
it.setOid(orderId);
it.setOoid(ooid);
it.setGid(shopCarItem.getGid());
it.setGoodsName(shopCarItem.getGoodsName());
it.setGoodsPrice(shopCarItem.getGoodsPrice());
it.setQuantity(shopCarItem.getQuantity());
orderItems.add(it);
}
orderDto.setTotal(total);
//1.保存订单
orderMapper.insert(orderDto);
//2.保存订单对应的订单项
orderItemService.saveBatch(orderItems);
}
}
注意要使用到vo类
OrderDto
package com.cdl.spbootpro.model.dto;
import com.cdl.spbootpro.model.Order;
import lombok.Data;
/**
* @author cdl
* @site www.cdl.com
* @create 2022-11-08 16:01
*/
@Data
public class OrderDto extends Order {
private String gids;
}
雪花id的工具类
SnowFlake
package com.cdl.spbootpro.utils;
public class SnowFlake {
/**
* 起始的时间戳
*/
private final static long START_STMP = 1480166465631L;
/**
* 每一部分占用的位数
*/
private final static long SEQUENCE_BIT = 12; //序列号占用的位数
private final static long MACHINE_BIT = 5; //机器标识占用的位数
private final static long DATACENTER_BIT = 5;//数据中心占用的位数
/**
* 每一部分的最大值
*/
private final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT);
private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);
private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);
/**
* 每一部分向左的位移
*/
private final static long MACHINE_LEFT = SEQUENCE_BIT;
private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT;
private long datacenterId; //数据中心
private long machineId; //机器标识
private long sequence = 0L; //序列号
private long lastStmp = -1L;//上一次时间戳
public SnowFlake(long datacenterId, long machineId) {
if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) {
throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0");
}
if (machineId > MAX_MACHINE_NUM || machineId < 0) {
throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0");
}
this.datacenterId = datacenterId;
this.machineId = machineId;
}
/**
* 产生下一个ID
*
* @return
*/
public synchronized long nextId() {
long currStmp = getNewstmp();
if (currStmp < lastStmp) {
throw new RuntimeException("Clock moved backwards. Refusing to generate id");
}
if (currStmp == lastStmp) {
//相同毫秒内,序列号自增
sequence = (sequence + 1) & MAX_SEQUENCE;
//同一毫秒的序列数已经达到最大
if (sequence == 0L) {
currStmp = getNextMill();
}
} else {
//不同毫秒内,序列号置为0
sequence = 0L;
}
lastStmp = currStmp;
return (currStmp - START_STMP) << TIMESTMP_LEFT //时间戳部分
| datacenterId << DATACENTER_LEFT //数据中心部分
| machineId << MACHINE_LEFT //机器标识部分
| sequence; //序列号部分
}
private long getNextMill() {
long mill = getNewstmp();
while (mill <= lastStmp) {
mill = getNewstmp();
}
return mill;
}
private long getNewstmp() {
return System.currentTimeMillis();
}
public static void main(String[] args) {
SnowFlake snowFlake = new SnowFlake(2, 3);
long start = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
System.out.println(snowFlake.nextId());
}
System.out.println(System.currentTimeMillis() - start);
}
}
二、沙箱支付
配置沙箱支付
第一步:
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.支付成功后变更订单状态
完成支付宝沙箱支付功能接入
根据官方网站开发文档进行支付宝支付接入
在项目放置配置类的包下接入
AlipayConfig
package com.cdl.spbootpro.config;
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.Config;
import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
import com.cdl.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="2016093000634935";
//支付宝公钥
config.alipayPublicKey="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy/NfwxWr2SfktLUekBR+3w/MUjz1mnW7/wzTOkN1WWIx4i4Ak2m7XDl+evV76FPCcj40HfqgLXxxSVW5a1cCwJ8Z9EgEd7dd1J0EW6slx0v1XMHoPQgOkEVijSWZLLjVhw9x88IWtPTr93YGHYWgR7T9S0M58ABrXPO5eoRxjDdkPCdzyDSmeVixzXZcrhCBHsUMJqipEr8NQA6Iz8QYRYBvQxtkv8j7NZcu+tFfWZ0EPswbsYp/ie+LFjFxTKsov27aduM466Q9ECOYRhCJvB0IbTyY/KYc/VT8TvZIyBA3JP1w2KYoUnKgc5sAGt7ifVXjH3jc8rrC4rWeUIGVFQIDAQAB";
//签名方式
config.signType="RSA2";
//商户私钥(应用私钥),您的PKCS8格式RSA2私钥
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";
return config;
}
}
注意:公钥和私钥以及appid是自己的
自定义密钥
将密钥工具的公钥配进去会得到一个支付宝公钥放入Java代码
将密钥工具的私钥放入Java代码中的私钥
以及开发平台的appid也要填入
支付会引发页面跳转,所以要将ajax请求换成页面跳转的方式
order.js
$(function(){
$('.pay').click(function(){
//获取收货地址、联系人、联系电话
//let name = $(".fl.on").find("div:eq(0) p:eq(0)").html();
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 '';
}
}
OrderController
package com.cdl.spbootpro.controller;
import com.cdl.spbootpro.config.AlipayConfig;
import com.cdl.spbootpro.model.User;
import com.cdl.spbootpro.model.dto.OrderDto;
import com.cdl.spbootpro.model.vo.ShopCar;
import com.cdl.spbootpro.model.vo.ShopCarItem;
import com.cdl.spbootpro.service.IOrderService;
import com.cdl.spbootpro.utils.JsonResponseBody;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* <p>
* 订单信息表 前端控制器
* </p>
*
* @author cdl
* @since 2022-11-08
*/
@Controller
@RequestMapping("/order")
public class OrderController {
/**
* 从session中获取购物车对象
* @param user
* @param req
* @return
*/
private ShopCar getShopCar(User user,HttpServletRequest req){
//获取session
HttpSession session = req.getSession();
//从session中获取购物车对象
ShopCar shopCar= (ShopCar) session.getAttribute(user.getId()+"_shopCar");
//判断shopCar是否为空
if(null==shopCar){
//初始化购物车对象_
shopCar=new ShopCar();
//将初始化完成的购物车对象根据用户Id保存到session中
session.setAttribute(user.getId()+"_shopCar",shopCar);
}
return shopCar;
}
/**
* 由于用户结算商品时,不一定是将购物车中所有商品进行结算,有可能只有部分商品
* 必须根据前端页面用户勾选的商品ID从购物车中找到对应需要结算的商品并存入List<ShopCarItem>
* @param shopCar
* @param gids
* @return
*/
private List<ShopCarItem> getShopCarItems(ShopCar shopCar,String gids){
//根据逗号分割商品gids
List<String> ids= Arrays.asList(gids.split(","));
//定义结算商品集合
List<ShopCarItem> items=new ArrayList<>();
//循环遍历购物车中的商品并与勾选结算的商品ID进行比较
//shopCar.getItems():代表购物车中已有的商品集合
//ids:勾选结算的商品ID集合
for (ShopCarItem item : shopCar.getItems()) {
//判断购物车中的商品与勾选结算的商品ID是否一致
if(ids.contains(item.getGid()+"")){
items.add(item);
}
}
return items;
}
/**
* 根据勾选结算的商品跳转到订单页面
* @param user
* @param req
* @param gids
* @return
*/
@RequestMapping("/toOrder")
public ModelAndView toOrder(User user,
HttpServletRequest req,
String gids){
//根据用户ID获取session中对应的购物车 然后拿到购物车中的所有商品
ShopCar shopCar = getShopCar(user, req);
//从购物车中获取勾选结算的商品集合
List<ShopCarItem> shopCarItems = this.getShopCarItems(shopCar, gids);
ModelAndView mv=new ModelAndView();
mv.addObject("goods",shopCarItems);
mv.setViewName("order.html");
return mv;
}
@Autowired
private IOrderService orderService;
// @RequestMapping("/addOrder")
// @ResponseBody
// public JsonResponseBody addOrder(User user,
// HttpServletRequest req,
// OrderDto orderDto){
// //获取购物车
// ShopCar shopCar = this.getShopCar(user,req);
// //获取结算商品集合
// List<ShopCarItem> shopCarItems = this.getShopCarItems(shopCar, orderDto.getGids());
// //生成订单及订单项
// orderDto.setUserId(user.getId());
// orderService.addOrder(orderDto,shopCarItems);
// //从购物车中删除已结算的商品
// shopCar.delete(orderDto.getGids());
// //跳转支付页面(下节课内容)
// return new JsonResponseBody();
@RequestMapping("/addOrder")
@ResponseBody
public String addOrder(User user,
HttpServletRequest req,
OrderDto orderDto){
//获取购物车
ShopCar shopCar = this.getShopCar(user, req);
//获取结算商品集合
List<ShopCarItem> shopCarItems = this.getShopCarItems(shopCar, orderDto.getGids());
//生成订单及订单项
orderDto.setUserId(user.getId());
orderService.addOrder(orderDto,shopCarItems);
//从购物车中删除已结算的商品
shopCar.delete(orderDto.getGids());
//跳转支付页面
AlipayConfig alipayConfig = new AlipayConfig();
return alipayConfig.goAlipay(orderDto);
}
}
支付成功后变更订单状态
OrderController.java代码新增
OrderController
package com.cdl.spbootpro.controller;
import com.alipay.easysdk.factory.Factory;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.cdl.spbootpro.config.AlipayConfig;
import com.cdl.spbootpro.model.Order;
import com.cdl.spbootpro.model.User;
import com.cdl.spbootpro.model.dto.OrderDto;
import com.cdl.spbootpro.model.vo.ShopCar;
import com.cdl.spbootpro.model.vo.ShopCarItem;
import com.cdl.spbootpro.service.IOrderService;
import com.cdl.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.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
/**
* <p>
* 订单信息表 前端控制器
* </p>
*
* @author cdl
* @since 2022-11-08
*/
@Controller
@RequestMapping("/order")
public class OrderController {
/**
* 从session中获取购物车对象
* @param user
* @param req
* @return
*/
private ShopCar getShopCar(User user,HttpServletRequest req){
//获取session
HttpSession session = req.getSession();
//从session中获取购物车对象
ShopCar shopCar= (ShopCar) session.getAttribute(user.getId()+"_shopCar");
//判断shopCar是否为空
if(null==shopCar){
//初始化购物车对象_
shopCar=new ShopCar();
//将初始化完成的购物车对象根据用户Id保存到session中
session.setAttribute(user.getId()+"_shopCar",shopCar);
}
return shopCar;
}
/**
* 由于用户结算商品时,不一定是将购物车中所有商品进行结算,有可能只有部分商品
* 必须根据前端页面用户勾选的商品ID从购物车中找到对应需要结算的商品并存入List<ShopCarItem>
* @param shopCar
* @param gids
* @return
*/
private List<ShopCarItem> getShopCarItems(ShopCar shopCar,String gids){
//根据逗号分割商品gids
List<String> ids= Arrays.asList(gids.split(","));
//定义结算商品集合
List<ShopCarItem> items=new ArrayList<>();
//循环遍历购物车中的商品并与勾选结算的商品ID进行比较
//shopCar.getItems():代表购物车中已有的商品集合
//ids:勾选结算的商品ID集合
for (ShopCarItem item : shopCar.getItems()) {
//判断购物车中的商品与勾选结算的商品ID是否一致
if(ids.contains(item.getGid()+"")){
items.add(item);
}
}
return items;
}
/**
* 根据勾选结算的商品跳转到订单页面
* @param user
* @param req
* @param gids
* @return
*/
@RequestMapping("/toOrder")
public ModelAndView toOrder(User user,
HttpServletRequest req,
String gids){
//根据用户ID获取session中对应的购物车 然后拿到购物车中的所有商品
ShopCar shopCar = getShopCar(user, req);
//从购物车中获取勾选结算的商品集合
List<ShopCarItem> shopCarItems = this.getShopCarItems(shopCar, gids);
ModelAndView mv=new ModelAndView();
mv.addObject("goods",shopCarItems);
mv.setViewName("order.html");
return mv;
}
@Autowired
private IOrderService orderService;
// @RequestMapping("/addOrder")
// @ResponseBody
// public JsonResponseBody addOrder(User user,
// HttpServletRequest req,
// OrderDto orderDto){
// //获取购物车
// ShopCar shopCar = this.getShopCar(user,req);
// //获取结算商品集合
// List<ShopCarItem> shopCarItems = this.getShopCarItems(shopCar, orderDto.getGids());
// //生成订单及订单项
// orderDto.setUserId(user.getId());
// orderService.addOrder(orderDto,shopCarItems);
// //从购物车中删除已结算的商品
// shopCar.delete(orderDto.getGids());
// //跳转支付页面(下节课内容)
// return new JsonResponseBody();
@RequestMapping("/addOrder")
@ResponseBody
public String addOrder(User user,
HttpServletRequest req,
OrderDto orderDto){
//获取购物车
ShopCar shopCar = this.getShopCar(user, req);
//获取结算商品集合
List<ShopCarItem> shopCarItems = this.getShopCarItems(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.cdl.spbootpro.config;
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.Config;
import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
import com.cdl.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 = "2021000121687732";
//支付宝公钥
config.alipayPublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA06msMro+UNVoM4R76HzBRdOS4ACKR6PWEBBy6ObMnOerxz2sXI7NIXlI6IaxNN9lfZUShHIh6kwxFrXSyEIhGdTR3vDy2qI4yIbBKymcnHCX5x5KwuuM7OCMjmpI2iY6nLa3zqtnZNWDYQttI0/ff302CnUcXuHrm6PfSWgWJl31F19YHSbfnFIrYSOupaSszvQDR3eqcU54D6I8X86ALbBocYoP9euFvdMdDv2rUxEFNftUjck+Y7hOEovXca5xWUW0N3C0eizr2hR1srFk2xs6U8C0Qql+OzwTBlfzSLoSSyM99uxUEYS3FM7+xYM9veevwIDAQAB";
//签名方式
config.signType = "RSA2";
//商户私钥(应用私钥),您的PKCS8格式RSA2私钥
config.merchantPrivateKey = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDLbR5Td9oz9AAeOiESJuyMinuJogaDQyZd7GgaNwMsJP3DfyTR8lYX/tezKtjrFoJ3Ul82S/IY955xy9ITdsQ/oC4sRd1t0UPb4MWjZQyF0azy6uIv0Q8wd7JO2rD91ANGpJL41vC9VMZlIj0LZVNIJJVLmzG9RdqvmO3b8faDCJ7tsx04hTew2H8XOrukowFSUzOatIRjB9m23J6elZp4ZbOfr88jn4nxU/jclJnljJnEUaNlKryHvv7s8JuiUSZsK/IJYMQQ462UWSACT2uQrC3ET+owCECRFZrXVHz0UEw63UEH7NRVBjeldMVtudDgXnDvYnEZupxf2KVbvnuNAgMBAAECggEBALnODSkIC9HwSDtTtOkzjFRCGNx5laFHMEARsnRfUxJ7Jx3tf+ATjPeV2cbYmBECGmCKaFTbwWF0qtAd7t/AVzgWQpZFqh6oSWcIQv0fSvTfsyydxcMPHOSUL9U+gvMVN3jK0UNgb7s/N4cgYsmJ3yvB3muUcTYEG97PvFJtC1BaaK63r4ZLu6aWBaDpbYcJySRidVDIQYF9kOJQvW53LvmlnDD5tBJ5iI3UKuErnoKflIW/sd1QJZC/JXZXjRBzqa3M4lK9ZHQG8DLHVH5rmXDRfHfLoV5RXv51XwBFCFOrWhSwcvyUQXP/mgAPJaRjvS8fVHeOyf/41QA1ir+/1WIobQJrF0330QXBx19xJztSgLdpW7659QX1cgpIBGwXMnxWdOxCWPcgBxreAE8PK+2f9WoGfHTDBuEhb/fjkqjRakDEnT0+R8bim5XbkksCzy4uRSYq2u65WH6x2N7XDY9/buqNvhFjiqzv09ChD9CSNYz0usCgYEAz5FIA7D3bEXhhWgG7CS+JPs3K/P0bqwY6YgGoXi3REm8RFE0fqsJFu0vNqRkZu0jVGmb0UVZ96Clhug8thnO0/xYqHvhYPxFz37Yba4p4QBMYvtI1Bt0T1BLAsrq1Eau5XUo7aYEZbD+qQF0CA1wOsPCuMJgTjOg1ntrumoAHWcCgYBNKY7rqgwV0ktyxB+te+2tsU3JwOtEKPHRUmI4bQE2LBfGzRg3i8P6NPaE0ycDdXPxa2EZlaQH2HlqQLBkSJXWxOUfyCbN6+EZpiLo/b4QIyBkrgiOXrlNFfwRyK8XXRpHPm7QtX2nbRU3mwcdzmXfWiQqQT/fCsVuXvZH6Hkv2QKBgQDBgvV7k4GobKHrCOfjQgIPYjG2hXKttz5mgg2EfpGFVaTyoC5rpTMNL8UjkTGVj6GvceH1wU02AowvcNYhA4CCu7FAKnYdQDQpVV2bK5MZlHiikxj7vji6NOYpzVoO23L0szycCnnxAIj6sUMmuriV4KnqLDUy0wkwzNHLckV3IwKBgFdAIWdU/GivqhEwjOwTOgrUnT+PvDHRUYBm1kGlPCVcNrI2olkQ34Mt55mzFON1bAUhCiHjzcjYDovXxhmSNi2EasleNFAxzRpPQUaa36OZwR4Chiz0bvP1mFVZgs7XeFO+TJJlJabEHrhNkP3edPkMBla5EKvUvA9wZ3lccH2i";
return config;
}
}
点击去支付之后
用手机app(沙箱支付宝)扫码
输入支付密码
支付成功
自动跳转到图下
再跳
点击订单详情
账户金额发生改变