java实现网站微信扫码支付

网友投稿 325 2023-01-25


java实现网站微信扫码支付

一、网站微信扫码支付开发并没有现成的java示例,总结一下自己微信扫码支付心得

二、首先去微信公众平台申请账户

https://mp.weixin.qq.com

**

三、账户开通、开发者认证之后就可以进行微信支付开发了

1、微信统一下单接口调用获取预支付id,以及生成二维码所需的codeUrl

/**

* 保存订单,并生成二维码所需的codeUrl

*

* @param request

* @param response

* @param notifyURLBuf

* @param order

* @return

* @throws Exception

*/

@Override

public Map getWechatOrderInfo(String ip, Cuser user, String notifyUrl, Order order) throws Exception {

Map resultMap = new HashMap();

// 生成并保存订单

order.setUserId(user.getId());

// 支付方式 0:银联 1:支付宝 2:网上银行 3:微信 4:其他

order.setPayType("3");

// 生成订单号

order.setOrderNo(OrderNoGenerator.getOrderNo());

// 订单类型 1:消费 2:退款

order.setOrderType("1");

// 订单创建时间

order.setCreateTime(new Date());

// 订单更新时间

order.setUpdateTime(new Date());

// 订单状态 0: 交易中 1:完成 2:已取消

order.setOrderStatus("0");

// 付款状态 0:失败 1:成功 2、待付款

order.setPayStatus("2");

// 设置订单失效时间

Calendar calendar = Calendar.getInstance();

calendar.add(Calendar.HOUR, 2);

order.setExpireTime(calendar.getTime());

Integer orderId = this.balanceDao.saveOrder(order);

Map payPreIdMap = new HashMap<>();

payPreIdMap = WechatUtil.getPayPreId(String.valueOf(orderId), "体检报告", notifyUrl, ip,

String.valueOf((order.getMoney().multiply(new BigDecimal(100)).intValue())), orderId.toString());

String prePayId = payPreIdMap.get("prepay_id");

// 更新

order.setId(orderId);

order.setPrepayId(prePayId);

order.setCodeUrl(payPreIdMap.get("code_url"));

this.balanceDao.updateOrder(order);

// return WechatUtil.QRfromGoogle(order.getCodeUrl(), 300, 0);

resultMap.put("codeUrl", order.getCodeUrl());

resultMap.put("orderId", String.valueOf(order.getId()));

return resultMap;

}

此方法返回的数据如下

<![CDATA[SUCCESS]]>

<![CDATA[OK]]>

<![CDATA[wxaf0b*****8afbf]]>

<![CDATA[1408****02]]>

<![CDATA[zf0vGvdtVycBliwB]]>

<![CDATA[A2910F16086211153D747058063B3368]]>

<![CDATA[SUCCESS]]>

<![CDATA[wx201701191109388037e9a12310276591827]]>

<![CDATA[NATIVE]]>

