微信支付java版本之Native付款

最近工作中接触到一些关于微信支付方面的东西,看到给的DEMO都是PHP版本的,再加上微信支付文档写的确实不敢恭维,趟过不少坑之后闲下来做个总结。

一、前期准备 

做微信开发首先要申请一个公共账号,申请成功后会以邮件形式发给你一些必要信息,公共账号中有开发文档以及开发中必要信息,以及测试的数据查询。

二、工具类

1.MD5加密工具类 

package com.pay.utils.weixin;

import java.security.MessageDigest;

public class MD5Util {

public final static String MD5(String s) {

char hexDigits[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};

try {

byte[] btInput = s.getBytes();

// 获得MD5摘要算法的 MessageDigest 对象

MessageDigest mdInst = MessageDigest.getInstance("MD5");

// 使用指定的字节更新摘要

mdInst.update(btInput);

// 获得密文

byte[] md = mdInst.digest();

// 把密文转换成十六进制的字符串形式

int j = md.length;

char str[] = new char[j * 2];

int k = 0;

for (int i = 0; i < j; i++) {

byte byte0 = md[i];

str[k++] = hexDigits[byte0 >>> 4 & 0xf];

str[k++] = hexDigits[byte0 & 0xf];

}

return new String(str);

} catch (Exception e) {

e.printStackTrace();

return null;

}

}

}

2.CommonUtil工具类,用于装换成微信所需XML。以下return new String(xml.toString().getBytes(),"ISO8859-1");将工具类中的utf-8改成iso8859-1,否则微信订单中的中文会出现乱码,改后可以正确显示。 

package com.pay.utils.weixin;

import java.io.UnsupportedEncodingException;

import java.net.URLEncoder;

import java.util.*;

import java.util.Map.Entry;

