@[clownss] java开发微信付款码支付
微信支付–付款码支付
写在前面的话,各位大佬,晚上好!今儿是小弟第一次发表博客,我是一名刚入行的程序员,写的不好或是不对的地方,希望各位见谅。还请各位大佬能够指导,给予小弟一份帮助。谢谢大家!今天写的是我最近研究的微信付款码支付的一个小demo。
官方地址:https://pay.weixin.qq.com/wiki/doc/api/index.html
1.支付方式
微信官方提供了以下几种支付方式:
-
付款码支付:用户打开微信钱包-付款码的界面,商户扫码后提交完成支付
-
JSAPI支付:用户通过微信扫码、关注公众号等方式进入商家H5页面,并在微信内调用JSSDK完成支付
-
Native支付:用户打开“微信扫一扫”,扫描商户的二维码后完成支付
-
H5支付:用户在微信以外的手机浏览器请求微信支付的场景唤起微信支付
-
小程序支付:用户在微信小程序中使用微信支付的场景
我这里只是讨论的是
付款码支付
2.准备参数
微信付款码开发需要准备:appid,商户号,密钥
- appid(公众账号ID )微信分配的公众账号ID(企业号corpid即为此appId)
- mch_id (商户号 )微信支付分配的商户号
- key(密钥)微信API密钥
2.1付款码支付开发流程
-
第一步需要注册微信公众号,在微信公众号里面微信回给我们分配的开发者ID(AppID) 以及开发者密码(AppSecret) ,这两个需要我们妥善保管。appid在微信开发的几种模式都需要用到。
-
第二步就是需要注册商户号了,这里注册就比较严格了。商户平台会给我们分配商户号(mch_id )
-
第三步设置API密钥,简单流程就是:安装操作证书 -> 设置API密钥
操作指引:可参考
http://kf.qq.com/faq/161222NneAJf161222U7fARv.html
3.代码实现(简单开发)
这里主要写我在开发过程中具体实现,一个简单的jsp+servlet开发,需要下载官方的demo。
- 到maven仓库下载需要的jar包
wxpay-sdk-0.0.3.jar
和dom4j-1.6.1.jar
放到我们的项目中 - 编写
IWXPayDomain
接口,官方demo里面也有这个接口
/**
* 域名管理,实现主备域名自动切换
*/
public interface IWXPayDomain {
/**
* 上报域名网络状况
* @param domain 域名。 比如:api.mch.weixin.qq.com
* @param elapsedTimeMillis 耗时
* @param ex 网络请求中出现的异常。
* null表示没有异常
* ConnectTimeoutException,表示建立网络连接异常
* UnknownHostException, 表示dns解析异常
*/
void report(final String domain, long elapsedTimeMillis, final Exception ex);
/**
* 获取域名
* @param config 配置
* @return 域名
*/
DomainInfo getDomain(final WXPayConfig config);
class DomainInfo{
/**
* 域名
*/
public String domain;
/**
* 该域名是否为主域名。例如:api.mch.weixin.qq.com为主域名
*/
public boolean primaryDomain;
public DomainInfo(String domain, boolean primaryDomain) {
this.domain = domain;
this.primaryDomain = primaryDomain;
}
@Override
public String toString() {
return "DomainInfo{" +
"domain='" + domain + '\'' +
", primaryDomain=" + primaryDomain +
'}';
}
}
}
- 编写
MyConfig
类实现微信sdk里面的WXPayConfig
接口,这里面主要是准备我们自己的参数,就是上面准备的appid,商户号,密钥
public class MyConfig implements WXPayConfig {
/** 加载证书 这里证书需要到微信商户平台进行下载*/
private byte[] certData;
public MyConfig() throws Exception {
//证书只是撤销订单时会使用,在这里的demo中没有用到
/*String certPath = "自己商户平台下载的证书";
File file = new File(certPath);
InputStream certStream = new FileInputStream(file);
this.certData = new byte[(int) file.length()];
certStream.read(this.certData);
certStream.close();*/
}
/**
* 设置自己的appId ,商户号,密钥
* @return
*/
@Override
public String getAppID() {
return "自己的appId";
}
@Override
public String getMchID() {
return "自己的商户号";
}
@Override
public String getKey() {
return "自己的密钥";
}
@Override
public InputStream getCertStream() {
ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);
return certBis;
}
@Override
public int getHttpConnectTimeoutMs() {
return 8000;
}
@Override
public int getHttpReadTimeoutMs() {
return 10000;
}
/**
*这里的方法,实现必须如下
*/
IWXPayDomain getWXPayDomain() {
IWXPayDomain iwxPayDomain = new IWXPayDomain() {
@Override
public void report(String domain, long elapsedTimeMillis, Exception ex) {
}
@Override
public DomainInfo getDomain(WXPayConfig config) {
return new IWXPayDomain.DomainInfo("api.mch.weixin.qq.com", true);
}
};
return iwxPayDomain;
}
}
- 编写我们的支付方法(接口)了
public class MyWXPay {
private static final String PAY_SUCCESS = "SUCCESS";
private static final String PAY_USERPAYING = "USERPAYING";
private MyWXPay(){}
private static Log log = LogFactory.getLog(MyWXPay.class);
/**
* 扫码支付
* @throws Exception
*/
public static String scanCodeToPay(String auth_code) throws Exception {
MyConfig config = new MyConfig();
WXPay wxpay = new WXPay(config);
String out_trade_no = DateUtil.getCurrentTime();
Map<String, String> map = new HashMap<>(16);
map.put("attach", "订单额外描述");
map.put("auth_code", auth_code);
map.put("body", "付款码支付测试");
map.put("device_info", "1000");
map.put("nonce_str", WXPayUtil.generateNonceStr());
map.put("out_trade_no", out_trade_no);
map.put("spbill_create_ip", "14.17.22.52");
map.put("total_fee", "2");
//生成签名
String sign = WXPayUtil.generateSignature(map, config.getKey());
map.put("sign", sign);
String mapToXml = null;
try {
//调用微信的扫码支付接口
Map<String, String> resp = wxpay.microPay(map);
mapToXml = WXPayUtil.mapToXml(resp);
} catch (Exception e) {
e.printStackTrace();
log.error("微信支付失败"+ e);
}
//判断支付是否成功
String return_code = null;
String result_code = null;
String err_code_des = null;
String err_code = null;
//获取Document对象(主要是获取支付接口的返回信息)
Document doc = DocumentHelper.parseText(mapToXml);
//获取对象的根节点<xml>
Element rootElement = doc.getRootElement();
//获取对象的子节点
List<Element> elements = rootElement.elements();
for (Element element : elements) {
if(element.getName().equals("return_code")){
return_code = element.getTextTrim();
} else if(element.getName().equals("result_code")){
result_code = element.getTextTrim();
} else if(element.getName().equals("err_code_des")){
err_code_des = element.getTextTrim();
} else if(element.getName().equals("err_code")){
err_code = element.getTextTrim();
}
}
if(PAY_SUCCESS.equals(return_code) && PAY_SUCCESS.equals(result_code)){
log.info("微信免密支付成功!");
return PAY_SUCCESS;
} else if (PAY_USERPAYING.equals(err_code)){
for(int i = 0; i < 4; i++){
Thread.sleep(3000);
Map<String, String> data = new HashMap<>(16);
data.put("out_trade_no", out_trade_no);
//调用微信的查询接口
Map<String, String> orderQuery = wxpay.orderQuery(data);
String orderResp = WXPayUtil.mapToXml(orderQuery);
String trade_state = null;
//获取Document对象
Document orderDoc = DocumentHelper.parseText(orderResp);
//获取对象的根节点<xml>
Element rootElement1 = orderDoc.getRootElement();
//获取对象的子节点
List<Element> elements1 = rootElement1.elements();
for (Element element : elements1) {
if(element.getName().equals("trade_state")){
trade_state = element.getTextTrim();
}
}
if(PAY_SUCCESS.equals(trade_state)){
log.info("微信加密支付成功!");
return PAY_SUCCESS;
}
log.info("正在支付" + orderResp);
}
}
log.error("微信支付失败!");
return err_code_des;
}
}
我这里模拟了付款时需要输入密码,进行了三次轮询。里面的各个参数的含义,我这里就不详细写了,请参考官方文档:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_10&index=1
- 最后一步就是进行测试
@Test
public void test4(){
try {
String result = MyWXPay.scanCodeToPay("请填写测试微信二维码信息");
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
}
}
- 工具类代码
public class DateUtil {
private DateUtil(){
throw new RuntimeException("不能被实列化!");
}
/**
* 获取当前时间(14位)
* @return
*/
public static String getCurrentTime(){
Date now = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
return simpleDateFormat.format(now);
}
/**
* 获取当前时间戳,单位秒(10位)
* @return
*/
public static long getCurrentTimestamp() {
return System.currentTimeMillis()/1000;
}
/**
* 获取当前时间戳,单位毫秒(13位)
* @return
*/
public static long getCurrentTimestampMs() {
return System.currentTimeMillis();
}
}
今天的分享就是这些了,希望能给你有所帮助,写的不好还请大家见谅。在下一篇博客里我想给大家介绍第二种支付方式JSAPI支付
,希望得到大家的支持。谢谢大家!祝大家生活愉快,合家欢乐。