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

java微信公众号支付案例

2017-01-03 18:19 411 查看
一、基本设置
1、进入微信公众平台->微信支付->开发配置 设置授权目录,这个url精确到支付地址的上一级即可
2、公众号设置->功能设置  设置js接口安全域名,网页授权域名
二、获取网页授权
1、用户同意授权,获取code

            String APPID = "";
String uri="";
String REDIRECT_URI =URLEncoder.encode(uri);;
String code = "code";
String SCOPE = "snsapi_base";

String url = "https://open.weixin.qq.com/connect/oauth2/authorize?" +
"appid=" + APPID +
"&redirect_uri=" +
REDIRECT_URI+
"&response_type="+code+"&scope="+SCOPE+"&state=123#wechat_redirect";
response.sendRedirect(url);

code state 作为参数跳转到了设置的REDIRECT_URI中
2、通过code换取网页授权access_token

        SortedMap<String, String> paramMap1=new TreeMap<String, String>();
paramMap1.put("appid",Global.getResource("tuji.official_accounts.app_id"));
paramMap1.put("secret",Global.getResource("tuji.official_accounts.app_secret") );
paramMap1.put("code",code);
paramMap1.put("grant_type","authorization_code");
Map<String, String> resultMap=WeiXinUtil.getAccessToken(paramMap1);

String openId=resultMap.get("openid"); 
获取到 openid;
三、统一下单 

        SortedMap<String,Object> parmMap=new TreeMap<String, Object>();
        parmMap.put("openid",openId );         Map<String, Object> resultMap=new HashMap<String,Object>();
String urlStr="https://api.mch.weixin.qq.com/pay/unifiedorder";
//参数
parmMap.put("out_trade_no",hOrder.getOrderNumber());

parmMap.put("appid",Global.getResource("tuji.official_accounts.app_id"));

parmMap.put("mch_id",Global.getResource("weixin.mac_id"));//商户号
//parmMap.put("device_info",WeiXinUtil.DEVICE_INFO_WEB );//设备号
parmMap.put("nonce_str",create_nonce_str());//随机字符串
//parmMap.put("sign_type","MD5" );//签名类型,默认为MD5,支持HMAC-SHA256和MD5。

parmMap.put("body",hOrder.getGoodsName());//商品简单描述,这里放的是商品名称

int costPrice=0;
JSONArray jsonArray=new JSONArray();
JSONObject subJson=new JSONObject();
Double d =hOrder.getTotalPrice();
costPrice=HotelUtil.yuan2fen(d);
subJson.put("goods_id",hOrder.getGoodId()+"");
subJson.put("goods_name",hOrder.getGoodsName());
subJson.put("quantity",hOrder.getGoodsNumber().intValue());//商品数量
subJson.put("price",costPrice);

jsonArray.add(subJson);

JSONObject jsonObject=new JSONObject();
//jsonObject.put("cost_price",608800);//cost_price Int 可选 32 订单原价,商户侧一张小票订单可能被分多次支付,订单原价            用于记录整张小票的支付金额。当订单原价与支付金额不相等则被判定为拆单,无法享受优惠
//jsonObject.put("receipt_id","wx123" );//receipt_id String 可选 32 商家小票ID
jsonObject.put("goods_detail", jsonArray);

parmMap.put("detail",jsonObject.toString());//商品详细列表,使用Json格式,传输签名前请务必使用CDATA标签将JSON文本串保            护起来。
//parmMap.put("attach","lalala" );//附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用。

parmMap.put("total_fee",costPrice );//订单总金额,单位为分

//parmMap.put("fee_type","CNY");//符合ISO 4217标准的三位字母代码,默认人民币:CNY
//parmMap.put("goods_tag", );//商品标记,使用代金券或立减优惠功能时需要的参数

parmMap.put("trade_type","JSAPI");//取值如下:JSAPI,NATIVE,APP
//parmMap.put("product_id", );//rade_type=NATIVE时(即扫码支付),此参数必传。此参数为二维码中包含的商品ID,商户自行定义。
//parmMap.put("limit_pay","no_credit" );//上传此参数no_credit--可限制用户不能使用信用卡支付

parmMap.put("notify_url",Global.getResource("weixin.notify_url"));//异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。

