1 提示语,按照微信官方提供的代码,调用支付时不会加载到证书,只有退款才会涉及到证书的认证 https://pay.weixin.qq.com/wiki/doc/api/index.html
在开发微信支付的过程中,微信官方提供了wxpay-sdk以及README.MD文件中开发demo。官方暂时未提供maven项目依赖(或者直接引用提供的代码,拷贝进项目即可),我们需要自己将wxpay-sdk代码引入项目或者自己手动打包到本地或者私服通过maven来管理。
微信支付官方sdk地址:https://pay.weixin.qq.com/wiki/doc/api/download/WxPayAPI_JAVA.zip
2 微信坑之1 抽象类WXPayConfig方法使用默认的修饰符
当自己打包到本地或者私服项目通过maven管理wxpay-sdk,创建自己的实现类MyWXPayconfig继承WXPayconfig抽象类时会提示“must either be declared abstract or implement abstract method ‘getAppID()’ in 'WXPayConfig”问题。
官方的wxpay-sdk源码中WXPayconfig抽象类的抽象方法没有指定public修饰符,则使用的是默认的修饰符default,default修饰符在其他包内是没有访问权限的,所以我们无法继承WXPayconfig抽象类实现抽象方法。解决方案是通过修改官方wxpay-sdk源码,将抽象方法的修饰符从默认修改为public,然后重新打包到本地或者私服,解决该问题。
3 微信坑之2---需要继续WXPayConfig,官方提示需要实现WXPayConfig,然抽象类无法实现,需要继承,以及对getWXPayDomain方法重写
public class MyConfig extends WXPayConfig{
private byte[] certData;
public MyConfig() throws Exception {
String certPath = "/path/to/apiclient_cert.p12";
File file = new File(certPath);
InputStream certStream = new FileInputStream(file);
this.certData = new byte[(int) file.length()];
certStream.read(this.certData);
certStream.close();
}
public String getAppID() {
return "wx8888888888888888";
}
public String getMchID() {
return "12888888";
}
public String getKey() {
return "88888888888888888888888888888888";
}
public InputStream getCertStream() {
ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);
return certBis;
}
public int getHttpConnectTimeoutMs() {
return 6000;
}
public int getHttpReadTimeoutMs() {
return 8000;
}
public IWXPayDomain getWXPayDomain() {
// 这个方法需要这样实现, 否则无法正常初始化WXPay
IWXPayDomain iwxPayDomain = new IWXPayDomain() {
public void report(String domain, long elapsedTimeMillis, Exception ex) {
}
public DomainInfo getDomain(WXPayConfig config) {
return new IWXPayDomain.DomainInfo(WXPayConstants.DOMAIN_API, true);
}
};
return iwxPayDomain;
}
}
4 微信扫码支付
import com.github.wxpay.sdk.WXPay;
import java.util.HashMap;
import java.util.Map;
public class WXPayExample {
public static void main(String[] args) throws Exception {
MyConfig config = new MyConfig();
//正式环境
WXPay wxpay = new WXPay(config);
//使用沙箱环境,加密类型为MD5
//WXPay wxpay = new WXPay(config, WXPayConstants.SignType.MD5, true);
Map<String, String> data = new HashMap<String, String>();
data.put("body", "腾讯充值中心-QQ会员充值");
data.put("out_trade_no", "2016090910595900000012");
data.put("device_info", "");
data.put("fee_type", "CNY");
data.put("total_fee", "1");
data.put("spbill_create_ip", "123.12.12.123");
data.put("notify_url", "http://www.example.com/wxpay/notify");
data.put("trade_type", "NATIVE"); // 此处指定为扫码支付
data.put("product_id", "12");
try {
Map<String, String> resp = wxpay.unifiedOrder(data);
//获取生成二维码的url,然后调用生成二维码工具类,通过io流输出返回到浏览器
//直接打开微信扫码,支付成功之后就会回调传入的notify_url地址,用来处理业务逻辑
String urlCode = (String) map.get( "code_url" );
System.out.println(resp);
} catch (Exception e) {
e.printStackTrace();
}
}
//生成二维码工具类https://blog.csdn.net/weixin_41500775/article/details/118526242?spm=1001.2014.3001.5501
}
5 微信扫码回调处理
public static void main(String[] args) throws Exception {
String notifyData = "...."; // 支付结果通知的xml格式数据
MyConfig config = new MyConfig();
WXPay wxpay = new WXPay(config);
Map<String, String> notifyMap = WXPayUtil.xmlToMap(notifyData); // 转换成map
if (wxpay.isPayResultNotifySignatureValid(notifyMap)) {
// 签名正确
// 进行处理。
// 注意特殊情况:订单已经退款,但收到了支付结果成功的通知,不应把商户侧订单状态从退款改成支付成功
}
else {
// 签名错误,如果数据里没有sign字段,也认为是签名错误
}
}
6 微信退款
public class WXPayExample {
public static void main(String[] args) throws Exception {
MyConfig config = new MyConfig();
WXPay wxpay = new WXPay(config);
Map<String, String> data = new HashMap<String, String>();
data.put("out_trade_no", "2016090910595900000012");
//transaction_id、out_trade_no二选一,如果同时存在优先级:
//transaction_id> out_trade_no
data.put("transaction_id", transaction_id);
data.put("total_fee", total_fee);
data.put("refund_fee", total_fee);
try {
Map<String, String> resp = wxpay.refund(data);
System.out.println(resp);
} catch (Exception e) {
e.printStackTrace();
}
}
}