Native 下單
1、創(chuàng)建課程訂單保存到數(shù)據(jù)庫
1-1:需求:
之前的下單,只是獲取支付二維碼,但是并沒有將訂單存到數(shù)據(jù)庫
需求1:點擊確認支付后,創(chuàng)建商品的訂單存到數(shù)據(jù)庫
需求2:每次確認支付之前,要判斷這個人是否存在已下單未支付的訂單,有的話就不用再創(chuàng)建訂單了,把他的訂單查詢出來給他就行。
1-2:代碼:
需求1:點擊確認支付后,創(chuàng)建商品的訂單存到數(shù)據(jù)庫
需求2:每次確認支付之前,要判斷這個人是否存在已下單未支付的訂單,有的話就不用再創(chuàng)建訂單了,把他的訂單查詢出來給他就行。
1-3:測試結果:
成功在數(shù)據(jù)庫添加訂單,并且多次點擊確認下單,并不會重復添加訂單到數(shù)據(jù)庫
2、保存支付二維碼的url
2-1:需求:
上面創(chuàng)建訂單的時候,是沒有存二維碼的url到數(shù)據(jù)庫的,這里需要在創(chuàng)建訂單的時候,把url存進去。
Native調(diào)起支付
2-2:代碼:
解釋:
因為獲取支付二維碼url的代碼在創(chuàng)建訂單之后,所以第一次創(chuàng)建訂單是沒有支付二維碼的url的。
所以在往下的代碼中,添加了保存二維碼的代碼。
2-3:測試:
保存二維碼成功,并且在重復訪問的時候,因為存在二維碼,所以不會再去調(diào)用微信的下單接口。
因為二維碼有效期為2小時,所以后面還需要優(yōu)化,如果二維碼過期,需要再次更新數(shù)據(jù)庫中的二維碼。
2-4:完整代碼:
包含創(chuàng)建訂單和保存支付二維碼的代碼
后端:
WxPayController
@CrossOrigin //跨域
@RestController
@RequestMapping("/api/wx-pay")
@Api(tags = "網(wǎng)站微信支付API") //swagger 注解
@Slf4j
public class WxPayController
{
@Resource
private WxPayService wxPayService;
//調(diào)用統(tǒng)一下單API,生成支付二維碼的鏈接和訂單號
//swagger注解
@ApiOperation("調(diào)用統(tǒng)一下單API,生成支付二維碼")
@PostMapping("/native/{productId}")
public R nativePay(@PathVariable Long productId) throws Exception
{
log.info("發(fā)起支付請求");
//返回支付二維碼的鏈接和訂單號
Map<String,Object> map = wxPayService.nativePay(productId);
return R.ok().setData(map);
}
}
WxPayService
public interface WxPayService
{
//調(diào)用統(tǒng)一下單API,生成支付二維碼的鏈接和訂單號
Map<String, Object> nativePay(Long productId) throws Exception;
}
WxPayServiceImpl
//創(chuàng)建訂單,調(diào)用 Native 支付接口
@Service
@Slf4j
public class WxPayServiceImpl implements WxPayService
{
@Resource
private WxPayConfig wxPayConfig;
/* 原本應該注 入WxPayConfig 這個類,然后調(diào)用 getWxPayClient() 方法獲取 HttpClient請求對象
* 但是因為 getWxPayClient() 方法加了@Bean注解,交給了spring容器管理,所以項目啟動的時候就會執(zhí)行這個方法,
* 就會存在返回值為 CloseableHttpClient 類型的 HttpClient請求對象
* 所以這里可以直接注入這個 CloseableHttpClient 對象
*/
@Resource
private CloseableHttpClient wxPayClient;
@Resource
private OrderInfoService orderInfoService;
/**
* 創(chuàng)建訂單,調(diào)用 Native 支付接口
*
* @param productId 商品id
* @return code_url 和 訂單號
* @throws Exception
*/
//調(diào)用統(tǒng)一下單API,生成支付二維碼的鏈接和訂單號
@Override
public Map<String, Object> nativePay(Long productId) throws Exception
{
//生成訂單
OrderInfo orderInfo = orderInfoService.createOrderInfoByProduct(productId);
//獲取二維碼url-----如果是第一次生成訂單,那么這個訂單是沒有二維碼url的
String codeUrl = orderInfo.getCodeUrl();
//判斷--如果訂單存在,并且二維碼的url也存在,那么就不需要再去調(diào)用微信的下單接口來獲取支付二維碼了
if (orderInfo != null && !StringUtils.isEmpty(codeUrl))
{
//創(chuàng)建一個包含url和訂單號的返回值
Map<String, Object> map = new HashMap<>();
map.put("codeUrl", codeUrl);
map.put("orderNo", orderInfo.getOrderNo());
return map;
}
/*
* 官方提供的 Native下單 接口
* 支持商戶:【普通商戶】
* 請求方式:【POST】/v3/pay/transactions/native
* 請求域名:【主域名】https://api.mch.weixin.qq.com
* "https://api.mch.weixin.qq.com/v3/pay/transactions/native" 改成
* wxPayConfig.getDomain().concat(WxApiType.NATIVE_PAY.getType())
*/
log.info("調(diào)用統(tǒng)一下單API.....");
//調(diào)用統(tǒng)一下單API---拷貝官網(wǎng)的實例代碼進行修改---統(tǒng)一下單的接口地址
//封裝統(tǒng)一下單API 的url
HttpPost httpPost = new HttpPost(wxPayConfig.getDomain().concat(WxApiType.NATIVE_PAY.getType()));
// 請求body參數(shù)---------調(diào)用接口需要的參數(shù)
Gson gson = new Gson();
//數(shù)據(jù)類型不固定,所以就不寫泛型了
Map paramsMap = new HashMap();
//設置參數(shù) --- 根據(jù)官網(wǎng)要求設置對應的參數(shù)
paramsMap.put("appid", wxPayConfig.getAppid()); //公眾號ID
paramsMap.put("mchid", wxPayConfig.getMchId()); //直連商戶號
paramsMap.put("description", orderInfo.getTitle()); // 商品描述
paramsMap.put("out_trade_no", orderInfo.getOrderNo()); //商戶訂單號
paramsMap.put("notify_url", wxPayConfig.getNotifyDomain().concat(WxNotifyType.NATIVE_NOTIFY.getType())); //通知地址
//訂單金額有兩個參數(shù)--嵌套數(shù)據(jù)
Map amountMap = new HashMap();
amountMap.put("total", orderInfo.getTotalFee()); //總金額
amountMap.put("currency", "CNY"); //貨幣類型
paramsMap.put("amount", amountMap); // 訂單金額
//將參數(shù)轉成字符串
String jsonParams = gson.toJson(paramsMap);
log.info("支付的請求參數(shù):" + jsonParams);
//把參數(shù)設置到請求體當中
StringEntity entity = new StringEntity(jsonParams, "utf-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);
//希望得到的響應類型
httpPost.setHeader("Accept", "application/json");
//完成簽名并執(zhí)行請求
CloseableHttpResponse response = wxPayClient.execute(httpPost);
//這些就是對調(diào)用下單方法的響應結果的處理了
try
{
//字符串形式的響應體
String bodyAsString = EntityUtils.toString(response.getEntity());
//響應狀態(tài)碼
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200)
{ //處理成功
System.out.println("成功, 返回結果 = " + bodyAsString);
} else if (statusCode == 204)
{ //處理成功,無返回Body
System.out.println("成功");
} else
{
System.out.println("下單失敗, 響應碼 = " + statusCode + ", 返回結果 = " + bodyAsString);
throw new IOException("請求失敗 request failed");
}
//響應結果---如果下單成功,獲取響應結果, gson.fromJson()用于將 JSON 字符串轉換為 Java 對象
Map<String, String> resultMap = gson.fromJson(bodyAsString, HashMap.class);
//二維碼---從返回的結果中獲取二維碼的url, 從官網(wǎng)看出 code_url 是 二維碼的key
codeUrl = resultMap.get("code_url");
//保存二維碼
String orderNo = orderInfo.getOrderNo();
orderInfoService.saveCodeUrl(orderNo,codeUrl);
//創(chuàng)建一個包含url和訂單號的返回值
Map<String, Object> map = new HashMap<>();
map.put("codeUrl", codeUrl);
map.put("orderNo", orderInfo.getOrderNo());
return map;
} finally
{
response.close();
}
}
}
OrderInfoService
public interface OrderInfoService extends IService<OrderInfo> {
/**
* 根據(jù)商品id創(chuàng)建商品訂單
* @param productId 商品id
* @return 訂單對象
*/
OrderInfo createOrderInfoByProduct(Long productId);
/**
* 將支付二維碼的url存到訂單中
* @param orderNo 訂單編號
* @param codeUrl 支付二維碼的地址url
*/
void saveCodeUrl(String orderNo, String codeUrl);
}
OrderInfoServiceImpl
@Service
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService
{
@Resource
private ProductMapper productMapper;
@Resource
private OrderInfoMapper orderInfoMapper;
//創(chuàng)建商品訂單
@Override
public OrderInfo createOrderInfoByProduct(Long productId)
{
//用戶點擊確認支付,要先查找該用戶是否存在已下單未支付的訂單
OrderInfo orderInfo = this.getNoPayOrderByProductId(productId);
if (orderInfo != null)
{
//表示該用戶已經(jīng)下單了,還沒有支付,那就直接把他的訂單返回回去就行了,否則就創(chuàng)建新訂單
return orderInfo;
}
//根據(jù)商品的id獲取到該商品對象數(shù)據(jù)
Product product = productMapper.selectById(productId);
orderInfo = new OrderInfo();
orderInfo.setTitle(product.getTitle()); //訂單標題
orderInfo.setOrderNo(OrderNoUtils.getOrderNo()); //生成訂單號
orderInfo.setProductId(productId); //商品id
orderInfo.setTotalFee(1); //單位是:分
orderInfo.setOrderStatus(OrderStatus.NOTPAY.getType()); //支付狀態(tài)
//把商品訂單存到數(shù)據(jù)庫
orderInfoMapper.insert(orderInfo);
return orderInfo;
}
/**
* 根據(jù)商品id查詢已下單未支付的訂單,防止重復創(chuàng)建訂單
* @param productId 商品id
* @return 訂單對象
*/
private OrderInfo getNoPayOrderByProductId(Long productId)
{
//QueryWrapper 是 MyBatis-Plus 提供的一個用于構建查詢條件的工具類
QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
//相當于封裝查詢對象,這是查詢條件
//就是查詢該表中,是否有 列名 product_id 對應的值等于這個 productId ,有就查詢出來
queryWrapper.eq("product_id", productId);
queryWrapper.eq("order_status", OrderStatus.NOTPAY.getType());
//把 queryWrapper 作為查詢條件對象
//selectOne 就是查詢出一條,如果查詢出多條,則會報錯
OrderInfo orderInfo = orderInfoMapper.selectOne(queryWrapper);
return orderInfo;
}
/**
* 將支付二維碼的url存到訂單中
* @param orderNo 訂單編號
* @param codeUrl 支付二維碼的地址url
*/
@Override
public void saveCodeUrl(String orderNo, String codeUrl)
{
//QueryWrapper 是 MyBatis-Plus 提供的一個用于構建查詢條件的工具類
QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
//組裝查詢條件
queryWrapper.eq("order_no",orderNo);
//要修改的字段,存到這個 orderInfo 對象里面
OrderInfo orderInfo = new OrderInfo();
orderInfo.setCodeUrl(codeUrl);
//執(zhí)行sql
orderInfoMapper.update(orderInfo,queryWrapper);
}
}
3、顯示訂單列表
3-1:需求:
在我的訂單頁面按時間倒序顯示訂單列表
目前是有訂單,但是沒展示出來。
3-2:代碼:
前端:
調(diào)用后端接口的是api模塊
<script> 腳本模塊
<template> 模板,是用來定義組件的模板部分,用于描述組件的結構和布局
將后端返回的list商品訂單列表賦值給 orders.vue 這個類后,就需要對這個數(shù)據(jù)進行渲染。
后端:
創(chuàng)建一個訂單的controller
3-3:測試:
查看swagger
文章來源:http://www.zghlxwxcb.cn/news/detail-745113.html
查看訂單列表
成功顯示文章來源地址http://www.zghlxwxcb.cn/news/detail-745113.html
3-4:完整代碼
后端:
OrderInfoController
@CrossOrigin //開放前端的跨域訪問
@RestController
@RequestMapping(value = "/api/order-info")
@Api(tags = "商品訂單管理")
public class OrderInfoController
{
//依賴注入
@Resource
private OrderInfoService orderInfoService;
@ApiOperation("顯示商品訂單列表")
@GetMapping("/list")
public R getOrderInfoList()
{
List<OrderInfo> list =
orderInfoService.getOrderInfoListByCreateTimeDesc();
return R.ok().data("list",list);
}
}
OrderInfoService
/**
* 獲取商品訂單列表,并按時間倒序顯示
* @return 商品訂單列表,倒序顯示
*/
List<OrderInfo> getOrderInfoListByCreateTimeDesc();
OrderInfoServiceImpl
/**
* 獲取商品訂單列表,并按時間倒序顯示
* @return 商品訂單列表,倒序顯示
*/
@Override
public List<OrderInfo> getOrderInfoListByCreateTimeDesc()
{
//QueryWrapper 是 MyBatis-Plus 提供的一個用于構建查詢條件的工具類
QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
//組裝查詢條件
queryWrapper.orderByDesc("create_time");
//查詢
List<OrderInfo> list = orderInfoMapper.selectList(queryWrapper);
return list;
}
到了這里,關于03、SpringBoot + 微信支付 ---- 創(chuàng)建訂單、保存二維碼url、顯示訂單列表的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!