【微信支付】【java】Springboot对接开发微信支付

CSDN 2024-07-06 11:35:30 阅读 76

本文章是介绍java对接(微信小程序)微信支付,包括微信预下单、支付、退款等等。 

目录

 一、微信配置申请

1、微信支付配置申请

二、开发环境

1、开发环境

2、maven依赖

3、application.yml文件配置

三、代码开发

1、配置类

2、初始化商户配置

3、JSAPI微信预下单

3.1、先建个WxPayService服务类

3.1、R实体类

3.2、CreateOrderReq类

4、微信支付回调通知 

5、根据商户订单号查询订单(out_trade_no)

5.1  QueryOrderReq类

6、根据支付订单号查询订单 (transaction_id)

7、微信申请退款

8、退款回调通知 

四、mysql表结构

五、controller类


 一、微信配置申请

1、微信支付配置申请

详细操作流程参考官方文档:https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_8_1.shtml#part-1

配置完成需要以下信息:

APPID商户号(mchid)商户API私钥(apiclient_key.pem)商户证书序列号商户APIv3密钥

二、开发环境

1、开发环境

开发语言:java ,编译工具:idea ,框架:springboot ,仓库:maven

2、maven依赖

<code><dependency>

<groupId>com.github.wechatpay-apiv3</groupId>

<artifactId>wechatpay-java</artifactId>

<version>0.2.10</version>

</dependency>

3、application.yml文件配置

#微信支付配置

wx:

pay:

#应用id(小程序id)

appId: wx6b5xxxxxxxxxxxx

#商户号

merchantId: 1xxxxxxxxx

#商户API私钥

privateKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

#商户证书序列号

merchantSerialNumber: 315DDXXXXXXXXXXXXXXXXXXXXXXXXXXX

#商户APIv3密钥

apiV3Key: XXXXXXXXXXXXXXXXXXXXXXXXXX

#支付通知地址

payNotifyUrl: https://xxx.xxxx.xxx.xxx/xx/xxxx/xxxx/openapi/wx/payNotify

#退款通知地址

refundNotifyUrl: https://xxx.xxx.xxx.xxx/xxxx/xxxx/xxxx/openapi/wx/refundNotify

三、代码开发

1、配置类

import lombok.Data;

import org.springframework.boot.context.properties.ConfigurationProperties;

import org.springframework.stereotype.Component;

/**

* @author caozhen

* @ClassName WxPayConfig

* @description: 微信支付配置类

* @date 2024年01月03日

* @version: 1.0

*/

@Data

@Component

@ConfigurationProperties(prefix = "wx.pay")

public class WxPayConfig {

//APPID

private String appId;

//mchid

private String merchantId;

//商户API私钥

private String privateKey;

//商户证书序列号

private String merchantSerialNumber;

//商户APIv3密钥

private String apiV3Key;

//支付通知地址

private String payNotifyUrl;

//退款通知地址

private String refundNotifyUrl;

}

2、初始化商户配置

import com.wechat.pay.java.core.RSAAutoCertificateConfig;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;

/**

* @author caozhen

* @ClassName WxPayAutoCertificateConfig

* @description: 微信支付证书自动更新配置

* @date 2024年01月03日

* @version: 1.0

*/

@Configuration

public class WxPayAutoCertificateConfig {

@Resource

private WxPayConfig wxPayConfig;

/**

* 初始化商户配置

* @return

*/

@Bean

public RSAAutoCertificateConfig rsaAutoCertificateConfig() {

RSAAutoCertificateConfig config = new RSAAutoCertificateConfig.Builder()

.merchantId(wxPayConfig.getMerchantId())

.privateKey(wxPayConfig.getPrivateKey())

.merchantSerialNumber(wxPayConfig.getMerchantSerialNumber())

.apiV3Key(wxPayConfig.getApiV3Key())

.build();

return config;

}

}

3、JSAPI微信预下单

