开发前准备
文档
链接: 微信支付流程介绍V2. 链接: 微信扫码支付接口文档V2-SDK. 链接: 微信V3-官方提供github. 链接: 微信支付指引文档.
本文以刷脸支付分为例指引开发微信支付,因为这里用到了V2的接口和V3的接口 链接: 本文主要按照微信刷脸支付分支付:流程. 先明确一下份工,一下画框的地方是后端要解决的问题 第一个接口:提供给硬件调用的接口和此接口需要加密 返回给硬件什么参数? 剩下的接口就是V3的这时候就需要上面第四个连接提供的指引文档了
开发准备
微信开发大致流程首先找到要调用接口 -> 构建参数 -> 发起http调用 -> 同步接收数据 -> 存在回调接口接收回调【解密、幂等校验和回复成功】
@Bean
public RestTemplate restTemplate() {
return new RestTemplate(new OkHttp3ClientHttpRequestFactory());
}
maven
<-- 发起http调用 -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</dependency>
微信配置类
之前写的支付宝的配置是在配置文件中写死的,就算之后用远程配置也是比较麻烦的,这里直接放入字典表,构建后直接从库中、缓存中取出配置对维护和公用来说都很方便。
id | module_type | module_lable_type | module_lable_desc | module_lable_value | lable_desc |
---|
100 | pay | vxpay_config | vx_app_id | wx123********** | 微信:APPID | 101 | pay | vxpay_config | vx_mch_id | 123********** | 微信:商户号 | 102 | pay | vxpay_config | vx_mch_serial_number | 123********** | 微信:商家api序列号 | 103 | pay | vxpay_config | vx_mch_v3_private_key | 123********** | 微信:报文解密V3密钥key | 104 | pay | vxpay_config | vx_api_private_key | 123********** | 微信: API密钥 | 105 | pay | vxpay_config | vx_key_path | /**/vx/key/apiclient_key.pem | 微信:密钥【apiclient_key.pem】地址 | 106 | pay | vxpay_config | vx_service_id | 123********** | 微信:调用接口所需service_id | 107 | pay | vxpay_config | vx_pay_notify_url | http://IP:POST/vx/payCallBack | 微信:支付回调地址 | 108 | pay | vxpay_config | vx_refund_notify_url | http://IP:POST/vx/refundCallBack | 微信:退款回调地址 |
这里也提供了配置文件的写法基本不变
wx:
appId: wx123**********
# 商户号
mchid: 123**********
# 微信商家api序列号
mchSerialNo: 123**********
# 回调报文解密V3密钥key
v3Key: 123**********
# 商户的key【API密匙】存放路径
KeyPath: vx/key/apiclient_key.pem
#API密钥
keyApi: 123**********
微信V2-SDK
下载上面提供的第二个连接中API-SDK对应的JAVA版解压,然后放入项目中
微信V3工具
公共配置类也就是上面字典根据【module_lable_type】 得到【module_lable_desc 】不同值【module_lable_value 】 可以加上【@ConfigurationProperties(prefix = “wx”)】注解直接使用配置类中配置的参数
@Data
public class WxMpProperties {
private String appId;
private String mchId;
private String v3Key;
private String keyApi;
private String KeyPath;
private String mchSerialNo;
private String serviceId;
private String payNotifyUrl;
private String refundNotifyUrl;
}
此类用来发起http调用
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.HttpEntity;
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.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
public class HttpUtils {
private static final ObjectMapper JSON=new ObjectMapper();
public static String doGet(String url,WxMpProperties wxMpProperties){
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
HttpGet httpget = new HttpGet(url);
httpget.addHeader("Content-Type", "application/json;charset=UTF-8");
httpget.addHeader("Accept", "application/json");
try{
String token = WechatPayUtils.getToken("GET", new URL(url), "",wxMpProperties);
httpget.addHeader("Authorization", token);
CloseableHttpResponse httpResponse = httpClient.execute(httpget);
if(httpResponse.getStatusLine().getStatusCode() == 200){
String jsonResult = EntityUtils.toString( httpResponse.getEntity());
return jsonResult;
}else{
System.err.println(EntityUtils.toString( httpResponse.getEntity()));
}
}catch (Exception e){
e.printStackTrace();
}finally {
try {
httpClient.close();
}catch (Exception e){
e.printStackTrace();
}
}
return null;
}
public static Map<String,Object> doPostWexin(String url, String body, WxMpProperties wxMpProperties){
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(url);
httpPost.addHeader("Content-Type","application/json;chartset=utf-8");
httpPost.addHeader("Accept", "application/json");
try{
String token = WechatPayUtils.getToken("POST", new URL(url), body, wxMpProperties);
httpPost.addHeader("Authorization", token);
if(body==null){
throw new IllegalArgumentException("data参数不能为空");
}
StringEntity stringEntity = new StringEntity(body,"utf-8");
httpPost.setEntity(stringEntity);
CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
if(httpResponse.getStatusLine().getStatusCode() == 200){
String jsonResult = EntityUtils.toString(httpEntity);
return JSON.readValue(jsonResult, HashMap.class);
}else{
String s = EntityUtils.toString(httpEntity);
System.err.println("微信支付错误信息"+s);
return JSON.readValue(s, HashMap.class);
}
}catch (Exception e){
e.printStackTrace();
}finally {
try{
httpClient.close();
}catch (Exception e){
e.printStackTrace();
}
}
return null;
}
}
此类用来微信加密解密
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sensetime.box.pay.web.wechat.common.WxMpProperties;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import org.springframework.util.Base64Utils;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.security.cert.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class WechatPayUtils {
private static final ObjectMapper JSON=new ObjectMapper();
public static PrivateKey getPrivateKey(String filename) throws IOException {
System.out.println("filename:" + filename);
String content = new String(Files.readAllBytes(Paths.get(filename)), "utf-8");
try {
String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\\s+", "");
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("当前Java环境不支持RSA", e);
} catch (InvalidKeySpecException e) {
throw new RuntimeException("无效的密钥格式");
}
}
public static String decryptResponseBody(String associatedData, String nonce, String ciphertext) {
try {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec key = new SecretKeySpec(WxpayConfig.v3Key.getBytes(StandardCharsets.UTF_8), "AES");
GCMParameterSpec spec = new GCMParameterSpec(128, nonce.getBytes(StandardCharsets.UTF_8));
cipher.init(Cipher.DECRYPT_MODE, key, spec);
cipher.updateAAD(associatedData.getBytes(StandardCharsets.UTF_8));
byte[] bytes;
try {
bytes = cipher.doFinal(Base64Utils.decodeFromString(ciphertext));
} catch (GeneralSecurityException e) {
throw new IllegalArgumentException(e);
}
return new String(bytes, StandardCharsets.UTF_8);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new IllegalStateException(e);
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
throw new IllegalArgumentException(e);
}
}
public static boolean responseSignVerify(String wechatpaySerial, String wechatpaySignature, String wechatpayTimestamp, String wechatpayNonce, String body) {
FileInputStream fileInputStream = null;
try {
String signatureStr = buildMessageS(wechatpayTimestamp, wechatpayNonce, body);
Signature signer = Signature.getInstance("SHA256withRSA");
fileInputStream = new FileInputStream(WxpayConfig.KeyPath);
X509Certificate receivedCertificate = loadCertificate(fileInputStream);
signer.initVerify(receivedCertificate);
signer.update(signatureStr.getBytes(StandardCharsets.UTF_8));
return signer.verify(Base64.getDecoder().decode(wechatpaySignature));
} catch (Exception e ) {
e.printStackTrace();
} finally {
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return false;
}
public static X509Certificate loadCertificate(InputStream inputStream) {
try {
CertificateFactory cf = CertificateFactory.getInstance("X509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream);
cert.checkValidity();
return cert;
} catch (CertificateExpiredException e) {
throw new RuntimeException("证书已过期", e);
} catch (CertificateNotYetValidException e) {
throw new RuntimeException("证书尚未生效", e);
} catch (CertificateException e) {
throw new RuntimeException("无效的证书", e);
}
}
public static String buildMessageS(String wechatpayTimestamp, String wechatpayNonce, String body) {
return wechatpayTimestamp + "\n"
+ wechatpayNonce + "\n"
+ body + "\n";
}
public static String getToken(String method, URL url, String body, WxMpProperties wxMpProperties) throws Exception {
String nonceStr = getNonceStr();
long timestamp = System.currentTimeMillis() / 1000;
String message = buildMessage(method, url, timestamp, nonceStr, body);
String signature = sign(message.getBytes("utf-8"),wxMpProperties);
return "WECHATPAY2-SHA256-RSA2048 " + "mchid=\"" + wxMpProperties.getMchId() + "\","
+ "nonce_str=\"" + nonceStr + "\","
+ "timestamp=\"" + timestamp + "\","
+ "serial_no=\"" + wxMpProperties.getMchSerialNo() + "\","
+ "signature=\"" + signature + "\"";
}
public static Map<String, X509Certificate> refreshCertificate(WxMpProperties wxMpProperties) throws Exception {
Map<String, X509Certificate> certificateMap = new HashMap();
JsonNode jsonNode = JSON.readTree(HttpUtils.doGet(WechatUrlConfig.CERTIFICATESURL,wxMpProperties));
JsonNode data = jsonNode.get("data");
if (data != null) {
for (int i = 0; i < data.size(); i++) {
JsonNode encrypt_certificate = data.get(i).get("encrypt_certificate");
AesUtil aesUtil = new AesUtil(WxpayConfig.v3Key.getBytes());
String associated_data = encrypt_certificate.get("associated_data").toString().replaceAll("\"", "");
String nonce = encrypt_certificate.get("nonce").toString().replaceAll("\"", "");
String ciphertext = encrypt_certificate.get("ciphertext").toString().replaceAll("\"", "");
String certStr = aesUtil.decryptToString(associated_data.getBytes(), nonce.getBytes(), ciphertext);
CertificateFactory cf = CertificateFactory.getInstance("X509");
X509Certificate x509Cert = (X509Certificate) cf.generateCertificate(
new ByteArrayInputStream(certStr.getBytes("utf-8"))
);
String serial_no = data.get(i).get("serial_no").toString().replaceAll("\"", "");
certificateMap.put(serial_no, x509Cert);
}
}
return certificateMap;
}
public static String sign(byte[] message,WxMpProperties wxMpProperties) throws Exception {
Signature sign = Signature.getInstance("SHA256withRSA");
sign.initSign(getPrivateKey(wxMpProperties.getKeyPath()));
sign.update(message);
return Base64.getEncoder().encodeToString(sign.sign());
}
public static String buildMessage(String method, URL url, long timestamp, String nonceStr, String body) {
String canonicalUrl = url.getPath();
if (url.getQuery() != null) {
canonicalUrl += "?" + url.getQuery();
}
return method + "\n"
+ canonicalUrl + "\n"
+ timestamp + "\n"
+ nonceStr + "\n"
+ body + "\n";
}
public static boolean verify(X509Certificate certificate, byte[] message, String signature) {
try {
Signature sign = Signature.getInstance("SHA256withRSA");
sign.initVerify(certificate);
sign.update(message);
return sign.verify(Base64.getDecoder().decode(signature));
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("当前Java环境不支持SHA256withRSA", e);
} catch (SignatureException e) {
throw new RuntimeException("签名验证过程发生了错误", e);
} catch (InvalidKeyException e) {
throw new RuntimeException("无效的证书", e);
}
}
public static String getNonceStr() {
return UUID.randomUUID().toString()
.replaceAll("-", "")
.substring(0, 32);
}
private static String buildMessageTwo(String appId, long timestamp, String nonceStr, String packag) {
return appId + "\n"
+ timestamp + "\n"
+ nonceStr + "\n"
+ packag + "\n";
}
}
满足微信接口需求
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Random;
import static com.sensetime.box.pay.web.wechat.config.WechatPayUtils.sign;
public class WeixinchatPayUtils {
private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final Random RANDOM = new SecureRandom();
public static String getNonceStr() {
char[] nonceChars = new char[32];
for (int index = 0; index < nonceChars.length; ++index) {
nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
}
return new String(nonceChars);
}
private static String buildMessageTwo(String appId, long timestamp, String nonceStr, String packag) {
return appId + "\n"
+ timestamp + "\n"
+ nonceStr + "\n"
+ packag + "\n";
}
}
这里是本此用到的接口调用地址
public class WechatUrlConfig {
public static final String CERTIFICATESURL = "https://api.mch.weixin.qq.com/v3/certificates";
public static final String REFUNDSURL = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds";
public static final String SERVICEORDER = "https://api.mch.weixin.qq.com/v3/payscore/serviceorder";
public static final String ORDERCANCELPREFIX = "https://api.mch.weixin.qq.com/v3/payscore/serviceorder/";
public static final String ORDERCANCELSUFFIX = "/cancel";
public static final String SERVICEORDERCOMPLETEPREFIX = "https://api.mch.weixin.qq.com/v3/payscore/serviceorder/";
public static final String SERVICEORDERCOMPLETESUFFIX = "/complete";
public static final String GET_WXPAYFACE_AUTHINFO = "https://payapp.weixin.qq.com/face/get_wxpayface_authinfo";
public static final String FINDBYID = "https://api.mch.weixin.qq.com/v3/payscore/serviceorder";
public static final String FINDREFUND = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds/";
}
开发调用
V2刷脸授权接口【get_wxpayface_authinfo】
从上面接口分析我们需要硬件提供【rawdata,device_id】这两个参数,其他参数我们都有 返回给硬件端的数据主要是【authinfo】
@Autowired
private WxMpProperties wxMpProperties;
public Map<String,String> getWxFaceAuthInfoReqMap(WxFaceAuthInfoReq wxFaceAuthInfoReq){
map.put("appid",wxMpProperties.getAppId());
map.put("mch_id",wxMpProperties.getMchId());
map.put("nonce_str",WXPayUtil.generateNonceStr());
map.put("store_id","11111111111");
String text = "刷脸一号柜台";
String s = Base64.getEncoder().encodeToString(text.getBytes());
map.put("store_name",s);
map.put("device_id",wxFaceAuthInfoReq.getDeviceUuid());
map.put("rawdata",wxFaceAuthInfoReq.getRawdata());
map.put("sign_type","MD5");
long timeStampSec = System.currentTimeMillis()/1000;
String timestamp = String.format("%010d", timeStampSec);
map.put("now",timestamp);
map.put("version","1");
String sign = WXPayUtil.generateSignedXml(map, WxpayConfig.KEYAPI, SignType.MD5);
log.info("构建微信获取刷脸授权XML参数:【{}】",sign);
HttpHeaders headers = new HttpHeaders();
HttpEntity<String> stringHttpEntity = new HttpEntity<String>(sign,headers);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> exchange = restTemplate.exchange("https://payapp.weixin.qq.com/face/get_wxpayface_authinfo",
HttpMethod.POST,
stringHttpEntity,
String.class);
Map<String, String> stringMap = WXPayUtil.xmlToMap(exchange.getBody());
return stringMap;
}
V3支付相关接口【接口太多部分案例】
创建支付分订单
从文档中得知V3接口而且是同步接口,回调地址只是完成支付和确认订单的时候才会回调,所以我们这个接口使用【用户免确认模式】,还有订单风险金分为好多模式,这个具体看具体需求,风险金额上限是200元【找客服确认过】具体填多少这个还是要看具体业务。 入参: 订单号(自己平台的订单号) 微信用户openID(硬件端刷脸后会获得用户的openID) 具体操作步骤: 1、封装调用微信接口的数据 2、调用微信接口 3、同步获得微信数据 4、记录状态封装入库
private Map<String, Object> getOrderCreateMap(
WxPayPointsCreReq wxPayPointsCreReq) {
Map<String, Object> map = new HashMap();
map.put("out_order_no", wxPayPointsCreReq.getOrderCode());
map.put("appid", wxMpProperties.getAppId());
map.put("service_id", wxMpProperties.getServiceId());
map.put("service_introduction", "微信刷脸支付");
Map<String, Object> timeRangeMap = new HashMap<>();
Calendar calStart = Calendar.getInstance();
calStart.setTime(new Date());
calStart.add(Calendar.SECOND, Integer.valueOf("30"));
timeRangeMap.put("start_time",DateUtils.dateToString(DateUtils.YMDHMS,calStart.getTime()));
timeRangeMap.put("start_time_remark","交易开始");
Calendar calEnd = Calendar.getInstance();
calEnd.setTime(new Date());
calEnd.add(Calendar.SECOND, Integer.valueOf("120"));
timeRangeMap.put("end_time",DateUtils.dateToString(DateUtils.YMDHMS,calEnd.getTime()));
timeRangeMap.put("end_time_remark","交易结束");
map.put("time_range", timeRangeMap);
Map<String, Object> riskFundMap = new HashMap<>();
riskFundMap.put("name","");
BigDecimal risk_fund_amount = new BigDecimal("").multiply(new BigDecimal(100));
riskFundMap.put("amount",risk_fund_amount.intValue());
riskFundMap.put("description","商品的预估费用");
map.put("risk_fund", riskFundMap);
map.put("notify_url", "http:****************");
map.put("openid", wxPayPointsCreReq.getOpenId());
map.put("need_user_confirm", "1".equals("0"))?true:false);
log.info("创建微信支付订单map:【{}】",map);
ObjectMapper objectMapper = new ObjectMapper();
String body = objectMapper.writeValueAsString(map);
Map<String, Object> stringObjectMap = null;
WxPayPointsCreDto wxPayPointsCre = new WxPayPointsCreDto();
try {
stringObjectMap = HttpUtils.doPostWexin(
WechatUrlConfig.SERVICEORDER,
body,
wxMpProperties);
log.info("创建支付分订单得到参数---------stringObjectMap--------:{}",stringObjectMap);
if(!Objects.isNull(stringObjectMap) && !Objects.isNull(stringObjectMap.get("message"))){
log.info("创建支付分订单失败---------获得微信错误信息--------:{}",ResultRes.error(stringObjectMap.get("message").toString()));
return ResultRes.error(ResEnum.PAYMENT_IS_NO_WECHAT_END.getValue(),stringObjectMap.get("message").toString());
}
} catch (Exception ex) {
ex.printStackTrace();
return ResultRes.error();
}
return map;
}
查询支付分订单
public Map<String,Object> findById(String out_order_no) throws Exception{
try {
String findById = HttpUtils.doGet(
WechatUrlConfig.FINDBYID +
"?service_id=" + wxMpProperties.getServiceId()+
"&out_order_no=" + out_order_no +
"&appid=" + wxMpProperties.getAppId(), wxMpProperties);
ObjectMapper JSON=new ObjectMapper();
HashMap<String,Object> hashMap = JSON.readValue(findById, HashMap.class);
log.info("查询支付分订单API,状态:{},数据集:【{}】",hashMap.get("state").toString(),hashMap);
return hashMap;
} catch (Exception ex) {
}
return null;
}
退款
从文档得知需要【transaction_id,商家退款单号,退款金额,这笔订单的订单金额】然后退款需要回调才知道结果
创建退款
private Map<String, Object> getRefundMap(ReFundedReq reFundedReq,
String out_order_no) {
Map<String, Object> byId = this.findById(out_order_no);
Map<String,Object> collection = (Map<String,Object>)byId.get("collection");
Object transaction_id= ((Map<String,Object>)((List<Map<String,Object>>)collection.get("details")).get(0))
.get("transaction_id");
Map<String, Object> map = new HashMap<>();
map.put("transaction_id",transaction_id.toString());
map.put("out_refund_no",reFundedReq.getOrderRefundUuId());
Map<String, Object> mapAmount = new HashMap<>();
mapAmount.put("refund",reFundedReq.getRefundAmount());
mapAmount.put("total",
new BigDecimal(reFundedReq.getAmount()).multiply(new BigDecimal(100)).intValue());
mapAmount.put("currency", "CNY");
map.put("notify_url", "http://IP:POST/vx/refundCallBack");
map.put("amount",mapAmount);
ObjectMapper objectMapper = new ObjectMapper();
String body = objectMapper.writeValueAsString(map);
try {
stringObjectMap = HttpUtils.doPostWexin(
WechatUrlConfig.REFUNDSURL,
body,wxMpProperties);
log.info("微信退款调用完成ID:{}",stringObjectMap );
} catch (Exception ex) {
}
return map;
}
退款回调
controller
@RequestMapping(value = "/refundCallBack",produces = MediaType.APPLICATION_JSON_VALUE)
@ApiOperation(value = "微信退款回调", nickname = "refundCallBack")
public String refundCallBack(HttpServletRequest request){
return wxPayService.refundCallBack(request);
}
回调工具方法
public static Map<String, X509Certificate> certificateMap = new ConcurrentHashMap<>();
private boolean verifiedSign(HttpServletRequest request,String body) throws Exception {
String serialNo = request.getHeader("Wechatpay-Serial");
String nonceStr = request.getHeader("Wechatpay-Nonce");
String timestamp = request.getHeader("Wechatpay-Timestamp");
String wechatSign = request.getHeader("Wechatpay-Signature");
String signStr = Stream.of(timestamp, nonceStr, body)
.collect(Collectors.joining("\n", "", "\n"));
if (certificateMap.isEmpty() || !certificateMap.containsKey(serialNo)) {
certificateMap= WechatPayUtils.refreshCertificate(wxMpProperties);
}
X509Certificate certificate = certificateMap.get(serialNo);
if (certificate == null){
return false;
}
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initVerify(certificate);
signature.update(signStr.getBytes());
return signature.verify(Base64Utils.decodeFromString(wechatSign));
}
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();
}
退款
@Override
public String refundCallBack(HttpServletRequest request) {
Map<String,String> map = new HashMap<>(2);
try {
String body = getRequestBody(request);
if (verifiedSign(request,body)){
HashMap hashMap = JSONObject.parseObject(body, HashMap.class);
String out_refund_no = (String)hashMap .get("out_refund_no");
map.put("code","SUCCESS");
map.put("message","成功");
return JSONObject.toJSONString(map);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
|