Java后端对接微信支付(微信小程序、APP、PC端扫码)非常全,包含查单、退款

最后

ActiveMQ消息中间件面试专题

  • 什么是ActiveMQ?
  • ActiveMQ服务器宕机怎么办?
  • 丢消息怎么办?
  • 持久化消息非常慢怎么办?
  • 消息的不均匀消费怎么办?
  • 死信队列怎么办?
  • ActiveMQ中的消息重发时间间隔和重发次数吗?

ActiveMQ消息中间件面试专题解析拓展:

BAT面试文档:ActiveMQ+redis+Spring+高并发多线程+JVM


redis面试专题及答案

  • 支持一致性哈希的客户端有哪些?
  • Redis与其他key-value存储有什么不同?
  • Redis的内存占用情况怎么样?
  • 都有哪些办法可以降低Redis的内存使用情况呢?
  • 查看Redis使用情况及状态信息用什么命令?
  • Redis的内存用完了会发生什么?
  • Redis是单线程的,如何提高多核CPU的利用率?

BAT面试文档:ActiveMQ+redis+Spring+高并发多线程+JVM


Spring面试专题及答案

  • 谈谈你对 Spring 的理解
  • Spring 有哪些优点?
  • Spring 中的设计模式
  • 怎样开启注解装配以及常用注解
  • 简单介绍下 Spring bean 的生命周期

Spring面试答案解析拓展

BAT面试文档:ActiveMQ+redis+Spring+高并发多线程+JVM


高并发多线程面试专题

  • 现在有线程 T1、T2 和 T3。你如何确保 T2 线程在 T1 之后执行,并且 T3 线程在 T2 之后执行?
  • Java 中新的 Lock 接口相对于同步代码块(synchronized block)有什么优势?如果让你实现一个高性能缓存,支持并发读取和单一写入,你如何保证数据完整性。
  • Java 中 wait 和 sleep 方法有什么区别?
  • 如何在 Java 中实现一个阻塞队列?
  • 如何在 Java 中编写代码解决生产者消费者问题?
  • 写一段死锁代码。你在 Java 中如何解决死锁?

高并发多线程面试解析与拓展

BAT面试文档:ActiveMQ+redis+Spring+高并发多线程+JVM


jvm面试专题与解析

  • JVM 由哪些部分组成?
  • JVM 内存划分?
  • Java 的内存模型?
  • 引用的分类?
  • GC什么时候开始?

JVM面试专题解析与拓展!

BAT面试文档:ActiveMQ+redis+Spring+高并发多线程+JVM

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

m.put(“mch_id”, OrderUtils.MCH_ID);

m.put(“nonce_str”, WXPayUtil.generateNonceStr());

//商品描述 例如:天天爱消除-游戏充值

m.put(“body”, “换芯易-” + order.getGoodsModel() + “购买”);

//订单号

m.put(“out_trade_no”, order.getOrderSn());

m.put(“total_fee”, order.getActualPrice().multiply(new BigDecimal(“100”)).longValue() + “”);

m.put(“spbill_create_ip”, clientIp);

m.put(“notify_url”, OrderUtils.NOTIFY_URL);

m.put(“trade_type”, “NATIVE”);

//trade_type=NATIVE时,此参数必传

m.put(“product_id”, order.getId());

//生成签名

m.put(“sign”, WXPayUtil.generateSignature(m, OrderUtils.APP_KEY));

//发送请求,请求路径:UNIFIED_ORDER_URL = “https://api.mch.weixin.qq.com/pay/unifiedorder”

HttpClient client = new HttpClient(OrderUtils.UNIFIED_ORDER_URL);

//设置xml格式的参数,要把map转为xml

client.setXmlParam(WXPayUtil.mapToXml(m));

//设置支持https

client.setHttps(true);

//执行请求发送

client.post();

//xml转为map接受结果

Map<String, String> response = WXPayUtil.xmlToMap(client.getContent());

long end = System.currentTimeMillis();

System.out.println(“请求https://api.mch.weixin.qq.com/pay/unifiedorder耗时:” + (end - begin) + “ms”);

System.out.println(“请求结果:” + JSON.toJSONString(response));

if (“SUCCESS”.equals(response.get(“return_code”)) && “SUCCESS”.equals(response.get(“result_code”))) {

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

//二维码地址

param.put(“code_url”, response.get(“code_url”));

param.put(“order_sn”, order.getOrderSn());

param.put(“order_id”, order.getId());

param.put(“total_fee”, order.getActualPrice().multiply(new BigDecimal(“100”)).longValue() + “”);

return param;

}

//为空代表下单失败

return null;

}