<![CDATA[weixin://wxpay/bizpayurl?pr=1UjorNX]]>

2、服务器端接受微信支付结果通知

/**

* 保存微信通知结果

*

* @param request

* @param response

* @return

* @throws Exception

*/

@Override

public String saveWechatNotify(String notifyInfoXml) throws Exception {

Map noticeMap = XMLUtil.doXMLParse(notifyInfoXml);

// 这个其实是订单 的id

String outTradeNo = noticeMap.get("out_trade_no");

Order order = this.balanceDao.getOrderById(Integer.valueOf(outTradeNo));

// 如果支付通知信息不为,说明请求已经处理过,直接返回

if (StringUtil.isNotEmpty(order.getNotifyInfo())) {

return "SUCCESS";

}

String sign = noticeMap.get("sign");

noticeMap.remove("sign");

// 验签通过

if (WechatUtil.getSignVeryfy(noticeMap, sign)) {

// 通信成功此字段是通信标识,非交易标识,交易是否成功需要查看result_code来判断

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

// 交易成功

if ("SUCCESS".equals(noticeMap.get("result_code"))) {

// 商户订单号

// 订单更新时间

order.setUpdateTime(new Date());

// ------------------------------

// 处理业务开始

// ------------------------------

// 是否交易成功,1:成功0:失败

// 微信支付成功

order.setPayStatus("1");

// 订单状态 0: 交易中 1:完成 2:已取消

order.setOrderStatus("1");

// 保存通知信息

order.setNotifyInfo(notifyInfoXml);

this.balanceDao.updateOrder(order);

// 处理业务完毕

} else {

// 错误时,返回结果未签名,记录retcode、retmsg看失败详情。

logger.info("查询验证签名失败或业务错误");

logger.info("retcode:" + noticeMap.get("retcode") + " retmsg:" + noticeMap.get("retmsg"));

}

return "SUCCESS";

} else {

logger.info("后台调用通信失败");

}

return "SUCCESS";

} else {

logger.info("通知签名验证失败");

}

return null;

}

3、上面代码用到的工具方法都在WechatUtil.java工具类中

package com.caifu.tencent.common;

import java.io.IOException;

import java.net.URISyntaxException;

import java.net.URLEncoder;

import java.util.ArrayList;

import java.util.Collections;

import java.util.HashMap;

import java.util.LinkedList;

import java.util.List;

import java.util.Map;

import java.util.Random;

import org.apache.commons.httpclient.HttpStatus;

import org.apache.http.NameValuePair;

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

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

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

import org.apache.http.client.utils.URIBuilder;

import org.apache.http.entity.StringEntity;

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

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

import org.apache.http.message.BasicNameValuePair;

import org.apache.http.util.EntityUtils;

import org.jdom2.JDOMException;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import com.caifu.login.utils.XMLUtil;

public class WechatUtil {

private static Logger logger = LoggerFactory.getLogger(WechatUtil.class);

public static final String TAG = "Wechat.Util";

private static final int timeout = 5000;

public static byte[] httpPost(String url, String entity) throws URISyntaxException, IOException {

if (url == null || url.length() == 0) {

logger.info(TAG, "httpPost, url is null");

return null;

}

CloseableHttpClient httpClient = HttpClients.createDefault();

URIBuilder uriBuilder = new URIBuilder(url);

HttpPost httpPost = new HttpPost(uriBuilder.build());

RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(timeout).setConnectionRequestTimeout(timeout).setConnectTimeout(timeout).build();

httpPost.setConfig(requestConfig);

// 避免汉字乱码导致请求失败,

httpPost.setEntity(new StringEntity(entity, "UTF-8"));

CloseableHttpResponse resp = null;

try {

resp = httpClient.execute(httpPost);

if (resp.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {

logger.info(TAG, "httpGet fail, status code = " + resp.getStatusLine().getStatusCode());

return null;

}

return EntityUtils.toByteArray(resp.getEntity());

} catch (ExceptinGjEuon e) {

logger.info(TAG, "httpPost exception, e = " + e.getMessage());

e.printStackTrace();

return null;

} finally {

if (httpClient != null) {

httpClient.close();

}

if (resp != null) {

resp.close();

}

}

}

/**

* 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串

*

* @param params

* 需要排序并参与字符拼接的参数组

* @return 拼接后字符串

*/

public static String createLinkString(Map params) {

List keys = new ArrayList(params.keySet());

Collections.sort(keys);

String prestr = "";

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

String key = keys.get(i);

String value = params.get(key);

if (i == keys.size() - 1) {// 拼接时,不包括最后一个&字符

prestr = prestr + key + "=" + value;

} else {

prestr = prestr + key + "=" + value + "&";

}

}

return prestr;

}

/**

* 根据反馈回来的信息,生成签名结果

*

* @param Params

* 通知返回来的参数数组

* @param sign

* 比对的签名结果

* @return 生成的签名结果

*/

public static boolean getSignVeryfy(Map Params, String sign) {

// 过滤空值、sign与sign_type参数

// Map sParaNew = AlipayCore.paraFilter(Params);

// 获取待签名字符串

String preSignStr = createLinkString(Params);

preSignStr += "&key=" + Configure.getKey();

// 获得签名验证结果

String resultSign = MD5.MD5Encode(preSignStr).toUpperCase();

// String resultSign = MD5Util.MD5Encode(preSignStr.toString(),

// "UTF-8").toLowerCase();

if (sign.equals(resultSign)) {

return true;

} else {

return false;

}

}

/**

* 装配xml,生成请求prePayId所需参数

*

* @param params

* @return

*/

public static String toXml(List params) {

StringBuilder sb = new StringBuilder();

sb.append("");

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

sb.append("<" + params.get(i).getName() + ">");

sb.append(params.get(i).getValue());

sb.append("" + params.get(i).getName() + ">");

}

sb.append("");

return sb.toString();

}

/**

* 生成签名

*/

public static String genPackageSign(List params) {

StringBuilder sb = new StringBuilder();

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

sb.append(params.get(i).getName());

sb.append('=');

sb.append(params.get(i).getValue());

sb.append('&');

}

sb.append("key=");

sb.append(Configure.getKey());

String packageSign = MD5.MD5Encode(sb.toString());

return packageSign;

}

