微信支付和微信退款

常用的支付

微信支付

下载官方工具类

pom文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 <!--微信小程序支付-->
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.6</version>
</dependency>
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>fluent-hc</artifactId>
<version>4.5.8</version>
</dependency>

工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/**
* 向指定 URL 发送POST方法的请求
*
* @param url 发送请求的 URL
* @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return 所代表远程资源的响应结果
*/
public static String sendPost(String url, String param) {
PrintWriter out = null;
BufferedReader in = null;
StringBuilder result = new StringBuilder();
try {
URL realUrl = new URL(url);
URLConnection conn = realUrl.openConnection();
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
conn.setRequestProperty("Accept-Charset", "utf-8");
conn.setRequestProperty("contentType", "utf-8");
conn.setDoOutput(true);
conn.setDoInput(true);
out = new PrintWriter(conn.getOutputStream());
out.print(param);
out.flush();
in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
String line;
while ((line = in.readLine()) != null) {
result.append(line);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
return result.toString();
}

支付

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
public Map<String, String> pay(PayVo payVo) {
log.info("===微信支付开始===");
// 获取openId,小程序支付使用
String openId = payVo.getOpenId();
// 金额
BigDecimal money = payVo.getMoney();
// 商户自定义订单号
String orderId = payVo.getOrderId();
//拼接参数
Map<String, String> param = new HashMap<>();
// 小程序appid
param.put("appid", appid);
// 商品描述
param.put("body", "xxx订单" + orderId);
// 商户号
param.put("mch_id", mch_id);
// 随机字符串,使用微信的工具类获取
param.put("nonce_str", WXPayUtil.generateNonceStr());
// 回调接口
param.put("notify_url", "填写自己的https的回调");
// 用户的opneid
param.put("openid", openId);
// 商户订单号(商户自己生成的订单号)
param.put("out_trade_no", orderId);
// ip地址
param.put("spbill_create_ip", payVo.getIp());
//把金额转换为分,并转换为字符串。
param.put("total_fee", String.valueOf((money.multiply(new BigDecimal(100)))));
// 交易的类型 JSAPI--JSAPI支付(或小程序支付)、NATIVE--Native支付、APP--app支付,MWEB--H5支付
param.put("trade_type", "JSAPI");
// 调用微信支付官网提供的工具类生成sign签名,第一个参数为param中的上面的参数,第二个为支付的秘钥
String xml;
String xmlStr;
Map<String, String> result = new HashMap<>();
try {
String sign = WXPayUtil.generateSignature(param, payKey);
//生成之后放入参数中
param.put("sign", sign);
//调用微信官网提供的工具类将map转换为xml格式的文件
xml = WXPayUtil.mapToXml(param);
//拼接请求路径,使用微信工具类
String url = "https://" + WXPayConstants.DOMAIN_API + WXPayConstants.UNIFIEDORDER_URL_SUFFIX;
//发送post请求,携带xml数据
xmlStr = HttpUtils.sendPost(url, xml);
log.info("微信支付返回的数据为=》" + xmlStr);
// 返回的数据转换为map数据,
Map<String, String> stringStringMap = WXPayUtil.xmlToMap(xmlStr);
log.info("返回转换的map数据=》" + stringStringMap);
//新建一个返回的mapA
if (stringStringMap.get("return_code").equals("SUCCESS")) {
//将结果放入result map中,返回前台用
result.put("appId", appid);
result.put("timeStamp", WXPayUtil.getCurrentTimestamp() + "");
result.put("nonceStr", WXPayUtil.generateNonceStr());
result.put("signType", WXPayConstants.MD5);
result.put("package", "prepay_id=" + stringStringMap.get("prepay_id"));
result.put("paySign", WXPayUtil.generateSignature(result, payKey));
log.info("微信支付拼装数据=》" + result);
} else {
result.put("code", "401");
result.put("message", stringStringMap.get("PARAM_ERROR"));
log.error("微信支付错误!==》订单号==>" + orderId);
return result;
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}

微信退款

工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/**
* 退款发送post
*
* @param url 地址
* @param xml 数据
* @return
*/
private Map<String, String> sendPost(String url, String xml) {
CloseableHttpClient build;
FileInputStream stream = null;
try {
KeyStore keyStore = KeyStore.getInstance("PKCS12");
// 直接写你的服务器文件路径就可以,可能需要注意你服务器文件的访问权限,以避免读取不到文件
// stream = IoUtil.toStream(new File("D:\\pay\\apiclient_cert.p12"));
stream = IoUtil.toStream(new File("/opt/cert/apiclient_cert.p12"));
// 这里的证书密码默认为微信分配的 商户号
keyStore.load(stream, mch_id.toCharArray());
// 这里需要注意的一点是,这里调用的loadKeyMaterial方法依旧是传入密码的那个方法,密码还是微信分配的 商户号
SSLContext sslContext = new SSLContextBuilder().loadKeyMaterial(keyStore, mch_id.toCharArray()).build();
// 这里就算是返回一个已经绑定好正式的CloseableHttpClient对象了
build = HttpClientBuilder.create().setSSLContext(sslContext)
.setConnectionManager(new PoolingHttpClientConnectionManager(RegistryBuilder
.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.INSTANCE)
.register("https", new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE))
.build()))
.build();
} catch (Exception e) {
e.printStackTrace();
log.error("加载微信支付证书异常");
return null;
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//发送post请求,携带xml数据
Executor executor = Executor.newInstance(build);
// 这里是请求对象,就是微信退款API需要的一些参数,请求的格式等,我这里就不做叙述了。微信文档中描述的很清楚
Request request = Request.Post(url).addHeader("Content-Type", ContentType.APPLICATION_XML.getMimeType())
.bodyString(xml, ContentType.create(ContentType.APPLICATION_XML.getMimeType(), "UTF-8"));
Map<String, String> data = new HashMap<>();
try {
// 这里发送请求,得到微信的返回值,值得注意的是微信退款的异步回调通知中返回的数据是加密过得
Response execute = executor.execute(request);
HttpResponse httpResponse = execute.returnResponse();
HttpEntity entity = httpResponse.getEntity();
String postResult = EntityUtils.toString(entity, "UTF-8");
log.info("微信申请退款结果返回===>"+postResult);
// 返回的数据转换为map数据,
data = WXPayUtil.xmlToMap(postResult);
log.info("解析微信申请退款map===>"+data);
} catch (Exception e) {
log.error("微信支付退款申请失败:{}", e.getMessage());
e.printStackTrace();
}
return data;
}

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
 /**
* 微信退款
*
* @param orderId 订单号
* @param totalMoney 订单金额
* @param money 退款金额
*/
public CommonResult<Integer> refund(String orderId, BigDecimal totalMoney, BigDecimal money) {
log.info("===微信订单退款开始===");
//拼接参数
Map<String, String> param = new HashMap<>();
param.put("appid", appid);
param.put("mch_id", mch_id);
// 随机字符串
param.put("nonce_str", WXPayUtil.generateNonceStr());
String xml = null;
try {
// 商户订单号
param.put("out_trade_no", orderId);
// 退款单号
param.put("out_refund_no", orderId);
//把金额转换为分,并转换为字符串。
param.put("total_fee", String.valueOf((totalMoney.multiply(new BigDecimal(100)))));
param.put("refund_fee", String.valueOf((money.multiply(new BigDecimal(100)))));
// 调用微信支付官网提供的工具类生成sign签名,第一个参数为param中的上面的参数,第二个为支付的秘钥
param.put("sign", WXPayUtil.generateSignature(param, payKey));
//调用微信官网提供的工具类将map转换为xml格式的文件
xml = WXPayUtil.mapToXml(param);
} catch (Exception e) {
e.printStackTrace();
}
//拼接请求路径
String url = "https://" + WXPayConstants.DOMAIN_API + WXPayConstants.REFUND_URL_SUFFIX;
Map<String, String> data = sendPost(url, xml);
if (data != null) {
if (data.get("return_code").equals("SUCCESS")) {
//支付成功,获取商户订单号
String out_trade_no = data.get("out_trade_no");
if(out_trade_no != null){
// 进行退款
// 写业务逻辑
log.info("订单号:"+out_trade_no+"退款成功");
return new CommonResult<>(1);
}else{
return new CommonResult<>(data.get("err_code_des"),null);
}
}
}
return new CommonResult<>("退款失败,错误信息请看日志",null);
}

相关文章

IJPay接入微信支付和支付宝支付