public class CommonUtil {

public static String CreateNoncestr(int length) {

String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

String res = "";

for (int i = 0; i < length; i++) {

Random rd = new Random();

res += chars.indexOf(rd.nextInt(chars.length() - 1));

}

return res;

}

public static String CreateNoncestr() {

String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

String res = "";

for (int i = 0; i < 16; i++) {

Random rd = new Random();

res += chars.charAt(rd.nextInt(chars.length() - 1));

}

return res;

}

public static String FormatQueryParaMap(HashMap<String, String> parameters)

throws SDKRuntimeException {

String buff = "";

try {

List<Map.Entry<String, String>> infoIds = new ArrayList<Map.Entry<String, String>>(

parameters.entrySet());

Collections.sort(infoIds,

new Comparator<Map.Entry<String, String>>() {

public int compare(Map.Entry<String, String> o1,

Map.Entry<String, String> o2) {

return (o1.getKey()).toString().compareTo(

o2.getKey());

}

});

for (int i = 0; i < infoIds.size(); i++) {

Map.Entry<String, String> item = infoIds.get(i);

if (item.getKey() != "") {

buff += item.getKey() + "="

+ URLEncoder.encode(item.getValue(), "utf-8") + "&";

}

}

if (buff.isEmpty() == false) {

buff = buff.substring(0, buff.length() - 1);

}

} catch (Exception e) {

throw new SDKRuntimeException(e.getMessage());

}

return buff;

}

public static String FormatBizQueryParaMap(HashMap<String, String> paraMap,

boolean urlencode) throws SDKRuntimeException {

String buff = "";

try {

List<Map.Entry<String, String>> infoIds = new ArrayList<Map.Entry<String, String>>(

paraMap.entrySet());

Collections.sort(infoIds,

new Comparator<Map.Entry<String, String>>() {

public int compare(Map.Entry<String, String> o1,

Map.Entry<String, String> o2) {

return (o1.getKey()).toString().compareTo(

o2.getKey());

}

});

for (int i = 0; i < infoIds.size(); i++) {

Map.Entry<String, String> item = infoIds.get(i);

//System.out.println(item.getKey());

if (item.getKey() != "") {

String key = item.getKey();

String val = item.getValue();

if (urlencode) {

val = URLEncoder.encode(val, "utf-8");

}

buff += key.toLowerCase() + "=" + val + "&";

}

}

if (buff.isEmpty() == false) {

buff = buff.substring(0, buff.length() - 1);

}

} catch (Exception e) {

throw new SDKRuntimeException(e.getMessage());

}

return buff;

}

public static boolean IsNumeric(String str) {

if (str.matches("\\d *")) {

return true;

} else {

return false;

}

}

public static String ArrayToXml(HashMap<String, String> arr) {

String xml = "<xml>";

Iterator<Entry<String, String>> iter = arr.entrySet().iterator();

while (iter.hasNext()) {

Entry<String, String> entry = iter.next();

String key = entry.getKey();

String val = entry.getValue();

if (IsNumeric(val)) {

xml += "<" + key + ">" + val + "</" + key + ">";

} else

xml += "<" + key + "><![CDATA[" + val + "]]></" + key + ">";

}

xml += "</xml>";

try {

return new String(xml.toString().getBytes(),"ISO8859-1");

} catch (UnsupportedEncodingException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

return "";

}

}

3.ClientCustomSSL工具类,用于生成sign以及创建微信订单package com.pay.utils.weixin;

import java.util.ArrayList;

import java.util.Collections;

import java.util.Comparator;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import org.springframework.util.StringUtils;

/**

* This example demonstrates how to create secure connections with a custom SSL

* context.

*/

public class ClientCustomSSL {

public static String GetBizSign(HashMap<String, String> bizObj)

throws SDKRuntimeException {

HashMap<String, String> bizParameters = new HashMap<String, String>();

List<Map.Entry<String, String>> infoIds = new ArrayList<Map.Entry<String, String>>(

bizObj.entrySet());

System.out.println(infoIds);

Collections.sort(infoIds, new Comparator<Map.Entry<String, String>>() {

public int compare(Map.Entry<String, String> o1,

Map.Entry<String, String> o2) {

return (o1.getKey()).toString().compareTo(o2.getKey());

}

});

System.out.println("--------------------");

System.out.println(infoIds);

for (int i = 0; i < infoIds.size(); i++) {

Map.Entry<String, String> item = infoIds.get(i);

if (item.getKey() != "") {

bizParameters.put(item.getKey().toLowerCase(), item.getValue());

}

}

//bizParameters.put("key", "12345678123456781234567812345671");

String bizString = CommonUtil.FormatBizQueryParaMap(bizParameters,

false);

bizString += "&key=12345678123456781234567812345671";

System.out.println("***************");

System.out.println(bizString);

// return SHA1Util.Sha1(bizString);

return MD5Util.MD5(bizString);

}

/**

* 微信创建订单

* @param nonceStr

* @param orderDescribe

* @param orderNo

* @param price

* @param timeStart

* @param timeExpire

* @return

* @throws SDKRuntimeException

*/

public static String CreateNativePackage(String nonceStr,String orderDescribe,String orderNo,String price,String timeStart,String timeExpire) throws SDKRuntimeException {

HashMap<String, String> nativeObj = new HashMap<String, String>();

nativeObj.put("appid", "见公众账号"); //公众账号Id

nativeObj.put("mch_id", "见邮件"); //商户号

nativeObj.put("nonce_str", nonceStr); //随机字符串

nativeObj.put("body", orderDescribe); //商品描述

nativeObj.put("attach", "tradeno"); //附加数据

nativeObj.put("out_trade_no", orderNo); //商户订单号(全局唯一)

nativeObj.put("total_fee", price); //总金额(单位为分,不能带小数点)

nativeObj.put("spbill_create_ip","192.168.0.144"); //终端Ip

nativeObj.put("time_start", timeStart); //交易起始时间

nativeObj.put("time_expire", timeExpire); //交易结束时间

nativeObj.put("notify_url", CustomizedPropertyPlaceholderConfigurer.getContextProperty("wxurl")+"/weixin_callback/weixinCallback/init.action"); //回调通知地址

nativeObj.put("trade_type", "NATIVE"); //交易类型

String sign = GetBizSign(nativeObj);

nativeObj.put("sign", sign.toUpperCase());

return CommonUtil.ArrayToXml(nativeObj);

} /**

* 微信订单支付查询

* @param nonceStr

* @param orderDescribe

* @param orderNo

* @param price

* @param timeStart

* @param timeExpire

* @return

* @throws SDKRuntimeException

*/

public static String SearchNativePackage(String transactionId,String outTradeNo,String nonceStr) throws SDKRuntimeException {

HashMap<String, String> nativeObj = new HashMap<String, String>();

nativeObj.put("appid", "见公众共账号"); //公众账号Id

nativeObj.put("mch_id", "见邮件");//商户号

nativeObj.put("nonce_str", nonceStr);//随机字符串

if(!StringUtils.isEmpty(transactionId)){

nativeObj.put("transaction_id", transactionId);

}

if(!StringUtils.isEmpty(outTradeNo)){

nativeObj.put("out_trade_no", outTradeNo);//随机字符串

}

String sign = GetBizSign(nativeObj);

nativeObj.put("sign", sign.toUpperCase());

return CommonUtil.ArrayToXml(nativeObj);

/**

* 微信退款

* @param outTradeNo

* @param outRefundNo

* @param totalFee

* @param refundFee

* @return

* @throws SDKRuntimeException

*/

public static String RefundNativePackage(String outTradeNo,String outRefundNo,String totalFee,String refundFee,String nonceStr) throws SDKRuntimeException {

HashMap<String, String> nativeObj = new HashMap<String, String>();

nativeObj.put("appid", "见公众账号");//公众账号Id

nativeObj.put("mch_id", "见邮件");//商户号

nativeObj.put("nonce_str", nonceStr);//随机字符串

nativeObj.put("out_trade_no", outTradeNo);//商户订单号(全局唯一)

nativeObj.put("out_refund_no", outRefundNo);//商户退款单号(全局唯一)

nativeObj.put("total_fee", totalFee);//总金额(单位为分,不能带小数点)

nativeObj.put("refund_fee", refundFee);//退款金额(单位为分,不能带小数点)

nativeObj.put("op_user_id", "邮件");

String sign = GetBizSign(nativeObj);

nativeObj.put("sign", sign.toUpperCase());

return CommonUtil.ArrayToXml(nativeObj);

}

/**

* 微信待支付

* @param nonceStr

* @param orderDescribe

* @param orderNo

* @param price

* @param timeStart

* @param timeExpire

* @return

* @throws SDKRuntimeException

*/

public static String CreateJsApiPackage(String nonceStr,String orderDescribe,String orderNo,String price,String timeStart,String timeExpire,String openId) throws SDKRuntimeException {

HashMap<String, String> nativeObj = new HashMap<String, String>();

nativeObj.put("appid", "见公众账号");//公众账号Id

nativeObj.put("openid", openId);//公众账号Id

nativeObj.put("mch_id", "见邮件")//商户号

nativeObj.put("nonce_str", nonceStr);//随机字符串

nativeObj.put("body", orderDescribe);//商品描述

nativeObj.put("attach", "tradeno");//附加数据

nativeObj.put("out_trade_no", orderNo);//商户订单号(全局唯一)

nativeObj.put("total_fee", price);//总金额(单位为分,不能带小数点)

nativeObj.put("spbill_create_ip","192.168.0.144");//终端Ip

nativeObj.put("time_start", timeStart);//交易起始时间

nativeObj.put("time_expire", timeExpire)//交易结束时间

nativeObj.put("notify_url",CustomizedPropertyPlaceholderConfigurer.getContextProperty("wxurl")+"/weixin_callback/weixinCallback/init.action");//通知地址

nativeObj.put("trade_type", "JSAPI");//交易类型

String sign = GetBizSign(nativeObj);

nativeObj.put("sign", sign.toUpperCase());

return CommonUtil.ArrayToXml(nativeObj);

}

/**

* 微信关闭订单

* @param nonceStr

* @param orderDescribe

* @param orderNo

* @param price

* @param timeStart

* @param timeExpire

* @param openId

* @return

* @throws SDKRuntimeException

*/

public static String CreateCloseOrder(String outTradeNo,String nonceStr) throws SDKRuntimeException {

HashMap<String, String> nativeObj = new HashMap<String, String>();

nativeObj.put("appid", "见公众账号");//公众账号Id

nativeObj.put("mch_id", "见邮件");//商户号

nativeObj.put("out_trade_no", outTradeNo);//商户订单号(全局唯一)

nativeObj.put("nonce_str", nonceStr);//随机字符串

String sign = GetBizSign(nativeObj);

nativeObj.put("sign", sign.toUpperCase());

return CommonUtil.ArrayToXml(nativeObj);

}

}

4.调用微信支付接口 

package com.pay.controller.weixin;

import java.io.File;

import java.io.FileInputStream;

import java.security.KeyStore;

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.List;

import javax.net.ssl.SSLContext;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import net.sf.json.JSONArray;

import net.sf.json.JSONObject;

import org.apache.http.HttpEntity;

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

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

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 org.dom4j.Document;

import org.dom4j.DocumentHelper;

import org.dom4j.Element;

import org.dom4j.io.SAXReader;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.http.HttpStatus;

import org.springframework.web.bind.annotation.RequestBody;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.ResponseStatus;

import org.springframework.web.bind.annotation.RestController;

import com.pay.bo.PayHist;

import com.pay.constants.PayHistoryPayStatus;

import com.pay.constants.PayHistoryPayType;

import com.pay.service.WeiXinPayService;

import com.pay.utils.weixin.ClientCustomSSL;

import com.pay.utils.weixin.CloseWeiXinOrderUtils;

import com.pay.utils.weixin.CustomizedPropertyPlaceholderConfigurer;

@RestController

@RequestMapping("/Pay")

public class WeiXinPayController {

@Autowired

WeiXinPayService weiXinPayService;

private static long standardTime = 1662652800000L;

/**

* 返回生成二维码的url

* @param request

* @param response

* @return

*/

@RequestMapping(value="/getUrl",method=RequestMethod.POST)

@ResponseStatus(HttpStatus.OK)

public Object getUrl(HttpServletResponse response,@RequestBody String body){

try{

JSONObject jsonO = JSONObject.fromObject(body);

PayHist ph = null;

// List<Map<String,Object>> td = weiXinPayService.getTrade(orderNo);

Date dt = new Date();

SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");

String nonceStr = sdf.format(dt).toString();

Date now = new Date();

String tradePayNo = jsonO.get("orderNo").toString()+String.format("%10d",standardTime - now.getTime()).substring(0, 10);

System.out.println("订单标号orderNo======="+jsonO.get("orderNo").toString());

System.out.println("10位随机数======="+String.format("%10d",standardTime - now.getTime()).substring(0, 10));

String price = Math.round(Float.valueOf(jsonO.get("price").toString())*100)+"";

Long timeExpireStrOld = dt.getTime();

Long timeNew = Long.parseLong(CustomizedPropertyPlaceholderConfigurer.getContextProperty("weixin.send2finish.overtime").toString());

Long timeExpireNew = timeExpireStrOld+timeNew;

Date dtTimeExpire = new Date(timeExpireNew);

SimpleDateFormat dtSdf = new SimpleDateFormat("yyyyMMddHHmmss");

String timeExpire = dtSdf.format(dtTimeExpire).toString();

System.out.println("nonceStr=="+nonceStr);

System.out.println("orderNo=="+jsonO.get("orderNo").toString());

System.out.println("price=="+price);

System.out.println("timeStart=="+nonceStr);

System.out.println("timeExpire=="+timeExpire);

JSONObject result = (JSONObject) setUrl(nonceStr,"订单",tradePayNo,price,nonceStr,timeExpire);

if(result.get("status").toString().equals("success")){

ph = new PayHist();

ph.setTradePayUrl(result.getString("weixinPayUrl"));//此字段为支付链接,可以此链接生成二维码扫码支付

ph.setPayTradeNo(jsonO.get("orderNo").toString());

ph.setTradePayNo(tradePayNo);

ph.setPayStatus(PayHistoryPayStatus.WECHAT_PAY_STATUS_WAIT);

ph.setPayType(PayHistoryPayType.WECHAT);

ph.setAppKey(jsonO.getString("appKey").toString());

ph.setPayAmount(price);

result.put("payTradeNo", ph.getPayTradeNo());

result.put("tradePayNo", ph.getTradePayNo());

result.put("payStatus", ph.getPayStatus());

result.put("payType", ph.getPayType());

}

return result;

}catch(Exception e){

e.printStackTrace();

JSONObject result = new JSONObject();

result.put("status","error");

result.put("msg",e.getMessage());

// return result.toString();

}

return null;

}

public Object setUrl(String nonceStr,String orderDescribe,String orderNo,String price,String timeStart,String timeExpire) {

try{

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

FileInputStream instream = new FileInputStream(new File(微信证书绝对路径));

try {

keyStore.load(instream, "商户ID".toCharArray());

}finally {

instream.close();

}

// Trust own CA and all self-signed certs

SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore,<span style="font-family: Arial, Helvetica, sans-serif;">商户ID</span>.toCharArray()).build();

// Allow TLSv1 protocol only

SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(

sslcontext, new String[] { "TLSv1" }, null,

SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

CloseableHttpClient httpclient = HttpClients.custom()

.setSSLSocketFactory(sslsf).build();

// HttpGet httpget = new

// HttpGet("https://api.mch.weixin.qq.com/secapi/pay/refund");

HttpPost httppost = new HttpPost(

"https://api.mch.weixin.qq.com/pay/unifiedorder");

String xml = ClientCustomSSL.CreateNativePackage(nonceStr,orderDescribe,orderNo,price,timeStart,timeExpire);

try {

StringEntity se = new StringEntity(xml);

httppost.setEntity(se);

System.out.println("executing request" + httppost.getRequestLine());

CloseableHttpResponse responseEntry = httpclient.execute(httppost);

try {

HttpEntity entity = responseEntry.getEntity();

System.out.println("----------------------------------------");

System.out.println(responseEntry.getStatusLine());

if (entity != null) {

System.out.println("Response content length: "

+ entity.getContentLength());

/* BufferedReader bufferedReader = new BufferedReader(

new InputStreamReader(entity.getContent()));

String text;

while ((text = bufferedReader.readLine()) != null) {

System.out.println("======="+text);

}*/

SAXReader saxReader = new SAXReader();

Document document = saxReader.read(entity.getContent());

Element rootElt = document.getRootElement();

System.out.println("根节点:" + rootElt.getName());

System.out.println("==="+rootElt.elementText("result_code"));

System.out.println("==="+rootElt.elementText("return_msg"));

String resultCode = rootElt.elementText("result_code");

JSONObject result = new JSONObject();

Document documentXml =DocumentHelper.parseText(xml);

Element rootEltXml = documentXml.getRootElement();

if(resultCode.equals("SUCCESS")){

System.out.println("=================prepay_id===================="+ rootElt.elementText("prepay_id"));

System.out.println("=================sign===================="+ rootEltXml.elementText("sign"));

result.put("weixinPayUrl", rootElt.elementText("code_url"));

result.put("prepayId", rootElt.elementText("prepay_id"));

result.put("status","success");

result.put("msg","success");

}else{

result.put("status","false");

result.put("msg",rootElt.elementText("err_code_des"));

}

return result;

}

EntityUtils.consume(entity);

}

finally {

responseEntry.close();

}

}

finally {

httpclient.close();

}

return null;

}catch(Exception e){

e.printStackTrace();

JSONObject result = new JSONObject();

result.put("status","error");

result.put("msg",e.getMessage());

return result;

}

}

}

httpclient  jar包和json jar包:下载地址。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

以上是 微信支付java版本之Native付款 的全部内容, 来源链接: utcz.com/p/210115.html

回到顶部