/**

*

* @param goodOrderNo

* @param body

* @param noticeUrl

* @param ip

* @param totalFee

* @return

*/

public static String genProductArgs(String goodOrderNo, String body, String noticeUrl, String ip, String totalFee, String productId) {

StringBuffer xml = new StringBuffer();

try {

String nonceStr = getNonceStr();

xml.append("");

List packageParams = new LinkedList();

packageParams.add(new BasicNameValuePair("appid", Configure.getAppid()));

packageParams.add(new BasicNameValuePair("body", body));

packageParams.add(new BasicNameValuePair("mch_id", Configure.getMchid()));

packageParams.add(new BasicNameValuePair("nonce_str", nonceStr));

packageParams.add(new BasicNameValuePair("notify_url", noticeUrl));

packageParams.add(new BasicNameValuePair("out_trade_no", goodOrderNo));

packageParams.add(new BasicNameValuePair("product_id", productId));

packageParams.add(new BasicNameValuePair("spbill_create_ip", ip));

packageParams.add(new BasicNameValuePair("total_fee", totalFee));

packageParams.add(new BasicNameValuePair("trade_type", "NATIVE"));

String sign = genPackageSign(packageParams);

packageParams.add(new BasicNameValuePair("sign", sign));

String xmlstring = toXml(packageParams);

return xmlstring;

} catch (Exception e) {

logger.info("genProductArgs fail, ex = " + e.getMessage());

return null;

}

}

/**

* 生成支付nGjEu签名

*

* @param params

* @return

*/

public static String genAppSign(List params) {

StringBuilder sb = new StringBuilder();

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

sb.append(params.get(i).getName());

sb.append('=');

sb.append(params.get(i).getValue());

sb.append('&');

}

sb.append("key=");

sb.append(Configure.getKey());

String appSign = MD5.MD5Encode(sb.toString()).toUpperCase();

logger.info("orion", appSign);

return appSign;

}

/**

* 生成调用微信支付所需参数

*

* @param prepayId

* @return

*/

public static Map genPayReq(String prepayId) {

Map resultMap = new HashMap();

String timeStamp = getTimeStamp();

String nonceStr = getNonceStr();

List signParams = new LinkedList();

signParams.add(new BasicNameValuePair("appid", Configure.getAppid()));

signParams.add(new BasicNameValuePair("noncestr", nonceStr));

signParams.add(new BasicNameValuePair("package", "Sign=WXPay"));

signParams.add(new BasicNameValuePair("partnerid", Configure.getMchid()));

signParams.add(new BasicNameValuePair("prepayid", prepayId));

signParams.add(new BasicNameValuePair("timestamp", timeStamp));

String sign = genAppSign(signParams);

resultMap.put("appid", Configure.getAppid());

resultMap.put("noncestr", nonceStr);

resultMap.put("packageValue", "Sign=WXPay");

resultMap.put("partnerid", Configure.getMchid());

resultMap.put("prepayid", prepayId);

resultMap.put("timestamp", timeStamp);

resultMap.put("sign", sign);

return resultMap;

}

/**

* 微信支付生成预支付订单

*

* @throws IOException

* @throws JDOMException

*/

public static Map getPayPreId(String goodOrderNo, String body, String noticeUrl, String ip, String totalFee, String productId) throws Exception {

String paramsXml = genProductArgs(goodOrderNo, body, noticeUrl, ip, totalFee, productId);

logger.info("orion", paramsXml);

byte[] buf = WechatUtil.httpPost(Configure.UNIFIEDORDER_API, paramsXml);

String contentXml = new String(buf);

Map resultMap = XMLUtil.doXMLParse(contentXml);

return resultMap;

}

