您的位置:首页 > 移动开发 > 微信开发

基于javaweb 的微信H5支付开发

2016-11-16 00:00 120 查看
摘要: 基于javaweb 的微信H5支付开发

基于javaweb 的微信H5支付开发

前言:最近要完成一个关于微信h5支付的需求,所以就花了一段时间来研究微信关于微信关于h5方面的相关文档,官方提供的文档内容相当复杂,而且相对内容比较分散。而且在整个支付流程中的问题也是状况百出,很多东西都没有给出详细的说明,我是在查询了大量的博客才将这个流程走通。一句话就是,这里的坑非常多,下面我将详细的介绍相应的流程,以及应该避免那些坑,本人也是初学者望各位大神多提意见。

一:token服务器验证(仅支持80端口):

我们需要在微信公众号的的管理界面设置一个路径和token值,微信服务器会访问该路径并且传递一个CheckModel对象过来,我们要做的是将该对象里面的echostr返回过去,微信仅支持访问80端口,所以如果使用tomcat的容器需要去修改server.xml文件(详情百度tomcat默认80端口访问server.xml配置)。

完成服务器token验证代码:(WeixinPayConstants类中有微信服务号相关的信息,在最后我会将相关代码给出来)

@Controller

@RequestMapping("/token")

public class TokenController {

@Autowired

private TokenService tokenService;

/**

* 开发者模式token校验

* @param tokenModel

* @throws ParseException

* @throws IOException

*/

@RequestMapping(value = "/check", method = RequestMethod.GET, produces = "text/plain")

public

@ResponseBody

String validate(CheckModel tokenModel, HttpServletRequest httpServletRequest) throws ParseException, IOException {

String wxToken = WeixinPayConstants.token;

tokenModel.setSignature(httpServletRequest.getParameter("signature"));

tokenModel.setTimestamp(Long.valueOf(httpServletRequest.getParameter("timestamp")));

tokenModel.setNonce(Long.valueOf(httpServletRequest.getParameter("nonce")));

tokenModel.setEchostr(httpServletRequest.getParameter("echostr"));

tokenModel.setEchostr(httpServletRequest.getParameter("echostr"));

return tokenService.validate(wxToken, tokenModel);

}


Validate方法:

@Service

public class TokenService {

/**

* 微信开发者验证

* @param wxToken

* @param tokenModel

* @return

*/

@Transactional

public String validate(String wxToken, CheckModel tokenModel){

String signature = tokenModel.getSignature();

Long timestamp = tokenModel.getTimestamp();

Long nonce =tokenModel.getNonce();

String echostr = tokenModel.getEchostr();

if(signature!=null&×tamp!=null&nonce!=null) {

String[] str = {wxToken, timestamp+"", nonce+""};

Arrays.sort(str); // 字典序排序

String bigStr = str[0] + str[1] + str[2];

// SHA1加密

String digest = EncoderHandler.encode("SHA1", bigStr).toLowerCase();

// 确认请求来至微信

if (digest.equals(signature)) {

//最好此处将echostr存起来,以后每次校验消息来源都需要用到

return echostr;

}

}

return "error";

}


CheckModel实体:

public class CheckModel extends ErrorCodeModel{

String signature;

Long timestamp;

Long nonce;

String echostr;

public String getSignature() {

return signature;

}

public void setSignature(String signature) {

this.signature = signature;

}

public Long getTimestamp() {

return timestamp;

}

public void setTimestamp(Long timestamp) {

this.timestamp = timestamp;

}

public Long getNonce() {

return nonce;

}

public void setNonce(Long nonce) {

this.nonce = nonce;

}

public String getEchostr() {

return echostr;

}

public void setEchostr(String echostr) {

this.echostr = echostr;

}

}


EncoderHandler类:

public class EncoderHandler {

private static final String ALGORITHM = "MD5";

private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5',

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

/**

* encode string

*

* @param algorithm

* @param str

* @return String

*/

public static String encode(String algorithm, String str) {

if (str == null) {

return null;

}

try {

MessageDigest messageDigest = MessageDigest.getInstance(algorithm);

messageDigest.update(str.getBytes());

return getFormattedText(messageDigest.digest());

} catch (Exception e) {

throw new RuntimeException(e);

}

}

/**

* encode By MD5

*

* @param str

* @return String

*/

public static String encodeByMD5(String str) {

if (str == null) {

return null;

}

try {

MessageDigest messageDigest = MessageDigest.getInstance(ALGORITHM);

messageDigest.update(str.getBytes());

return getFormattedText(messageDigest.digest());

} catch (Exception e) {

throw new RuntimeException(e);

}

}

/**

* Takes the raw bytes from the digest and formats them correct.

*

* @param bytes

*            the raw bytes from the digest.

* @return the formatted bytes.

*/

private static String getFormattedText(byte[] bytes) {

int len = bytes.length;

StringBuilder buf = new StringBuilder(len * 2);

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

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

buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);

buf.append(HEX_DIGITS[bytes[j] & 0x0f]);

}

return buf.toString();

}


当你写好这个功能的时候,在微信公众号后台管理:开发——》基本配置——》输入token验证地址,点击提交就会有相应的提示。



二、微信网页调起js sdk网页支付流程:

对页面授权—》发起支付—》回调—》根据相应返回参数判断支付结果进行页面跳转

1. 我们在任何一个页面要调起微信的支付接口都要先对这个页面进行授权,其次就是要在服务号的管理平台上对支付路径进行注册如下图。(在相应的页面需要调用微信的js文件 )<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>



完对授权路径的添加之后我们就可以进入代码的编写了:

1.1 在进入要调起支付页面的时候,页面通过ajax请求后端接口,并且得到相关信息:

后端方法实现:

/**

* 得到获取微信权限所需的相关参数

*

* @param request

* @return

*/

//返回js权限相关的信息给前台

@ResponseBody

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

public String getWeiXinConfig(HttpServletRequest request) {

//  处理JsAPI_ticket 问题(存储数据库)

String jsapi_ticket = getJsapiTicket();

logger.info("获取到的信息:------------:" + JSON.toJSON(jsapi_ticket));

String url = request.getParameter("url");

long timastamp = WeiXinDateUtil.getNowTimeStamp();

WeiXinConfig weiXinConfig = new WeiXinConfig();

weiXinConfig.setApp_id(WeixinPayConstants.appid);

weiXinConfig.setTimestamp(String.valueOf(timastamp));

weiXinConfig.setNonceStr(RandomUtil.generateString(20));

//设置config模块的签名

SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();

parameters.put("jsapi_ticket", jsapi_ticket);

parameters.put("timestamp", timastamp);

parameters.put("noncestr", RandomUtil.generateString(20));

parameters.put("url", url);

String sign = WeiXinCrateSign.createSign("utf-8", parameters);

weiXinConfig.setSignature(sign);

String jsonString = JSON.toJSONString(weiXinConfig);

return jsonString;

}


获取jsapi_ticket:

/**

* 从数据库中查询出当前的JsAPI_ticket或者从网络中获取

*

* @return

*/

private String getJsapiTicket() {

WeiXinJurisdictionConfig weiXinJurisdictionConfig = weiXinJurisdictionConfigService.selectByPrimaryKey(1);

logger.info("数据库获取到的微信JsAPITicket信息:------------:" + JSON.toJSON(weiXinJurisdictionConfig));

if (weiXinJurisdictionConfig.getJsapiTicket() == "0") {

String jsapi = GetJsAPITicket.getJsAPITicket();

logger.info("微信服务器获取到的微信JsAPITicket信息:------------:" + jsapi);

weiXinJurisdictionConfig.setJsapiTicket(jsapi);

logger.info("修改了JsAPITicket之后的实体:------------:" + weiXinJurisdictionConfig);

weiXinJurisdictionConfigService.updateByPrimaryKeySelective(weiXinJurisdictionConfig);

return jsapi;

} else {

return weiXinJurisdictionConfig.getJsapiTicket();

}

}

WeiXinJurisdictionConfig类:

public class WeiXinJurisdictionConfig {

private Integer id;

private String jsapiTicket;

private String accessToken;

public Integer getId() {

return id;

}

public void setId(Integer id) {

this.id = id;

}

public String getJsapiTicket() {

return jsapiTicket;

}

public void setJsapiTicket(String jsapiTicket) {

this.jsapiTicket = jsapiTicket == null ? null : jsapiTicket.trim();

}

public String getAccessToken() {

return accessToken;

}

public void setAccessToken(String accessToken) {

this.accessToken = accessToken == null ? null : accessToken.trim();

}

}


从网络获取jsapi_ticket:

public class GetJsAPITicket {

/**

* 获取JsAPIticket

* @return

*/

public static String getJsAPITicket(){

String access_token = GetAccessToken.getAccess_token();

String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+ access_token +"&type=jsapi";

String jsAPITicketString = GetAccessToken.getJsonString(url);

JsAPITicket jsAPITicket = JSON.parseObject(jsAPITicketString,JsAPITicket.class);

System.out.println("jsapitiket: "+jsAPITicket.getTicket());

return jsAPITicket.getTicket();

}

}

JsAPITicket类:

public class JsAPITicket {

private String ticket;

private int expiresIn;

public String getTicket() {

return ticket;

}

public void setTicket(String ticket) {

this.ticket = ticket;

}

public int getExpiresIn() {

return expiresIn;

}

public void setExpiresIn(int expiresIn) {

this.expiresIn = expiresIn;

}

}


根据以上代码可得要想获取jsapi_ticket首先要获取AccessToken:

/**

* Created by Administrator on 2016/8/19.

*/

public class GetAccessToken {

/**

* 获取Accesstoken

* @return access_token

*/

public static String getAccess_token() {

AccessToken accessToken = null;

String jsonString = null;

String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="

+ WeixinPayConstants.appid+ "&secret=" + WeixinPayConstants.appsecret;

jsonString = getJsonString(url);

accessToken = JSON.parseObject(jsonString,AccessToken.class);

System.out.println("access_token:---------------- "+accessToken.getAccess_token());

return accessToken.getAccess_token();

}

/**

* 获取json字符串通过get方式

* @param url 地址

* @return

*/

public static String getJsonString(String url){

String message = null;

try {

URL urlGet = new URL(url);

HttpURLConnection http = (HttpURLConnection) urlGet

.openConnection();

http.setRequestMethod("GET"); // 必须是get方式请求

http.setRequestProperty("Content-Type",

"application/x-www-form-urlencoded");

http.setDoOutput(true);

http.setDoInput(true);

System.setProperty("sun.net.client.defaultConnectTimeout", "30000");// 连接超时30秒

System.setProperty("sun.net.client.defaultReadTimeout", "30000"); // 读取超时30秒

http.connect();

InputStream is = http.getInputStream();

int size = is.available();

byte[] jsonBytes = new byte[size];

is.read(jsonBytes);

message = new String(jsonBytes, "UTF-8");

is.close();

} catch (Exception e) {

e.printStackTrace();

}

return message;

}

}


AccessToken类:

/**

* Created by Administrator on 2016/8/19.

*/

public class AccessToken {

private String access_token;

private String expires_in;

public String getAccess_token() {

return access_token;

}

public void setAccess_token(String access_token) {

this.access_token = access_token;

}

public String getExpires_in() {

return expires_in;

}

public void setExpires_in(String expires_in) {

this.expires_in = expires_in;

}

}


当以上步骤都走完的时候这是前台的ajax 的success中就会,调起wx.config()(注意里面的参数的名的大小写,以及有那些参数,还有需要调起的接口需要在jsApiList中列出来,详情参考下面的代码或微信官方文档);对该页面进行授权,当授权成功的时候就会执行wx.ready();

2. // 注意:所有的JS接口只能在公众号绑定的域名下调用,公众号开发者需要先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。

// 如果发现在 Android 不能分享自定义内容,请到官网下载最新的包覆盖安装,Android 自定义分享接口需升级至 6.0.2.58 版本及以上。

// 完整 JS-SDK 文档地址:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html

$(function () {

$.ajax({

url: path+"/weiXin/weiXinPay/getWeiXinConfig",

type: "POST",

data: {url: window.location.href},

success: function (data) {

var weixinConfig = JSON.parse(data);

wx.config({

appId: weixinConfig.app_id,

timestamp: weixinConfig.timestamp,

nonceStr: weixinConfig.nonceStr,

signature: weixinConfig.signature,

jsApiList: [// 所有要调用的 API 都要加到这个列表中

"chooseWXPay"

]

});

wx.ready(function () {

$.ajax({

url: path+"/weiXin/weiXinPay/getOrder",

type: "POST",

data: {},

success: function (data) {

if (data != null) {

var weixinPay = JSON.parse(data);

wx.chooseWXPay({

timestamp: weixinPay.timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符

nonceStr: weixinPay.nonceStr, // 支付签名随机串,不长于 32 位

package: weixinPay.package, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)

signType: weixinPay.signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'

paySign: weixinPay.paySign, // 支付签名

success: function (res) {

// 支付成功后的回调函数

根据相应的返回参数判断支付结果,并且进行相应的页面跳转

},

error: function (res) {

alert(res + "失败!")

}

});

}else{

alert("出错了!");

}

},

error: function (data) {

alert(data + "REEOR")

}

})

})

},

error: function (data) {

alert(data + "REEOR")

}

})

})


