java 7 微信支付 ssl_微信支付 Java后台接口

本文详细介绍了微信支付的流程,包括获取金额、构造订单、签名认证、服务端请求微信获取预付订单、移动端支付及回调处理。主要涉及微信支付API的调用,包括参数构造、签名生成、回调验证等关键步骤,适用于Java后端开发者实现微信支付功能。
摘要由CSDN通过智能技术生成

第一:首先有两个条件:

第二:大致步骤:

获取金额->构造商户自己的订单->签名认证->服务端请求微信获取微信订单->构造移动端所需参数->移动端客户支付->微信回调->商户自己的业务逻辑实现

第三:具体实现:

构造移动端所需参数

/**

* 构造客户端所需的参数(这里是业务层代码实现,控制层不再罗列)

* return 返回map的JSON串

*/

public String getOnlinePayInfo(HttpServletRequest request) throws Exception {

String orderId = "orderId"; // 这里构造自己的订单

String totalFee = request.getParameter("totalFee"); //金额由客户端获取还是服务端生成根据自己的需求而定

String noncestr = WeChatUtil.getRandomString();

String notify_url = Config.ReadStringPropertie("serverPath") + "/" + request.getContextPath()

+ "/onlinePay/callBackWXpay";

int fee = (int) (Float.parseFloat(totalFee + "F") * 100); // 微信支付的金额,微信支付金额的单位是分,这里需要自行转换

SortedMap reqMap = new TreeMap<>();

reqMap.put("appid", WeChatConfig.AppId); // APPID

reqMap.put("mch_id", WeChatConfig.MchId); // 商户ID

reqMap.put("nonce_str", noncestr); // 32位随机字符串

reqMap.put("body","我要支付"); // 商品描述

reqMap.put("out_trade_no", orderId); //商户系统内部的订单号,

reqMap.put("total_fee", fee + ""); //订单总金额,微信支付的单位为分

reqMap.put("spbill_create_ip", WeChatUtil.getHostIp()); //用户端实际ip

reqMap.put("notify_url", notify_url); //回调通知地址

reqMap.put("trade_type", "APP"); //交易类型

reqMap.put("sign", WeChatUtil.createSign(WeChatConfig.input_charset, reqMap));// 签名

// 请求微信,目的是获取prepay_id,必需先转换成xml格式;需要对xml进行转码,不然会报编码格式的问题

String retStr = HttpClientUtil.postHttplient(WeChatConfig.PrepayUrl, new String(WeChatUtil.getRequestXml(reqMap).toString().getBytes("utf-8")));

// 构造客户端需要的参数

Map wxpayRet = WeChatUtil.doXMLParse(retStr);

SortedMap retMap = new TreeMap<>();

if (wxpayRet.get("return_code").equals("SUCCESS")) {

retMap.put("appid", WeChatConfig.AppId);

retMap.put("noncestr", noncestr);

retMap.put("partnerid", WeChatConfig.MchId);

retMap.put("prepayid", wxpayRet.get("prepay_id"));

retMap.put("package", "Sign=WXPay");

retMap.put("timestamp", System.currentTimeMillis() / 1000); // 时间戳为10位

retMap.put("sign", WeChatUtil.createSign(WeChatConfig.input_charset, retMap));

}

return JSONUtil.writeMapJSON(retMap);

}

移动端支付后的回调

/**

* 微信支付的回调方法

*

* @param request 请求

* @param response 响应

*/

@RequestMapping(value = "/callBackWXpay", method = {RequestMethod.GET, RequestMethod.POST})

public synchronized void callBackWXpay(HttpServletRequest request, HttpServletResponse response) {

SortedMap ret = new TreeMap<>();

try {

if (service.callBackWXpay(request)) {

ret.put("return_code", "SUCCESS");

ret.put("return_msg", "OK");

response.getWriter().write(WeChatUtil.getRequestXml(ret));

} else {

ret.put("return_code", "FALSE");

ret.put("return_msg", "支付失败");

response.getWriter().write(WeChatUtil.getRequestXml(ret));

}

} catch (Exception e) {

e.printStackTrace();

}

}