3.1、先建个WxPayService服务类

import com.alibaba.fastjson.JSONObject;

import com.baomidou.mybatisplus.mapper.EntityWrapper;

import com.baomidou.mybatisplus.mapper.Wrapper;

import com.hvit.user.exception.DataAccessException;

import com.hvit.user.util.DateUtils;

import com.hvit.user.util.R;

import com.hvit.user.yst.entity.WxOrderEntity;

import com.hvit.user.yst.entity.WxPayLogEntity;

import com.hvit.user.yst.request.CreateOrderReq;

import com.hvit.user.yst.request.QueryOrderReq;

import com.hvit.user.yst.request.WxNotifyReq;

import com.hvit.user.yst.service.WKShoppingMallService;

import com.hvit.user.yst.service.data.WxOrderDataService;

import com.hvit.user.yst.service.data.WxPayLogDataService;

import com.wechat.pay.java.core.RSAAutoCertificateConfig;

import com.wechat.pay.java.core.exception.HttpException;

import com.wechat.pay.java.core.exception.MalformedMessageException;

import com.wechat.pay.java.core.exception.ServiceException;

import com.wechat.pay.java.core.notification.NotificationParser;

import com.wechat.pay.java.core.notification.RequestParam;

import com.wechat.pay.java.service.payments.jsapi.*;

import com.wechat.pay.java.service.payments.jsapi.model.*;

import com.wechat.pay.java.service.payments.jsapi.model.Amount;

import com.wechat.pay.java.service.payments.model.Transaction;

import com.wechat.pay.java.service.refund.RefundService;

import com.wechat.pay.java.service.refund.model.*;

import io.swagger.annotations.ApiModelProperty;

import io.swagger.models.auth.In;

import lombok.extern.slf4j.Slf4j;

import org.apache.commons.lang3.StringUtils;

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

import org.springframework.scheduling.annotation.Async;

import org.springframework.stereotype.Service;

import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

import javax.servlet.ServletInputStream;

import javax.servlet.http.HttpServletRequest;

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.math.BigDecimal;

import java.util.Date;

import java.util.HashMap;

import java.util.LinkedHashMap;

import java.util.Map;

/**

* @author caozhen

* @ClassName WxPayService

* @description: 微信支付

* @date 2024年01月03日

* @version: 1.0

*/

@Slf4j

@Service

public class WxPayService {

@Resource

private WxPayConfig wxPayConfig;

@Autowired

private RSAAutoCertificateConfig rsaAutoCertificateConfig;

@Autowired

private WxOrderDataService wxOrderDataService;

@Autowired

private WxPayLogDataService wxPayLogDataService;

/***

* 预支付订单

* @param req

* @return

*/

public R createOrder(CreateOrderReq req) throws Exception {

if (req == null) {

return R.error("创建订单失败,缺少参数!");

}

//先解密

String orderNo = req.getOutTradeNo();

Integer totalFee = req.getTotal();

//创建初始化订单

//todo,创建订单这边你们自己来(后面我会放出表结构)

//请求微信支付相关配置

JsapiServiceExtension service =

new JsapiServiceExtension.Builder()

.config(rsaAutoCertificateConfig)

.signType("RSA") // 不填默认为RSA

.build();

PrepayWithRequestPaymentResponse response = new PrepayWithRequestPaymentResponse();

try {

PrepayRequest request = new PrepayRequest();

request.setAppid(wxPayConfig.getAppId());

request.setMchid(wxPayConfig.getMerchantId());

request.setDescription(description);

request.setOutTradeNo(orderNo);

request.setNotifyUrl(wxPayConfig.getPayNotifyUrl());

Amount amount = new Amount();

//amount.setTotal(totalFee.multiply(new BigDecimal("100")).intValue());

amount.setTotal(totalFee);

request.setAmount(amount);

Payer payer = new Payer();

payer.setOpenid(req.getWxOpenId());

request.setPayer(payer);

log.info("请求预支付下单,请求参数:{}", JSONObject.toJSONString(request));

// 调用预下单接口

response = service.prepayWithRequestPayment(request);

log.info("订单【{}】发起预支付成功,返回信息:{}", orderNo, response);

} catch (HttpException e) { // 发送HTTP请求失败

log.error("微信下单发送HTTP请求失败,错误信息:{}", e.getHttpRequest());

return R.error("下单失败");

} catch (ServiceException e) { // 服务返回状态小于200或大于等于300,例如500

log.error("微信下单服务状态错误,错误信息:{}", e.getErrorMessage());

return R.error("下单失败");

} catch (MalformedMessageException e) { // 服务返回成功,返回体类型不合法,或者解析返回体失败

log.error("服务返回成功,返回体类型不合法,或者解析返回体失败,错误信息:{}", e.getMessage());

return R.error("下单失败");

}

return R.ok().put("data", response);

}

}