当执行wx.ready() 时整个流程是:生成一个订单—》调用微信的获取点单id的接口—》获取到订单id,然后将一系列的相关签名和其他参数传递到页面—》调起微信的相关控件,输入密码完成支付。

2.1 根据上面的ajax请求访问后端获取订单信息的相关接口:

后端处理代码:

/**

* 获取微信支付所需的相关参数

*

* @param httpServletRequest

* @param session

* @return

* @throws Exception

*/

@ResponseBody

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

public String getOrderInfo(HttpServletRequest httpServletRequest, HttpSession session) throws Exception {

String orderXml;//微信下单xml

String orderInfo;//订单的简介

String nonce_str;//32位以内随机字符串

String out_trade_no;//商户订单号

int total_fee;

String jsonString = null;

getWeiXinOpenIdReturn(session);//获取用户的openid存放到session中

logger.info("session获取出来的订单信息:------------>>>>>>>saleProduct:" + JSON.toJSON(session));

// 下单所用到真实的信息,从系统session获取

WeiXinOrderNeedInfo weiXinOrderNeedInfo = (WeiXinOrderNeedInfo) session.getAttribute("weiXinOrderNeedInfo");

if (weiXinOrderNeedInfo != null) {

logger.info("session获取出来的订单信息:------------>>>>>>>saleProduct:" + JSON.toJSON(weiXinOrderNeedInfo));

orderInfo = "菜小乐支付订单";//  订单的简介

nonce_str = weiXinOrderNeedInfo.getNonce_str();

out_trade_no = weiXinOrderNeedInfo.getOut_trade_no();// 商户订单号(商户自己系统内生成的订单号32位以内)

total_fee = weiXinOrderNeedInfo.getTotal_fee();// 总金额,单位默认为分

String openid = String.valueOf(session.getAttribute("openId"));// 用户的openid

WeiXinGetOrder weiXinGetOrder = new WeiXinGetOrder();

weiXinGetOrder.setAppid(WeixinPayConstants.appid);

weiXinGetOrder.setBody(orderInfo);

weiXinGetOrder.setMch_id(WeixinPayConstants.mch_id);

weiXinGetOrder.setNonce_str(nonce_str);

weiXinGetOrder.setNotify_url(WeixinPayConstants.notify_url);//  接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数。

weiXinGetOrder.setOpenid(openid);

weiXinGetOrder.setOut_trade_no(out_trade_no);

weiXinGetOrder.setSpbill_create_ip(GetClientIp.getIpAddr(httpServletRequest)); //用户页面的ip

weiXinGetOrder.setTrade_type("JSAPI");

weiXinGetOrder.setTotal_fee(total_fee);

//设置并得到签名

SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();

parameters.put("appid", WeixinPayConstants.appid);

parameters.put("body", orderInfo);

parameters.put("mch_id", WeixinPayConstants.mch_id);

parameters.put("nonce_str", nonce_str);

parameters.put("notify_url", WeixinPayConstants.notify_url);//  接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数。

parameters.put("openid", openid);

parameters.put("out_trade_no", out_trade_no);

parameters.put("spbill_create_ip", GetClientIp.getIpAddr(httpServletRequest));//用户页面的ip

parameters.put("trade_type", "JSAPI");

parameters.put("total_fee", total_fee);

String sign = WeiXinCrateSign.createSign("utf-8", parameters);

System.out.println("签名------------------" + sign);

weiXinGetOrder.setSign(sign);

orderXml = getOrderXml(weiXinGetOrder);

System.out.println("直接字符串输出" + orderXml);

//获取相关的订单信息,注意得到的是xml格式的信息,需要在下面对其解析

String stringObject = CommonUtil.httpsRequest(WeixinPayConstants.createOrderURL, "POST", orderXml).toString();

System.out.println("返回的xmlstring" + stringObject);

//将map对象转换成xml格式数据

Map map = ObjectAndXmlUtil.doXMLParse(stringObject);

String prepay_id = String.valueOf(map.get("prepay_id"));

logger.info("-----统一下单接口的订单id:" + JSON.toJSON(map.get("prepay_id")));

WeiXinPay weiXinPay = new WeiXinPay();

String nonceStr = RandomUtil.generateString(15);

String timaStamp = String.valueOf(WeiXinDateUtil.getNowTimeStamp());

weiXinPay.setPackage("prepay_id=" + prepay_id);

weiXinPay.setTimeStamp(timaStamp);//

weiXinPay.setNonceStr(nonceStr);

weiXinPay.setAppId(WeixinPayConstants.appid);

weiXinPay.setSignType("MD5");

SortedMap<Object, Object> parameter = new TreeMap<Object, Object>();

parameter.put("timeStamp", timaStamp);

parameter.put("appId", WeixinPayConstants.appid);

parameter.put("nonceStr", nonceStr);

parameter.put("signType", "MD5");

parameter.put("package", weiXinPay.getPackage());

weiXinPay.setPaySign(WeiXinCrateSign.createSign("utf-8", parameter));

jsonString = JSON.toJSONString(weiXinPay);

}

return jsonString;

}


