JavaWeb - 小米商城 :订单支付[沙箱支付]
1.功能描述
接上篇 JavaWeb - 小米商城:提交订单 订单创建后进入支付界面,整合支付宝沙箱支付。如 以下H5页面所示:
参考的博客:https://blog.csdn.net/hhb442/article/details/123304287
支付提示界面:
当点击提交订单, 此时将订单数据存储到数据表
支付宝支付:
一般的开发中使用的是沙箱做模拟支付
支付过程提示:
**使用沙箱app扫码支付成功后跳转到支付成功提示界面 **
我的订单列表:
支付成功可以通过点击我的订单查看订单列表
订单详情界面
通过点击订单列表中订单详情按钮打开该
2.沙箱支付功能分析
2.1 在pom文件中添加依赖
<!-- 支付宝沙箱支付的依赖 -->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.16.2.ALL</version>
</dependency>
3.代码实现
3.1前端
3.1.1 修改链接地址
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>订单成功</title>
<link href="css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="css/login2.css">
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/includeHeader.js"></script>
<script>
$(document).ready(function () {//当页面加载完成执行代码
var oid = getParams("oid");
var money = getParams("money");
$("#oidh4").text("订单号:" + oid);
$("#moneyh4").text("订单总金额:" + money);
$("#payalink").attr("href", "pay.do?action=alipay&oid=" + oid + "&omoney=" + money);
$("#Weixinlink").attr("href", "payWeixin.do?action=alipay&oid=" + oid + "&omoney=" + money);
});
</script>
</head>
<body>
<div id="headtop">
</div>
<div class="container">
<hr>
<div class="row" style="width: 30%;margin: 0 auto;padding-top: 20px">
<div class="panel panel-success">
<div class="panel-heading">
<h3 class="panel-title">订单提示</h3>
</div>
<div class="panel-body">
<h3 class="text-default"><span class="glyphicon glyphicon-ok-sign"></span> 订单添加成功!!
</h3>
<hr>
<h4 id="oidh4"></h4>
<h4 id="moneyh4"></h4>
<span class="h3">立即支付</span>
<a id="payalink" class="btn btn-warning">支付宝支付</a>
<a id="Weixinlink" class="btn btn-success">微信支付</a>
</div>
</div>
</div>
</div>
<!--网站版权部分开始-->
//......
</body>
</html>
3.2后端
3.2.1 PayServlet
在 PayServlet类中首先设置如下私有属性
APP_ID (appId,从沙箱管理页面获得) APP_PRIVATE_KEY (应用私钥,最开始在密钥工具生成而 来) ALIPAY_PUBLIC_KEY (支付宝公钥,上一步骤获得) GATEWAY_URL (支付宝网关地址,在开发 平台沙箱管理页面中获得) SIGN_TYPE (签名类型) NOTIFY_URL (异步回调地址,须是公网IP,后 面再解释) RETURN_URL (同步回调地址,可以是私网IP)
@WebServlet("/pay.do")
public class PayServlet extends BaseServlet {
//appid
private final String APP_ID = "2021000119697420";
//应用私钥
private final String APP_PRIVATE_KEY = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQ";
private final String CHARSET = "UTF-8";
// 支付宝公钥
private final String ALIPAY_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6Gamayt9Z";
//这是沙箱接口路径,正式路径为https://openapi.alipay.com/gateway.do
private final String GATEWAY_URL = "https://openapi.alipaydev.com/gateway.do";
private final String FORMAT = "JSON";
//签名方式
private final String SIGN_TYPE = "RSA2";
//支付宝异步通知路径,付款完毕后会异步调用本项目的方法,必须为公网地址
private final String NOTIFY_URL = "http://127.0.0.1/notifyUrl";
//支付宝同步通知路径,也就是当付款完毕后跳转本项目的页面,可以不是公网地址
private final String RETURN_URL = "http://localhost:8080/pay.do?action=returnUrl";
/**
* 支付方法
*/
public String alipay(HttpServletRequest req, HttpServletResponse resp) {
HttpSession session = req.getSession();
String dona_id = req.getParameter("oid");
String money = req.getParameter("omoney");
Float dona_money = Float.parseFloat(money);
//把dona_id项目id 放在session中
session.setAttribute("dona_id", dona_id);
//生成订单号(支付宝的要求?)
String time = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
String user = UUID.randomUUID().toString().replace("-", "").toUpperCase();
String OrderNum = time + user;
//调用封装好的方法(给支付宝接口发送请求)
try {
return sendRequestToAlipay(OrderNum, dona_money, "小米商城");
} catch (Exception e) {
e.printStackTrace();
}
return Constants.REDIRECT + "/error.html";
}
/**
* 参数1:订单号
* 参数2:订单金额
* 参数3:订单名称
*/
//支付宝官方提供的接口
private String sendRequestToAlipay(String outTradeNo, Float totalAmount, String subject) throws AlipayApiException {
//获得初始化的AlipayClient
AlipayClient alipayClient = new DefaultAlipayClient(GATEWAY_URL, APP_ID, APP_PRIVATE_KEY, FORMAT, CHARSET, ALIPAY_PUBLIC_KEY, SIGN_TYPE);
//设置请求参数
AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
alipayRequest.setReturnUrl(RETURN_URL);
alipayRequest.setNotifyUrl(NOTIFY_URL);
//商品描述(可空)
String body = "小米商城模拟支付:" + subject;
alipayRequest.setBizContent("{\"out_trade_no\":\"" + outTradeNo + "\","
+ "\"total_amount\":\"" + totalAmount + "\","
+ "\"subject\":\"" + subject + "\","
+ "\"body\":\"" + body + "\","
+ "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
//请求
String result = alipayClient.pageExecute(alipayRequest).getBody();
return result;
}
/**
* 支付宝的异步通知路径
*/
public String returnUrl(HttpServletRequest req, HttpServletResponse resp) {
//接收到付款成功的提示
System.out.println("接收到付款成功的提示");
//修改订单的状态 为 已支付
System.out.println("=================================同步回调=====================================");
try {
// 获取支付宝GET过来反馈信息
Map<String, String> params = new HashMap<String, String>();
Map<String, String[]> requestParams = req.getParameterMap();
for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
String name = (String) iter.next();
String[] values = (String[]) requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
}
// 乱码解决,这段代码在出现乱码时使用
valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
params.put(name, valueStr);
}
System.out.println(params);//查看参数都有哪些
//验证签名(支付宝公钥)
boolean signVerified = AlipaySignature.rsaCheckV1(params, ALIPAY_PUBLIC_KEY, CHARSET, SIGN_TYPE); // 调用SDK验证签名
//验证签名通过
// 商户订单号
String out_trade_no = new String(req.getParameter("out_trade_no").getBytes("ISO-8859-1"), "UTF-8");
// 支付宝交易流水号
String trade_no = new String(req.getParameter("trade_no").getBytes("ISO-8859-1"), "UTF-8");
// 付款金额
float money = Float.parseFloat(new String(req.getParameter("total_amount").getBytes("ISO-8859-1"), "UTF-8"));
System.out.println("商户订单号=" + out_trade_no);
System.out.println("支付宝交易号=" + trade_no);
System.out.println("付款金额=" + money);
//TODO 在这里编写自己的业务代码(对数据库进行操作)
//在这里编写自己的业务代码(对数据库的操作)
String oid = req.getSession().getAttribute("dona_id").toString();
IOrderService orderService = new OrderServiceImpl();
boolean flag = orderService.updateOrderState(OrderStatus.PAY.ordinal(),oid);
if (flag){
System.out.println("订单状态修改成功");
}else {
System.out.println("订单状态修改失败");
}
System.out.println("修改订单的状态 为 已支付");
return Constants.REDIRECT + "/message.html?msg=支付成功!";
} catch (Exception e) {
e.printStackTrace();
System.out.println("支付失败");
return Constants.REDIRECT + "/error.html?msg=支付失败!";
}
}
}
3.2.2 编写OrderServiceImpl码
public class OrderServiceImpl implements IOrderService {
private IOrderDao orderDao = null;
private ICartDao cartDao = null;
private IOrderDetailDao orderDetailDao = null;
public OrderServiceImpl() {
orderDao = new OrderDaoImpl();
cartDao = new CartDaoImpl();
orderDetailDao = new OrderDetailDaoImpl();
}
//..........
@Override
public boolean updateOrderState(int status,String oid) {
return orderDao.updateOrderState(status,oid);
}
@Override
public List<OrdersView> queryAllDataByUid(int uid) {
return orderDao.queryAllDataByUid(uid);
}
}
3.2.3 编写OrderDaoImpl代码
public class OrderDaoImpl implements IOrderDao {
private QueryRunner queryRunner = null;
public OrderDaoImpl() {
queryRunner = new QueryRunner();
}
//......
@Override
public boolean updateOrderState(int status, String oid) {
String sql = "update tb_order set status=? where id=?";
try {
int n = queryRunner.update(DBUtils.getConn(), sql, status, oid);
return n >= 1 ? true : false;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
//......
}
4. 我的订单列表码实现
4.1 前端
4.1.1 修改orderList.html文件
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>订单列表</title>
<link href="css/bootstrap.min.css" rel="stylesheet">
<script type="text/javascript" src="js/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="css/login2.css">
<link href="css/bootstrap.min.css" rel="stylesheet">
<script type="text/javascript">
function showOrder(orderId) {
location.href = "orderDetail.html?oid=" + orderId;
}
function changeStatus(orderId) {
location.href = "order.do?action=changeStatus&oid=" + orderId;
}
$(document).ready(function () {
//获取购物车的session数据显示到页面
$.get("order.do?action=showMyOrder", "", function (result) {
if (result.flag === true) {
var index = 0;
for (var i in result.data) {
index++;
var odhtml = ' <tr>' +
'<td>' + index + '</td>' +
'<td>' + result.data[i].oid + '</td>' +
'<td>' + result.data[i].totalMoney + '</td>' +
'<td>' +
'<font color="red">';
var statu = "";
if (result.data[i].ostate === 1) {
statu = "未支付";
}
if (result.data[i].ostate === 2) {
statu = "已支付,待发货";
}
if (result.data[i].ostate === 3) {
statu = "已发货,待收货";
}
if (result.data[i].ostate === 4) {
statu = "订单完成";
}
if (result.data[i].ostate === 5) {
statu = "未支付";
}
odhtml += statu + '</font>' +
' </td>' +
' <td>' + result.data[i].orderTime + '</td>' +
' <td>' + result.data[i].address + '</td>' +
'<td>' +
'<button type="button" class="btn btn-danger btn-sm" οnclick="showOrder(\'' + result.data[i].oid + '\')">订单详情</button>';
var qrstr = "";
if (result.data[i].ostate === 3) {
qrstr = '<button type="button" class="btn btn-warning btn-sm" οnclick="changeStatus(\'' + result.data[i].oid + '\')">确认收货</button>';
}
odhtml += qrstr + '</td>' + '</tr>';
$("#orderBody").append(odhtml);
$("#utip").text( result.data[i].userName);
}
}else {
var odhtml = '<tr><td colspan="7">当前用户没有订单数据</td></tr>'
$("#orderBody").append(odhtml);
}
$("#sizetip").append(index);
});
});
</script>
<script type="text/javascript" src="js/includeHeader.js"></script>
</head>
<body style="background-color:#f5f5f5">
<div id="headtop">
</div>
<div class="container" style="background-color: white;">
<div class="row" style="margin-left: 40px">
<h3>我的订单列表
<small >温馨提示: <em id="utip"></em>有<font color="red" id="sizetip"></font>个订单</small></h3>
</div>
<div class="row" style="margin-top: 40px;">
<div class="col-md-12">
<table id="tb_list" class="table table-striped table-hover table-bordered table-condensed">
<thead>
<tr>
<th>序号</th>
<th>订单编号</th>
<th>总金额</th>
<th>订单状态</th>
<th>订单时间</th>
<th>收货地址</th>
<th>操作</th>
</tr>
</thead>
<tbody id="orderBody">
</tbody>
</table>
</div>
</div>
</div>
<!-- 底部 -->
<!--网站版权部分开始-->
//.....
</body>
</html>
4.2 后端
4.2.1 OrderServlet
@WebServlet("/order.do")
public class OrderServlet extends BaseServlet {
private ResultData resultData = new ResultData();
//....
/**
* 显示我的订单信息
*/
public String showMyOrder(HttpServletRequest req, HttpServletResponse resp) {
HttpSession session = req.getSession();
System.out.println(session.getId());
resultData.setFlag(true);
User user = (User) session.getAttribute(Constants.LOGINUSER);
System.err.println(user);
if (user == null) {
resultData.setFlag(false);
} else {
OrderServiceImpl orderService = new OrderServiceImpl();
List<OrdersView> ordersViews = orderService.queryAllDataByUid(user.getId());
if (ordersViews!=null && ordersViews.size()!=0){
resultData.setData(ordersViews);
}else {
resultData.setFlag(false);
}
}
String json = JSON.toJSONString(resultData);
resp.setContentType("application/json;charset=utf-8");
return json;
}
}
4.2.2 OrderServiceImpl
public class OrderServiceImpl implements IOrderService {
private IOrderDao orderDao = null;
private ICartDao cartDao = null;
private IOrderDetailDao orderDetailDao = null;
public OrderServiceImpl() {
orderDao = new OrderDaoImpl();
cartDao = new CartDaoImpl();
orderDetailDao = new OrderDetailDaoImpl();
}
//........
@Override
public List<OrdersView> queryAllDataByUid(int uid) {
return orderDao.queryAllDataByUid(uid);
}
}
4.2.3 OrderDaompl
public class OrderDaoImpl implements IOrderDao {
private QueryRunner queryRunner = null;
public OrderDaoImpl() {
queryRunner = new QueryRunner();
}
//.......
@Override
public List<OrdersView> queryAllDataByUid(int uid) {
String sql = "select o.id as oid,o.uid as uid,u.username as userName,o.time as orderTime," +
" a.phone as telephone,a.detail as address,o.`status` as ostate,o.money as totalMoney " +
" from tb_user u,tb_order o, tb_address a " +
" where u.id=? and u.id=o.uid and o.aid=a.id";
List<OrdersView> ordersViews = null;
QueryRunner qrun = new QueryRunner(DBUtils.getDataSource());
try {
ordersViews = qrun.query(sql, uid, new BeanListHandler<>(OrdersView.class));
} catch (SQLException e) {
e.printStackTrace();
}
return ordersViews;
}
}