com.zopen.wechat.pay.service.WechatPayService Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of zopen-ato-starter Show documentation
Show all versions of zopen-ato-starter Show documentation
Alibaba Tencent And Others For Spring Boot.
package com.zopen.wechat.pay.service;
import com.zcj.util.UtilRandom;
import com.zcj.util.UtilString;
import com.zcj.util.UtilXml;
import com.zopen.ato.properties.WechatPayProperties;
import com.zopen.wechat.exception.WechatAssert;
import com.zopen.wechat.pay.dto.*;
import com.zopen.wechat.pay.dto.companypay.CompanyPayRequest;
import com.zopen.wechat.pay.dto.companypay.CompanyPayResponse;
import com.zopen.wechat.pay.util.SignUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
@Component("atoWechatPayService")
public class WechatPayService {
private static final Logger logger = LoggerFactory.getLogger(WechatPayService.class);
private static final String PAY_APP_UNIFIED_ORDER = "https://api.mch.weixin.qq.com/pay/unifiedorder";
private static final String PAY_ORDER_QUERY = "https://api.mch.weixin.qq.com/pay/orderquery";
private static final String PAY_COMPANY_TO_USER = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
@Autowired
private RestTemplate restTemplate;
@Autowired
private WechatPayProperties wechatPayProperties;
/**
* 企业付款到零钱(读取 spring boot 的 application 中的配置)
*
* @param appId *企业号appId
* @param outTradeNo *商户订单号
* @param openId *收款用户openid
* @param amount *金额,单位:分
* @param desc *企业付款备注
* @param ip *用户端或者服务端的IP
* @return com.zopen.wechat.pay.dto.CompanyPayResponse
*/
public CompanyPayResponse companyToUserByBoot(String appId, String outTradeNo, String openId, Integer amount, String desc, String ip) {
String appKey = wechatPayProperties.getAppKey();
String mchId = wechatPayProperties.getMchId();
return companyToUser(appId, appKey, mchId, outTradeNo, openId, amount, desc, ip);
}
/**
* 企业付款到零钱
*
* @param appId *商户账号appid(例:wxec38b8ff840bd989)
* @param appKey *商户平台的秘钥Key(例:192006250b4c09247ec02edce69f6a2d)
* @param mchId *商户号(例:10013274)
* @param outTradeNo *商户订单号
* @param openId *收款用户openid
* @param amount *金额,单位:分
* @param desc *企业付款备注
* @param ip *用户端或者服务端的IP
* @return com.zopen.wechat.pay.dto.CompanyPayResponse
*/
public CompanyPayResponse companyToUser(String appId, String appKey, String mchId, String outTradeNo, String openId, Integer amount, String desc, String ip) {
// 验证参数
WechatAssert.notNullAndEmpty(appId, "appId 不能为空");
WechatAssert.notNullAndEmpty(appKey, "appKey 不能为空");
WechatAssert.notNullAndEmpty(mchId, "mchId 不能为空");
WechatAssert.notNullAndEmpty(outTradeNo, "outTradeNo 不能为空");
WechatAssert.notNullAndEmpty(openId, "openId 不能为空");
WechatAssert.notNull(amount, "amount 不能为空");
WechatAssert.notNullAndEmpty(desc, "desc 不能为空");
WechatAssert.notNullAndEmpty(ip, "ip 不能为空");
WechatAssert.checkArgument(amount != null && amount > 0, "amount 取值错误");
// 构建请求参数
CompanyPayRequest request = new CompanyPayRequest();
request.setNonce_str(UtilRandom.getRandomChar(16));
request.setMch_appid(appId);
request.setMchid(mchId);
request.setPartner_trade_no(outTradeNo);
request.setOpenid(openId);
request.setCheck_name("NO_CHECK");
request.setAmount(amount);
request.setDesc(desc);
request.setSpbill_create_ip(ip);
// 签名
String sign = SignUtil.getSign(request, appKey);
WechatAssert.notNullAndEmpty(sign, "签名失败");
request.setSign(sign);
// 发送请求
String responseXml = post(PAY_COMPANY_TO_USER, request, "企业付款到零钱");
CompanyPayResponse response = UtilXml.convertXmlStrToObject(CompanyPayResponse.class, responseXml);
// 验证返回的结果
if (!response.success()) {
WechatAssert.notNull(null, response.errorInfo());
}
return response;
}
/**
* 查询订单
*
* @param outTradeNo * 商户订单号
* @param appId * 公众号或小程序的appId
* @return com.zopen.wechat.pay.dto.QueryResponse
*/
public QueryResponse orderQuery(String outTradeNo, String appId) {
// 验证参数
WechatAssert.notNullAndEmpty(appId, "appId 未设置");
WechatAssert.notNullAndEmpty(wechatPayProperties.getAppKey(), "appKey 未设置");
WechatAssert.notNullAndEmpty(wechatPayProperties.getMchId(), "mchId 未设置");
WechatAssert.notNullAndEmpty(outTradeNo, "outTradeNo 不能为空");
// 构建请求参数
QueryRequest request = new QueryRequest();
request.setAppid(appId);
request.setMch_id(wechatPayProperties.getMchId());
request.setOut_trade_no(outTradeNo);
request.setNonce_str(UtilRandom.getRandomChar(16));
// 签名
String sign = SignUtil.getSign(request, wechatPayProperties.getAppKey());
WechatAssert.notNullAndEmpty(sign, "签名失败");
request.setSign(sign);
// 发送请求
String responseXml = post(PAY_ORDER_QUERY, request, "查询订单");
QueryResponse response = UtilXml.convertXmlStrToObject(QueryResponse.class, responseXml);
// 验证返回的结果
if (!response.success()) {
WechatAssert.notNull(null, response.errorInfo());
}
// 验证签名
String responseSign = response.getSign();
String responseSign2 = SignUtil.getSign(response, wechatPayProperties.getAppKey());
if (!responseSign.equals(responseSign2)) {
WechatAssert.notNull(null, "签名错误");
}
return response;
}
/**
* 统一下单(APP 下单),装箱后返回给客户端
*
* @param appId * 小程序或公众号的appId
* @param body * 商品描述
* @param clientIp * 终端IP
* @param totalFee * 总金额,单位:分
* @param outTradeNo * 商户订单号
* @return 需要传给 APP 的内容
*/
public AppPayClientDto unifiedOrderByApp(String appId, String body, String clientIp, Integer totalFee, String outTradeNo) {
PayResponse response = unifiedOrderBase(appId, body, clientIp, totalFee, outTradeNo, 1, null);
return AppPayClientDto.formAppPayResponse(response, wechatPayProperties.getAppKey());
}
/**
* 统一下单(Native 下单)
*
* @param appId * 小程序或公众号的appId
* @param body * 商品描述
* @param clientIp * 终端IP
* @param totalFee * 总金额,单位:分
* @param outTradeNo * 商户订单号
* @return 微信返回的内容
*/
public PayResponse unifiedOrderByNative(String appId, String body, String clientIp, Integer totalFee, String outTradeNo) {
return unifiedOrderBase(appId, body, clientIp, totalFee, outTradeNo, 2, null);
}
/**
* 统一下单(小程序下单、微信浏览器H5下单)
*
* @param appId * 小程序或公众号的appId
* @param body * 商品描述
* @param clientIp * 终端IP
* @param totalFee * 总金额,单位:分
* @param outTradeNo * 商户订单号
* @param openId * 微信用户open_id
* @return 需要传给小程序的内容
*/
public JsApiPayClientDto unifiedOrderByJsApi(String appId, String body, String clientIp, Integer totalFee, String outTradeNo, String openId) {
PayResponse response = unifiedOrderBase(appId, body, clientIp, totalFee, outTradeNo, 3, openId);
return JsApiPayClientDto.formPayResponse(response, wechatPayProperties.getAppKey());
}
// payType(1:APP 下单;2:Native 下单;3:小程序下单/微信浏览器H5下单)
private PayResponse unifiedOrderBase(String appId, String body, String clientIp, Integer totalFee, String outTradeNo, Integer payType, String openIdByJsApi) {
// 验证参数
WechatAssert.notNullAndEmpty(appId, "appId 未设置");
WechatAssert.notNullAndEmpty(wechatPayProperties.getAppKey(), "appKey 未设置");
WechatAssert.notNullAndEmpty(wechatPayProperties.getMchId(), "mchId 未设置");
WechatAssert.notNullAndEmpty(wechatPayProperties.getDomainUrl(), "domainUrl 未设置");
WechatAssert.notNullAndEmpty(body, "body 不能为空");
WechatAssert.notNullAndEmpty(clientIp, "clientId 不能为空");
WechatAssert.checkArgument(totalFee != null && totalFee > 0, "totalFee 取值错误");
WechatAssert.notNullAndEmpty(outTradeNo, "outTradeNo 不能为空");
// 构建请求参数 https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1
PayRequest request = new PayRequest();
if (payType == 1) {
request.initAppPay();
} else if (payType == 2) {
request.initNativePay(outTradeNo);
} else if (payType == 3) {
request.initJsAPI(openIdByJsApi);
}
request.setAppid(appId);
request.setMch_id(wechatPayProperties.getMchId());
request.setBody(body);
request.setOut_trade_no(outTradeNo);
request.setTotal_fee(totalFee);
request.setSpbill_create_ip(clientIp);
request.setNotify_url(wechatPayProperties.getDomainUrl() + "/ato/wechat/pay/callback");
// 签名
String sign = SignUtil.getSign(request, wechatPayProperties.getAppKey());
WechatAssert.notNullAndEmpty(sign, "签名失败");
request.setSign(sign);
// 发送请求
String responseXml = post(PAY_APP_UNIFIED_ORDER, request, "统一下单");
PayResponse response = UtilXml.convertXmlStrToObject(PayResponse.class, responseXml);
// 验证返回的结果
if (!response.success()) {
WechatAssert.notNull(null, response.errorInfo());
}
// 验证签名
String responseSign = response.getSign();
String responseSign2 = SignUtil.getSign(response, wechatPayProperties.getAppKey());
if (!responseSign.equals(responseSign2)) {
WechatAssert.notNull(null, "签名错误");
}
return response;
}
private String post(String url, Object request, String requestName) {
String body = UtilXml.convertToXml(request);
String rid = UtilString.getSoleCode();
logger.info(">>发送{}请求[{}]:\n{}", requestName, rid, body);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_XML);
HttpEntity formEntity = new HttpEntity<>(body, headers);
ResponseEntity responseEntity = restTemplate.postForEntity(url, formEntity, String.class);
String result = responseEntity.getBody();
logger.info("<<返回内容[{}]:\n{}", rid, result);
return result;
}
// --------------------------------
@Deprecated
public QueryResponse orderQuery(String outTradeNo) {
return orderQuery(outTradeNo, wechatPayProperties.getAppId());
}
@Deprecated
public CompanyPayResponse companyToUserByBoot(String outTradeNo, String openId, Integer amount, String desc, String ip) {
String mchAppId = wechatPayProperties.getAppId();
String appKey = wechatPayProperties.getAppKey();
String mchId = wechatPayProperties.getMchId();
return companyToUser(mchAppId, appKey, mchId, outTradeNo, openId, amount, desc, ip);
}
@Deprecated
public AppPayClientDto unifiedOrderByAppToClientDto(String body, String clientIp, Integer totalFee, String outTradeNo) {
return unifiedOrderByApp(wechatPayProperties.getAppId(), body, clientIp, totalFee, outTradeNo);
}
@Deprecated
public PayResponse unifiedOrderByApp(String body, String clientIp, Integer totalFee, String outTradeNo) {
return unifiedOrderBase(wechatPayProperties.getAppId(), body, clientIp, totalFee, outTradeNo, 1, null);
}
@Deprecated
public PayResponse unifiedOrderByNative(String body, String clientIp, Integer totalFee, String outTradeNo) {
return unifiedOrderByNative(wechatPayProperties.getAppId(), body, clientIp, totalFee, outTradeNo);
}
@Deprecated
public JsApiPayClientDto unifiedOrderByJsApi(String body, String clientIp, Integer totalFee, String outTradeNo, String openId) {
return unifiedOrderByJsApi(wechatPayProperties.getAppId(), body, clientIp, totalFee, outTradeNo, openId);
}
}