上面代码中最重要的返回结果就是code_url。即生成的支付二维码地址,然后用微信扫码并付款即可。

4.APP统一下单


应用场景是APP端调用微信支付,对接uniapp开发的app

归纳如下:

appidAPP的app_id
mch_id商户号
nonce_str随机字符串,可以调用 WXPayUtil下 generateNonceStr方法生成
sign

可以调用 WXPayUtil下 generateSignature方法生成,这个方法需要用到准备工作中的商户API密钥(APP_KEY)来加密。

body商品描述,建议软件名字+产品操作,例如天天爱消除-游戏充值
out_trade_no我们自己生成的订单号,保证同一商号下唯一即可
total_fee金额,注意单位是分
spbill_create_ip用户客户端ip
notify_url支付结果通知回调地址
trade_type交易类型,我们这里填APP

但是下完单之后,怎么样才能让前端调用微信支付呢?这里需要查看uniapp 官方文档 微信小程序支付:

我们可以看到常规的比如 appid、商户号 需要,充要的是预支付id prepayid和签名 。

代码实现如下:

public Map<String, String> unifiedOrderByApp(Order order, String clientIp) throws Exception {

long begin = System.currentTimeMillis();

//使用map封装微信支付需要的固定参数

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

//1、设置支付参数

m.put(“appid”, OrderUtils.APP_APP_ID);

m.put(“mch_id”, OrderUtils.MCH_ID);

m.put(“nonce_str”, WXPayUtil.generateNonceStr());

//商品描述 例如:天天爱消除-游戏充值

m.put(“body”, “换芯易-” + order.getGoodsModel() + “购买”);

//订单号

m.put(“out_trade_no”, order.getOrderSn());

m.put(“total_fee”, order.getActualPrice().multiply(new BigDecimal(“100”)).longValue() + “”);

m.put(“spbill_create_ip”, clientIp);

m.put(“notify_url”, OrderUtils.NOTIFY_URL);

m.put(“trade_type”, “APP”);

//生成签名

m.put(“sign”, WXPayUtil.generateSignature(m, OrderUtils.APP_KEY));

//发送请求,请求路径:UNIFIED_ORDER_URL = “https://api.mch.weixin.qq.com/pay/unifiedorder”

HttpClient client = new HttpClient(OrderUtils.UNIFIED_ORDER_URL);

//设置xml格式的参数,要把map转为xml

client.setXmlParam(WXPayUtil.mapToXml(m));

//设置支持https

client.setHttps(true);

//执行请求发送

client.post();

//xml转为map接受结果

Map<String, String> response = WXPayUtil.xmlToMap(client.getContent());

long end = System.currentTimeMillis();

System.out.println(“请求https://api.mch.weixin.qq.com/pay/unifiedorder耗时:” + (end - begin) + “ms”);

System.out.println(“请求结果:” + JSON.toJSONString(response));

if (“SUCCESS”.equals(response.get(“return_code”)) && “SUCCESS”.equals(response.get(“result_code”))) {

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

param.put(“appid”, OrderUtils.APP_APP_ID);

//随机字符串

param.put(“noncestr”, WXPayUtil.generateNonceStr());

//固定值

param.put(“package”, “Sign=WXPay”);

param.put(“partnerid”, OrderUtils.MCH_ID);

param.put(“prepayid”, response.get(“prepay_id”));

//时间戳,但是单位为s,不是毫秒

param.put(“timestamp”, String.valueOf(System.currentTimeMillis() / 1000));

//param.put(“package”, response.get(“sign”));

param.put(“sign”, WXPayUtil.generateSignature(param, OrderUtils.APP_KEY));

return param;

}

//为空代表下单失败

return null;

}

按照uniapp官方要求的格式封装返回结果给前端。

5.三种支付方式返回结果


对于上面三种支付方式,他们的返回结果我都没有细细分析,因为官方文档写得很详细,我们非常需要关注的也就预支付id这个返回结果。所以贴一下官方文档,有兴趣可以仔细看看(重要的我会标注)

共有

其中APP和JSAPI得着重关注 预支付id

native扫码支付主要关注 code_url

6.查单


我们实际业务中,过于依赖微信支付的回调结果来判断订单状态显然是不太合适的,所以自己去查单这种操作十分常见。查单需要的必填参数归纳如下:

appidapp_id
mch_id商户号
nonce_str随机字符串,可以调用 WXPayUtil下 generateNonceStr方法生成
sign

可以调用 WXPayUtil下 generateSignature方法生成,这个方法需要用到准备工作中的商户API密钥(APP_KEY)来加密。

out_trade_no我们自己生成的订单号,保证同一商号下唯一即可,这个订单号需要和我们当时调用统一下单传过去的单号一致

ps:这里的out_trade_no可以用transaction_id代替,但是一般我们查单的时候可能还没有transaction_id,所以只能用我们自己程序业务订单号out_trade_no去查,因为transaction_id需要调查单接口才能得到,也就是说如果我们以后"二次查单"可以用这个参数。

代码实现入下:

public Map<String, String> queryOrderStatus(String orderSn) throws Exception {

long beginTime = System.currentTimeMillis();

//1、封装参数

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

m.put(“appid”, OrderUtils.APP_APP_ID);

m.put(“mch_id”, OrderUtils.MCH_ID);

m.put(“out_trade_no”, orderSn);

m.put(“nonce_str”, WXPayUtil.generateNonceStr());

//生成签名

m.put(“sign”, WXPayUtil.generateSignature(m, OrderUtils.APP_KEY));

//发送请求,请求路径:UNIFIED_ORDER_URL = “https://api.mch.weixin.qq.com/pay/orderquery”

HttpClient client = new HttpClient(OrderUtils.ORDER_QUERY_URL);

client.setXmlParam(WXPayUtil.mapToXml(m));

client.setHttps(true);

client.post();

//3、返回第三方的数据

Map<String, String> result = WXPayUtil.xmlToMap(client.getContent());

long endTime = System.currentTimeMillis();

System.out.println(“请求https://api.mch.weixin.qq.com/pay/orderquery耗时:” + (endTime - beginTime) + “ms”);

System.out.println(“请求结果:” + JSON.toJSONString(result));

return result;

}

返回结果参数部分如下,重要的标注起来:

一般情况下主要是利用trade_state来判断用户是否支付成功从而更新订单或记录交易成功物流等业务操作。

Map<String, String> map = orderDao.queryOrderStatus(orderSn);

if (map == null) {

return ApiResponse.createApiResponse(ApiResponse.HTTP_STATE_400_ERROR_10001, “微信支付出错”);

}

//微信

if (“SUCCESS”.equals(map.get(“trade_state”))) {

//更新订单或记录交易成功物流等业务操作

}

7.退款


言简意赅,就是方便( rnm,退钱 )

重要参数

appidapp_id
mch_id商户号
nonce_str随机字符串,可以调用 WXPayUtil下 generateNonceStr方法生成
sign

可以调用 WXPayUtil下 generateSignature方法生成,这个方法需要用到准备工作中的商户API密钥(APP_KEY)来加密。

out_trade_no我们自己生成的订单号,保证同一商号下唯一即可,这个订单号需要和我们当时调用统一下单传过去的单号一致
transaction_id和上面的out_trade_no 二选一 ,官方推荐transaction_id
out_refund_no其实和统一下单的时候的订单号原理差不多,我们自己随机生成一个,保证同一商户系统下唯一即可
total_fee要退款的订单的金额
refund_fee实际要退款的金额

代码实现如下:

public Map<String, String> refundOrder(RefundTrace refundTrace, Order order) throws Exception {

long begin = System.currentTimeMillis();

//使用map封装微信支付需要的固定参数

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

//1、设置支付参数

m.put(“appid”, OrderUtils.WX_APP_ID);

m.put(“mch_id”, OrderUtils.MCH_ID);

m.put(“nonce_str”, WXPayUtil.generateNonceStr());

//微信支付订单号

m.put(“transaction_id”, order.getPayId());

//商户退款单号

m.put(“out_refund_no”, refundTrace.getRefundSn());

//订单金额

m.put(“total_fee”, order.getActualPrice().multiply(new BigDecimal(“100”)).longValue() + “”);

//退款金额 即实际退款金额

m.put(“refund_fee”, refundTrace.getRefundAmount().multiply(new BigDecimal(“100”)).longValue() + “”);

//退款原因

m.put(“refund_desc”, refundTrace.getRefundReason());

m.put(“notify_url”, OrderUtils.NOTIFY_URL);

//生成签名

m.put(“sign”, WXPayUtil.generateSignature(m, OrderUtils.APP_KEY));

发送请求,请求路径:ORDER_REFUND_URL = “https://api.mch.weixin.qq.com/secapi/pay/refund”

String content = HttpRequestUtils.refundRequest(WXPayUtil.mapToXml(m));

//xml转为map接受结果

Map<String, String> response = WXPayUtil.xmlToMap(content);

long end = System.currentTimeMillis();

System.out.println(“请求https://api.mch.weixin.qq.com/secapi/pay/refund耗时:” + (end - begin) + “ms”);

System.out.println(“请求结果:” + JSON.toJSONString(response));

if (“SUCCESS”.equals(response.get(“return_code”)) && “SUCCESS”.equals(response.get(“result_code”))) {

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

param.put(“refund_id”, response.get(“refund_id”));

param.put(“refund_fee”, response.get(“refund_fee”));

return param;

}

//为空代表退款失败

return null;

}

这里注意一下!!!! 因为操作涉及到把商户方的钱转回到买方的操作,所以安全系数比较高,调用退款api官方要求证书

证书申请途径如下:

微信商户平台(pay.weixin.qq.com)–>账户中心–>账户设置–>API安全–>申请API证书

申请到证书,需要放到项目下:

那么我们这里的http请求就不能用之前的了,需要配置该证书

上面代码中使用的refundRequest函数细节如下:

public static String refundRequest(String order) throws Exception {

try {

KeyStore clientStore = KeyStore.getInstance(“PKCS12”);

// 读取项目存放的PKCS12证书文件

FileInputStream instream = new FileInputStream(“apiclient_cert.p12”);

try {

// 指定PKCS12的密码(商户ID)

clientStore.load(instream, OrderUtils.MCH_ID.toCharArray());

} finally {

instream.close();

}

SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(clientStore, OrderUtils.MCH_ID.toCharArray()).build();

// 指定TLS版本

SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{“TLSv1”}, null,

SSLConnectionSocketFactory.getDefaultHostnameVerifier());

// 设置httpclient的SSLSocketFactory

CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();

try {

HttpPost httpost = new HttpPost(OrderUtils.ORDER_REFUND_URL); // 设置响应头信息

// httpost.addHeader(“Connection”, “keep-alive”);

// httpost.addHeader(“Accept”, “*/*”);

// httpost.addHeader(“Content-Type”, CONTENT_TYPE_FORM.toString());

// httpost.addHeader(“X-Requested-With”, “XMLHttpRequest”);

// httpost.addHeader(“Cache-Control”, “max-age=0”);

// httpost.addHeader(“User-Agent”, DEFAULT_USER_AGENT);

httpost.setEntity(new StringEntity(order, “UTF-8”));

CloseableHttpResponse response = httpclient.execute(httpost);

try {

HttpEntity entity = response.getEntity();

String jsonStr = EntityUtils.toString(response.getEntity(), “UTF-8”);

EntityUtils.consume(entity);

return jsonStr;

} finally {

response.close();

}

} finally {

httpclient.close();

}

} catch (Exception e) {

throw new RuntimeException(e);

}

}

8.补充


我所使用的HttpClient工具类源码,我这里使用主要用于发送带xml参数的post请求

public class HttpClient {

private String url;

private Map<String, String> param;

private int statusCode;

private String content;

private String xmlParam;

private boolean isHttps;

public boolean isHttps() {

return isHttps;

}

public void setHttps(boolean isHttps) {

this.isHttps = isHttps;

}

public String getXmlParam() {

return xmlParam;

}

public void setXmlParam(String xmlParam) {

this.xmlParam = xmlParam;

}

public HttpClient(String url, Map<String, String> param) {

this.url = url;

this.param = param;

}

public HttpClient(String url) {

this.url = url;

}

public void setParameter(Map<String, String> map) {

param = map;

}

public void addParameter(String key, String value) {

if (param == null) {

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

}

param.put(key, value);

}

public void post() throws ClientProtocolException, IOException {

HttpPost http = new HttpPost(url);

setEntity(http);

execute(http);

}

public void put() throws ClientProtocolException, IOException {

HttpPut http = new HttpPut(url);

最后

毕竟工作也这么久了 ,除了途虎一轮,也七七八八面试了不少大厂,像阿里、饿了么、美团、滴滴这些面试过程就不一一写在这篇文章上了。我会整理一份详细的面试过程及大家想知道的一些问题细节

美团面试经验

美团面试
字节面试经验
字节面试
菜鸟面试经验
菜鸟面试
蚂蚁金服面试经验
蚂蚁金服
唯品会面试经验
唯品会

因篇幅有限,图文无法详细发出

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

d post() throws ClientProtocolException, IOException {

HttpPost http = new HttpPost(url);

setEntity(http);

execute(http);

}

public void put() throws ClientProtocolException, IOException {

HttpPut http = new HttpPut(url);

最后

毕竟工作也这么久了 ,除了途虎一轮,也七七八八面试了不少大厂,像阿里、饿了么、美团、滴滴这些面试过程就不一一写在这篇文章上了。我会整理一份详细的面试过程及大家想知道的一些问题细节

美团面试经验

[外链图片转存中…(img-E7B0q5RV-1715293998612)]
字节面试经验
[外链图片转存中…(img-P3hOmbQf-1715293998612)]
菜鸟面试经验
[外链图片转存中…(img-qPZkubRv-1715293998613)]
蚂蚁金服面试经验
[外链图片转存中…(img-8k8qZIgN-1715293998613)]
唯品会面试经验
[外链图片转存中…(img-08owAR9s-1715293998613)]

因篇幅有限,图文无法详细发出

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

  • 23
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对接微信支付,你需要使用微信支付提供的开发工具包(SDK)来实现支付功能。以下是一个简单示例,展示如何使用Java代码对接微信支付: ```java import com.github.wxpay.sdk.WXPay; import com.github.wxpay.sdk.WXPayConfig; import com.github.wxpay.sdk.WXPayConstants; import com.github.wxpay.sdk.WXPayUtil; import java.util.HashMap; import java.util.Map; public class WechatPaymentProgram { public static void main(String[] args) { // 商户号 String mchId = "your_mch_id"; // 商户密钥 String key = "your_mch_key"; // 应用ID String appId = "your_app_id"; // 回调URL String notifyUrl = "your_notify_url"; // 创建配置对象 WXPayConfig config = new WXPayConfig() { @Override public String getAppID() { return appId; } @Override public String getMchID() { return mchId; } @Override public String getKey() { return key; } }; // 创建WXPay对象 WXPay wxPay = new WXPay(config, WXPayConstants.SignType.MD5); // 创建订单参数 Map<String, String> data = new HashMap<>(); data.put("body", "商品描述"); data.put("out_trade_no", "商户订单号"); data.put("total_fee", "订单金额(单位为分)"); data.put("spbill_create_ip", "用户IP地址"); data.put("notify_url", notifyUrl); data.put("trade_type", "NATIVE"); // 支付 try { // 调用统一下单接口 Map<String, String> resp = wxPay.unifiedOrder(data); // 判断返回结果 if ("SUCCESS".equals(resp.get("return_code")) && "SUCCESS".equals(resp.get("result_code"))) { String qrCodeUrl = resp.get("code_url"); // 获取支付二维码链接 System.out.println("请描以下二维码进行支付:" + qrCodeUrl); // TODO: 根据实际情况处理支付结果通知等逻辑 } else { System.out.println("下单失败:" + resp.get("return_msg")); } } catch (Exception e) { e.printStackTrace(); } } } ``` 在这个示例中,你需要替换代码中的 `your_mch_id`、`your_mch_key`、`your_app_id`和 `your_notify_url` 分别为你的微信商户号、商户密钥、应用ID和支付结果通知URL。然后根据实际情况填充订单参数,调用统一下单接口获取支付二维码链接,并输出给用户。最后根据微信支付结果通知的回调结果处理支付结果逻辑。 请注意,这只是一个简单的示例,并没有完整考虑所有的异常情况和业务逻辑。在实际应用中,你还需要处理用户支付后的回调通知、订单查询、退款等功能。建议阅读微信支付官方文档和相关SDK的使用文档,了解完整的接口和流程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值