每一个订单都对应一个微信用户,所以在此之前我们要获取用户的openid:

/**

* 获取微信用户的openid

*

* @param session

*/

public void getWeiXinOpenIdReturn(HttpSession session) {

String code = String.valueOf(session.getAttribute("returnCode"));

System.out.println("code值----------" + code);

String oauth_url = WeixinPayConstants.oauth_url.replace("APPID", WeixinPayConstants.appid).replace("SECRET", WeixinPayConstants.appsecret).replace("CODE", code);

logger.info("oauth_url:" + oauth_url);

JSONObject jsonObject = CommonUtil.httpsRequestToJsonObject(oauth_url, "POST", null);

logger.info("jsonObject:" + jsonObject);

Object errorCode = jsonObject.get("errcode");

if (errorCode != null) {

logger.info("code不合法");

} else {

String openId = jsonObject.getString("openid");

logger.info("openId:" + openId);

logger.info("openId:" + openId);

session.setAttribute("openId", openId);

System.out.println("openid-----------" + openId);

}

}


具体获取openid的相关代码:

public class CommonUtil {

/**

* 获取用户openid的网络实现

* @param requestUrl

* @param requestMethod

* @param outputStr

* @return

*/

public static JSONObject httpsRequestToJsonObject(String requestUrl, String requestMethod, String outputStr) {

JSONObject jsonObject = null;

try {

StringBuffer buffer = httpsRequest(requestUrl, requestMethod, outputStr);

jsonObject = JSONObject.fromObject(buffer.toString());

} catch (ConnectException ce) {

System.out.println("连接超时:" + ce.getMessage());

} catch (Exception e) {

System.out.println("https请求异常:" + e.getMessage());

}

return jsonObject;

}

/**

* /获取openid的post方法

* @param requestUrl

* @param requestMethod

* @param output

* @return

* @throws NoSuchAlgorithmException

* @throws KeyManagementException

* @throws IOException

*/

public static StringBuffer httpsRequest(String requestUrl, String requestMethod, String output)

throws NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException,

IOException{

URL url = new URL(requestUrl);

HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();

connection.setDoOutput(true);

connection.setDoInput(true);

connection.setUseCaches(false);

connection.setRequestMethod(requestMethod);

if (null != output) {

OutputStream outputStream = connection.getOutputStream();

outputStream.write(output.getBytes("UTF-8"));

outputStream.close();

}

// 从输入流读取返回内容

InputStream inputStream = connection.getInputStream();

InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");

BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

String str = null;

StringBuffer buffer = new StringBuffer();

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

buffer.append(str);

}

bufferedReader.close();

inputStreamReader.close();

inputStream.close();

inputStream = null;

connection.disconnect();

return buffer;

}