// service中callBackWXpay的实现

@Override

public boolean callBackWXpay(HttpServletRequest request) throws Exception {

String inputLine;

String notityXml = "";

Map retMap = new HashMap();

// 取出回调中的数据

while (null != (inputLine = request.getReader().readLine())) {

notityXml += inputLine;

}

request.getReader().close();

Map responseMap = WeChatUtil.doXMLParse(notityXml);

String return_code = responseMap.get("return_code");

String orderId = responseMap.get("out_trade_no"); // 商户订单号

// 验证签名,判断支付是否成功

if (WeChatUtil.checkSign(responseMap)) {

if (StringUtils.isNotBlank(return_code) && return_code.equals("SUCCESS")) {

// 这里处理支付成功的业务逻辑

return true;

}

}

} else {

// 这里处理支付失败的业务逻辑

}

return false;

}

用到的工具类

/**

* 微信支付的配置信息

* Created by zhangcg on 2017/4/5.

*/

public class WeChatConfig {

/**

* 预支付请求地址

*/

public static final String PrepayUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder";

/**

* 查询订单地址

*/

public static final String OrderUrl = "https://api.mch.weixin.qq.com/pay/orderquery";

/**

* 关闭订单地址

*/

public static final String CloseOrderUrl = "https://api.mch.weixin.qq.com/pay/closeorder";

/**

* 申请退款地址

*/

public static final String RefundUrl = "https://api.mch.weixin.qq.com/secapi/pay/refund";

/**

* 查询退款地址

*/

public static final String RefundQueryUrl = "https://api.mch.weixin.qq.com/pay/refundquery";

/**

* 下载账单地址

*/

public static final String DownloadBillUrl = "https://api.mch.weixin.qq.com/pay/downloadbill";

/**

* 商户APPID

*/

public static final String AppId = "***";

/**

* 商户账户 获取支付能力后,从邮件中得到

*/

public static final String MchId = "***";

/**

* 商户秘钥 32位,在微信商户平台中设置

*/

public static final String AppSercret = "***";

/**

* 编码格式

*/

public static final String input_charset = "UTF-8";

/**

* 商品描述

*/

public static final String body ="***";

}

import org.jdom.Document;

import org.jdom.Element;

import org.jdom.JDOMException;

import org.jdom.input.SAXBuilder;

import java.io.ByteArrayInputStream;

import java.io.IOException;

import java.io.InputStream;

import java.net.InetAddress;

import java.net.UnknownHostException;

import java.util.*;

/**

* 微信支付的工具类

* Created by zhangcg on 2017/4/5.

*/

public class WeChatUtil {

/**

* 组装请求的xml

*

* @param parameters 集合参数

* @return

*/

public static String getRequestXml(SortedMap parameters) {

StringBuffer sb = new StringBuffer();

sb.append("");

Set es = parameters.entrySet();

Iterator it = es.iterator();

while (it.hasNext()) {

Map.Entry entry = (Map.Entry) it.next();

String k = (String) entry.getKey();

String v = (String) entry.getValue();

if ("sign".equalsIgnoreCase(k)) {

} else if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k)) {

sb.append("" + "" + k + ">");

} else {

sb.append("" + v + "" + k + ">");

}

}

sb.append("" + "" + "sign" + ">");

sb.append("");

return sb.toString();

}

/**

* 得到随机字符串

*

* @return

*/

public static String getRandomString() {

int length = 32;

String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

Random random = new Random();

StringBuffer sb = new StringBuffer();

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

int number = random.nextInt(62);//[0,62)

sb.append(str.charAt(number));

}

return sb.toString();

}

/**

* 定义签名,微信根据参数字段的ASCII码值进行排序 加密签名,故使用SortMap进行参数排序

*

* @param characterEncoding 编码格式

* @param parameters 集合参数

* @return 生成带签名的串

*/

