1.微信支付

通过微信平台为商家提供代收款服务

1.1微信支付的业务--商户注册微信支付业务:

微信支付开发详解 微信支付及支付回调(1)

微信支付开发详解 微信支付及支付回调(2)

微信支付开发详解 微信支付及支付回调(3)

1.2申请支付订单--商户向支付平台申请支付链接

支付订单,并不是用户提交的商品订单,而是商品向微信支付平台申请的支付链接

1.2.1导入微信支付的依赖

wxpay的maven依赖:

<dependency>

<groupId>com.github.wxpay</groupId>

<artifactId>wxpay-sdk</artifactId>

<version>0.0.3</version>

</dependency>

1.2.2创建微信支付配置类,配置商品信息

创建一类,实现WXPayConfig接口

重写三分方法,分别设置商品AppID\商户ID\商户密钥

package com.qfedu.config;

import com.github.wxpay.sdk.WXPayConfig;

import java.io.InputStream;

/**

* @Description:

* @Author : Jerry

* @create : 2022-07-02 18:16

*/

public class MyPayConfig implements WXPayConfig {

@Override

public String getAppID() {

return "wx632c8f211f8122c6";

}

@Override

public String getMchID() {

return "1497984412";

}

@Override

public String getKey() {

return "sbNCm1JnevqI36LrEaxFwcaT0hkGxFnc";

}

@Override

public InputStream getCertStream() {

return null;

}

@Override

public int getHttpConnectTimeoutMs() {

return 0;

}

@Override

public int getHttpReadTimeoutMs() {

return 0;

}

}

微信支付开发详解 微信支付及支付回调(4)

1.2.3设置订单的参数

//设置当前订单信息

HashMap<String,String> data = new HashMap<>();

data.put("fee_type","CNY"); //支付币种

data.put("total_fee","0.1"); //支付总金额

data.put("body","咪咪虾条"); // 商品描述

//使用当前用户订单的编号作为当前支付交易的交易号

data.put("out_trade_no", orderId);

data.put("trade_type","NATIVE"); //交易类型

data.put("notify_url","/pay/success"); //设置支付完成时的回调方法接口

修改OrderService的实现类:

package com.qfedu.fmmall.service.impl;

import com.qfedu.fmmall.dao.OrderItemMapper;

import com.qfedu.fmmall.dao.OrdersMapper;

import com.qfedu.fmmall.dao.ProductSkumapper;

import com.qfedu.fmmall.dao.ShoppingCartMapper;

import com.qfedu.fmmall.entity.OrderItem;

import com.qfedu.fmmall.entity.Orders;

import com.qfedu.fmmall.entity.ProductSku;

import com.qfedu.fmmall.entity.ShoppingCartVO;

import com.qfedu.fmmall.service.OrderService;

import com.qfedu.fmmall.vo.R;

import com.qfedu.fmmall.vo.ResStatus;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;

import java.util.*;

/**

* @Description:

* @Author : Jerry

* @create : 2022-07-01 17:46

*/

@Service

