该功能我在程自己在学习时候尝试搭建的,可能会有很多问题,在这里只是做一下记录。直接上代码。 如果想要源码楼主或者加群725395843 这里是技术讨论群。供大家讨论。
JAVA开发微信支付-公众号支付/微信浏览器支付(JSAPI)
写这篇文章的目的有2个,一是自己的项目刚开发完微信支付功能,趁热回个炉温习一下,二也是帮助像我这样对微信支付不熟悉,反复看了多天文档还是一知半解,原理都没摸清,更不要说实现了。本以为网上的微信开发教程会和“java的重写与重载”一样铺天盖地,可搜出来的结果,要么是PHP的教程(微信支付官网推荐就是PHP),要么星星点点就那么几篇,想对比的看看思路都成问题,官网下载的JAVA-SDK-DEMO也恕我技术低下,看的糊里糊涂。等自己开发完的那一刻,才豁然开朗,才知道走通完支付这条路的过程走了多少弯路,我是第一次接触支付,想必大部分能看这篇文章的兄弟也是被微信官方文档给绕的出不来才出此下策,内容有误请指正。好了这回真正的正题了:
步骤一:获取微信支付四大参数
首先要想支持微信支付,必须拥有两个账号:①微信公众已认证的服务号,并且需要开通微信支付该能(必须是企业才有资格申请,请你找你家产品去申请吧),②微信商户平台账号;这两个账号一个不能少。此处已默认你已有上两个账号。
此处是账号模板,请参考:
微信公众平台:账户:con*******om 登录密码 ******
公众APPID:wx15*********a8
APPSECEPT : c210***************892d7
微信商户平台:账户:149**********6742 登录密码:******
商户ID:14******42
API密钥:5d5************b35b
其中比较不好找的是商户的API密钥:在商户平台的账户中心下:需要用户自行下载证书及安装,(略)
至此我们需要的APPID(appid),APPSECEPT(appsecret),商户ID(mch_id),API密钥(paternerKey),四个重要参数已拿到,括号中是我们代码所用的变量名称请提前熟悉。
步骤二:平台配置
1.配置支付目录:商户平台:
配置此目录是代码中“微信支付”所在页面的地址,可以是目录不一定是全路径-如http://www.wangtao.com/order/-----此一级域名需要ICP备案。
点击添加
2.配置授权域名:微信公众平台:
支付过程需要获取用户openid,必须经过网页授权配置才可以,要不然获取不到openid。
点击设置,按说明设置
步骤三:开发流程:
微信支付原理(说白了就是调用官方文档的“统一下单”接口,之后将微信服务器返回的参数做个加工后,返回到前台(JSP页面),就OK了。咱们要做的就是想方设法的凑齐统一下单的所有参数“而已”,“而已”,“而已”,这个而已也就是最大的挑战)。所有参数解释请参考:官方文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1;
咱们只考虑必填参数,其他参数可以就看你的了。
先来看看所有参数:
其中的必填参数有:
1. appid APPID (已有)
2. mch_id 商户ID (已有)
3. nonce_str 随机字符串
4. sign 签名
5. body 所支付的名称
6. out_trade_no 咱们自己所提供的订单号,需要唯一
7. total_fee 支付金额
8. spbill_create_ip IP地址
9. notify_url 回调地址
10. trade_type 支付类型
11. openid 支付人的微信公众号对应的唯一标识
只要把这11个凑齐就齐活,现在咱们从第3个开始一个一个的获取;在这之前先从官网把公众号支付的sdk下载下来,如图
主要是用其中的WXPayUtil工具类中的一些方法。当然其他的类我看不懂,要是看懂了,就不至于这么费劲了。
好了开始咱们的取值之旅了:
1. appid APPID (已有)
2. mch_id 商户ID (已有)
3. nonce_str 随机字符串用WXPayUtil中的generateNonceStr()即可,就是生成UUID的方法;
4. sign 签名 用WXPayUtil中的generateSignature(finalMap<String, String> data, String key)方法,data是将除了sign外,其他10个参数放到map中,key是四大配置参数中的API秘钥(paternerKey)(这里不要着急管它,最后处理它);
5. body 所支付的名称
6. out_trade_no 自己后台生成的订单号,只要保证唯一就好:如“2018013000001”
7. total_fee 支付金额 单位:分,为了测试此值给1,表示支付1分钱
8. spbill_create_ip IP地址 网上很多ip的方法,自己找,此处测试给“127.0.0.1”
9. notify_url 回调地址:这是微信支付成功后,微信那边会带着一大堆参数(XML格式)请求这个地址多次,这个地址做我们业务处理如:修改订单状态,赠送积分等。Ps:支付还没成功还想这么远干嘛,最后再说。地址要公网可以访问。
10. trade_type 支付类型 咱们是公众号支付此处给“JSAPI”
11. openid 支付人的微信公众号对应的唯一标识,每个人的openid在不同的公众号是不一样的,这11个参数里,最费劲的就是他了,其他的几乎都已经解决,现在开发得到这个参数。
获得openid的部分内容应该不属于微信支付的范畴,属于微信公众号网页授权的东西,详情请参考微信网页授权:
https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842
废话不多说上代码。
jsp页面。
注意注意:这里要引入微信官方得js
<script type="text/javascript" src="/Dgsc/js/jquery-2.2.3.min.js"></script>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=1.0" />
<meta name="apple-mobile-web-app-capable" content="yes">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
</head>
<body οnlοad="javascript:pay();">
<script type="text/javascript" src="/Dgsc/js/jquery-2.2.3.min.js"></script>
<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js" type="text/javascript"></script>
<script>
function pay(){
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();
}
}
function onBridgeReady(){
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId" : "${appid}", //公众号名称,由商户传入
"timeStamp": "${timeStamp}", //时间戳,自1970年以来的秒数
"nonceStr" : "${nonceStr}", //随机串
"package" : "${packageValue}",
"signType" : "MD5", //微信签名方式:
"paySign" : "${paySign}" //微信签名
},function(res){
if(res.err_msg == "get_brand_wcpay_request:ok"){
//支付成功
}else if(res.err_msg == "get_brand_wcpay_request:cancel"){
//支付错误
}else{
alert("支付失败!");
}
});
}
</script>
</body>
</html>
Controller 代码 一些校验我都去掉了 根据你自己得业务写校验
/**
* 订单支付
*
* @param map
* @param request
* @param id
* @return
* @throws Exception
*/
@RequestMapping(value = "payorder")
public String payorder(Model map, HttpServletRequest request, Integer id,
HttpServletResponse response, Integer address_id) throws Exception {
// 声明公共账号的基本信息
String GZHID = ;// 微信公众号id
String GZHSecret = ;// 微信公众号密钥id
String SHHID = ;// 商户号id
String SHHKEY = ;// 商户号对应的密钥
// 根据订单号查询订单是否存在
ScOrder order = orderService.getOrderbyId(id);
if (order.getStatus() != 1) {
logger.error("该订单已支付订单号为>>>>>" + order + "<<<<<<<<<<<<");
map.addAttribute("errorMessage", "该订单已支付");
return "pages/mallPages/payOrderMessage";
}
/*------1.获取参数信息------- */
// 商户订单号
String out_trade_no = String.valueOf(id);
// 价格
Double freight = order.getFreight();// 获取运费
BigDecimal bd1 = new BigDecimal(Double.toString(freight));
BigDecimal bd2 = new BigDecimal(Double.toString(order.getSumprice()));
Double price = bd1.add(bd2).doubleValue();
String money = String.valueOf(price);
// 金额转化为分为单位
String finalmoney = SccarController.getMoney(String.valueOf(money));
// 获取用户的code
String code = request.getParameter("code");if (order.getSumprice() <= 0) // 防止抓包修改订单金额造成损失
{
map.addAttribute("errorMessage", "亲您想多了,之能支付不能倒付");
return "pages/mallPages/payOrderMessage";
}
/*------3.生成预支付订单需要的的package数据------- */
// 随机数
String nonce_str = MD5Util.getMessageDigest(String.valueOf(
new Random().nextInt(10000)).getBytes());
// 订单生成的机器 IP
String spbill_create_ip = request.getRemoteAddr();
// 交易类型 :jsapi代表微信公众号支付
String trade_type = "JSAPI";
// 这里notify_url是 微信处理完支付后的回调的应用系统接口url。
String notify_url = "";SortedMap<String, String> packageParams = new TreeMap<String, String>();
packageParams.put("appid", GZHID);
packageParams.put("mch_id", SHHID);
packageParams.put("nonce_str", nonce_str);
packageParams.put("body", "费用");
packageParams.put("out_trade_no", out_trade_no);
packageParams.put("total_fee", finalmoney);
packageParams.put("spbill_create_ip", spbill_create_ip);
packageParams.put("notify_url", notify_url);
packageParams.put("trade_type", trade_type);
packageParams.put("openid", openid);/*------4.根据package数据生成预支付订单号的签名sign------- */
RequestHandler reqHandler = new RequestHandler(request, response);
reqHandler.init(GZHID, GZHSecret, SHHKEY);
String sign = reqHandler.createSign(packageParams);/*------5.生成需要提交给统一支付接口https://api.mch.weixin.qq.com/pay/unifiedorder 的xml数据-------*/
String xml = "<xml>" + "<appid>" + GZHID + "</appid>" + "<mch_id>"
+ SHHID + "</mch_id>" + "<nonce_str>" + nonce_str
+ "</nonce_str>" + "<sign>" + sign + "</sign>"
+ "<body><![CDATA[" + "费用" + "]]></body>" + "<out_trade_no>"
+ out_trade_no + "</out_trade_no>" + "<total_fee>" + finalmoney
+ "</total_fee>" + "<spbill_create_ip>" + spbill_create_ip
+ "</spbill_create_ip>" + "<notify_url>" + notify_url
+ "</notify_url>" + "<trade_type>" + trade_type
+ "</trade_type>" + "<openid>" + openid + "</openid>"
+ "</xml>";
/*------6.调用统一支付接口https://api.mch.weixin.qq.com/pay/unifiedorder 生产预支付订单----------*/
String createOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
String prepay_id = "";
try {
prepay_id = GetWxOrderno.getPayNo(createOrderURL, xml);
if (prepay_id.equals("")) {
logger.debug("统一支付接口获取预支付订单出错");
map.addAttribute("errorMessage", "统一支付接口获取预支付订单出错");
return "pages/mallPages/payOrderMessage";
}
} catch (Exception e) {
logger.error("统一支付接口获取预支付订单出错" + e);
map.addAttribute("errorMessage", "统一支付接口获取预支付订单出错");
return "pages/mallPages/payOrderMessage";
}/* 将prepay_id(预订单号)存到库中 */
order.setPorderNo(prepay_id);// 将订单号放入参数中
orderService.savePOrderNo(order);// 保存预订单号入库条件是订单号/*------7.将预支付订单的id和其他信息生成签名并一起返回到jsp页面 ------- */
nonce_str = MD5Util.getMessageDigest(String.valueOf(
new Random().nextInt(10000)).getBytes());
SortedMap<String, String> finalpackage = new TreeMap<String, String>();
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
String packages = "prepay_id=" + prepay_id;
finalpackage.put("appId", GZHID);
finalpackage.put("timeStamp", timestamp);
finalpackage.put("nonceStr", nonce_str);
finalpackage.put("package", packages);
finalpackage.put("signType", "MD5");
String finalsign = reqHandler.createSign(finalpackage);map.addAttribute("appid", GZHID);
map.addAttribute("timeStamp", timestamp);
map.addAttribute("nonceStr", nonce_str);
map.addAttribute("packageValue", packages);
map.addAttribute("paySign", finalsign);
map.addAttribute("success", "ok");
map.addAttribute("order_id",id);
return "pages/mallPages/pay";
}
MD5Util
package cn.com.sinosoft.util;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;public class MD5Util {
/**
* 字符串签名
* @author BaiGang
*/
public static String genSign(String json) {
String signStr = json;
// 创建数组
byte[] bytes = null;
// 创建MD5
MessageDigest md5;
try {
// 得到MD5
md5 = MessageDigest.getInstance("MD5");
try {
// 对json字符串加密
bytes = md5.digest(signStr.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}// 将MD5输出的二进制结果转换为小写的十六进制
StringBuilder sign = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
String hex = Integer.toHexString(bytes[i] & 0xFF);
if (hex.length() == 1) {
//sign.append("0");
}
//sign.append(hex);
}
return sign.toString();
}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" };
/**
* 对传入的数据提取摘要
* @param buffer
* @return
*/
public final static String getMessageDigest(byte[] buffer) {
char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
try {
MessageDigest mdTemp = MessageDigest.getInstance("MD5");
mdTemp.update(buffer);
byte[] md = mdTemp.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) {
return null;
}
}
}
RequestHandler
package cn.com.sinosoft.http;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;import cn.com.sinosoft.util.MD5Util;
import cn.com.sinosoft.util.TenpayUtil;/*
'微信支付服务器签名支付请求请求类
'============================================================================
'api说明:
'init(app_id, app_secret, partner_key, app_key);
'初始化函数,默认给一些参数赋值,如cmdno,date等。
'setKey(key_)'设置商户密钥
'getLasterrCode(),获取最后错误号
'GetToken();获取Token
'getTokenReal();Token过期后实时获取Token
'createMd5Sign(signParams);生成Md5签名
'genPackage(packageParams);获取package包
'createSHA1Sign(signParams);创建签名SHA1
'sendPrepay(packageParams);提交预支付
'getDebugInfo(),获取debug信息
'============================================================================
'*/
public class RequestHandler {
/** Token获取网关地址地址 */
private String tokenUrl;
/** 预支付网关url地址 */
private String gateUrl;
/** 查询支付通知网关URL */
private String notifyUrl;
/** 商户参数 */
private String appid;
private String appkey;
private String partnerkey;
private String appsecret;
private String key;
/** 请求的参数 */
private SortedMap parameters;
/** Token */
private String Token;
private String charset;
/** debug信息 */
private String debugInfo;
private String last_errcode;private HttpServletRequest request;
private HttpServletResponse response;
/**
* 初始构造函数。
*
* @return
*/
public RequestHandler(HttpServletRequest request,
HttpServletResponse response) {
this.last_errcode = "0";
this.request = request;
this.response = response;
//this.charset = "GBK";
this.charset = "UTF-8";
this.parameters = new TreeMap();
// 验证notify支付订单网关
notifyUrl = "https://gw.tenpay.com/gateway/simpleverifynotifyid.xml";
}/**
* 初始化函数。
*/
public void init(String app_id, String app_secret, String partner_key) {
this.last_errcode = "0";
this.Token = "token_";
this.debugInfo = "";
this.appid = app_id;
this.partnerkey = partner_key;
this.appsecret = app_secret;
this.key = partner_key;
}public void init() {
}/**
* 获取最后错误号
*/
public String getLasterrCode() {
return last_errcode;
}/**
*获取入口地址,不包含参数值
*/
public String getGateUrl() {
return gateUrl;
}/**
* 获取参数值
*
* @param parameter
* 参数名称
* @return String
*/
public String getParameter(String parameter) {
String s = (String) this.parameters.get(parameter);
return (null == s) ? "" : s;
}
//设置密钥
public void setKey(String key) {
this.partnerkey = key;
}
//设置微信密钥
public void setAppKey(String key){
this.appkey = key;
}
// 特殊字符处理
public String UrlEncode(String src) throws UnsupportedEncodingException {
return URLEncoder.encode(src, this.charset).replace("+", "%20");
}// 获取package的签名包
public String genPackage(SortedMap<String, String> packageParams)
throws UnsupportedEncodingException {
String sign = createSign(packageParams);StringBuffer sb = 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();
sb.append(k + "=" + UrlEncode(v) + "&");
}// 去掉最后一个&
String packageValue = sb.append("sign=" + sign).toString();
// System.out.println("UrlEncode后 packageValue=" + packageValue);
return packageValue;
}/**
* 创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
*/
public String createSign(SortedMap<String, String> packageParams) {
StringBuffer sb = 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 (null != v && !"".equals(v) && !"sign".equals(k)
&& !"key".equals(k)) {
sb.append(k + "=" + v + "&");
}
}
sb.append("key=" + this.getKey());
String sign = MD5Util.MD5Encode(sb.toString(), this.charset)
.toUpperCase();
return sign;}
/**
* 创建package签名
*/
public boolean createMd5Sign(String signParams) {
StringBuffer sb = new StringBuffer();
Set es = this.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".equals(k) && null != v && !"".equals(v)) {
sb.append(k + "=" + v + "&");
}
}// 算出摘要
String enc = TenpayUtil.getCharacterEncoding(this.request,
this.response);
String sign = MD5Util.MD5Encode(sb.toString(), enc).toLowerCase();String tenpaySign = this.getParameter("sign").toLowerCase();
// debug信息
this.setDebugInfo(sb.toString() + " => sign:" + sign + " tenpaySign:"
+ tenpaySign);return tenpaySign.equals(sign);
}
//输出XML
public String parseXML() {
StringBuffer sb = new StringBuffer();
sb.append("<xml>");
Set es = this.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(null != v && !"".equals(v) && !"appkey".equals(k)) {
sb.append("<" + k +">" + getParameter(k) + "</" + k + ">\n");
}
}
sb.append("</xml>");
return sb.toString();
}
public static String setXML(String return_code, String return_msg) {
return "<xml><return_code><![CDATA[" + return_code
+ "]]></return_code><return_msg><![CDATA[" + return_msg
+ "]]></return_msg></xml>";
}/**
* 设置debug信息
*/
protected void setDebugInfo(String debugInfo) {
this.debugInfo = debugInfo;
}
public void setPartnerkey(String partnerkey) {
this.partnerkey = partnerkey;
}
public String getDebugInfo() {
return debugInfo;
}
public String getKey() {
return key;
}}
GetWxOrderno 微信支付订单处理类
package cn.com.sinosoft.util;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.input.SAXBuilder;import cn.com.sinosoft.http.HttpClientConnectionManager;
/**
* 微信支付订单处理类
* @author aofavx
*/
@SuppressWarnings("deprecation")
public class GetWxOrderno
{
public static DefaultHttpClient httpclient;static
{
httpclient = new DefaultHttpClient();
httpclient = (DefaultHttpClient)HttpClientConnectionManager.getSSLInstance(httpclient);
}/**
* 提交数据到统一支付接口,获取微信生成的统一支付订单号
* @param url
* @param xmlParam
* @return
*/
@SuppressWarnings("rawtypes")
public static String getPayNo(String url,String xmlParam){
DefaultHttpClient client = new DefaultHttpClient();
client.getParams().setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, true);
HttpPost httpost= HttpClientConnectionManager.getPostMethod(url);
String prepay_id = "";
try {
httpost.setEntity(new StringEntity(xmlParam, "UTF-8"));
HttpResponse response = httpclient.execute(httpost);
String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
if(jsonStr.indexOf("FAIL")!=-1){
return prepay_id;
}
Map map = doXMLParse(jsonStr);
prepay_id = (String) map.get("prepay_id");
} catch (Exception e) {
e.printStackTrace();
}
return prepay_id;
}
/**
* 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。
* @param strxml
* @return
* @throws JDOMException
* @throws IOException
*/
public static Map doXMLParse(String strxml) throws Exception {
if(null == strxml || "".equals(strxml)) {
return null;
}
Map m = new HashMap();
InputStream in = String2Inputstream(strxml);
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, URLDecoder.decode(v,"utf-8"));
}
//关闭流
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(getChildrenText(list));
}
sb.append(value);
sb.append("</" + name + ">");
}
}
return sb.toString();
}
public static InputStream String2Inputstream(String str) {
return new ByteArrayInputStream(str.getBytes());
}
}
//提交支付后的微信异步返回接口 这里有的用不上就去掉 这里要做异步确认 和去重校验
/**
* 提交支付后的微信异步返回接口
*/
@RequestMapping(value = "/weixinNotify")
@ResponseBody
public void weixinNotify(HttpServletRequest request,
HttpServletResponse response) {
String out_trade_no = null;
String return_code = null;
try {
InputStream inStream = request.getInputStream();
ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = inStream.read(buffer)) != -1) {
outSteam.write(buffer, 0, len);
}
outSteam.close();
inStream.close();
String resultStr = new String(outSteam.toByteArray(), "utf-8");
logger.info("成功的支付回调:" + resultStr);
Map<String, Object> resultMap = parseXmlToList(resultStr);
String result_code = (String) resultMap.get("result_code");// 业务结果
String is_subscribe = (String) resultMap.get("is_subscribe");
// 微信订单号
String transaction_id = (String) resultMap.get("transaction_id");// 微信支付单号
// 签名
String sign = (String) resultMap.get("sign");
String time_end = (String) resultMap.get("time_end");
String bank_type = (String) resultMap.get("bank_type");
// 商户的订单号
out_trade_no = (String) resultMap.get("out_trade_no");// 商户订单号
return_code = (String) resultMap.get("return_code");// 返回状态吗request.setAttribute("out_trade_no", out_trade_no);
// 通知微信.异步确认成功.必写.不然微信会一直通知后台.八次之后就认为交易失败了.
logger.error(RequestHandler.setXML("SUCCESS", "OK"));
//response.getWriter().write(RequestHandler.setXML("SUCCESS", "OK"));
writeMessageToResponse(response,RequestHandler.setXML("SUCCESS", "OK"));
} catch (Exception e) {
logger.error("微信回调接口出现错误:", e);
writeMessageToResponse(response,RequestHandler.setXML("FAIL", "error"));
}
if (return_code.equals("SUCCESS")) {
// 支付成功的业务逻辑
Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put("pay_time", new Date());
paramMap.put("PorderNo", out_trade_no);
try {
orderService.updateorderByPorderNo(paramMap);
// 新增 支付成功以后修改购买商品的库存
//orderService.updateStockById(Integer.parseInt(out_trade_no));//修改所购买产品的库存
ScOrder order =orderService.getOrderbyId(Integer.parseInt(out_trade_no));
User user=userService.getUserById(order.getUser_id());
Uap uap1=new Uap();
uap1.setUa_id(order.getUa_id());
uap1.setStatus(1);
UserActivity ua=activityService.getUserActivityById(order.getUa_id());
Activity activity=activityService.getActivityById(ua.getActivity_id());
uap1.setUser_id(user.getId());
logger.error(uap1.getUa_id()+""+uap1.getStatus()+""+uap1.getUser_id());
List<UseractivityUser> uaus=activityService.getUserActivityuserinfo(uap1);
if(uaus!=null&&uaus.size()>0){
activityService.updateUserActivityUserstatus(uaus.get(uaus.size()-1));
}
uap1.setUser_id(0);
List<Uap> uaps=activityService.getUserActivityuser(uap1);
logger.error("ua_id"+ua.getId()+"activitynumber"+(activity.getNumber()-1)+"uapssize"+uaps.size());
if(uaps.size()==activity.getNumber()-1){
logger.error("开始修改");
ua.setSuccess(1);
activityService.updateUserActivity(ua);
}
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}} else {
// 支付失败的业务逻辑
logger.info("支付失败,订单号为" + out_trade_no + "错误原因");
}
}
其他使用得方法
/**
* description: 解析微信通知xml
*
* @param xml
* @return
* @author ex_yangxiaoyi
* @see
*/
@SuppressWarnings({ "unused", "rawtypes", "unchecked" })
private static Map parseXmlToList(String xml) {
Map retMap = new HashMap();
try {
StringReader read = new StringReader(xml);
// 创建新的输入源SAX 解析器将使用 InputSource 对象来确定如何读取 XML 输入
InputSource source = new InputSource(read);
// 创建一个新的SAXBuilder
SAXBuilder sb = new SAXBuilder();
// 通过输入源构造一个Document
Document doc = (Document) sb.build(source);
Element root = doc.getRootElement();// 指向根节点
List<Element> es = root.getChildren();
if (es != null && es.size() != 0) {
for (Element element : es) {
retMap.put(element.getName(), element.getValue());
}
}
} catch (Exception e) {
e.printStackTrace();
}
return retMap;
}
/**
* 元转换成分
*
* @param money
* @return
*/
public static String getMoney(String amount) {
if (amount == null) {
return "";
}
// 金额转化为分为单位
String currency = amount.replaceAll("\\$|\\¥|\\,", ""); // 处理包含, ¥
// 或者$的金额
int index = currency.indexOf(".");
int length = currency.length();
Long amLong = 0l;
if (index == -1) {
amLong = Long.valueOf(currency + "00");
} else if (length - index >= 3) {
amLong = Long.valueOf((currency.substring(0, index + 3)).replace(
".", ""));
} else if (length - index == 2) {
amLong = Long.valueOf((currency.substring(0, index + 2)).replace(
".", "") + 0);
} else {
amLong = Long.valueOf((currency.substring(0, index + 1)).replace(
".", "") + "00");
}
return amLong.toString();
}