public static String createSign(String characterEncoding, SortedMap parameters) {

StringBuffer sb = new StringBuffer();

Set es = parameters.entrySet();

Iterator it = es.iterator();

while (it.hasNext()) {

Map.Entry entry = (Map.Entry) it.next();

String k = (String) entry.getKey();

Object v = entry.getValue();

if (null != v && !"".equals(v)

&& !"sign".equals(k) && !"key".equals(k)) {

sb.append(k + "=" + v + "&");

}

}

sb.append("key=" + WeChatConfig.AppSercret);//最后加密时添加商户密钥,由于key值放在最后,所以不用添加到SortMap里面去,单独处理,编码方式采用UTF-8

String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();

return sign;

}

public static boolean checkSign(Map map) {

String charset = "UTF-8";

String signFromAPIResponse = map.get("sign");

if (null == signFromAPIResponse || "".equals(signFromAPIResponse)) {

return false;

}

SortedMap packageParams = new TreeMap<>();

for (String parameter : map.keySet()) {

String parameterValue = map.get(parameter);

String v = "";

if (null != parameterValue) {

v = parameterValue.trim();

}

packageParams.put(parameter, v);

}

StringBuffer stringBuffer = new StringBuffer();

Set es = packageParams.entrySet();

Iterator it = es.iterator();

while (it.hasNext()) {

Map.Entry entry = (Map.Entry) it.next();

String k = (String) entry.getKey();

String v = (String) entry.getValue();

if (!"sign".equals(k) && null != v && !"".equals(v)) {

stringBuffer.append(k + "=" + v + "&");

}

}

stringBuffer.append("key=" + WeChatConfig.AppSercret);

String resultSign = "";

String tobesign = stringBuffer.toString();

if (null == charset || "".equals(charset)) {

resultSign = MD5Util.MD5Encode(tobesign, WeChatConfig.input_charset).toUpperCase();

} else {

resultSign = MD5Util.MD5Encode(tobesign, WeChatConfig.input_charset).toUpperCase();

}

String tenpaySign = (packageParams.get("sign")).toUpperCase();

return tenpaySign.equals(resultSign);

}

/**

* 解析xml

*

* @param strxml

* @return

* @throws JDOMException

* @throws IOException

*/

public static Map doXMLParse(String strxml) throws JDOMException, IOException {

strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");

if (null == strxml || "".equals(strxml)) {

return null;

}

Map m = new HashMap();

InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));

SAXBuilder builder = new SAXBuilder();

Document doc = builder.build(in);

Element root = doc.getRootElement();

List list = root.getChildren();

Iterator it = list.iterator();

while (it.hasNext()) {

Element e = (Element) it.next();

String k = e.getName();

String v;

List children = e.getChildren();

if (children.isEmpty()) {

v = e.getTextNormalize();

} else {

v = getChildrenText(children);

}

m.put(k, v);

}

//关闭流

in.close();

return m;

}

public static String getChildrenText(List children) {

StringBuffer sb = new StringBuffer();

if (!children.isEmpty()) {

Iterator it = children.iterator();

while (it.hasNext()) {

Element e = (Element) it.next();

String name = e.getName();

String value = e.getTextNormalize();

List list = e.getChildren();

sb.append("");

if (!list.isEmpty()) {

sb.append(getChildrenText(list));

}

sb.append(value);

sb.append("" + name + ">");

}

}

return sb.toString();

}

/**

* 得到本地机器的IP

*

* @return

*/

public static String getHostIp() {

String ip = "";

try {

ip = InetAddress.getLocalHost().getHostAddress();

} catch (UnknownHostException e) {

e.printStackTrace();

}

return ip;

}

}

import org.apache.commons.httpclient.HttpClient;

import org.apache.commons.httpclient.methods.PostMethod;

import org.apache.commons.httpclient.methods.StringRequestEntity;

import org.apache.commons.httpclient.params.HttpMethodParams;

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 javax.net.ssl.SSLContext;