3.1、R实体类

import java.util.HashMap;

import java.util.Map;

/**

*

* @author 曹震

* @date 2024-1-03

*/

public class R extends HashMap<String, Object> {

private static final long serialVersionUID = 1L;

public R() {

put("code", 0);

}

public R(Integer code) {

put("code", code);

put("data", new HashMap<String, Object>());

}

public R(Integer code, String msg) {

put("code", code);

put("msg", msg);

put("data", new HashMap<String, Object>());

}

public static R error() {

return error(500, "未知异常,请联系管理员");

}

public static R errorDebug(String message) {

return error(500, "未知异常 " + message + ",请联系管理员");

}

public static R error(String msg) {

return error(500, msg);

}

public static R error(int code, String msg) {

R r = new R();

r.put("code", code);

r.put("msg", msg);

return r;

}

public R errorInfo(String msg) {

this.put("errorMsg", msg);

return this;

}

public static R ok(String msg) {

R r = new R();

r.put("msg", msg);

r.put("data", new HashMap<String, Object>());

return r;

}

public static R ok(Map<String, Object> map) {

R r = new R();

r.putAll(map);

r.put("data", new HashMap<String, Object>());

return r;

}

public static R ok() {

return new R().put("msg", "success").put("data", new HashMap<String, Object>());

}

public static R ok(Integer size) {

return new R().put("data", new HashMap<String, Object>((int)Math.round(size / 0.75)));

}

@Override

public R put(String key, Object value) {

super.put(key, value);

return this;

}

/**

* 添加返回结果数据

*

* @param key

* @param value

* @return

*/

public R putData(String key, Object value) {

Map<String, Object> map = (HashMap<String, Object>)this.get("data");

map.put(key, value);

return this;

}

}

3.2、CreateOrderReq类

import io.swagger.annotations.ApiModelProperty;

import lombok.Data;

/**

* @author caozhen

* @ClassName CreateOrderReq

* @description: TODO

* @date 2024年01月03日

* @version: 1.0

*/

@Data