String spbill_create_ip =getIp2(request);
parmMap.put("spbill_create_ip",spbill_create_ip );//APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。

//传入的参数
/*parmMap.put("time_start", );//订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。
parmMap.put("time_expire", );//订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。
parmMap.put("out_trade_no", );//商户系统内部订单号,要求32个字符内、且在同一个商户号下唯一。
parmMap.put("openid", );//trade_type=JSAPI时(即公众号支付),此参数必传,此参数为微信用户在商户对应appid下的唯一标识。
*/
//做签名
//String sign=getSign(parmMap);
String sign=WeiXinUtil.createSign(parmMap,Global.getResource("weixin.key"));//做签名的key是商户平台设置的
parmMap.put("sign",sign);//签名

String xmlInfo="";
try {
// xmlInfo=unifiedorderMap2Xml(parmMap);
xmlInfo=XMLUtil.arraySortToXml(parmMap, true);
xmlInfo=new String(xmlInfo.toString().getBytes(), "ISO8859-1");//此处解决body为中文的问题
} catch (Exception e) {
throw new WxPayException("unifiedorderMap2Xml错误");
}

String resultStr="";
try {
resultStr=XmlPostUtil.post(urlStr, xmlInfo);
} catch (Exception e) {
throw new WxPayException("XmlPostUtil.post错误");
}

try {
//resultMap=PayCommonUtil.getMapFromXML(resultStr);
resultMap=XMLUtil.doXMLParse(resultStr);
} catch (Exception e) {
throw new WxPayException("getMapFromXML错误");
}

return resultMap;

下单用到的工具类

/**
* 签名 sortMap。
*/
public static String createSign(SortedMap<String, Object> paramMap,String key) {
List list = new ArrayList(paramMap.keySet());
Object[] ary = list.toArray();
Arrays.sort(ary);
list = Arrays.asList(ary);
String str = "";
for(int i=0;i<list.size();i++){
str+=list.get(i)+"="+paramMap.get(list.get(i)+"")+"&";
}
str+="key="+key;
str = MD5Util.MD5Encode(str, "UTF-8").toUpperCase();

return str;

}

 /**
* SortedMap转成xml
* @param parm
* @param isAddCDATA isAddCDATA true 带<![CDATA[]];false 不带
* @return
*/
public static String arraySortToXml(SortedMap<String, Object> parm, boolean isAddCDATA) {
StringBuffer strbuff = new StringBuffer("<xml>");
if (parm != null && !parm.isEmpty()) {
for (Entry<String, Object> entry : parm.entrySet()) {
strbuff.append("<").append(entry.getKey()).append(">");
if (isAddCDATA) {
strbuff.append("<![CDATA[");
if (StringUtils.isNotEmpty(entry.getValue())) {
strbuff.append(entry.getValue());
}
strbuff.append("]]>");
} else {
if (StringUtils.isNotEmpty(entry.getValue())) {
strbuff.append(entry.getValue());
}
}
strbuff.append("</").append(entry.getKey()).append(">");
}
}
return strbuff.append("</xml>").toString();
}

/**
* 发送xml数据请求到server端
*
* @param url
* xml请求数据地址
* @param xmlString
* 发送的xml数据流
* @return null发送失败,否则返回响应内容
*/
public static String post(String url, String xmlString) {
// 关闭
System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog");
System.setProperty("org.apache.commons.logging.simplelog.showdatetime", "true");
System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.commons.httpclient", "stdout");

// 创建httpclient工具对象
HttpClient client = new HttpClient();
// 创建post请求方法
PostMethod myPost = new PostMethod(url);
// 设置请求超时时间
client.setConnectionTimeout(300 * 1000);
String responseString = null;
try {
// 设置请求头部类型
myPost.setRequestHeader("Content-Type", "text/xml");
myPost.setRequestHeader("charset", "UTF-8");

// 设置请求体,即xml文本内容,注:这里写了两种方式,一种是直接获取xml内容字符串,一种是读取xml文件以流的形式
myPost.setRequestBody(xmlString);
// InputStream
// body=this.getClass().getResourceAsStream(xmlFileName);
// myPost.setRequestBody(body);
// myPost.setRequestEntity(new
// StringRequestEntity(xmlString,"text/xml","utf-8"));
int statusCode = client.executeMethod(myPost);
if (statusCode == HttpStatus.SC_OK) {
BufferedInputStream bis = new BufferedInputStream(myPost.getResponseBodyAsStream());
byte[] bytes = new byte[1024];
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int count = 0;
while ((count = bis.read(bytes)) != -1) {
bos.write(bytes, 0, count);
}
byte[] strByte = bos.toByteArray();
responseString = new String(strByte, 0, strByte.length, "UTF-8");
bos.close();
bis.close();
}
} catch (Exception e) {
e.printStackTrace();
}
myPost.releaseConnection();
return responseString;
}

