jsapi支付java_Java实现JsApi方式的微信支付

要使用JsApi进行微信支付,首先要从微信获得一个prepay_id,然后通过调用微信的jsapi完成支付,JS API的返回结果get_brand_wcpay_request:ok仅在用户成功完成支付时返回。由于前端交互复杂,get_brand_wcpay_request:cancel或者get_brand_wcpay_request:fail可以统一处理为用户遇到错误或者主动放弃,不必细化区分。

示例代码如下:

function onBridgeReady(){

WeixinJSBridge.invoke(

'getBrandWCPayRequest', {

"appId" : "wx2421b1c4370ec43b", //公众号名称,由商户传入

"timeStamp":" 1395712654", //时间戳,自1970年以来的秒数

"nonceStr" : "e61463f8efa94090b1f366cccfbbb444", //随机串

"package" : "u802345jgfjsdfgsdg888",

"signType" : "MD5", //微信签名方式:

"paySign" : "70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信签名

},

function(res){

if(res.err_msg == "get_brand_wcpay_request:ok" ) {} // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。

}

);

}

if (typeof WeixinJSBridge == "undefined"){

if( document.addEventListener ){

document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);

}else if (document.attachEvent){

document.attachEvent('WeixinJSBridgeReady', onBridgeReady);

document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);

}

}else{

onBridgeReady();

}

下面讲的是获得参数来调用jsapi

我们调用JSAPI时,必须获得用户的openid,(trade_type=JSAPI,openid为必填参数。)

首先定义一个请求的对象:

package com.unstoppedable.protocol;

import com.thoughtworks.xstream.annotations.XStreamAlias;

import com.unstoppedable.common.Configure;

import com.unstoppedable.common.RandomStringGenerator;

import com.unstoppedable.common.Signature;

import java.lang.reflect.Field;

import java.util.HashMap;

import java.util.Map;

@XStreamAlias("xml")