将要下单的信息转换为xml格式的数据(要在每条数据中加上<![CDATA]>,腾讯官方文档是没有加的,但是接口又需要加上,当初我在这里也卡了很长一段时间):

/**

* 将要下单的订单信息转化成xml

*

* @param weiXinGetOrder

* @return

*/

private String getOrderXml(WeiXinGetOrder weiXinGetOrder) {

String data = "<xml>" +

"<appid>" + "<![CDATA[" + weiXinGetOrder.getAppid() + "]]>" + "</appid>" +

"<body>" + "<![CDATA[" + weiXinGetOrder.getBody() + "]]>" + "</body>" +

"<mch_id>" + "<![CDATA[" + weiXinGetOrder.getMch_id() + "]]>" + "</mch_id>" +

"<nonce_str>" + "<![CDATA[" + weiXinGetOrder.getNonce_str() + "]]>" + "</nonce_str>" +

"<notify_url>" + "<![CDATA[" + weiXinGetOrder.getNotify_url() + "]]>" + "</notify_url>" +

"<openid>" + "<![CDATA[" + weiXinGetOrder.getOpenid() + "]]>" + "</openid>" +

"<out_trade_no>" + "<![CDATA[" + weiXinGetOrder.getOut_trade_no() + "]]>" + "</out_trade_no>" +

"<spbill_create_ip>" + "<![CDATA[" + weiXinGetOrder.getSpbill_create_ip() + "]]>" + "</spbill_create_ip>" +

"<total_fee>" + "<![CDATA[" + weiXinGetOrder.getTotal_fee() + "]]>" + "</total_fee>" +

"<trade_type>" + "<![CDATA[" + weiXinGetOrder.getTrade_type() + "]]>" + "</trade_type>" +

"<sign>" + "<![CDATA[" + weiXinGetOrder.getSign() + "]]>" + "</sign>" +

"</xml>";//将实体转化成xml(string)

return data;

}