public static String getNonceStr() {

Random random = new Random();

return MD5.MD5Encode(String.valueOf(random.nextInt(10000)));

}

public static String getTimeStamp() {

return String.valueOf(System.currentTimeMillis() / 1000);

}

/**

* 生成支付二维码

* @param request

* @param response

* @param width

* @param height

* @param text 微信生成预定id时,返回的codeUrl

*/

public static void getQRcode(HttpServletRequest request, HttpServletResponse response, Integer width, Integer height, String text) {

if (width == null) {

width = 300;

}

if (height == null) {

height = 300;

}

String format = "jpg";

Hashtable hints = new Hashtable();

hints.put(EncodeHintType.CHARACTER_SET, "utf-8");

BitMatrix bitMatrix;

try {

bitMatrix = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, width, height, hints);

MatrixToImageWriter.writeToStream(bitMatrix, format, response.getOutputStream());

} catch (WriterException e) {

e.printStackTrace();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

生成二维码需要两jar

com.google.zxing

core

3.3.0

com.google.zxing

javase

3.3.0

4、下面是用到的配置类

package com.caifu.tencent.common;

/**

* User: rizenguo

* Date: 2014/10/29

* Time: 14:40

* 这里放置各种配置数据

*/

public class Configure {

//这个就是自己要保管好的私有Key了(切记只能放在自己的后台代码里,不能放在任何可能被看到源代码的客户端程序中)

// 每次自己Post数据给API的时候都要用这个key来对所有字段进行签名,生成的签名会放在Sign这个字段,API收到Post数据的时候也会用同样的签名算法对Post过来的数据进行签名和验证

// 收到API的返回的时候也要用这个key来对返回的数据算下签名,跟API的Sign数据进行比较,如果值不一致,有可能数据被第三方给篡改

private static String key = "A6gB0Dy4dsfdssuPCPsdfdshkSCDQcr3eXS";

private static String appSecret="7584sdfdsfe4f26fadsfsdfs56f10728a";

private static String appID = "wxaf0b86sdfsdf8afbf";

private static String mchID = "14012313702";

//受理模式下给子商户分配的子商户号

private static String subMchID = "";

//HTTPS证书的本地路径

private static String certLocalPath = "";

//HTTPS证书密码,默认密码等于商户号MCHID

private static String certPassword = "";

//是否使用异步线程的方式来上报API测速,默认为异步模式

private static boolean useThreadToDoReport = true;

//机器IP

private static String ip = "";

//以下是几个API的路径:

//1)被扫支付API

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

public static String PAY_API = "https://api.mch.weixin.qq.com/pay/micropay";

//2)被扫支付查询API

public static String PAY_QUERY_API = "https://api.mch.weixin.qq.d/pay/orderquery";

//3)退款API

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

//4)退款查询API

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

//5)撤销API

public static String REVERSE_API = "https://api.mch.weixin.qq.com/secapi/pay/reverse";

//6)下载对账单API

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

//7) 统计上报API

public static String REPORT_API = "https://api.mch.weixin.qq.com/payitil/report";

public static boolean isUseThreadToDoReport() {

return useThreadToDoReport;

}

public static void setUseThreadToDoReport(boolean useThreadToDoReport) {

Configure.useThreadToDoReport = useThreadToDoReport;

}

public static String HttpsRequestClassName = "com.tencent.common.HttpsRequest";

public static void setKey(String key) {

Configure.key = key;

}

public static void setAppID(String appID) {

Configure.appID = appID;

}

public static void setMchID(String mchID) {

Configure.mchID = mchID;

}

public static void setSubMchID(String subMchID) {

Configure.subMchID = subMchID;

}

public static void setCertLocalPath(String certLocalPath) {

Configure.certLocalPath = certLocalPath;

}

public static void setCertPassword(String certPassword) {

Configure.certPassword = certPassword;

}

public static void setIp(String ip) {

Configure.ip = ip;

}

public static String getKey(){

return key;

}

public static String getAppid(){

return appID;

}

public static String getMchid(){

return mchID;

}

public static String getSubMchid(){

return subMchID;

}

public static String getCertLocalPath(){

return certLocalPath;

}

public static String getCertPassword(){

return certPassword;

}

public static String getIP(){

return ip;

}

public static void setHttpsRequestClassName(String name){

HttpsRequestClassName = name;

}

}

在这里需要注意的配置

private static String key = “A6gB0Dy4dsfdssuPCPsdfdshkSCDQcr3eXS”;

这里的key 是登陆https://pay.weixin.qq.com/index.php/core/info (微信商户平台)设置的api_key

5、xml 解析工具类

package com.caifu.login.utils;

import java.io.ByteArrayInputStream;

import java.io.IOException;

import java.io.InputStream;

import java.util.HashMap;

import java.util.Iterator;

import java.util.List;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.dom4j.io.SAXReader;

import org.jdom2.Document;

import org.jdom2.Element;

import org.jdom2.JDOMException;

import org.jdom2.input.SAXBuilder;

/**

* xml工具类

*

* @author miklchen

*

*/

public class XMLUtil {

/**

* 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的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 = XMLUtil.getChildrenText(children);

}

m.put(k, v);

}

// 关闭流

in.close();

return m;

}

/**

* 获取子结点的xml

*

* @param children

* @return String

*/

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("<" + name + ">");

if (!list.isEmpty()) {

sb.append(XMLUtil.getChildrenText(list));

}

sb.append(value);

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

}

}