public class UnifiedOrderReqData {

private String appid;

private String mch_id;

private String device_info;

private String nonce_str;

private String sign;

private String body;

private String detail;

private String attach;

private String out_trade_no;

private String fee_type;

private int total_fee;

private String spbill_create_ip;

private String time_start;

private String time_expire;

private String goods_tag;

private String notify_url;

private String trade_type;

private String product_id;

private String limit_pay;

private String openid;

private UnifiedOrderReqData(UnifiedOrderReqDataBuilder builder) {

this.appid = builder.appid;

this.mch_id = builder.mch_id;

this.device_info = builder.device_info;

this.nonce_str = RandomStringGenerator.getRandomStringByLength(32);

this.body = builder.body;

this.detail = builder.detail;

this.attach = builder.attach;

this.out_trade_no = builder.out_trade_no;

this.fee_type = builder.fee_type;

this.total_fee = builder.total_fee;

this.spbill_create_ip = builder.spbill_create_ip;

this.time_start = builder.time_start;

this.time_expire = builder.time_expire;

this.goods_tag = builder.goods_tag;

this.notify_url = builder.notify_url;

this.trade_type = builder.trade_type;

this.product_id = builder.product_id;

this.limit_pay = builder.limit_pay;

this.openid = builder.openid;

this.sign = Signature.getSign(toMap());

}

public String getAppid() {

return appid;

}

public String getMch_id() {

return mch_id;

}

public String getDevice_info() {

return device_info;

}

public String getNonce_str() {

return nonce_str;

}

public String getSign() {

return sign;

}

public String getBody() {

return body;

}

public String getDetail() {

return detail;

}

public String getAttach() {

return attach;

}

public String getOut_trade_no() {

return out_trade_no;

}

public String getFee_type() {

return fee_type;

}

public int getTotal_fee() {

return total_fee;

}

public String getSpbill_create_ip() {

return spbill_create_ip;

}

public String getTime_start() {

return time_start;

}

public String getTime_expire() {

return time_expire;

}

public String getGoods_tag() {

return goods_tag;

}

public String getNotify_url() {

return notify_url;

}

public String getTrade_type() {

return trade_type;

}

public String getProduct_id() {

return product_id;

}

public String getLimit_pay() {

return limit_pay;

}

public String getOpenid() {

return openid;

}

public Map toMap() {

Map map = new HashMap();

Field[] fields = this.getClass().getDeclaredFields();

for (Field field : fields) {

Object obj;

try {

obj = field.get(this);

if (obj != null) {

map.put(field.getName(), obj);

}

} catch (IllegalArgumentException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

}

}

return map;

}

public static class UnifiedOrderReqDataBuilder {

private String appid;

private String mch_id;

private String device_info;

private String body;

private String detail;

private String attach;

private String out_trade_no;

private String fee_type;

private int total_fee;

private String spbill_create_ip;

private String time_start;

private String time_expire;

private String goods_tag;

private String notify_url;

private String trade_type;

private String product_id;

private String limit_pay;

private String openid;

/**

* 使用配置中的 appid 和 mch_id

*

* @param body

* @param out_trade_no

* @param total_fee

* @param spbill_create_ip

* @param notify_url

* @param trade_type

*/

public UnifiedOrderReqDataBuilder(String body, String out_trade_no, Integer total_fee,

String spbill_create_ip, String notify_url, String trade_type) {

this(Configure.getAppid(), Configure.getMchid(), body, out_trade_no, total_fee,

spbill_create_ip, notify_url, trade_type);

}

public UnifiedOrderReqDataBuilder(String appid, String mch_id, String body, String out_trade_no, Integer total_fee,

String spbill_create_ip, String notify_url, String trade_type) {

if (appid == null) {

throw new IllegalArgumentException("传入参数appid不能为null");

}

if (mch_id == null) {

throw new IllegalArgumentException("传入参数mch_id不能为null");

}

if (body == null) {

throw new IllegalArgumentException("传入参数body不能为null");

}

if (out_trade_no == null) {

throw new IllegalArgumentException("传入参数out_trade_no不能为null");

}

if (total_fee == null) {

throw new IllegalArgumentException("传入参数total_fee不能为null");

}

if (spbill_create_ip == null) {

throw new IllegalArgumentException("传入参数spbill_create_ip不能为null");

}

if (notify_url == null) {

throw new IllegalArgumentException("传入参数notify_url不能为null");

}

if (trade_type == null) {

throw new IllegalArgumentException("传入参数trade_type不能为null");

}

this.appid = appid;

this.mch_id = mch_id;

this.body = body;

this.out_trade_no = out_trade_no;

this.total_fee = total_fee;

this.spbill_create_ip = spbill_create_ip;

this.notify_url = notify_url;

this.trade_type = trade_type;

}

public UnifiedOrderReqDataBuilder setDevice_info(String device_info) {

this.device_info = device_info;

return this;

}

public UnifiedOrderReqDataBuilder setDetail(String detail) {

this.detail = detail;

return this;

}

public UnifiedOrderReqDataBuilder setAttach(String attach) {

this.attach = attach;

return this;

}

public UnifiedOrderReqDataBuilder setFee_type(String fee_type) {

this.fee_type = fee_type;

return this;

}

public UnifiedOrderReqDataBuilder setTime_start(String time_start) {

this.time_start = time_start;

return this;

}

public UnifiedOrderReqDataBuilder setTime_expire(String time_expire) {

this.time_expire = time_expire;

return this;

}

public UnifiedOrderReqDataBuilder setGoods_tag(String goods_tag) {

this.goods_tag = goods_tag;

return this;

}

public UnifiedOrderReqDataBuilder setProduct_id(String product_id) {

this.product_id = product_id;

return this;

}

public UnifiedOrderReqDataBuilder setLimit_pay(String limit_pay) {

this.limit_pay = limit_pay;

return this;

}

public UnifiedOrderReqDataBuilder setOpenid(String openid) {

this.openid = openid;

return this;

}

public UnifiedOrderReqData build() {

if ("JSAPI".equals(this.trade_type) && this.openid == null) {

throw new IllegalArgumentException("当传入trade_type为JSAPI时,openid为必填参数");

}

if ("NATIVE".equals(this.trade_type) && this.product_id == null) {

throw new IllegalArgumentException("当传入trade_type为NATIVE时,product_id为必填参数");

}

return new UnifiedOrderReqData(this);

}

}

}

因为有些参数为必填,有些参数为选填。而且sign要等所有参数传入之后才能计算的出,所以这里用了builder模式。关于builder模式。关于每个参数的定义,参考说明文档https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1

我们选用httpclient进行网络传输。

package com.unstoppedable.common;

import com.thoughtworks.xstream.XStream;

import com.thoughtworks.xstream.io.xml.DomDriver;

import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder;

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

import org.apache.http.HttpEntity;

import org.apache.http.HttpResponse;

import org.apache.http.client.ClientProtocolException;

import org.apache.http.client.ResponseHandler;

import org.apache.http.client.config.RequestConfig;

import org.apache.http.client.methods.HttpGet;

import org.apache.http.client.methods.HttpPost;

import org.apache.http.conn.ConnectTimeoutException;

import org.apache.http.conn.ConnectionPoolTimeoutException;

import org.apache.http.conn.ssl.SSLConnectionSocketFactory;

import org.apache.http.conn.ssl.SSLContexts;

import org.apache.http.entity.StringEntity;

import org.apache.http.impl.client.CloseableHttpClient;

import org.apache.http.impl.client.HttpClients;

import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;

import java.io.File;

import java.io.FileInputStream;

import java.io.IOException;

import java.net.SocketTimeoutException;

import java.security.KeyStore;

/**

* Created by hupeng on 2015/7/28.

*/