ObjectAndXmlUtil类(进行实体与xml数据之间的相互转化):

public class ObjectAndXmlUtil {

/**

* 将微信xml转化成实体

* * @param xmlStr

*

* @return

*/

public static WeiXinGetOrder XMLStringToBeanWeiXinGetOrder(String xmlStr) {

XStream xstream = new XStream();

WeiXinGetOrder weiXinGetOrder = (WeiXinGetOrder) xstream.fromXML(xmlStr);

return weiXinGetOrder;

}

public static InputStream String2Inputstream(String str) {

return new ByteArrayInputStream(str.getBytes());

}

/**

* 获取子结点的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();

}

/**

* 解析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 map = 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);

}

map.put(k, v);

}

//关闭流

in.close();

return map;

}

}


WeiXinGetOrder类,相关参数在代码中有相关说明:

/**

* Created by Administrator on 2016/8/18.

*/

@XmlRootElement

public class WeiXinGetOrder implements Serializable {

private String appid;//公众号id

private String mch_id;//商户号

private String nonce_str;//不少于32位随机字符串

private String sign;//签名

private String body;//商品的描述(浏览器打开的移动网页的主页title名-商品概述)

private String out_trade_no;//商户订单号(商户自己系统内生成的订单号32位以内)

private int total_fee;//总金额,单位默认为分

private String spbill_create_ip;//提交用户终端的ip

private String notify_url;//接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数。

private String trade_type;//交易类型 取值如下:JSAPI

private String openid;//交易类型 取值如下:JSAPI

public String getOpenid() {

return openid;

}

public void setOpenid(String openid) {

this.openid = openid;

}

public String getAppid() {

return appid;

}

public void setAppid(String appid) {

this.appid = appid;

}

public String getBody() {

return body;

}

public void setBody(String body) {

this.body = body;

}

public String getMch_id() {

return mch_id;

}

public void setMch_id(String mch_id) {

this.mch_id = mch_id;

}

public String getNonce_str() {

return nonce_str;

}

public void setNonce_str(String nonce_str) {

this.nonce_str = nonce_str;

}

public String getNotify_url() {

return notify_url;

}

public void setNotify_url(String notify_url) {

this.notify_url = notify_url;

}

public String getOut_trade_no() {

return out_trade_no;

}

public void setOut_trade_no(String out_trade_no) {

this.out_trade_no = out_trade_no;

}

public String getSign() {

return sign;

}

public void setSign(String sign) {

this.sign = sign;

}

public String getSpbill_create_ip() {

return spbill_create_ip;

}

public void setSpbill_create_ip(String spbill_create_ip) {

this.spbill_create_ip = spbill_create_ip;

}

public int getTotal_fee() {

return total_fee;

}

public void setTotal_fee(int total_fee) {

this.total_fee = total_fee;

}

public String getTrade_type() {

return trade_type;

}

public void setTrade_type(String trade_type) {

this.trade_type = trade_type;

} }


在上面的实体类中有一个属性是sign:我在这里也给出微信的签名算法(官方的签名规定:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3):

@SuppressWarnings("unchecked")

//api 密钥

private static String Key = WeixinPayConstants.partnerkey;

/**

* 微信签名算法

* @param characterEncoding 编码格式

* @param parameters 签名所涉及到数据

* @return sign 签名

*/

public static String createSign(String characterEncoding,SortedMap<Object,Object> parameters){

StringBuffer sb = new StringBuffer();

Set es = parameters.entrySet();//所有参与传参的参数按照accsii排序(升序)

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=" + Key);

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

return sign;

}


后端的相关步骤执行完之后,程序会执行到上面给出来的ajax的success方法中,通过判断返回值就可以判断是否支付成功,并进行先关的页面跳转:

https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7

结束:由于本人也是新手,这些代码很low仅仅是简单的实现了支付的功能而已,后期有时间在来重构这些代码了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息