return sb.toString();

}

/**

* 将requestxml通知结果转出啊成map

* @param request

* @return

* @throws Exception

*/

public static Map parseXml(HttpServletRequest request) throws Exception {

// 解析结果存储在HashMap

Map map = new HashMap();

InputStream inputStream = request.getInputStream();

// 读取输入流

SAXReader reader = new SAXReader();

org.dom4j.Document document = reader.read(inputStream);

// 得到xml根元素

org.dom4j.Element root = document.getRootElement();

// 得到根元素的所有子节点

List elementList = root.elements();

// 遍历所有子节点

for (org.dom4j.Element e : elementList)

map.put(e.getName(), e.getText());

// 释放资源

inputStream.close();

inputStream = null;

return map;

}

}

6、整个后台服务已经完成,最后关闭页面微信支付二维码,告知用户支付已经完成了

var f;

/* 定时任务方法,异步请求去查询订单是否支付*/

function GetOrder() {

var orderId = $('#orderId').val();

if (orderId != '') {

$.ajax({

url : "${base}/balance/auth/isPay?orderId=" + orderId,

type : "GET",

async : false,

success : function(d) {

if (d == "1") {

//当获取到微信支付结果时,关闭二维码div

$(".weixinpay").css("display", "none");

$("#zhichutankuang").css("display", "block");

////当获取到微信支付结果时,关闭定时任务

clearInterval(f);

// layer.alert('付款成功', {

// skin : http://'layui-layer-molv', // 样式类名

// closeBtn : 0

// }, function() {

// location.href = "${base}/balance/auth/presentation?tjNo=" + $("#tjNo").val();

// });

}

}

});

}

}

//异步请求获取生成二维码的url

$(".paylast").click(function() {

var $payType = $('input:radio:checked').val();

var $money = $("#money").val();

var $tjReportType = $("#tjReportType").val();

var $tjNo = $("#tjNo").val();

$.ajax({

url : "${base}/balance/auth/wechatInfo",

type : "POST",

async : false,

data : {

payType : $payType,

money : $money,

tjNo : $tjNo,

tjReportType : $tjReportType

},

success : function(d) {

if (d.resultCode == "1000") {

//当请求成功时,设置二维码图片地址

$("#codeImg").attr('src', d.obj);

$("#orderId").val(d.attributes.orderId);

////当请求成功时,启动定时任务,每隔3秒去后台查询一次订单是否成功

f = setInterval(GetOrder, 3000);

// GetOrder(true);

}

}

});

$(".selpaycon").css("display", "none");

$(".weixinpay").css("display", "block");

});


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:java实现字符串四则运算公式解析工具类的方法
下一篇:用不同用户连接共享文件夹(不同用户访问不同的共享文件)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~