public class HttpService {

private static Log logger = LogFactory.getLog(HttpService.class);

private static CloseableHttpClient httpClient = buildHttpClient();

//连接超时时间,默认10秒

private static int socketTimeout = 5000;

//传输超时时间,默认30秒

private static int connectTimeout = 5000;

private static int requestTimeout = 5000;

public static CloseableHttpClient buildHttpClient() {

try {

KeyStore keyStore = KeyStore.getInstance("PKCS12");

FileInputStream instream = new FileInputStream(new File(Configure.getCertLocalPath()));//加载本地的证书进行https加密传输

try {

keyStore.load(instream, Configure.getCertPassword().toCharArray());//设置证书密码

} finally {

instream.close();

}

// Trust own CA and all self-signed certs

SSLContext sslcontext = SSLContexts.custom()

.loadKeyMaterial(keyStore, Configure.getCertPassword().toCharArray())

.build();

// Allow TLSv1 protocol only

SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(

sslcontext,

new String[]{"TLSv1"},

null,

SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);

RequestConfig requestConfig = RequestConfig.custom()

.setConnectTimeout(connectTimeout)

.setConnectionRequestTimeout(requestTimeout)

.setSocketTimeout(socketTimeout).build();

httpClient = HttpClients.custom()

.setDefaultRequestConfig(requestConfig)

.setSSLSocketFactory(sslsf)

.build();

return httpClient;

} catch (Exception e) {

throw new RuntimeException("error create httpclient......", e);

}

}

public static String doGet(String requestUrl) throws Exception {

HttpGet httpget = new HttpGet(requestUrl);

try {

logger.debug("Executing request " + httpget.getRequestLine());

// Create a custom response handler

ResponseHandler responseHandler = new ResponseHandler() {

@Override

public String handleResponse(

final HttpResponse response) throws ClientProtocolException, IOException {

int status = response.getStatusLine().getStatusCode();

if (status >= 200 && status < 300) {

HttpEntity entity = response.getEntity();

return entity != null ? EntityUtils.toString(entity) : null;

} else {

throw new ClientProtocolException("Unexpected response status: " + status);

}

}

};

return httpClient.execute(httpget, responseHandler);

} finally {

httpget.releaseConnection();

}

}

public static String doPost(String url, Object object2Xml) {

String result = null;

HttpPost httpPost = new HttpPost(url);

//解决XStream对出现双下划线的bug

XStream xStreamForRequestPostData = new XStream(new DomDriver("UTF-8", new XmlFriendlyNameCoder("-_", "_")));

//将要提交给API的数据对象转换成XML格式数据Post给API

String postDataXML = xStreamForRequestPostData.toXML(object2Xml);

logger.info("API,POST过去的数据是:");

logger.info(postDataXML);

//得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别

StringEntity postEntity = new StringEntity(postDataXML, "UTF-8");

httpPost.addHeader("Content-Type", "text/xml");

httpPost.setEntity(postEntity);

//设置请求器的配置

logger.info("executing request" + httpPost.getRequestLine());

try {

HttpResponse response = httpClient.execute(httpPost);

HttpEntity entity = response.getEntity();

result = EntityUtils.toString(entity, "UTF-8");

} catch (ConnectionPoolTimeoutException e) {

logger.error("http get throw ConnectionPoolTimeoutException(wait time out)", e);

} catch (ConnectTimeoutException e) {

logger.error("http get throw ConnectTimeoutException", e);

} catch (SocketTimeoutException e) {

logger.error("http get throw SocketTimeoutException", e);

} catch (Exception e) {

logger.error("http get throw Exception", e);

} finally {

httpPost.abort();

}

return result;

}

}

然后是我们的总入口:

package com.unstoppedable.service;

import com.unstoppedable.common.Configure;

import com.unstoppedable.common.HttpService;

import com.unstoppedable.common.XMLParser;

import com.unstoppedable.protocol.UnifiedOrderReqData;

import org.xml.sax.SAXException;

import javax.xml.parsers.ParserConfigurationException;

import java.io.IOException;

import java.util.Map;

/**

* Created by hupeng on 2015/7/28.

*/

public class WxPayApi {

public static Map UnifiedOrder(UnifiedOrderReqData reqData) throws IOException, SAXException, ParserConfigurationException {

String res = HttpService.doPost(Configure.UNIFIED_ORDER_API, reqData);

return XMLParser.getMapFromXML(res);

}

public static void main(String[] args) throws Exception {

UnifiedOrderReqData reqData = new UnifiedOrderReqData.UnifiedOrderReqDataBuilder("appid", "mch_id", "body", "out_trade_no", 1, "spbill_create_ip", "notify_url", "JSAPI").setOpenid("openid").build();

System.out.println(UnifiedOrder(reqData));

}

}

返回的xml为:

return_code 和result_code都为SUCCESS的时候会返回我们需要的prepay_id。。。

然后在jsapi中使用他就可以了。。

代码托管在https://github.com/hupengcool/wxpay_jsapi ,欢迎指正

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值