public class OrderServiceImpl implements OrderService {

@Autowired

private ShoppingCartMapper shoppingCartMapper;

@Autowired

private OrdersMapper ordersMapper;

@Autowired

private OrderItemMapper orderItemMapper;

@Autowired

private ProductSkuMapper productSkuMapper;

/**

* 保存订单业务

* @param cids 在购物车列表页面选择得购物车记录的ID

* @param order

* @return

*/

@Transactional

public Map<String,String> addOrder(String cids, Orders order) {

Map<String,String> map = new HashMap<>();

//1.校验库存:根据cids查询当前订单中关联的购物车记录详情(包括库存)

String[] arr = cids.split(",");

List<Integer> cidList = new ArrayList<>();

for (int i = 0; i<arr.length; i ){

cidList.add(Integer.parseInt(arr[i]));

}

List<ShoppingCartVO> list = shoppingCartMapper.selectShopCartByCids(cidList);

boolean f = true;

String untitled = "";

for (ShoppingCartVO sc: list){

if(Integer.parseInt(sc.getCartNum())>sc.getSkuStock()){

f = false;

}

//获取所有商品名称,以,分割拼接称字符串

untitled = untitled sc.getProductName() ",";

}

if(f){

//2. 保存订单

//收货人信息:姓名,电话,地址,商品总价格,支付方式,订单创建时间

//订单初始状态(待支付 1)

order.setUntitled(untitled);

order.setCreateTime(new Date());

order.setStatus("1");

//生成订单编号

String orderId = UUID.randomUUID().toString().replace("-", " ");

order.setOrderId(orderId);

ordersMapper.insert(order);

//3.生成商品快照

for(ShoppingCartVO sc:list){

int cnum = Integer.parseInt(sc.getCartNum());

String itemId = System.currentTimeMillis() "" (new Random().nextInt(89999) 10000);//增大容错率

OrderItem orderItem = new OrderItem(itemId, orderId, sc.getProductId(), sc.getProductName(), sc.getProductImg(), sc.getSkuId(), sc.getSkuName(), new BigDecimal(sc.getSellPrice())

, cnum, new BigDecimal(sc.getSellPrice()*cnum), new Date(), new Date(), 0);

orderItemMapper.insert(orderItem);

}

//4.扣减库存:根据套餐id修改套餐库存量

for (ShoppingCartVO sc: list){

String skuId = sc.getSkuId();

int newStock = sc.getSkuStock() - Integer.parseInt(sc.getCartNum());

//updateByExampleSelective只添加修改的,其他的不变

ProductSku productSku = new ProductSku();

productSku.setSkuId(skuId);

productSku.setStock(newStock);

productSkuMapper.updateByPrimaryKeySelective(productSku);

}

//5.删除购物车:当购物车中得记录购买成功之后,购物车中对应做删除操作

for(int cid:cidList){

shoppingCartMapper.deleteByPrimaryKey(cid);

}

map.put("orderId",orderId);

map.put("productNames",untitled);

return map;

}else {

//表示库存不足

return null;

}

}

}

OrderController:(微信支付实现)

package com.qfedu.controller;

import com.github.wxpay.sdk.WXPay;

import com.qfedu.config.MyPayConfig;

import com.qfedu.fmmall.entity.Orders;

import com.qfedu.fmmall.service.OrderService;

import com.qfedu.fmmall.vo.R;

import com.qfedu.fmmall.vo.ResStatus;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.*;

import java.util.HashMap;

import java.util.Map;

/**

* @Description:

* @Author : Jerry

* @create : 2022-07-01 19:40

*/

@RestController

@CrossOrigin

@requestMapping("/order")

public class OrderController {

@Autowired

private OrderService orderService;

@PostMapping("/add")

public R add(String cids, @RequestBody Orders order){

R r = null;

try {

Map<String, String> orderInfo = orderService.addOrder(cids, order);

String orderId = orderInfo.get("orderId");

if(orderId!=null){

//设置当前订单信息

HashMap<String,String> data = new HashMap<>();

data.put("fee_type","CNY"); //支付币种

data.put("total_fee",order.getActualAmount()*100 ""); //支付总金额

data.put("body",orderInfo.get("productNames")); // 商品描述

//使用当前用户订单的编号作为当前支付交易的交易号

data.put("out_trade_no", orderId);

data.put("trade_type","NATIVE"); //交易类型

data.put("notify_url","/pay/success"); //设置支付完成时的回调方法接口

//发送请求,获取响应

//微信支付:申请支付连接

WXPay wxPay = new WXPay(new MyPayConfig());

Map<String, String> resp = wxPay.unifiedOrder(data);

orderInfo.put("payUrl",resp.get("code_url"));

//orderInfo中包含了:订单编号,购买的商品名称,支付链接

r = new R(ResStatus.OK,"提交订单成功!!!",orderInfo);

}else {

r = new R(ResStatus.NO,"提交订单失败!!!",null);

}

} catch (Exception e) {

r = new R(ResStatus.NO,"提交订单失败!!!",null);

}

return r;

}

}

2.支付回调

支付回调:当用户支付成功之后,支付平台会向我们指定的服务器接口发送请求传递订单支付状态数据

2.1 创建一个控制器定义回调接口

package com.qfedu.controller;

import com.github.wxpay.sdk.WXPayUtil;

import com.qfedu.fmmall.service.OrderService;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.PostMapping;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletInputStream;

import javax.servlet.http.HttpServletRequest;

import java.util.HashMap;

import java.util.Map;

/**

* @Description: 回调接口:当用户支付成功之后,微信支付平台就会请求这个接口,将支付状态的数据传递过来

* @Author : Jerry

* @create : 2022-07-02 18:44

*/

@RestController

@RequestMapping("/pay")