import java.io.BufferedReader;

import java.io.File;

import java.io.FileInputStream;

import java.io.InputStreamReader;

import java.security.KeyStore;

import java.util.Map;

/**

* Created by zhangcg on 2017/4/5.

*/

public class HttpClientUtil {

public static String post(String url, Map headMap, Map params) {

try {

HttpClient httpclient = new HttpClient();

httpclient.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "UTF-8");

PostMethod httpPost = new PostMethod(url);

if (null != headMap) {

for (String key : headMap.keySet()) {

httpPost.setRequestHeader(key, headMap.get(key));

}

}

if (null != params) {

for (String pkey : params.keySet()) {

httpPost.addParameter(pkey, params.get(pkey));

}

}

httpclient.executeMethod(httpPost);

BufferedReader reader = new BufferedReader(new InputStreamReader(httpPost.getResponseBodyAsStream()));

StringBuffer stringBuffer = new StringBuffer();

String str = "";

while ((str = reader.readLine()) != null) {

stringBuffer.append(str);

}

reader.close();

return stringBuffer.toString();

} catch (Exception e) {

e.printStackTrace();

}

return null;

}

public static String postHttplient(String url, String xmlInfo) {

try {

HttpClient httpclient = new HttpClient();

httpclient.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "UTF-8");

PostMethod httpPost = new PostMethod(url);

httpPost.setRequestEntity(new StringRequestEntity(xmlInfo));

httpclient.executeMethod(httpPost);

BufferedReader reader = new BufferedReader(new InputStreamReader(httpPost.getResponseBodyAsStream()));

StringBuffer stringBuffer = new StringBuffer();

String str = "";

while ((str = reader.readLine()) != null) {

stringBuffer.append(str);

}

reader.close();

return stringBuffer.toString();

} catch (Exception e) {

e.printStackTrace();

}

return null;

}

public static String postHttplientNeedSSL(String url, String xmlInfo, String cretPath, String mrchId)

throws Exception {

//选择初始化密钥文件格式

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

//得到密钥文件流

FileInputStream instream = new FileInputStream(new File(cretPath));

try {

//用商户的ID 来解读文件

keyStore.load(instream, mrchId.toCharArray());

} finally {

instream.close();

}

//用商户的ID 来加载

SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mrchId.toCharArray()).build();

// Allow TLSv1 protocol only

SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);

//用最新的httpclient 加载密钥

CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();

StringBuffer ret = new StringBuffer();

try {

HttpPost httpPost = new HttpPost(url);

httpPost.setEntity(new StringEntity(xmlInfo));

CloseableHttpResponse response = httpclient.execute(httpPost);

try {

HttpEntity entity = response.getEntity();

if (entity != null) {

BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));

String text;

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

ret.append(text);

}

}

EntityUtils.consume(entity);

} finally {

response.close();

}

} finally {

httpclient.close();

}

return ret.toString();

}

}

import java.security.MessageDigest;

/**

* 微信MD5加密工具

* Created by zhangcg on 2017/4/5.

*/

public class MD5Util {

private static String byteArrayToHexString(byte b[]) {

StringBuffer resultSb = new StringBuffer();

for (int i = 0; i < b.length; i++)

resultSb.append(byteToHexString(b[i]));

return resultSb.toString();

}

private static String byteToHexString(byte b) {

int n = b;

if (n < 0)

n += 256;

int d1 = n / 16;

int d2 = n % 16;

return hexDigits[d1] + hexDigits[d2];

}

public static String MD5Encode(String origin, String charsetname) {

String resultString = null;

try {

resultString = new String(origin);

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

if (charsetname == null || "".equals(charsetname))

resultString = byteArrayToHexString(md.digest(resultString

.getBytes()));

else

resultString = byteArrayToHexString(md.digest(resultString

.getBytes(charsetname)));

} catch (Exception exception) {

}

return resultString;

}

private static final String hexDigits[] = {"0", "1", "2", "3", "4", "5",

"6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值