本编在对接V3支付的时候连连撞头,希望后来人能少走点弯路,如果有bug请海涵啊,希望各位大佬也能给我点意见,话不多说上代码:
service层
package com.tiyaa.mall.pay.service.impl;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.squareup.okhttp.HttpUrl;
import com.tiyaa.mall.common.enums.CommonEnum;
import com.tiyaa.mall.common.exceptions.BackendException;
import com.tiyaa.mall.pay.config.WeChatConfig;
import com.tiyaa.mall.pay.config.WeChatPayConfig;
import com.tiyaa.mall.pay.constants.WeChatConstant;
import com.tiyaa.mall.pay.dto.BuyCreateDto;
import com.tiyaa.mall.pay.dto.BuyUrlMapBo;
import com.tiyaa.mall.pay.enums.PayTypeEnum;
import com.tiyaa.mall.pay.enums.WeChatApiTypeEnum;
import com.tiyaa.mall.pay.service.WeChatPayService;
import com.tiyaa.mall.pay.utils.PayUtil;
import com.tiyaa.mall.pay.vo.QueryPayVo;
import com.tiyaa.mall.pay.vo.QueryRefundVo;
import com.wechat.pay.contrib.apache.httpclient.auth.ScheduledUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;/*** @author xyl* @date 2022/8/23 10:33* @explain*/
@Slf4j
@Service
public class WeChatPayServiceImpl extends WeChatConfig implements WeChatPayService {@Resourceprivate CloseableHttpClient wxPayClient;@Autowiredprivate ScheduledUpdateCertificatesVerifier verifier;@Autowiredprivate WeChatPayConfig weChatPayConfig;/*** 微信下单** @param dto* @return {@link {@link HashMap < String, String>}}* @author xyl* @date 2022/7/12 16:22* @explain*/@Overridepublic HashMap<String, String> buy(BuyCreateDto dto) {//下单mapBuyUrlMapBo bo = getBuyUrlMapBo(dto);HashMap<String, Object> buyMap = bo.getBuyMap();//支付金额封装mapHashMap<String, Object> amountMap = new HashMap<>();amountMap.put("total", dto.getTotal());amountMap.put("currency", "CNY");//加入金额buyMap.put("amount", amountMap);try {//生成签名Gson gson = new Gson();String json = gson.toJson(buyMap);HttpUrl httpurl = HttpUrl.parse(domainUrl.concat(WeChatApiTypeEnum.GET_CERTIFICATES.getType()));HashMap<String, String> token = getToken(WeChatConstant.GET, httpurl, json);HttpPost httpPost = new HttpPost(bo.getUrl());StringEntity entity = new StringEntity(json, "utf-8");entity.setContentType("application/json");httpPost.setEntity(entity);httpPost.setHeader("Accept", "application/json");CloseableHttpResponse response = wxPayClient.execute(httpPost);//响应体String bodyAsString = EntityUtils.toString(response.getEntity());JSONObject jsonObject = JSON.parseObject(bodyAsString);System.out.println("响应体" + bodyAsString);//响应状态码int statusCode = response.getStatusLine().getStatusCode();System.out.println("状态码" + statusCode);if (statusCode != 200) {throw new BackendException(bodyAsString);}//封装返回参数return getResMap(dto.getPayType(), buyMap, token, jsonObject);} catch (Exception e) {log.warn("微信支付失败,错误信息:{}", e.getMessage());System.out.println(("微信支付失败,错误信息:{}" + e.getMessage()));throw new BackendException(CommonEnum.PARAMETER_ERROR);}}private boolean verifiedSign(String serialNo, String signStr, String signature) {return verifier.verify(serialNo, signStr.getBytes(StandardCharsets.UTF_8), signature);}/*** 微信下单组装返回** @param buyMap 支付map* @param token 签名* @param jsonObject 下单返回结果* @return {@link {@link HashMap< String, String>}}* @author xyl* @date 2022/7/12 16:05* @explain*/private HashMap<String, String> getResMap(Integer payType, HashMap<String, Object> buyMap, HashMap<String, String> token, JSONObject jsonObject) throws InvalidKeyException, SignatureException {HashMap<String, String> resMap = new HashMap<>();StringBuilder stringBuilder = new StringBuilder();String appid = buyMap.get("appid").toString();resMap.put("appId", appid);stringBuilder.append(appid).append("\n").append(token.get("timestamp")).append("\n").append(token.get("nonce_str")).append("\n");if (payType.equals(PayTypeEnum.WX_APP_WECHAT_PAY.getCode()) || payType.equals(PayTypeEnum.WX_H5_WECHAT_PAY.getCode())) {resMap.put("package", "prepay_id=" + jsonObject.get("prepay_id").toString());stringBuilder.append(resMap.get("package")).append("\n");} else {resMap.put("package", WeChatConstant.PACKAGE);resMap.put("prepayId", jsonObject.get("prepay_id").toString());resMap.put("partnerId", token.get("mchid"));stringBuilder.append(jsonObject.get("prepay_id").toString()).append("\n");}resMap.put("nonceStr", token.get("nonce_str"));resMap.put("timeStamp", token.get("timestamp"));log.warn("签名字符串:" + stringBuilder);String sign = sign(stringBuilder.toString().getBytes(StandardCharsets.UTF_8));log.warn("获取的签名:" + sign);resMap.put("signType", "RSA");resMap.put("paySign", sign);System.out.println(resMap);return resMap;}/*** 构建下单基础信息** @param dto* @return {@link {@link HashMap< String, Object>}}* @author xyl* @date 2022/7/12 9:18* @explain*/private BuyUrlMapBo getBuyUrlMapBo(BuyCreateDto dto) {BuyUrlMapBo bo = new BuyUrlMapBo();HashMap<String, Object> buyMap = new HashMap<>();//微信小程序if (dto.getPayType() == PayTypeEnum.WX_APP_WECHAT_PAY.getCode()) {//小程序appIdbuyMap.put(WeChatConstant.APP_ID, smallAppId);//用户openIdHashMap<String, Object> payerMap = new HashMap<>();payerMap.put("openid", dto.getOpenId());buyMap.put("payer", payerMap);//微信api接口String url = domainUrl.concat(WeChatApiTypeEnum.JSAPI_PAY.getType());bo.setUrl(url);//微信app} else if (dto.getPayType() == PayTypeEnum.APP_WECHAT_PAY.getCode()) {buyMap.put(WeChatConstant.APP_ID, appAppId);//微信api接口String url = domainUrl.concat(WeChatApiTypeEnum.APP_PAY.getType());bo.setUrl(url);//微信H5 jsapi支付,本质上不算H5支付,只能公众号内部调用} else if (dto.getPayType() == PayTypeEnum.WX_H5_WECHAT_PAY.getCode()) {buyMap.put(WeChatConstant.APP_ID, h5AppId);//用户openIdHashMap<String, Object> payerMap = new HashMap<>();payerMap.put("openid", dto.getOpenId());buyMap.put("payer", payerMap);//微信api接口String url = domainUrl.concat(WeChatApiTypeEnum.JSAPI_PAY.getType());bo.setUrl(url);} else {log.warn("发起支付失败,支付方式错误,请求参数:{}", dto);throw new BackendException(CommonEnum.PARAMETER_ERROR);}buyMap.put(WeChatConstant.MCH_ID, mchId);buyMap.put("description", "商品购买");buyMap.put("out_trade_no", dto.getOutTradeNo());buyMap.put("notify_url", payNotifyUrl);bo.setBuyMap(buyMap);return bo;}/*** 获取微信支付平台证书** @param method 提交方式* @param url 接口* @param body 主体* @return {@link {@link String}}* @author xyl* @date 2022/7/12 10:45* @explain*/public HashMap<String, String> getToken(String method, HttpUrl url, String body) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException {//随机字符串String nonceStr = PayUtil.createNonceStr();//当前时间戳long timestamp = System.currentTimeMillis() / 1000;String message = buildMessage(method, url, timestamp, nonceStr, body);String signature = sign(message.getBytes(StandardCharsets.UTF_8));HashMap<String, String> map = new HashMap<>();map.put("mchid", mchId);map.put("nonce_str", nonceStr);map.put("timestamp", String.valueOf(timestamp));map.put("serial_no", serialNo);map.put("signature", signature);return map;}/*** 构建消息** @param method 方式* @param url 请求连接* @param timestamp 时间戳* @param nonceStr 随机字符串* @param body 传递的主体* @return {@link {@link String}}* @author xyl* @date 2022/7/12 10:51* @explain*/String buildMessage(String method, HttpUrl url, long timestamp, String nonceStr, String body) {String canonicalUrl = url.encodedPath();if (url.encodedQuery() != null) {canonicalUrl += "?" + url.encodedQuery();}return method + "\n"+ canonicalUrl + "\n"+ timestamp + "\n"+ nonceStr + "\n"+ body + "\n";}/*** 生成签名** @param message* @return {@link {@link String}}* @author xyl* @date 2022/7/12 10:47* @explain*/String sign(byte[] message) throws InvalidKeyException, SignatureException {Signature sign = null;try {PrivateKey merchantPrivateKey = weChatPayConfig.getPrivateKey();sign = Signature.getInstance("SHA256withRSA");sign.initSign(merchantPrivateKey);try {sign.update(message);} catch (SignatureException e) {e.printStackTrace();}} catch (NoSuchAlgorithmException e) {e.printStackTrace();}return Base64.getEncoder().encodeToString(sign.sign());}/*** 微信支付回调** @param request 请求体* @param response 响应体* @return {@link {@link HashMap< String, String>}}* @author xyl* @date 2022/7/12 16:39* @explain*/@Overridepublic HashMap<String, String> weChatPayNotify(HttpServletRequest request, HttpServletResponse response) {//获取报文String body = getRequestBody(request);log.info("微信支付回调,获得报文:{}", body);//随机串String nonceStr = request.getHeader("Wechatpay-Nonce");//微信传递过来的签名String signature = request.getHeader("Wechatpay-Signature");//证书序列号(微信平台)String serialNo = request.getHeader("Wechatpay-Serial");//时间戳String timestamp = request.getHeader("Wechatpay-Timestamp");//构造签名串//应答时间戳\n//应答随机串\n//应答报文主体\nString signStr = Stream.of(timestamp, nonceStr, body).collect(Collectors.joining("\n", "", "\n"));log.warn("微信支付回调,构建签名串:{}", signStr);HashMap<String, String> resultMap = new HashMap<>(2);try {//验证签名是否通过boolean result = verifiedSign(serialNo, signStr, signature);log.warn("微信支付回调,验证签名结果:{}", result);if (result) {//解密数据String plainBody = decryptBody(body);log.warn("微信支付回调,解密后的明文:{}", plainBody);Map<String, String> map = convertWeChatPayMsgToMap(plainBody);//获取订单号String orderNo = map.get(WeChatConstant.OUT_TRADE_NO);//处理业务逻辑 TODOif (map.get(WeChatConstant.TRADE_STATE).equals(WeChatConstant.SUCCESS)) {//处理业务逻辑 TODO}//响应微信map.put("code", "SUCCESS");map.put("message", "成功");}} catch (Exception e) {log.warn("微信支付回调异常:{}", e.getMessage());}return resultMap;}/*** 解密body的密文* <p>* "resource": {* "original_type": "transaction",* "algorithm": "AEAD_AES_256_GCM",* "ciphertext": "",* "associated_data": "",* "nonce": ""* }** @param body* @return {@link {@link String}}* @author xyl* @date 2022/7/12 16:36* @explain*/private String decryptBody(String body) throws GeneralSecurityException {AesUtil aesUtil = new AesUtil(apiV3Key.getBytes(StandardCharsets.UTF_8));JSONObject object = JSONObject.parseObject(body);JSONObject resource = object.getJSONObject("resource");String ciphertext = resource.getString("ciphertext");String associatedData = resource.getString("associated_data");String nonce = resource.getString("nonce");return aesUtil.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8), nonce.getBytes(StandardCharsets.UTF_8), ciphertext);}/*** 转换body为map** @param plainBody* @return {@link {@link Map< String, String>}}* @author xyl* @date 2022/7/12 16:35* @explain*/private Map<String, String> convertWeChatPayMsgToMap(String plainBody) {Map<String, String> paramsMap = new HashMap<>(2);JSONObject jsonObject = JSONObject.parseObject(plainBody);//商户订单号paramsMap.put(WeChatConstant.OUT_TRADE_NO, jsonObject.getString(WeChatConstant.OUT_TRADE_NO));//交易状态paramsMap.put(WeChatConstant.TRADE_STATE, jsonObject.getString(WeChatConstant.TRADE_STATE));//微信交易单号paramsMap.put(WeChatConstant.TRANSACTION_ID, jsonObject.getString(WeChatConstant.TRANSACTION_ID));//交易金额String amount = jsonObject.get("amount").toString();JSONObject amountJson = JSONObject.parseObject(amount);paramsMap.put(WeChatConstant.TOTAL, amountJson.getString(WeChatConstant.TOTAL));log.warn("微信V3支付回调,封装返回参数:{}", paramsMap);return paramsMap;}/*** 读取数据流** @param request* @return {@link {@link String}}* @author xyl* @date 2022/7/12 16:33* @explain*/private String getRequestBody(HttpServletRequest request) {StringBuilder sb = new StringBuilder();try (ServletInputStream inputStream = request.getInputStream();BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));) {String line;while ((line = reader.readLine()) != null) {sb.append(line);}} catch (IOException e) {log.warn("读取数据流异常:{}", e.getMessage());}return sb.toString();}/*** 查询订单支付情况** @param orderNo* @return {@link {@link QueryPayVo}}* @author xyl* @date 2022/8/24 16:07* @explain*/@Overridepublic QueryPayVo queryPay(String orderNo) throws SignatureException, InvalidKeyException, NoSuchAlgorithmException, IOException {String url = domainUrl.concat(WeChatApiTypeEnum.QUERY_PAY.getType() + orderNo + "?mchid=" + mchId);JSONObject json = getHttpResponse(url);//交易金额String amount = json.get("amount").toString();JSONObject amountJson = JSONObject.parseObject(amount);return new QueryPayVo(json.get("out_trade_no").toString(), json.get("transaction_id").toString(), json.get("trade_type").toString(), json.get("trade_state").toString(), json.get("trade_state_desc").toString(), json.get("success_time").toString(), amountJson.get("total").toString());}/*** 发起Git请求** @param url* @return {@link {@link HttpResponse}}* @author xyl* @date 2022/8/25 9:18* @explain*/private JSONObject getHttpResponse(String url) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException, IOException {HttpClient httpClient = HttpClientBuilder.create().build();HttpUrl httpurl = HttpUrl.parse(url);String getSign = getGetSign(httpurl);HttpGet httpGet = new HttpGet(url);httpGet.addHeader("Accept", "application/json");httpGet.addHeader("Authorization", getSign);HttpResponse execute = httpClient.execute(httpGet);String s = EntityUtils.toString(execute.getEntity());JSONObject json = JSONObject.parseObject(s);int statusCode = execute.getStatusLine().getStatusCode();if (statusCode != 200) {throw new BackendException(json.get("message").toString());}return json;}/*** 微信支付GET获取签名** @param httpurl 请求URL* @return {@link {@link String}}* @author xyl* @date 2022/8/24 16:07* @explain*/public String getGetSign(HttpUrl httpurl) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException {HashMap<String, String> token = getToken(WeChatConstant.GET, httpurl, "");return "WECHATPAY2-SHA256-RSA2048 mchid=\"" + token.get("mchid") + "\",nonce_str=\"" + token.get("nonce_str") + "\",signature=\"" + token.get("signature") + "\",timestamp=\"" + token.get("timestamp") + "\",serial_no=\"" + token.get("serial_no") + "\"";}/*** 根据退款订单号查询退款情况** @param refundOrderNo* @return {@link {@link QueryRefundVo}}* @author xyl* @date 2022/8/25 10:18* @explain*/@Overridepublic QueryRefundVo queryRefund(String refundOrderNo) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException, IOException {String url = domainUrl.concat(WeChatApiTypeEnum.QUERY_REFUND.getType() + refundOrderNo);JSONObject json = getHttpResponse(url);//交易金额String amount = json.get("amount").toString();JSONObject amountJson = JSONObject.parseObject(amount);String total = amountJson.get("total").toString();String refund = amountJson.get("refund").toString();return new QueryRefundVo(json.get("refund_id").toString(), json.get("out_refund_no").toString(), json.get("transaction_id").toString(), json.get("out_trade_no").toString(), json.get("channel").toString(), json.get("user_received_account").toString(), json.get("success_time").toString(), json.get("status").toString(), total, refund);}}
相关的配置:
package com.tiyaa.mall.pay.config;import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;/*** @author xyl* @date 2022/8/23 10:04* @explain*/
@Configuration
@Data
public class WeChatConfig {/*** 小程序*/@Value("${weChat.small.appId}")public String smallAppId;@Value("${weChat.small.secret}")public String smallSecret;/*** h5 微信内頁jspapi调用*/@Value("${weChat.h5.appId}")public String h5AppId;@Value("${weChat.h5.secret}")public String h5Secret;/*** app*/@Value("${weChat.app.appId}")public String appAppId;@Value("${weChat.app.secret}")public String appSecret;/*** 商户号 秘钥key 商户API证书序列号 v3秘钥*/@Value("${weChat.mch.mchId}")public String mchId;@Value("${weChat.mch.mchKey}")public String mchKey;@Value("${weChat.mch.serialNo}")public String serialNo;@Value("${weChat.mch.apiV3Key}")public String apiV3Key;/*** 支付回调 退款回调 微信服务地址*/@Value("${weChat.notifyUrl.payNotifyUrl}")public String payNotifyUrl;@Value("${weChat.notifyUrl.refundNotifyUrl}")public String refundNotifyUrl;@Value("${weChat.notifyUrl.domainUrl}")public String domainUrl;/*** 项目*/@Value("${spring.profiles.active}")public String active;}
package com.tiyaa.mall.pay.config;import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.ScheduledUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;/*** @author xyl* @date 2022/8/23 10:15* @explain*/
@Configuration
public class WeChatPayConfig extends WeChatConfig {/*** 获取商户的私钥文件** @return*/public PrivateKey getPrivateKey() {InputStream resourceAsStream = this.getClass().getResourceAsStream("/cert/apiclient_key.pem");return PemUtil.loadPrivateKey(resourceAsStream);}/*** 获取签名验证器** @return*/@Beanpublic ScheduledUpdateCertificatesVerifier getVerifier() {//获取商户私钥PrivateKey privateKey = getPrivateKey();System.out.println(privateKey);//私钥签名对象PrivateKeySigner privateKeySigner = new PrivateKeySigner(serialNo, privateKey);//身份认证对象WechatPay2Credentials wechatPay2Credentials = new WechatPay2Credentials(mchId, privateKeySigner);// 使用定时更新的签名验证器,不需要传入证书return new ScheduledUpdateCertificatesVerifier(wechatPay2Credentials,apiV3Key.getBytes(StandardCharsets.UTF_8));}/*** 获取http请求对象** @param verifier* @return*/@Bean(name = "wxPayClient")public CloseableHttpClient getWxPayClient(ScheduledUpdateCertificatesVerifier verifier) {//获取商户私钥PrivateKey privateKey = getPrivateKey();WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create().withMerchant(mchId, serialNo, privateKey).withValidator(new WechatPay2Validator(verifier));// ... 接下来,你仍然可以通过builder设置各种参数,来配置你的HttpClient// 通过WeChatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新return builder.build();}/*** 获取HttpClient,无需进行应答签名验证,跳过验签的流程*/@Bean(name = "wxPayNoSignClient")public CloseableHttpClient getWxPayNoSignClient() {//获取商户私钥PrivateKey privateKey = getPrivateKey();//用于构造HttpClientWechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()//设置商户信息.withMerchant(mchId, serialNo, privateKey)//无需进行签名验证、通过withValidator((response) -> true)实现.withValidator((response) -> true);// 通过WeChatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新return builder.build();}
}
DTO:
package com.tiyaa.mall.pay.dto;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;/*** @author xyl* @date 2022/7/11 17:16* @explain*/
@Data
@ApiModel("下单dto")
public class BuyCreateDto {@ApiModelProperty(value = "商户订单号(自己的订单号)")private String outTradeNo;@ApiModelProperty(value = "支付的类型字典11")private Integer payType;@ApiModelProperty(value = "支付金额")private Long total;@ApiModelProperty(value = "用户OpenId")private String openId;public BuyCreateDto() {}public BuyCreateDto(String outTradeNo, Integer payType, Long total, String openId) {this.outTradeNo = outTradeNo;this.payType = payType;this.total = total;this.openId = openId;}
}
package com.tiyaa.mall.pay.dto;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import java.util.HashMap;/*** @author xyl* @date 2022/7/12 13:13* @explain*/
@Data
@ApiModel("获取URL和构建支付mapBo")
public class BuyUrlMapBo {@ApiModelProperty(value = "微信支付API接口")private String url;@ApiModelProperty(value = "构建的支付信息map")private HashMap<String, Object> buyMap;
}
枚举:
package com.tiyaa.mall.pay.enums;import lombok.AllArgsConstructor;
import lombok.Getter;/*** @author xyl* @date 2022/7/12 9:05* @explain*/
@AllArgsConstructor
@Getter
public enum WeChatApiTypeEnum {/*** 获取商户平台证书的URL*/GET_CERTIFICATES("/v3/certificates"),/*** JSAPI下单*/JSAPI_PAY("/v3/pay/transactions/jsapi"),/*** APP下单*/APP_PAY("/v3/pay/transactions/app"),/*** H5下单*/H5_PAY("/v3/pay/transactions/h5"),/*** 订单查询*/QUERY_PAY("/v3/pay/transactions/out-trade-no/"),/*** 订单查询*/QUERY_REFUND("/v3/refund/domestic/refunds/");/*** 类型*/private final String type;
}
package com.tiyaa.mall.pay.enums;/*** @author chenbinbin* @date 2022-03-25 9:25* 支付类型枚举类*/
public enum PayTypeEnum {/*** @author chenbinbin* @date 2022-03-25 9:25* 支付类型枚举类*/WX_APP_WECHAT_PAY(0, "小程序微信支付"),WX_H5_WECHAT_PAY(1, "公众号微信支付"),H5_ALIPAY(2, "H5支付宝支付"),APP_WECHAT_PAY(3, "APP微信支付"),APP_ALIPAY(4, "APP支付宝支付"),USER_BALANCE_PAY(5, "余额支付"),BROWSER_H5_WECHAT_PAY(6, "外部浏览器H5微信支付"),;private int code;private String msg;PayTypeEnum() {}PayTypeEnum(int code, String msg) {this.code = code;this.msg = msg;}public int getCode() {return code;}public void setCode(int code) {this.code = code;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}
}
vo:
package com.tiyaa.mall.pay.vo;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;/*** @author xyl* @date 2022/8/24 15:50* @explain*/
@Data
@ApiModel("支付查询返回Vo")
public class QueryPayVo {@ApiModelProperty(value = "订单号")private String orderNo;@ApiModelProperty(value = "微信订单号")private String transactionId;@ApiModelProperty(value = "交易类型,枚举值:\n" +"JSAPI:公众号支付\n" +"NATIVE:扫码支付\n" +"APP:APP支付\n" +"MICROPAY:付款码支付\n" +"MWEB:H5支付\n" +"FACEPAY:刷脸支付")private String tradeType;@ApiModelProperty(value = "交易状态,枚举值:\n" +"SUCCESS:支付成功\n" +"REFUND:转入退款\n" +"NOTPAY:未支付\n" +"CLOSED:已关闭\n" +"REVOKED:已撤销(仅付款码支付会返回)\n" +"USERPAYING:用户支付中(仅付款码支付会返回)\n" +"PAYERROR:支付失败(仅付款码支付会返回)\n" +"示例值:SUCCESS")private String tradeState;@ApiModelProperty(value = "交易状态描述\n" +"示例值:支付成功")private String tradeStateDesc;@ApiModelProperty(value = "支付完成时间,遵循rfc3339标准格式,格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE,yyyy-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss表示时分秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。例如:2015-05-20T13:29:35+08:00表示,北京时间2015年5月20日 13点29分35秒。\n" +"示例值:2018-06-08T10:34:56+08:00")private String successTime;@ApiModelProperty(value = "\t订单总金额,单位为分。\n" +"示例值:100")private String total;public QueryPayVo(String orderNo, String transactionId, String tradeType, String tradeState, String tradeStateDesc, String successTime, String total) {this.orderNo = orderNo;this.transactionId = transactionId;this.tradeType = tradeType;this.tradeState = tradeState;this.tradeStateDesc = tradeStateDesc;this.successTime = successTime;this.total = total;}
}
package com.tiyaa.mall.pay.vo;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;/*** @author xyl* @date 2022/8/25 9:26* @explain*/
@Data
@ApiModel("微信查询退款Vo")
public class QueryRefundVo {@ApiModelProperty(value = "微信支付退款单号\n" +"示例值:50000000382019052709732678859")private String refundId;@ApiModelProperty(value = "商户系统内部的退款单号,商户系统内部唯一,只能是数字、大小写字母_-|*@ ,同一退款单号多次请求只退一笔。\n" +"示例值:1217752501201407033233368018")private String outRefundNo;@ApiModelProperty(value = "微信支付交易订单号\n" +"示例值:1217752501201407033233368018")private String transactionId;@ApiModelProperty(value = "原支付交易对应的商户订单号\n" +"示例值:1217752501201407033233368018")private String outTradeNo;@ApiModelProperty(value = "\t枚举值:\n" +"ORIGINAL:原路退款\n" +"BALANCE:退回到余额\n" +"OTHER_BALANCE:原账户异常退到其他余额账户\n" +"OTHER_BANKCARD:原银行卡异常退到其他银行卡\n" +"示例值:ORIGINAL")private String channel;@ApiModelProperty(value = "取当前退款单的退款入账方,有以下几种情况:\n" +"1)退回银行卡:{银行名称}{卡类型}{卡尾号}\n" +"2)退回支付用户零钱:支付用户零钱\n" +"3)退还商户:商户基本账户商户结算银行账户\n" +"4)退回支付用户零钱通:支付用户零钱通\n" +"示例值:招商银行信用卡0403")private String userReceivedAccount;@ApiModelProperty(value = "退款成功时间,当退款状态为退款成功时有返回。\n" +"示例值:2020-12-01T16:18:12+08:00")private String successTime;@ApiModelProperty(value = "款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往商户平台-交易中心,手动处理此笔退款。\n" +"枚举值:\n" +"SUCCESS:退款成功\n" +"CLOSED:退款关闭\n" +"PROCESSING:退款处理中\n" +"ABNORMAL:退款异常\n" +"示例值:SUCCESS")private String status;@ApiModelProperty(value = "订单总金额,单位为分\n" +"示例值:100")private String total;@ApiModelProperty(value = "退款标价金额,单位为分,可以做部分退款\n" +"示例值:100")private String refund;public QueryRefundVo(String refundId, String outRefundNo, String transactionId, String outTradeNo, String channel, String userReceivedAccount, String successTime, String status, String total, String refund) {this.refundId = refundId;this.outRefundNo = outRefundNo;this.transactionId = transactionId;this.outTradeNo = outTradeNo;this.channel = channel;this.userReceivedAccount = userReceivedAccount;this.successTime = successTime;this.status = status;this.total = total;this.refund = refund;}
}
因为阿里代码规范,还设置了点常量
package com.tiyaa.mall.pay.constants;import org.springframework.stereotype.Component;/*** 微信支付支付常量** @author xyl* @date 2022/8/23 14:40* @explain*/
public class WeChatConstant {public static final String PROD = "prod";public static final String APP_ID = "appid";public static final String MCH_ID = "mchid";public static final String GET = "GET";public static final String PACKAGE = "Sign=WXPay";public static final String SUCCESS = "SUCCESS";public static final String TRADE_STATE = "trade_state";public static final String OUT_TRADE_NO = "out_trade_no";public static final String ACCOUNT_NO = "account_no";public static final String TRANSACTION_ID = "transaction_id";public static final String TOTAL = "total";}
当前支付 和 退款查询 因为小编被安排了其他事情,对接支付后续在更新