public class PayController {

@Autowired

private OrderService orderService;

/**

* 1.接收微信支付平台传递的数据(使用request的输入流接收)

*/

@PostMapping("/callback")

public String success(HttpServletRequest request) throws Exception {

ServletInputStream is = request.getInputStream();

byte[] bs = new byte[1024];

int len = -1;

StringBuilder builder = new StringBuilder();

while ((len = is.read(bs)) != -1){

builder.append(new String(bs,0,len));

}

String s = builder.toString();

//使用帮助类将xml接口的字符串转换成map

Map<String,String> map = WXPayUtil.xmlToMap(s);

if(map!=null && "success".equalsIgnoreCase(map.get("result_code"))){

//支付成功

//2.修改订单状态为“待发货/已支付”

String orderId = map.get("out_trade_no");

int i = orderService.updateOrderStatus(orderId, "2");

System.out.println("--orderId:" orderId);

//3.响应微信支付平台

if(i>0){

HashMap<String,String> resp = new HashMap<>();

resp.put("return_code","success");

resp.put("return_msg","OK");

resp.put("appid",map.get("appid"));

resp.put("result_code","success");

return WXPayUtil.mapToXml(resp);

}

}

//支付失败

return null;

}

}

微信支付开发详解 微信支付及支付回调(5)

2.2 设置回调URL

在订单接口中申请支付链接的时候将回调接口的路径设置给微信支付平台

2.3 Ngrok实现内网穿透

网站:ngrok.cc

注册账号,申请隧道id

开通隧道:

微信支付开发详解 微信支付及支付回调(6)

微信支付开发详解 微信支付及支付回调(7)

获取隧道id:

微信支付开发详解 微信支付及支付回调(8)

下载客户端

2.4 前端通过轮询访问获取订单支付状态

流程图:

微信支付开发详解 微信支付及支付回调(9)

接口实现:

service接口:

package com.qfedu.fmmall.service;

import com.qfedu.fmmall.entity.Orders;

import com.qfedu.fmmall.vo.R;

import java.util.Map;

/**

* @Description: 订单接口

* @Author : Jerry

* @create : 2022-07-01 17:45

*/

public interface OrderService {

public Map<String,String> addOrder(String cids, Orders order);

public int updateOrderStatus(String orderId,String status);

public R getOrderById(String orderId);

}

service实现类:

@Override

public R getOrderById(String orderId) {

Orders orders = ordersMapper.selectByPrimaryKey(orderId);

return new R(ResStatus.OK,"success",orders.getStatus());

}

controller:

@GetMapping("/status/{oid}")

public R getOrderStatus(@PathVariable("oid") String orderId,

@RequestHeader("token")String token){

R r = orderService.getOrderById(orderId);

return r;

}

2.5 webSocket消息推送:

实现流程:

微信支付开发详解 微信支付及支付回调(10)

2.5.1 创建webSocket服务器

添加依赖:

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-websocket</artifactId>

</dependency>

添加websocket服务节点配置:(Java配置方式)

@Configuration

public class WebSocketConfig {

@Bean

public ServerEndpointExporter getServerEndpointExporter(){

return new ServerEndpointExporter();

}

}

创建websocket服务器:

package com.qfedu.websocket;

import org.springframework.stereotype.Component;

import org.springframework.web.bind.annotation.PostMapping;

import javax.websocket.OnClose;

import javax.websocket.OnOpen;

import javax.websocket.session;

import javax.websocket.server.PathParam;

import javax.websocket.server.ServerEndpoint;

import java.io.IOException;

import java.util.concurrent.ConcurrentHashMap;

/**

* @Description:

* @Author : Jerry

* @create : 2022-07-03 13:06

*/

@Component

@ServerEndpoint("/webSocket/{oid}")

public class WebSocketServer {

private static ConcurrentHashMap<String,Session> sessionMap = new ConcurrentHashMap<>();

/**

* 前端发送请求建立websocket连接,就会执行 @OnOpen 方法

*/

@OnOpen

public void open(@PathParam("oid") String orderId, Session session){

System.out.println("---------建立连接:" orderId);

sessionMap.put(orderId,session);

}

/**

* 前端关闭页面或者主动关闭webSocket连接,都会执行close

*/

@OnClose

public void close(@PathParam("oid") String orderId){

sessionMap.remove(orderId);

}

public static void sendMsg(String orderId,String msg){

try {

Session session = sessionMap.get(orderId);

session.getBasicRemote().sendText(msg);

} catch (IOException e) {

e.printStackTrace();

}

}

}

修改回调接口:

微信支付开发详解 微信支付及支付回调(11)

,