java版微信支付
2015-07-23 16:12
603 查看
前言:
由于最近公司项目需要接入网页版微信支付,我在官网上查询了很久,发现微信官网只提供了扫码支付等java demo,或者只有php等其它语言的微信支付,只提供了支付的一些API,所以这里需要自己根据官网提供的api自己写支付。
1,请先查看微信支付的流程图,了解下微信支付的过程。
1,在手机微信上打开一个h5页面(微信已经提供桌面版微信了,我们可以直接在桌面上面调试更加方便)
2,生成一个JAVA的订单接口,然后返回一个我们自己的订单号。
3,将订单号、商品信息、价格等信息拼接生成统一下单接口获得prepay_id
注:调用下单接口时需要先获取openid
3.1)调用用户授权接口获得code值
3.2)将得到的code的值去获取openid
3.3)根据得到的openid获得prepay_id
4,用户点击支付,获取用户授权
5,授权成功进入微信端支付界面进行支付操作
6,支付成功后回调自己配置界面,微信端通知后端服务器
-----------------------------------------------------------------------------------------------------------------------------------------------------
进入正题
1,如何申请成为公众号,申请成为支付服务号这些这里就不提了
2,配置微信公众平台服务号(记住是进入服务号账号)
2.1)进入微信公众平台,点击微信支付按钮(如图)
2.2)添加你的支付授权测试目录跟正式授权支付目录、并且添加测试微信号
注:授权目录一定是支付页面的上级目录,如:我的支付页面为:http://www.baidu.com/test/pay/index.jsp,那么我的授权目录是http://www.baidu.com/test/pay/
注意是以/结束。
2.3)进入微信开发者中心,找到网页授权获取用户基本信息添加网页授权域名(如www.baidu.com,不需要带http://,也不能是ip地址)
3,根据微信支付需要的配置去获取对应的信息
3.1)appid公众号APPID、mch_id微信支付商户号在微信申请成功后发送到邮箱获取
3.2)应用密钥AppSecret在开发者中心->配置项->开发者ID查看
3.3)商户支付密钥Key以及证书路径
在微信支付商户平台,在【账户设置-密码安全-API安全】中下载以及设置
3.4)配置支付页面已经支付回调页面(www.test.com/pay/testPay/index.jsp)
---------------------------------------------------------------------------------------------------------------
代码部分
1,支付配置页面
package com.weixin.config;
public class WeixinConfig {
//=======【基本信息设置】=====================================
//微信公众号身份的唯一标识。审核通过后,在微信发送的邮件中查看
public static final String APPID = "wxb69e254afdb3fae4";
//受理商ID,身份标识
public static final String MCHID = "1246043803";
//商户支付密钥Key。审核通过后,在微信发送的邮件中查看
public static final String KEY = "qwertyuioplkjhgfdsazxcvbnm125871";
//JSAPI接口中获取openid,审核后在公众平台开启开发模式后可查看
public static final String APPSECRET = "d896864455e000ea86e722e95e34d2d3";
//=======【JSAPI路径设置】===================================
//获取access_token过程中的跳转uri,通过跳转将code传入jsapi支付页面
public static final String JS_API_CALL_URL = "http://www.weixin.com/weixin/webApp/pay/index.jsp";
//=======【证书路径设置】=====================================
//证书路径,注意应该填写绝对路径
public static final String SSLCERT_PATH = "/home/wwwroot/weixin/webApp/WxPayPubHelper/cacert/apiclient_cert.pem";
public static final String SSLKEY_PATH = "/home/wwwroot/weixin/webApp/WxPayPubHelper/cacert/apiclient_key.pem";
//=======【异步通知url设置】===================================
//异步通知url,商户根据实际开发过程设定
public static final String NOTIFY_URL = "http://www.weixin.com/weixin/webApp/pay/notify_url.jsp";
//=======【http超时设置】===================================
//使用HTTP POST方法,此处可修改其超时时间,默认为30秒
public static final int POST_TIMEOUT = 30000;
//统一下单接口
public static final String UNIFIED_ORDER = "https://api.mch.weixin.qq.com/pay/unifiedorder";
}
2,支付方法页面
package com.weixin.commons;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.SortedMap;
import java.util.TreeMap;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.log4j.Logger;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import com.golf.utils.MD5Utils;
import com.weixin.config.WeixinConfig;
public class WeixinCommon {
private Logger logger = Logger.getLogger(WeixinCommon.class);
private String code;
private String prepay_id;
public static void main(String args[]){
WeixinCommon common = new WeixinCommon();
String url = common.createOauthUrlForCode(WeixinConfig.JS_API_CALL_URL);
System.out.println(url);
//common.httpRequest(url);
//System.out.println(common.createOauthUrlForCode("http://local/indx.html"));
}
/**
* 写日志
*/
public void logger(String msg){
logger.info(msg);
}
/**
* 作用:通过http向微信提交code,以获取openid
* 1、发送http请求
* 2、格式化json数据
* 3、获取openid
*/
public String getOpenid(){
String url = createOauthUrlForOpenid();
String open_id = "";
ObjectMapper mapper = new ObjectMapper();
try {
String response_msg = httpGetRequest(url);
logger("getOpenid method is response_msg: "+response_msg);
if(!"".equals(response_msg)){
JsonNode node = mapper.readTree(response_msg);
JsonNode child_node = node.get("openid");
open_id = child_node.getTextValue();
}
} catch (JsonProcessingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return open_id;
}
public String httpGetRequest(String url) {
HttpClient client = new HttpClient();
String response_msg = "";
GetMethod get = new GetMethod(url);
client.getHttpConnectionManager().getParams().setConnectionTimeout(WeixinConfig.POST_TIMEOUT);
//get.setRequestHeader("Content-Type", "text/html; charset=utf-8");
try {
int success = client.executeMethod(get);
if(success > 0){
response_msg = get.getResponseBodyAsString();
logger("httpGetRequest method response_msg:"+response_msg);
}
} catch (HttpException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
if(get != null){
get.releaseConnection();
}
}
return response_msg;
}
public String httpPostRequest(String content,String url) {
HttpClient client = new HttpClient();
String response_msg = "";
PostMethod post = new PostMethod(url);
//post.setQueryString(content);
//post.setRequestBody(content);
RequestEntity requestEntity = new StringRequestEntity(content);
post.setRequestEntity(requestEntity);
post.setRequestHeader("Content-type", "text/xml; charset=utf-8");
client.getHttpConnectionManager().getParams().setConnectionTimeout(WeixinConfig.POST_TIMEOUT);
try {
int success = client.executeMethod(post);
if(success > 0){
response_msg = post.getResponseBodyAsString();
logger("httpPostRequest method response_msg:"+response_msg);
}
} catch (HttpException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
if(post != null){
post.releaseConnection();
}
}
return response_msg;
}
/**
* 作用:生成可以获得openid的url
*/
public String createOauthUrlForOpenid()
{
SortedMap<String,Object> url_map = new TreeMap<String,Object>();
url_map.put("appid", WeixinConfig.APPID);
url_map.put("secret", WeixinConfig.APPSECRET);
url_map.put("code", this.code);
url_map.put("grant_type", "authorization_code");
String bizString = formatBizQueryParaMap(url_map);
return "https://api.weixin.qq.com/sns/oauth2/access_token?"+bizString;
}
/**
* 作用:生成可以获得code的url
*/
public String createOauthUrlForCode(String redirectUrl){
SortedMap<String,Object> url_map = new TreeMap<String,Object>();
url_map.put("redirect_uri", redirectUrl);
url_map.put("appid", WeixinConfig.APPID);
url_map.put("scope", "snsapi_base");
url_map.put("response_type", "code");
//url_map.put("scope", "snsapi_userinfo");
url_map.put("state", "STATE"+"#wechat_redirect");
String biz_string = formatBizQueryParaMap(url_map);
String code = "https://open.weixin.qq.com/connect/oauth2/authorize?"+biz_string;
logger("request code is :"+code);
return code;
}
/**
* 作用:格式化参数,签名过程需要使用
* 将参数按照ASCII字母顺序升序排序
*/
private String formatBizQueryParaMap(SortedMap<String,Object> url_map){
StringBuilder builder = new StringBuilder();
String str = "";
for(Map.Entry<String, Object> entry : url_map.entrySet()){
builder.append("&"+entry.getKey()+"="+entry.getValue());
}
if(builder.length() > 0){
str = builder.toString().substring(1);
}
return str;
}
/**
* 获取预支付prepayId
* @return
*/
public String getPrepayId(SortedMap<String,Object> sorted_map)
{
String response = postXml(sorted_map);
Map<String,Object> result = xmlToArray(response);
String prepay_id = String.valueOf(result.get("prepay_id"));
return prepay_id;
}
/**
* 作用:将xml转为array
*/
public Map<String,Object> xmlToArray(String xml)
{
Map<String,Object> map_value = new HashMap<String,Object>();
Document document;
try {
document = DocumentHelper.parseText(xml);
Element root_element = document.getRootElement();
List<Element> child_element = root_element.elements();
for(Element ele : child_element){
map_value.put(ele.getName(), ele.getText());
}
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return map_value;
}
/**
* 作用:post请求xml 调用统一下单接口
*/
private String postXml(SortedMap<String,Object> sorted_map)
{
String xml = createXml(sorted_map);
return httpPostRequest(xml,WeixinConfig.UNIFIED_ORDER);
}
/**
* 作用:设置标配的请求参数,生成签名,生成接口参数xml
*/
private String createXml(SortedMap<String,Object> sorted_map)
{
//$this->parameters["sign"] = $this->getSign($this->parameters);//签名
sorted_map.put("appid", WeixinConfig.APPID);
sorted_map.put("mch_id", WeixinConfig.MCHID);
sorted_map.put("nonce_str", createNoncestr());
sorted_map.put("sign", getSign(sorted_map));
String xml = arrayToXml(sorted_map);
logger("create prepay request parameters is :"+xml);
return xml;
}
/**
* 作用:产生随机字符串,不长于32位
*/
public String createNoncestr()
{
String chars = "abcdefghijklmnopqrstuvwxyz0123456789";
String str ="";
int current_str_length = 0;
Random random = new Random();
for ( int i = 0; i < 32; i++ ) {
current_str_length = random.nextInt(chars.length()-1);
str+= chars.substring(current_str_length,current_str_length+1);
}
return str;
}
/**
* 作用:生成签名
*/
public String getSign(SortedMap<String,Object> value_map)
{
//将值按照key=value的形式格式化为字符串
String str= formatBizQueryParaMap(value_map);
//签名步骤二:在string后加入KEY
str = str+"&key="+WeixinConfig.KEY;
//签名步骤三:MD5加密
str = MD5Utils.encrypt(str);
//签名步骤四:所有字符转为大写
return str.toUpperCase();
}
/**
* 作用:array转xml
*/
private String arrayToXml(SortedMap<String,Object> map_value)
{
String xml = "<xml>";
for(Map.Entry<String, Object> entry : map_value.entrySet()){
if(entry.getValue() instanceof Integer){
xml+="<"+entry.getKey()+">"+entry.getValue()+"</"+entry.getKey()+">";
}else{
xml+="<"+entry.getKey()+"><![CDATA["+entry.getValue()+"]]></"+entry.getKey()+">";
}
}
xml +="</xml>";
return xml;
}
/**
* 作用:设置jsapi的参数
*/
public Object getParameters()
{
SortedMap<String,Object> order_map = new TreeMap<String,Object>();
order_map.put("appId", WeixinConfig.APPID);
order_map.put("timeStamp", System.currentTimeMillis()/1000);
order_map.put("nonceStr", createNoncestr());
order_map.put("package", "prepay_id="+prepay_id);
order_map.put("signType", "MD5");
order_map.put("paySign", getSign(order_map));
ObjectMapper mapper = new ObjectMapper();
String jsonObject = "";
try {
jsonObject = mapper.writeValueAsString(order_map);
} catch (JsonGenerationException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
logger("order pay info is : "+jsonObject);
return jsonObject;
}
public void setCode(String code)
{
this.code = code;
}
public void setPrepay_id(String prepay_id) {
this.prepay_id = prepay_id;
}
}
3,JSP支付页面
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="com.weixin.config.*"%>
<%@ page import="com.weixin.commons.*"%>
<%@ page import="java.net.URLEncoder" %>
<%@ page import="java.util.TreeMap"%>
<%@ page import="java.util.SortedMap"%>
<%
WeixinCommon common = new WeixinCommon();
String parameters = request.getParameter("parameters");
String code = request.getParameter("code");
common.logger("page enter and parameters is :"+parameters +" and code is :"+code);
if(parameters == null || "".equals(parameters)){
return ;
}
String opendid = "";
if(code == null || "".equals(code)){
String parameter_path = "?parameters="+parameters;
common.logger("request code path is : "+parameter_path);
//触发微信返回code码
String url = common.createOauthUrlForCode(WeixinConfig.JS_API_CALL_URL+parameter_path);
response.sendRedirect(url);
return;
}else{
//获取code码,以获取openid
common.setCode(code);
opendid = common.getOpenid();
common.logger("code is exist and get opendid is :"+opendid);
}
//由于在我测试的时候如果传入多个参数会出现参数遗漏的情况,
//所以这里我把所有的参数按照一定的规则以逗号隔开处理,然后统一获取
//如果大家未遇到这种情况可以忽略
String[] param = parameters.split(",");
String out_trade_no = param[0];
String out_trade_name = URLEncoder.encode(param[1],"UTF-8");
String out_trade_fee = param[2];
common.logger("out_trade_no is :"+out_trade_no+" and out_trade_name is:"+out_trade_name+" and out_trade_fee is :"+out_trade_fee);
//=========步骤2:使用统一支付接口,获取prepay_id============
SortedMap<String,Object> order_map = new TreeMap<String,Object>();
order_map.put("openid",opendid);//商品描述
order_map.put("body",out_trade_name);//商品描述
order_map.put("out_trade_no",out_trade_no);//商户订单号
order_map.put("total_fee",out_trade_fee);//总金额
order_map.put("notify_url",WeixinConfig.NOTIFY_URL);//通知地址
order_map.put("trade_type","JSAPI");//交易类型
String prepay_id = common.getPrepayId(order_map);
common.logger("current prepay_id is : "+prepay_id);
common.setPrepay_id(prepay_id);
//=========步骤3:使用jsapi调起支付============
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=0.5, maximum-scale=2.0, user-scalable=yes" />
<style type="text/css">
body{
margin:0px;
padding:0px;
}
.title{
margin-top: 12%;
text-align: center;
font-size: 1.5em;
font-weight: bold;
}
.price{
margin-top: 5%;
text-align: center;
font-size: 3em;
font-weight: bold;
}
.line{
margin-top: 10%;
height:1px;
background-color:#969696;
margin-bottom: 10%;
}
.rec{
float:left;
font-weight: 600;
color: #7c7c7c;
margin-left:2%;
}
.com{
float:right;
font-weight: 600;
margin-right:2%;
}
.clear{
clear:both;
}
.submit{
text-align: center;
}
.submit span{
text-decoration: center;
display:block;
border-radius: 5px;
width:90%;
height:50px;
line-height: 50px;
margin-left:5%;
background-color: #06be04;
color:#fff;
font-weight: bold;
}
</style>
<title>微信安全支付</title>
<script type="text/javascript">
//调用微信JS api 支付
function jsApiCall()
{
WeixinJSBridge.invoke(
'getBrandWCPayRequest',
<%out.println(common.getParameters());%>
,
function(res){
//WeixinJSBridge.log(res.err_msg);
alert(res.err_msg);
if(res.err_msg == "get_brand_wcpay_request:ok"){
window.location.href="call_back.html";
}
}
);
}
function callpay()
{
if (typeof WeixinJSBridge == "undefined"){
if( document.addEventListener ){
document.addEventListener('WeixinJSBridgeReady', jsApiCall, false);
}else if (document.attachEvent){
document.attachEvent('WeixinJSBridgeReady', jsApiCall);
document.attachEvent('onWeixinJSBridgeReady', jsApiCall);
}
}else{
jsApiCall();
}
}
</script>
</head>
<body onload="callpay()">
</body>
</html>
-------------------------------------------------------------------------------------------------------------------
到这里,一个支付的接口就完成了,我这个只是简单的实现支付,里面的异常判断,一些逻辑优化就需要大家自己去优化了。因为微信提供的错误信息比较少,而且必须在微信客户端测试,所以大家在测试的时候最好是每走一步就打印一个日志,这样可以方便查询到底是哪里出错了,如果是走到最后一步出现get_brand_wcpay_request:fail 一般情况就是配置不对,需要仔细的查看每一个配置,或者是在调用支付接口的时候参数值不对。每获取一个微信提供的值成功后,则代表你这步已经成功了,不然微信不会返回正确的信息给你。
demo下载地址:http://download.csdn.net/detail/xuelinmei_happy/8926681
由于最近公司项目需要接入网页版微信支付,我在官网上查询了很久,发现微信官网只提供了扫码支付等java demo,或者只有php等其它语言的微信支付,只提供了支付的一些API,所以这里需要自己根据官网提供的api自己写支付。
1,请先查看微信支付的流程图,了解下微信支付的过程。
1,在手机微信上打开一个h5页面(微信已经提供桌面版微信了,我们可以直接在桌面上面调试更加方便)
2,生成一个JAVA的订单接口,然后返回一个我们自己的订单号。
3,将订单号、商品信息、价格等信息拼接生成统一下单接口获得prepay_id
注:调用下单接口时需要先获取openid
3.1)调用用户授权接口获得code值
3.2)将得到的code的值去获取openid
3.3)根据得到的openid获得prepay_id
4,用户点击支付,获取用户授权
5,授权成功进入微信端支付界面进行支付操作
6,支付成功后回调自己配置界面,微信端通知后端服务器
-----------------------------------------------------------------------------------------------------------------------------------------------------
进入正题
1,如何申请成为公众号,申请成为支付服务号这些这里就不提了
2,配置微信公众平台服务号(记住是进入服务号账号)
2.1)进入微信公众平台,点击微信支付按钮(如图)
2.2)添加你的支付授权测试目录跟正式授权支付目录、并且添加测试微信号
注:授权目录一定是支付页面的上级目录,如:我的支付页面为:http://www.baidu.com/test/pay/index.jsp,那么我的授权目录是http://www.baidu.com/test/pay/
注意是以/结束。
2.3)进入微信开发者中心,找到网页授权获取用户基本信息添加网页授权域名(如www.baidu.com,不需要带http://,也不能是ip地址)
3,根据微信支付需要的配置去获取对应的信息
3.1)appid公众号APPID、mch_id微信支付商户号在微信申请成功后发送到邮箱获取
3.2)应用密钥AppSecret在开发者中心->配置项->开发者ID查看
3.3)商户支付密钥Key以及证书路径
在微信支付商户平台,在【账户设置-密码安全-API安全】中下载以及设置
3.4)配置支付页面已经支付回调页面(www.test.com/pay/testPay/index.jsp)
---------------------------------------------------------------------------------------------------------------
代码部分
1,支付配置页面
package com.weixin.config;
public class WeixinConfig {
//=======【基本信息设置】=====================================
//微信公众号身份的唯一标识。审核通过后,在微信发送的邮件中查看
public static final String APPID = "wxb69e254afdb3fae4";
//受理商ID,身份标识
public static final String MCHID = "1246043803";
//商户支付密钥Key。审核通过后,在微信发送的邮件中查看
public static final String KEY = "qwertyuioplkjhgfdsazxcvbnm125871";
//JSAPI接口中获取openid,审核后在公众平台开启开发模式后可查看
public static final String APPSECRET = "d896864455e000ea86e722e95e34d2d3";
//=======【JSAPI路径设置】===================================
//获取access_token过程中的跳转uri,通过跳转将code传入jsapi支付页面
public static final String JS_API_CALL_URL = "http://www.weixin.com/weixin/webApp/pay/index.jsp";
//=======【证书路径设置】=====================================
//证书路径,注意应该填写绝对路径
public static final String SSLCERT_PATH = "/home/wwwroot/weixin/webApp/WxPayPubHelper/cacert/apiclient_cert.pem";
public static final String SSLKEY_PATH = "/home/wwwroot/weixin/webApp/WxPayPubHelper/cacert/apiclient_key.pem";
//=======【异步通知url设置】===================================
//异步通知url,商户根据实际开发过程设定
public static final String NOTIFY_URL = "http://www.weixin.com/weixin/webApp/pay/notify_url.jsp";
//=======【http超时设置】===================================
//使用HTTP POST方法,此处可修改其超时时间,默认为30秒
public static final int POST_TIMEOUT = 30000;
//统一下单接口
public static final String UNIFIED_ORDER = "https://api.mch.weixin.qq.com/pay/unifiedorder";
}
2,支付方法页面
package com.weixin.commons;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.SortedMap;
import java.util.TreeMap;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.log4j.Logger;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import com.golf.utils.MD5Utils;
import com.weixin.config.WeixinConfig;
public class WeixinCommon {
private Logger logger = Logger.getLogger(WeixinCommon.class);
private String code;
private String prepay_id;
public static void main(String args[]){
WeixinCommon common = new WeixinCommon();
String url = common.createOauthUrlForCode(WeixinConfig.JS_API_CALL_URL);
System.out.println(url);
//common.httpRequest(url);
//System.out.println(common.createOauthUrlForCode("http://local/indx.html"));
}
/**
* 写日志
*/
public void logger(String msg){
logger.info(msg);
}
/**
* 作用:通过http向微信提交code,以获取openid
* 1、发送http请求
* 2、格式化json数据
* 3、获取openid
*/
public String getOpenid(){
String url = createOauthUrlForOpenid();
String open_id = "";
ObjectMapper mapper = new ObjectMapper();
try {
String response_msg = httpGetRequest(url);
logger("getOpenid method is response_msg: "+response_msg);
if(!"".equals(response_msg)){
JsonNode node = mapper.readTree(response_msg);
JsonNode child_node = node.get("openid");
open_id = child_node.getTextValue();
}
} catch (JsonProcessingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return open_id;
}
public String httpGetRequest(String url) {
HttpClient client = new HttpClient();
String response_msg = "";
GetMethod get = new GetMethod(url);
client.getHttpConnectionManager().getParams().setConnectionTimeout(WeixinConfig.POST_TIMEOUT);
//get.setRequestHeader("Content-Type", "text/html; charset=utf-8");
try {
int success = client.executeMethod(get);
if(success > 0){
response_msg = get.getResponseBodyAsString();
logger("httpGetRequest method response_msg:"+response_msg);
}
} catch (HttpException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
if(get != null){
get.releaseConnection();
}
}
return response_msg;
}
public String httpPostRequest(String content,String url) {
HttpClient client = new HttpClient();
String response_msg = "";
PostMethod post = new PostMethod(url);
//post.setQueryString(content);
//post.setRequestBody(content);
RequestEntity requestEntity = new StringRequestEntity(content);
post.setRequestEntity(requestEntity);
post.setRequestHeader("Content-type", "text/xml; charset=utf-8");
client.getHttpConnectionManager().getParams().setConnectionTimeout(WeixinConfig.POST_TIMEOUT);
try {
int success = client.executeMethod(post);
if(success > 0){
response_msg = post.getResponseBodyAsString();
logger("httpPostRequest method response_msg:"+response_msg);
}
} catch (HttpException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
if(post != null){
post.releaseConnection();
}
}
return response_msg;
}
/**
* 作用:生成可以获得openid的url
*/
public String createOauthUrlForOpenid()
{
SortedMap<String,Object> url_map = new TreeMap<String,Object>();
url_map.put("appid", WeixinConfig.APPID);
url_map.put("secret", WeixinConfig.APPSECRET);
url_map.put("code", this.code);
url_map.put("grant_type", "authorization_code");
String bizString = formatBizQueryParaMap(url_map);
return "https://api.weixin.qq.com/sns/oauth2/access_token?"+bizString;
}
/**
* 作用:生成可以获得code的url
*/
public String createOauthUrlForCode(String redirectUrl){
SortedMap<String,Object> url_map = new TreeMap<String,Object>();
url_map.put("redirect_uri", redirectUrl);
url_map.put("appid", WeixinConfig.APPID);
url_map.put("scope", "snsapi_base");
url_map.put("response_type", "code");
//url_map.put("scope", "snsapi_userinfo");
url_map.put("state", "STATE"+"#wechat_redirect");
String biz_string = formatBizQueryParaMap(url_map);
String code = "https://open.weixin.qq.com/connect/oauth2/authorize?"+biz_string;
logger("request code is :"+code);
return code;
}
/**
* 作用:格式化参数,签名过程需要使用
* 将参数按照ASCII字母顺序升序排序
*/
private String formatBizQueryParaMap(SortedMap<String,Object> url_map){
StringBuilder builder = new StringBuilder();
String str = "";
for(Map.Entry<String, Object> entry : url_map.entrySet()){
builder.append("&"+entry.getKey()+"="+entry.getValue());
}
if(builder.length() > 0){
str = builder.toString().substring(1);
}
return str;
}
/**
* 获取预支付prepayId
* @return
*/
public String getPrepayId(SortedMap<String,Object> sorted_map)
{
String response = postXml(sorted_map);
Map<String,Object> result = xmlToArray(response);
String prepay_id = String.valueOf(result.get("prepay_id"));
return prepay_id;
}
/**
* 作用:将xml转为array
*/
public Map<String,Object> xmlToArray(String xml)
{
Map<String,Object> map_value = new HashMap<String,Object>();
Document document;
try {
document = DocumentHelper.parseText(xml);
Element root_element = document.getRootElement();
List<Element> child_element = root_element.elements();
for(Element ele : child_element){
map_value.put(ele.getName(), ele.getText());
}
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return map_value;
}
/**
* 作用:post请求xml 调用统一下单接口
*/
private String postXml(SortedMap<String,Object> sorted_map)
{
String xml = createXml(sorted_map);
return httpPostRequest(xml,WeixinConfig.UNIFIED_ORDER);
}
/**
* 作用:设置标配的请求参数,生成签名,生成接口参数xml
*/
private String createXml(SortedMap<String,Object> sorted_map)
{
//$this->parameters["sign"] = $this->getSign($this->parameters);//签名
sorted_map.put("appid", WeixinConfig.APPID);
sorted_map.put("mch_id", WeixinConfig.MCHID);
sorted_map.put("nonce_str", createNoncestr());
sorted_map.put("sign", getSign(sorted_map));
String xml = arrayToXml(sorted_map);
logger("create prepay request parameters is :"+xml);
return xml;
}
/**
* 作用:产生随机字符串,不长于32位
*/
public String createNoncestr()
{
String chars = "abcdefghijklmnopqrstuvwxyz0123456789";
String str ="";
int current_str_length = 0;
Random random = new Random();
for ( int i = 0; i < 32; i++ ) {
current_str_length = random.nextInt(chars.length()-1);
str+= chars.substring(current_str_length,current_str_length+1);
}
return str;
}
/**
* 作用:生成签名
*/
public String getSign(SortedMap<String,Object> value_map)
{
//将值按照key=value的形式格式化为字符串
String str= formatBizQueryParaMap(value_map);
//签名步骤二:在string后加入KEY
str = str+"&key="+WeixinConfig.KEY;
//签名步骤三:MD5加密
str = MD5Utils.encrypt(str);
//签名步骤四:所有字符转为大写
return str.toUpperCase();
}
/**
* 作用:array转xml
*/
private String arrayToXml(SortedMap<String,Object> map_value)
{
String xml = "<xml>";
for(Map.Entry<String, Object> entry : map_value.entrySet()){
if(entry.getValue() instanceof Integer){
xml+="<"+entry.getKey()+">"+entry.getValue()+"</"+entry.getKey()+">";
}else{
xml+="<"+entry.getKey()+"><![CDATA["+entry.getValue()+"]]></"+entry.getKey()+">";
}
}
xml +="</xml>";
return xml;
}
/**
* 作用:设置jsapi的参数
*/
public Object getParameters()
{
SortedMap<String,Object> order_map = new TreeMap<String,Object>();
order_map.put("appId", WeixinConfig.APPID);
order_map.put("timeStamp", System.currentTimeMillis()/1000);
order_map.put("nonceStr", createNoncestr());
order_map.put("package", "prepay_id="+prepay_id);
order_map.put("signType", "MD5");
order_map.put("paySign", getSign(order_map));
ObjectMapper mapper = new ObjectMapper();
String jsonObject = "";
try {
jsonObject = mapper.writeValueAsString(order_map);
} catch (JsonGenerationException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
logger("order pay info is : "+jsonObject);
return jsonObject;
}
public void setCode(String code)
{
this.code = code;
}
public void setPrepay_id(String prepay_id) {
this.prepay_id = prepay_id;
}
}
3,JSP支付页面
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="com.weixin.config.*"%>
<%@ page import="com.weixin.commons.*"%>
<%@ page import="java.net.URLEncoder" %>
<%@ page import="java.util.TreeMap"%>
<%@ page import="java.util.SortedMap"%>
<%
WeixinCommon common = new WeixinCommon();
String parameters = request.getParameter("parameters");
String code = request.getParameter("code");
common.logger("page enter and parameters is :"+parameters +" and code is :"+code);
if(parameters == null || "".equals(parameters)){
return ;
}
String opendid = "";
if(code == null || "".equals(code)){
String parameter_path = "?parameters="+parameters;
common.logger("request code path is : "+parameter_path);
//触发微信返回code码
String url = common.createOauthUrlForCode(WeixinConfig.JS_API_CALL_URL+parameter_path);
response.sendRedirect(url);
return;
}else{
//获取code码,以获取openid
common.setCode(code);
opendid = common.getOpenid();
common.logger("code is exist and get opendid is :"+opendid);
}
//由于在我测试的时候如果传入多个参数会出现参数遗漏的情况,
//所以这里我把所有的参数按照一定的规则以逗号隔开处理,然后统一获取
//如果大家未遇到这种情况可以忽略
String[] param = parameters.split(",");
String out_trade_no = param[0];
String out_trade_name = URLEncoder.encode(param[1],"UTF-8");
String out_trade_fee = param[2];
common.logger("out_trade_no is :"+out_trade_no+" and out_trade_name is:"+out_trade_name+" and out_trade_fee is :"+out_trade_fee);
//=========步骤2:使用统一支付接口,获取prepay_id============
SortedMap<String,Object> order_map = new TreeMap<String,Object>();
order_map.put("openid",opendid);//商品描述
order_map.put("body",out_trade_name);//商品描述
order_map.put("out_trade_no",out_trade_no);//商户订单号
order_map.put("total_fee",out_trade_fee);//总金额
order_map.put("notify_url",WeixinConfig.NOTIFY_URL);//通知地址
order_map.put("trade_type","JSAPI");//交易类型
String prepay_id = common.getPrepayId(order_map);
common.logger("current prepay_id is : "+prepay_id);
common.setPrepay_id(prepay_id);
//=========步骤3:使用jsapi调起支付============
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=0.5, maximum-scale=2.0, user-scalable=yes" />
<style type="text/css">
body{
margin:0px;
padding:0px;
}
.title{
margin-top: 12%;
text-align: center;
font-size: 1.5em;
font-weight: bold;
}
.price{
margin-top: 5%;
text-align: center;
font-size: 3em;
font-weight: bold;
}
.line{
margin-top: 10%;
height:1px;
background-color:#969696;
margin-bottom: 10%;
}
.rec{
float:left;
font-weight: 600;
color: #7c7c7c;
margin-left:2%;
}
.com{
float:right;
font-weight: 600;
margin-right:2%;
}
.clear{
clear:both;
}
.submit{
text-align: center;
}
.submit span{
text-decoration: center;
display:block;
border-radius: 5px;
width:90%;
height:50px;
line-height: 50px;
margin-left:5%;
background-color: #06be04;
color:#fff;
font-weight: bold;
}
</style>
<title>微信安全支付</title>
<script type="text/javascript">
//调用微信JS api 支付
function jsApiCall()
{
WeixinJSBridge.invoke(
'getBrandWCPayRequest',
<%out.println(common.getParameters());%>
,
function(res){
//WeixinJSBridge.log(res.err_msg);
alert(res.err_msg);
if(res.err_msg == "get_brand_wcpay_request:ok"){
window.location.href="call_back.html";
}
}
);
}
function callpay()
{
if (typeof WeixinJSBridge == "undefined"){
if( document.addEventListener ){
document.addEventListener('WeixinJSBridgeReady', jsApiCall, false);
}else if (document.attachEvent){
document.attachEvent('WeixinJSBridgeReady', jsApiCall);
document.attachEvent('onWeixinJSBridgeReady', jsApiCall);
}
}else{
jsApiCall();
}
}
</script>
</head>
<body onload="callpay()">
</body>
</html>
-------------------------------------------------------------------------------------------------------------------
到这里,一个支付的接口就完成了,我这个只是简单的实现支付,里面的异常判断,一些逻辑优化就需要大家自己去优化了。因为微信提供的错误信息比较少,而且必须在微信客户端测试,所以大家在测试的时候最好是每走一步就打印一个日志,这样可以方便查询到底是哪里出错了,如果是走到最后一步出现get_brand_wcpay_request:fail 一般情况就是配置不对,需要仔细的查看每一个配置,或者是在调用支付接口的时候参数值不对。每获取一个微信提供的值成功后,则代表你这步已经成功了,不然微信不会返回正确的信息给你。
demo下载地址:http://download.csdn.net/detail/xuelinmei_happy/8926681
相关文章推荐
- 微信应用签名生成工具
- iOS下微信语音播放之切换听筒和扬声器的方法解决方案
- 微信整合的时候 出现这个“redirect_uri 参数错误”
- Android ActionBar应用实战,高仿微信主界面的设计
- 微信公众号怎么推送消息_微信公众号发送消息
- 微信号和微信公众号有什么区别
- 如何注册一个微信公众号
- 用Go写了一个类似Proxy的小程序,可以用来访问goolge个人使用还是可以的.
- 微信开放平台 公众号第三方平台开发 教程五 代公众号发起网页授权源码
- 微信开放平台 公众号第三方平台开发 教程四 代公众号调用接口的SDK和demo
- 微信开放平台 公众号第三方平台开发 教程三 一键登录授权给第三方平台
- 微信开放平台 公众号第三方平台开发 教程二 创建公众号第三方平台
- 微信开放平台公众号第三方平台开发 教程一 平台介绍
- 使用图灵api创建微信聊天机器人
- 【Android微信开发】微信开发平台安卓版(二)
- 在Hadoop2.2.0上运行Wordcount小程序
- 没有微信api提示浏览器微信分享按钮的位置
- 【Android微信开发】关于开发微信开放平台安卓版(一)
- 【IOS】简单的测试银联和微信支付
- 微信 杂记