/**
* 解析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, v);
}

// 关闭流
in.close();

return m;
}

获取到 prepay_id=resultMap.get("prepay_id");
四、调用支付控件

$(".submit")
.bind(
"click",
function() {

var whitch = $(".selected div").html();
if (whitch == "微信支付") {
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() {
var appId = "${appId}";
var timeStamp = "${timeStamp}";
var nonceStr = "${nonceStr}";
var package1 = "${package}";
var signType = "${signType}";
var paySign = "${paySign}";

WeixinJSBridge.invoke('getBrandWCPayRequest', {
"appId" : appId,//公众号名称,由商户传入
"timeStamp" : timeStamp,//时间戳,自1970年以来的秒数
"nonceStr" : nonceStr,//随机串
"package" : package1,
"signType" : signType,//微信签名方式:
"paySign" : paySign
//微信签名
}, function(res) {
if (res.err_msg == "get_brand_wcpay_request:ok") {
window.location.href="${ctx}/api/v1/hotel/paySuccess";
}else if(res.err_msg == "get_brand_wcpay_request:fail"){
alert('支付失败');
}else if(res.err_msg == "get_brand_wcpay_request:cancel"){
alert('支付取消');
}else{
alert(res.err_msg);
}
});
}

五、支付结果通知


/**

* 下单回掉地址

* @return

*/

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

@ResponseBody

public String notifyUrl(HttpServletRequest request,HttpServletResponse response,Model model){

System.out.println("==开始进入h5支付回调方法==");

String xml_review_result = WeiXinUtil.getXmlRequest(request);

System.out.println("微信支付结果:"+xml_review_result);

Map<String, String> resultMap = null;

try {

resultMap = XMLUtil.doXMLParse(xml_review_result);

System.out.println("resultMap:"+resultMap);

if(resultMap != null && resultMap.size() > 0){

String sign_receive = (String)resultMap.get("sign");//返回的签名

System.out.println("sign_receive:"+sign_receive);

resultMap.remove("sign");//删除签名

String checkSign = WeiXinUtil.getSign(resultMap,Global.getResource("weixin.key"));//生成新签名

System.out.println("checkSign:"+checkSign);



//签名校验成功

if(checkSign != null && sign_receive != null &&

checkSign.equals(sign_receive.trim())){

System.out.println("weixin receive check Sign sucess");

try{

//获得返回结果

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


if("SUCCESS".equals(return_code)){//交易成功

String out_trade_no = (String)resultMap.get("out_trade_no");//获取商户的订单号

System.out.println("weixin pay sucess,out_trade_no:"+out_trade_no);

//处理支付成功以后的逻辑,处理订单,相关的商品 减去相应数量


    
String resultXml="<xml><return_code><![CDATA[SUCCESS]]></return_code>"+
        "<return_msg><![CDATA[OK]]></return_msg></xml>";

    return resultXml;


}else{//交易失败

String resultXml="<xml><return_code><![CDATA[FAIL]]></return_code>"+

                "<return_msg><![CDATA[FAIL]]></return_msg></xml>";

return resultXml;

}

}catch(Exception e){

e.printStackTrace();

}

}else{

//签名校验失败

System.out.println("weixin receive check Sign fail");

String checkXml = "<xml><return_code><![CDATA[FAIL]]></return_code>"+

"<return_msg><![CDATA[check sign fail]]></return_msg></xml>";

return checkXml;

}

}

} catch (Exception e) {

e.printStackTrace();

}

return null;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 微信 公众号 支付