JavaWeb-仿小米商场(8) 订单支付[沙箱支付]
时间:2022-10-20 20:00:00
JavaWeb-模仿小米商场(8) 订单支付[沙箱支付]
1 功能描述
接上篇 JavaWeb - 仿小米商城(7)
点击支付宝支付按钮完成相应的支付操作 沙箱支付的逻辑可以通过使用支付宝沙箱支付来模拟用户支付
参考博客:https://blog.csdn.net/hhb442/article/details/123304287
支付提示界面:点击提交页面时,将订单数据存储在数据表中
付款成功可以通过我的订单查看订单
2 提交订单功能分析
2.1 抽象的功能逻辑
当商品购物车点击生成订单时,首先判断用户是否登录。如果用户没有登录,用户需要先完成登录 ,然后从购物车获取用户对象session根据购物车数据创建订单对象和订单细节列表list集合
商品购物车是面向数据库中的 tb_order表和订单细节表tb_orderDetail,将数据添加到数据库中对应的表中,
建立相应的购物车 CartServlet 类、CartService 接口和实现类,CartDao 接口和实现类。
建立相应的订单 OrderServlet 类、OrderService 接口和实现类、OrderDao 接口和实现类。
订单细节对应 OrderDetailServlet 类、OrderDetailService 接口和实现类,OrderDetailDao 接口和实现类。
提示:好需要创建辅助设备vo类
显示订单列表需要一个vo类别包括订单信息、地址信息和用户信息
OrderView : oid uid orderTime userName telphon address totalMoney ostate
GoodOrdersDetailVo: pid pimg pname star pubdate, price num money
3.1 实现沙箱支付
3.1.1 修改支付宝按钮链接
3.1.2沙箱支付PayServlet代码:
@WebServlet("/pay.do") public class PayServlet extends BaseServlet {
//appid private final String APP_ID = "2021000119697423"; //使用私钥 private final String APP_PRIVATE_KEY = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDnSxnNeuFy7ChdPC04Ak3QfqIqyd27nAewaFc6D9dism9wfYlxKovTLQBjaqO AAwjvo/24 VvpD6Ku5Oj zG9FG0J6veR7AAMKcuaPimDWO8Yv7y1P12MBCH3cxNhikdgE5JVCVDtU/av AKVdOs4hFmyOS0httTjaoBIhKTlESLFs6d3sOeCY2bIXiV0l FRVoJHs5OkXkjALnm 1mdRycZtz8Igjf80hhfVbdnOuhbnEVUN7VoTkd43KLuirDjEx/G8CbolW1yGYhCUJs7nYxzpVlUvIeCwRS6JRFQ7N8OWR7wzsAtdVoElc05Mt1IMECTm4WFzAi x8VLwX42XAgMBAAECggEAKEAkjGK/Cy3X1GndgKq9 fOfqwyYPsbne6acz2jkVbOxuwTNv1jlHmntcF lgTIm6q2GBjQgwG33yFLeXaIgRMRiOWCfltBYLcW0PfJlbQs0CL2NTIlrcSti8dof3FChHTIqvAuz/qkm /aQFIxVRu ZYG c0AouQClPi88xlv8wtd9E5ZHk9iWwc2KEfiROk pOSkaCQxK3TV14qP/WJfMHQmySB8hHeQZ67TdOuJpdbskIDi/g0UrrzPX7DjJMdv GIggMBOQ3Jf6w/w25TYRxOuXnnYEVBJJMt5NVpE84OCr 6rHzGNp4N cubY7fSLGLN5QwCrjeRoEQlTnyIQKBgQD33XH2dHXgBF/vEboYXHzFE2fHU 5sxXHqrI5dYC7foPDcFxqC7cz4 D/MXxwATqdKyOwjbKK4i6xAaGrTBBYjW2Nu1BfBi3zLUZUF GUzLYLOhPKrGyybmO3DGHgIxlQGgCR60oKGbNxxX1MPoh4H5ogn9FQqz ANDrGeFRqccQKBgQDu4mvIj/k6LM JMouK5A60LQh4uPzfubU1YTR1M50clPcOWteI2 y d8IhzwWw1GE5UMvQ K0rjJ3Uwj6AzSeFUn9mKY07Ihz3jn/7xvMBLYw0o3uaYPpl 5c6YDWEoqNlSlIN09Bk73Q5Vgrp00PF1d H16bgyD00oZpGe0buhwKBgBHY S7E3gP bKX7QcolRrquFgftTDq60OQT/sBMf7OMlCtU4ozQ8LRws69UneCLyVICO7alSOY 8G1G14JQRgPPvc4qKXe/QoIlYrSmWSshOM0EF7EoaMLfdSdaKLKBDWXWbkoFxG5HgmwLcCCtDLqG6ADwf sBQuHN0A5Q LSRAoGBALG5dqMSqkNjz0utdS/yGBZoYqMeTdRNH8oE9bg0nDEFiwD9CNnjdTEHfEEW o7ikyrHN7vTJ1L9HPeLRGEjQMHp7KqfQ1m5OX/cXs985pH7xxHqhy0F9YUmNw7RQT/amGHld0KeUa6mj/uQTjJEYWmwgstX3 ngT9j2WgcR9GXFAoGBAIgjeJQjPbqql3grItUxM 3zPsYywR2U7HDxb/WbWDfgC FIzTUOVFg4kZmMDvkCvZVrGccY9c8ItN64JC9n5zvUpGFRihAuHOGl5VuzUfhtXsMhAyKdf6NXTdurk35ioX91oJlWN4AdxjGyOxzKr0oSTjs6km3qLjWuKb4tSae4"; private final String CHARSET = "UTF-8"; // 支付宝公钥 private final String ALIPAY_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCA8AMIIBCgKCAQEAs4aFo85tjgc0Sn/OxeHn0GeiAcxrom1MFAVgK7mTj+gXMzXk1NUg97E/a/UfhOGQ5xWxMAbMQGDKuseRycpo8KxUl6vQKFSrsPM+hM0G80YFgpIf4iaWC1qj4AsfOEBxUQBbdIlF1Ibt2dlIddqVe7Qfge+fI4rxixOhnE2yAlSZajwsHqZL6MagPSMYCnD3qZXGEZQOsH2lDqlH1aoijFI4LzqoEnL1QYBOVOKO8SIcud9f2Aw6t8I/fuBKAyDoOS7MAm8ISRxi6Lal6De95A4dvdWBBQgF9GDNH2UE0MWA0hDDDIFtpvrPMcXkN7qvRWBKqReZbSIkorDo0MM+dwIDAQAB"; //这是沙箱接口路径,正式路径为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";
/** * 支付方法 * * @param req * @param resp * @return */
public String alipay(HttpServletRequest req, HttpServletResponse resp) {
String dona_id = req.getParameter("oid");
HttpSession session = req.getSession();
String money = req.getParameter("money");
System.out.println(money);
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, "xiaomi_shop");
} catch (AlipayApiException 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;
}
/** * 支付宝同步通知路径 * * @param request * @param resp * @return * @throws ServletException * @throws IOException */
public String returnUrl(HttpServletRequest request, HttpServletResponse resp) {
//接收到付款成功提示则
System.out.println("接收到付款成功提示");
//修改订单状态为已支付
System.out.println("订单状态已修改");
System.out.println("=================================同步回调=====================================");
try {
// 获取支付宝GET过来反馈信息
Map<String, String> params = new HashMap<String, String>();
Map<String, String[]> requestParams = request.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);//查看参数都有哪些
//验证签名(支付宝公钥)
AlipaySignature.rsaCheckV1(params, ALIPAY_PUBLIC_KEY, CHARSET, SIGN_TYPE); // 调用SDK验证签名
//验证签名通过
// 商户订单号
String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"), "UTF-8");
// 支付宝交易流水号
String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"), "UTF-8");
// 付款金额
float money = Float.parseFloat(new String(request.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 在这里编写自己的业务代码(对数据库的操作)
HttpSession session = request.getSession();
String oid = (String) session.getAttribute("dona_id");
IOrderService orderService = new OrderServiceImpl();
boolean falg = orderService.updateOrderState(oid, OrderStatus.PAY.ordinal());
if (falg){
System.out.println("订单状态修改成功");
}else{
System.out.println("订单状态修改失败");
}
//跳转到提示页面(成功或者失败的提示页面)
///model.addAttribute("flag", 1);
//model.addAttribute("msg", "支持");
//修改订单状态为已支付
System.out.println("订单状态已修改");
return Constants.REDIRECT + "/message.html?msg=success";
} catch (Exception e) {
e.printStackTrace();
return Constants.REDIRECT + "/error.html?msg=fail";
}
}
}
点击支付跳转至支付页面, 通过手机支付宝沙箱app扫码支付
扫码支付成功后会跳转到成功页面
4 用户订单列表
4.1:用户订单列表链接修改
订单列表页面orderList.html页面ajax请求的的js代码 用于在页面加载完成时根据数据库数据渲染页面
<script>
//获取购物车列表
$(document).ready(function () {
//获取session数据显示到页面
$.get("order.do?action=showMyOrder", "", function (result) {
var index = 0;
if (result.flag === true) {
//登录
for (var i in result.data) {
index++;
var money = result.data[i].quantity * result.data[i].price;
var temp =
' ' +
' ' + index + ' ' +
' ' + result.data[i].oid + ' ' +
' ' + result.data[i].totalMoney + ' ' +
' ' +
' ';
var statu = "";
if (result.data[i].ostate == 0) {
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 = "待评价"
}
temp += statu;
temp += ' ' +
' ' +
' ' + result.data[i].orderTime + ' ' +
' ' + result.data[i].address + ' ' +
' ' +
' ';
var str = ' ';
temp += str;
temp +=
' ' +
' ' +
$("#orderBody").append(temp)
$("#utip").text(result.data[i].userName);
}
} else {
var error = "订单空空如也 "
$("#orderBody").append(error)
}
$("#sizetip").text(index);
});
});
</script>
4.2后端
4.2.1后端OrderServlet
在 AddressServlet类中根据购物车信息创建订单数据
@WebServlet("/order.do")
public class OrderServlet extends BaseServlet {
private ResultData resultData = new ResultData();
/** * 显示我的订单信息 * * @param req * @param resp * @return * @throws ServletException * @throws IOException */
public String showMyOrder(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resultData.setData(true);
HttpSession session = req.getSession();
User user = (User) session.getAttribute(Constants.LOGINUSER);
System.err.println(user);
if (user == null) {
resultData.setData(false);
} else {
IOrderService orderService = new OrderServiceImpl();
List<OrderView> olist = orderService.queryAllDataByUId(user.getId());
if (olist != null && !olist.isEmpty()) {
resultData.setFlag(true);
resultData.setData(olist);
}else{
resultData.setFlag(false);
}
}
String json = JSON.toJSONString(resultData);
resp.setContentType("application/json;charset=utf-8");
return json;
}
}
4.2.2 OrdarDaoImpl
订单表的dao层实现
public class OrderDaoImpl implements IOrderDao {
//.........
/** * 通过id查询OrderView视图类得数据查询方法 * @param uid * @return */
@Override
public List<OrderView> 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 telphon,a.detail as address,o.status as ostate ,o.money as totalMoney from tb_user u,tb_order o,tb_address a " +
" where o.uid=? and o.uid=u.id and o.aid=a.id; ";
List<OrderView> query = null;
QueryRunner run = new QueryRunner(DBUtils.getDataSource());
try {
query = run.query(sql, uid, new BeanListHandler<>(OrderView.class));
} catch (SQLException e) {
e.printStackTrace();
}
return query;
//....
}
4.2.3 编写OrderServiceImpl代码
订单创建涉及到多张数据表,必须做事务控制:
public class OrderServiceImpl implements IOrderService {
//......
@Override
public List<OrderView> queryAllDataByUId(int uid) {
return orderDao.queryAllDataByUId(uid);
}
//......
}
e.printStackTrace();
}
return query;
//…
}
#### 4.2.3 编写OrderServiceImpl代码
订单创建涉及到多张数据表,必须做事务控制:
```java
public class OrderServiceImpl implements IOrderService {
//......
@Override
public List queryAllDataByUId(int uid) {
return orderDao.queryAllDataByUId(uid);
}
//......
}