public class CreateOrderReq {

@ApiModelProperty(name = "description", value = "商品描述")

private String description;

@ApiModelProperty(name = "wxOpenId", value = "用户小程序openid")

private String wxOpenId;

@ApiModelProperty(name = "outTradeNo", value = "商户订单号")

private String outTradeNo;

@ApiModelProperty(name = "totalFee", value = "支付金额,单位:分")

private Long totalFee;

4、微信支付回调通知 

/***

* 微信支付回调通知

* @param request

* @return

* @throws IOException

*/

@Transactional

public synchronized String payNotify(HttpServletRequest request) throws Exception {

log.info("------收到支付通知------");

// 请求头Wechatpay-Signature

String signature = request.getHeader("Wechatpay-Signature");

// 请求头Wechatpay-nonce

String nonce = request.getHeader("Wechatpay-Nonce");

// 请求头Wechatpay-Timestamp

String timestamp = request.getHeader("Wechatpay-Timestamp");

// 微信支付证书序列号

String serial = request.getHeader("Wechatpay-Serial");

// 签名方式

String signType = request.getHeader("Wechatpay-Signature-Type");

// 构造 RequestParam

RequestParam requestParam = new RequestParam.Builder()

.serialNumber(serial)

.nonce(nonce)

.signature(signature)

.timestamp(timestamp)

.signType(signType)

.body(HttpServletUtils.getRequestBody(request))

.build();

// 初始化 NotificationParser

NotificationParser parser = new NotificationParser(rsaAutoCertificateConfig);

// 以支付通知回调为例,验签、解密并转换成 Transaction

log.info("验签参数:{}", requestParam);

Transaction transaction = parser.parse(requestParam, Transaction.class);

log.info("验签成功!-支付回调结果:{}", transaction.toString());

Map<String, String> returnMap = new HashMap<>(2);

returnMap.put("code", "FAIL");

returnMap.put("message", "失败");

//修改订单前,建议主动请求微信查询订单是否支付成功,防止恶意post

Wrapper wrapper = new EntityWrapper<WxOrderEntity>();

wrapper.eq("out_trade_no", transaction.getOutTradeNo());

//wrapper.eq("transaction_id", transaction.getTransactionId());

WxOrderEntity wxOrderEntity = wxOrderDataService.selectOne(wrapper);

if (wxOrderEntity != null) {

if (wxOrderEntity.getPayStatus() == 1) {

//此时已经是支付成功,不在处理订单信息

returnMap.put("code", "SUCCESS");

returnMap.put("message", "成功");

return JSONObject.toJSONString(returnMap);

}

}

if (Transaction.TradeStateEnum.SUCCESS != transaction.getTradeState()) {

log.info("内部订单号【{}】,微信支付订单号【{}】支付未成功", transaction.getOutTradeNo(), transaction.getTransactionId());

if (wxOrderEntity != null) {

wxOrderEntity.setUpdateTime(new Date());

wxOrderEntity.setPayStatus(2);

wxOrderEntity.setPayNonce(nonce);

wxOrderEntity.setTransactionId(transaction.getTransactionId());

//修改订单信息

wxOrderDataService.updateById(wxOrderEntity);

}

return JSONObject.toJSONString(returnMap);

}

if (wxOrderEntity != null) {

wxOrderEntity.setUpdateTime(new Date());

wxOrderEntity.setPayTime(DateUtils.stringToDateTime(transaction.getSuccessTime()));

wxOrderEntity.setPayDate(DateUtils.stringToDateTime(transaction.getSuccessTime()));

wxOrderEntity.setPayStatus(1);

wxOrderEntity.setPayNonce(nonce);

wxOrderEntity.setTransactionId(transaction.getTransactionId());

//修改订单信息

wxOrderDataService.updateById(wxOrderEntity);

//同时处理支付记录

Wrapper payWrapper = new EntityWrapper<WxPayLogEntity>();

wrapper.eq("out_trade_no", transaction.getOutTradeNo());

wrapper.eq("pay_status", 1);//支付

WxPayLogEntity wxPayLogEntity = wxPayLogDataService.selectOne(payWrapper);

if (wxPayLogEntity == null) {

wxPayLogEntity = new WxPayLogEntity();

wxPayLogEntity.setCreateTime(new Date());

wxPayLogEntity.setOutTradeNo(wxOrderEntity.getOutTradeNo());

wxPayLogEntity.setPayStatus(1);

wxPayLogEntity.setTotalFee(wxOrderEntity.getTotalFee());

wxPayLogEntity.setTransactionId(wxOrderEntity.getTransactionId());

wxPayLogEntity.setWxOpenId(wxOrderEntity.getWxOpenId());

wxPayLogDataService.insert(wxPayLogEntity);

}

}

returnMap.put("code", "SUCCESS");

returnMap.put("message", "成功");

return JSONObject.toJSONString(returnMap);

}

5、根据商户订单号查询订单(out_trade_no)

/***

* 根据商户订单号查询订单 outTradeNo

* @param req

* @return

*/

@Transactional

public R queryOrderByOrderNo(QueryOrderReq req) {

QueryOrderByOutTradeNoRequest queryRequest = new QueryOrderByOutTradeNoRequest();

queryRequest.setMchid(wxPayConfig.getMerchantId());

queryRequest.setOutTradeNo(req.getOrderNo());

try {

JsapiServiceExtension service =

new JsapiServiceExtension.Builder()

.config(rsaAutoCertificateConfig)

.signType("RSA") // 不填默认为RSA

.build();

Transaction result = service.queryOrderByOutTradeNo(queryRequest);

LinkedHashMap retmap = new LinkedHashMap();

//支付成功

if (Transaction.TradeStateEnum.SUCCESS == result.getTradeState()) {

log.info("内部订单号【{}】,微信支付订单号【{}】支付成功", result.getOutTradeNo(), result.getTransactionId());

retmap.put("out_trade_no", result.getOutTradeNo());

retmap.put("transaction_id", result.getTransactionId());

retmap.put("success", true);

retmap.put("msg", "支付成功!");

retmap.put("success_time", DateUtils.getDateTimeString(DateUtils.stringToDateTime(result.getSuccessTime())));

//主动查询

Wrapper wrapper = new EntityWrapper<WxOrderEntity>();

wrapper.eq("out_trade_no", req.getOrderNo());

WxOrderEntity wxOrderEntity = wxOrderDataService.selectOne(wrapper);

if (wxOrderEntity != null) {

if (wxOrderEntity.getPayStatus() != 1) {

wxOrderEntity.setPayStatus(1);

wxOrderEntity.setTransactionId(result.getTransactionId());

wxOrderEntity.setPayDate(DateUtils.stringToDateTime(result.getSuccessTime()));

wxOrderEntity.setPayTime(DateUtils.stringToDateTime(result.getSuccessTime()));

wxOrderEntity.setUpdateTime(new Date());

wxOrderDataService.updateById(wxOrderEntity);

//同时处理支付记录

Wrapper payWrapper = new EntityWrapper<WxPayLogEntity>();

wrapper.eq("out_trade_no", req.getOrderNo());

WxPayLogEntity wxPayLogEntity = wxPayLogDataService.selectOne(payWrapper);

if (wxPayLogEntity == null) {

wxPayLogEntity = new WxPayLogEntity();

wxPayLogEntity.setCreateTime(new Date());

wxPayLogEntity.setOutTradeNo(wxOrderEntity.getOutTradeNo());

wxPayLogEntity.setPayStatus(1);

wxPayLogEntity.setTotalFee(wxOrderEntity.getTotalFee());

wxPayLogEntity.setTransactionId(result.getTransactionId());

wxPayLogEntity.setWxOpenId(wxOrderEntity.getWxOpenId());

wxPayLogDataService.insert(wxPayLogEntity);

}

}

}

} else {

log.info("内部订单号【{}】,微信支付订单号【{}】支付未成功", result.getOutTradeNo(), result.getTransactionId());

retmap.put("out_trade_no", result.getOutTradeNo());

retmap.put("transaction_id", result.getTransactionId());

retmap.put("success", false);

retmap.put("msg", "支付失败!");

retmap.put("success_time", null);

}

return R.ok().put("data", retmap);

} catch (ServiceException e) {

log.error("订单查询失败,返回码:{},返回信息:{}", e.getErrorCode(), e.getErrorMessage());

return R.error("订单查询失败!");

}

}

5.1  QueryOrderReq类

mport io.swagger.annotations.ApiModelProperty;

import lombok.Data;

/**

* @author caozhen

* @ClassName QueryOrderReq

* @description: 支付查询

* @date 2024年01月04日

* @version: 1.0

*/

@Data

public class QueryOrderReq {

@ApiModelProperty(name = "paymentNo", value = "微信支付订单号,同:transaction_id")

private String paymentNo;

@ApiModelProperty(name = "orderNo", value = "商户订单号,同:out_trade_no")

private String orderNo;

}

6、根据支付订单号查询订单 (transaction_id)

/***

* 根据支付订单号查询订单 paymentNo

* @param req

* @return

*/

@Transactional

public R queryOrderByPaymentNo(QueryOrderReq req) {

QueryOrderByIdRequest queryRequest = new QueryOrderByIdRequest();

queryRequest.setMchid(wxPayConfig.getMerchantId());

queryRequest.setTransactionId(req.getPaymentNo());

try {

JsapiServiceExtension service =

new JsapiServiceExtension.Builder()

.config(rsaAutoCertificateConfig)

.signType("RSA") // 不填默认为RSA

.build();

Transaction result = service.queryOrderById(queryRequest);

LinkedHashMap map = new LinkedHashMap();

//支付成功

if (Transaction.TradeStateEnum.SUCCESS == result.getTradeState()) {

log.info("内部订单号【{}】,微信支付订单号【{}】支付成功", result.getOutTradeNo(), result.getTransactionId());

map.put("out_trade_no", result.getOutTradeNo());

map.put("transaction_id", result.getTransactionId());

map.put("success", true);

map.put("msg", "支付成功!");

map.put("success_time", DateUtils.getDateTimeString(DateUtils.stringToDateTime(result.getSuccessTime())));

//主动查询

Wrapper wrapper = new EntityWrapper<WxOrderEntity>();

wrapper.eq("transaction_id", req.getPaymentNo());

WxOrderEntity wxOrderEntity = wxOrderDataService.selectOne(wrapper);

if (wxOrderEntity != null) {

if (wxOrderEntity.getPayStatus() != 1) {

wxOrderEntity.setPayStatus(1);

wxOrderEntity.setPayDate(DateUtils.stringToDateTime(result.getSuccessTime()));

wxOrderEntity.setPayTime(DateUtils.stringToDateTime(result.getSuccessTime()));

wxOrderEntity.setUpdateTime(new Date());

wxOrderDataService.updateById(wxOrderEntity);

//同时处理支付记录

Wrapper payWrapper = new EntityWrapper<WxPayLogEntity>();

wrapper.eq("transaction_id", req.getPaymentNo());

WxPayLogEntity wxPayLogEntity = wxPayLogDataService.selectOne(payWrapper);

if (wxPayLogEntity == null) {

wxPayLogEntity = new WxPayLogEntity();

wxPayLogEntity.setCreateTime(new Date());

wxPayLogEntity.setOutTradeNo(wxOrderEntity.getOutTradeNo());

wxPayLogEntity.setPayStatus(1);

wxPayLogEntity.setTotalFee(wxOrderEntity.getTotalFee());

wxPayLogEntity.setTransactionId(result.getTransactionId());

wxPayLogEntity.setWxOpenId(wxOrderEntity.getWxOpenId());

wxPayLogDataService.insert(wxPayLogEntity);

}

}

}

} else {

log.info("内部订单号【{}】,微信支付订单号【{}】支付未成功", result.getOutTradeNo(), result.getTransactionId());

map.put("out_trade_no", result.getOutTradeNo());

map.put("transaction_id", result.getTransactionId());

map.put("success", false);

map.put("msg", "支付失败!");

map.put("success_time", null);

}

return R.ok().put("data", map);

} catch (ServiceException e) {

log.error("订单查询失败,返回码:{},返回信息:{}", e.getErrorCode(), e.getErrorMessage());

return R.error("订单查询失败!");

}

}

7、微信申请退款

/***

* 微信申请退款

* @param outTradeNo 商户订单号

* @param totalAmount

* @return

*/

public R createRefund(String outTradeNo, Long totalAmount) {

//返回参数

LinkedHashMap map = new LinkedHashMap();

map.put("out_trade_no", outTradeNo);

map.put("success", false);

map.put("msg", "正在申请退款中!");

String outRefundNo = "REFUND_" + outTradeNo;

map.put("out_refund_no", outRefundNo);

//申请退款订单,需要变更订单记录

Wrapper wrapper = new EntityWrapper<WxOrderEntity>();

wrapper.eq("out_trade_no", outTradeNo);

WxOrderEntity wxOrderEntity = wxOrderDataService.selectOne(wrapper);

if (wxOrderEntity == null) {

return R.error("订单不存在,申请退款不存在!");

}

wxOrderEntity.setPayStatus(4);//退款中

wxOrderEntity.setUpdateTime(new Date());

wxOrderDataService.updateById(wxOrderEntity);

try {

// 构建退款service

RefundService service = new RefundService.Builder()

.config(rsaAutoCertificateConfig)

.build();

CreateRequest request = new CreateRequest();

// 调用request.setXxx(val)设置所需参数,具体参数可见Request定义

request.setOutTradeNo(outTradeNo);

request.setOutRefundNo(outRefundNo);

AmountReq amount = new AmountReq();

amount.setTotal(totalAmount);

amount.setRefund(totalAmount);

amount.setCurrency("CNY");

request.setAmount(amount);

request.setNotifyUrl(wxPayConfig.getRefundNotifyUrl());

//接收退款返回参数

Refund refund = service.create(request);

log.info("退款返回信息:{}", refund);

if (refund.getStatus().equals(Status.SUCCESS)) {

map.put("success", true);

map.put("msg", "退款成功!");

//说明退款成功,开始接下来的业务操作

//主动查询

Wrapper againWrapper = new EntityWrapper<WxOrderEntity>();

againWrapper.eq("out_trade_no", outTradeNo);

WxOrderEntity orderEntity = wxOrderDataService.selectOne(againWrapper);

if (orderEntity != null) {

orderEntity.setPayStatus(3);//退款成功

orderEntity.setUpdateTime(new Date());

wxOrderDataService.updateById(orderEntity);

//同时处理退款记录

Wrapper payWrapper = new EntityWrapper<WxPayLogEntity>();

payWrapper.eq("out_trade_no", outTradeNo);

payWrapper.eq("pay_status", 2);//退款

WxPayLogEntity wxPayLogEntity = wxPayLogDataService.selectOne(payWrapper);

if (wxPayLogEntity == null) {

wxPayLogEntity = new WxPayLogEntity();

wxPayLogEntity.setCreateTime(new Date());

wxPayLogEntity.setOutTradeNo(outTradeNo);

wxPayLogEntity.setPayStatus(2);

wxPayLogEntity.setTotalFee(totalAmount.intValue());

wxPayLogEntity.setTransactionId(wxOrderEntity.getTransactionId());

wxPayLogEntity.setOutRefundNo(outRefundNo);

wxPayLogEntity.setWxOpenId(wxOrderEntity.getWxOpenId());

wxPayLogDataService.insert(wxPayLogEntity);

}

}

}

} catch (ServiceException e) {

log.error("退款失败!,错误信息:{}", e.getMessage());

return R.error("退款失败!");

} catch (Exception e) {

log.error("服务返回成功,返回体类型不合法,或者解析返回体失败,错误信息:{}", e.getMessage());

return R.error("退款失败!");

}

return R.ok().put("data", map);

}

8、退款回调通知 

待续......有需要的再联系我!

四、mysql表结构

SET NAMES utf8mb4;

SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------

-- Table structure for t_wx_order

-- ----------------------------

DROP TABLE IF EXISTS `t_wx_order`;

CREATE TABLE `t_wx_order` (

`uuid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,

`trade_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '商品名称',

`description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '订单描述',

`out_trade_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '(商户)订单流水号',

`transaction_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '微信订单号',

`total_fee` int(10) NULL DEFAULT NULL COMMENT '订单金额(单位:分)',

`pay_nonce` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '支付成功后的随机32位字符串',

`pay_time` datetime NULL DEFAULT NULL COMMENT '支付时间',

`pay_date` date NULL DEFAULT NULL COMMENT '支付日期',

`pay_status` int(3) NULL DEFAULT 0 COMMENT '0:待支付,1:支付成功,2:支付失败,3:退款成功,4:正在退款中,5:未知',

`wx_open_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '微信小程序openid',

`status` int(2) NULL DEFAULT 0 COMMENT '0:未删除,1:已删除',

`create_time` datetime NULL DEFAULT NULL COMMENT '创建订单时间',

`update_time` datetime NULL DEFAULT NULL COMMENT '修改订单时间',

PRIMARY KEY (`uuid`) USING BTREE

) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '微信商品订单表' ROW_FORMAT = Dynamic;

-- ----------------------------

-- Table structure for t_wx_pay_log

-- ----------------------------

DROP TABLE IF EXISTS `t_wx_pay_log`;

CREATE TABLE `t_wx_pay_log` (

`uuid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,

`wx_open_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '微信用户openid',

`out_trade_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '(商户)订单流水号',

`out_refund_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '(商户)退款流水号',

`transaction_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '微信订单号',

`total_fee` int(10) NULL DEFAULT NULL COMMENT '支付金额',

`pay_status` int(2) NULL DEFAULT NULL COMMENT '1:支付,2:退款',

`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',

PRIMARY KEY (`uuid`) USING BTREE

) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '微信用户支付记录表' ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;

五、controller类

退款回调通知,和controller就不写了,如果需要,联系我即可!

哎呀呀呀,缺少了一个类,代码如下:

import javax.servlet.ServletInputStream;

import javax.servlet.http.HttpServletRequest;

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

/**

* @author caozhen

* @ClassName HttpServletUtils

* @description: TODO

* @date 2024年01月04日

* @version: 1.0

*/

public class HttpServletUtils {

/**

* 获取请求体

*

* @param request

* @return

* @throws IOException

*/

public static String getRequestBody(HttpServletRequest request) throws IOException {

ServletInputStream stream = null;

BufferedReader reader = null;

StringBuffer sb = new StringBuffer();

try {

stream = request.getInputStream();

// 获取响应

reader = new BufferedReader(new InputStreamReader(stream));

String line;

while ((line = reader.readLine()) != null) {

sb.append(line);

}

} catch (IOException e) {

throw new IOException("读取返回支付接口数据流出现异常!");

} finally {

reader.close();

}

return sb.toString();

}

}

如果你在微信支付回调通知中出现 “签名错误”,并且你是windows服务器,请在HttpServletUtils 类中,将reader = new BufferedReader(new InputStreamReader(stream));   替换成:reader = new BufferedReader(new InputStreamReader(stream,"UTF-8"));

替换完整代码:

import javax.servlet.ServletInputStream;

import javax.servlet.http.HttpServletRequest;

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

/**

* @author caozhen

* @ClassName HttpServletUtils

* @description: TODO

* @date 2024年01月04日

* @version: 1.0

*/

public class HttpServletUtils {

/**

* 获取请求体

*

* @param request

* @return

* @throws IOException

*/

public static String getRequestBody(HttpServletRequest request) throws IOException {

ServletInputStream stream = null;

BufferedReader reader = null;

StringBuffer sb = new StringBuffer();

try {

stream = request.getInputStream();

// 获取响应

reader = new BufferedReader(new InputStreamReader(stream,"UTF-8"));

String line;

while ((line = reader.readLine()) != null) {

sb.append(line);

}

} catch (IOException e) {

throw new IOException("读取返回支付接口数据流出现异常!");

} finally {

reader.close();

}

return sb.toString();

}

}



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。