首页 > 代码库 > 微信公众号支付H5-java版代码

微信公众号支付H5-java版代码

1,工具类

 

package net.jeeshop.core.util;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;

import java.io.*;
import java.math.BigDecimal;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;

/**
*/
public class PayCommonUtil {
//微信参数配置
public static String API_KEY = "xxxxxxxxxxxxxx";
// APPID
public static String APPID = "wx323323333333";
// 商户ID
public static String MCH_ID = "123232323";

/**
* 发起支付
*
* @param orderId 订单ID
* @param amount 钱(元)
* @param body 订单说明
* @param openId 会员openID
* @param ip 会员IP
* @param url 回调URl
* @return
*/
public static SortedMap<String, String> pay(String orderId, BigDecimal amount, String body, String openId, String ip, String url) {
String error = "";
String prepayId = getPrepayId(orderId, amount, body, openId, url, ip);

SortedMap<String, String> map = new TreeMap<String, String>();
map.put("appId", PayCommonUtil.APPID);
map.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
map.put("nonceStr", PayCommonUtil.getRandomString(32));

if (prepayId == null) {
error = "验签失败!";
map.put("error", error);
}

map.put("package", "prepay_id=" + prepayId);
map.put("signType", "MD5");
String sign = PayCommonUtil.createSign("UTF-8", map);
map.put("paySign", sign);
return map;
}

/**
* 返回微信预支付prepay_id
*
* @param orderId 订单ID
* @param amount 钱(元)
* @param body 订单说明
* @param openid 会员openID
* @param notify_url 回调URl
* @param ip 会员IP
* @return
*/
public static String getPrepayId(String orderId, BigDecimal amount, String body, String openid, String notify_url, String ip) {
SortedMap<String, String> para = new TreeMap<String, String>();
para.put("appid", PayCommonUtil.APPID);
para.put("mch_id", PayCommonUtil.MCH_ID);
para.put("nonce_str", PayCommonUtil.getRandomString(32));
para.put("body", body);
para.put("out_trade_no", orderId);
para.put("fee_type", "CNY");

BigDecimal total = amount.multiply(new BigDecimal(100));
java.text.DecimalFormat df = new java.text.DecimalFormat("0");

para.put("total_fee", df.format(total));
para.put("spbill_create_ip", ip);
para.put("notify_url", notify_url);
para.put("trade_type", "JSAPI");
para.put("openid", openid);
String sign = createSign("UTF-8", para);
para.put("sign", sign);
String requestXML = PayCommonUtil.getRequestXml(para);
String result = PayCommonUtil.httpsRequest("https://api.mch.weixin.qq.com/pay/unifiedorder", "POST", requestXML);
Map<String, String> map = null;
try {
map = PayCommonUtil.doXMLParse(result);

// 返回信息
if ("SUCCESS".equals(map.get("return_code")) && "SUCCESS".equals(map.get("result_code"))) {
return map.get("prepay_id");
} else {
return null;
}
} catch (JDOMException e) {
return null;
} catch (IOException e) {
return null;
}
}

//随机字符串生成
private static String getRandomString(int length) {
String base = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
Random random = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < length; i++) {
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
return sb.toString();
}

//请求xml组装
private static String getRequestXml(SortedMap<String, String> parameters) {
StringBuffer sb = new StringBuffer();
sb.append("<xml>");
Set es = parameters.entrySet();
Iterator it = es.iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String key = (String) entry.getKey();
String value = http://www.mamicode.com/(String) entry.getValue();
if ("attach".equalsIgnoreCase(key) || "body".equalsIgnoreCase(key) || "sign".equalsIgnoreCase(key)) {
sb.append("<" + key + ">" + "<![CDATA[" + value + "]]></" + key + ">");
} else {
sb.append("<" + key + ">" + value + "</" + key + ">");
}
}
sb.append("</xml>");
return sb.toString();
}

// 生成签名
private static String createSign(String characterEncoding, SortedMap<String, String> parameters) {
StringBuffer sb = new StringBuffer();
Set es = parameters.entrySet();
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=" + API_KEY);
String sign = MD5.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
return sign;
}

/**
* 验证回调签名
*/
public static boolean isTenpaySign(Map<String, String> map) {
String charset = "utf-8";
String signFromAPIResponse = map.get("sign");
// API返回的数据签名数据不存在,有可能被第三方篡改!!!
if (signFromAPIResponse == null || signFromAPIResponse.equals("")) {
return false;
}

//过滤空 设置 TreeMap
SortedMap<String, String> packageParams = new TreeMap<String, String>();
for (String parameter : map.keySet()) {
String parameterValue = http://www.mamicode.com/map.get(parameter);
String v = "";
if (null != parameterValue) {
v = parameterValue.trim();
}
packageParams.put(parameter, v);
}

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 (!"sign".equals(k) && null != v && !"".equals(v)) {
sb.append(k + "=" + v + "&");
}
}
sb.append("key=" + API_KEY);
//算出签名
String resultSign = "";
String tobesign = sb.toString();
if (null == charset || "".equals(charset)) {
resultSign = MD5.MD5Encode(tobesign, charset).toUpperCase();
} else {
resultSign = MD5.MD5Encode(tobesign, charset).toUpperCase();
}
String tenpaySign = ((String) packageParams.get("sign")).toUpperCase();
return tenpaySign.equals(resultSign);
}

// 请求方法
private static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {
try {

URL url = new URL(requestUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();

conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
// 设置请求方式(GET/POST)
conn.setRequestMethod(requestMethod);
conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
// 当outputStr不为null时向输出流写数据
if (null != outputStr) {
OutputStream outputStream = conn.getOutputStream();
// 注意编码格式
outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();
}
// 从输入流读取返回内容
InputStream inputStream = conn.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;
conn.disconnect();
return buffer.toString();
} catch (ConnectException ce) {
} catch (Exception e) {
}
return null;
}

//xml解析
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 = getChildrenText(children);
}

m.put(k, v);
}

//关闭流
in.close();

return m;
}

/**
* 循环查找子节点
*
* @param children
* @return
*/
private 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 = http://www.mamicode.com/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();
}
}

 

 

2,action

 

package net.jeeshop.web.action.member.pay;

import com.alibaba.fastjson.JSON;
import net.jeeshop.core.AllinpayMain.StringUtils;
import net.jeeshop.core.front.SystemManager;
import net.jeeshop.core.util.PayCommonUtil;
import net.jeeshop.services.front.account.bean.Account;
import net.jeeshop.services.front.order.OrderService;
import net.jeeshop.services.front.order.bean.Order;
import net.jeeshop.services.front.orderpay.OrderpayService;
import net.jeeshop.services.front.orderpay.bean.Orderpay;
import net.jeeshop.web.util.LoginUserHolder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

/**
* Created by Administrator on 2017-02-24.
*/
@Controller("WeiXinPayAction")
@RequestMapping("/member/webchatPay")
public class WeiXinPayAction {

@Autowired
private OrderService orderService;
@Autowired
private OrderpayService orderpayService;

public static String wxnotify = "/api/json/money/wxpay/succ";

@RequestMapping(value = "http://www.mamicode.com/pay")
@ResponseBody
public String pay(HttpServletRequest request) throws Exception {
HashMap<String, Object> map = new HashMap<String, Object>();
Account acc = LoginUserHolder.getLoginAccount();
if (LoginUserHolder.getLoginAccount() == null) {
map.put("error","用户未登陆");
return JSON.toJSONString(map);
}

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

// 没有订单ID
if(StringUtils.isEmpty(orderId)){
map.put("error","没有订单ID");
return JSON.toJSONString(map);
}

Order order = orderService.selectById(orderId);
if (order == null) {
map.put("error","根据订单号查询不到订单信息!");
return JSON.toJSONString(map);
}

// 订单状态不是未支付
if(Order.order_paystatus_y.equals(order.getPaystatus())){
map.put("error","订单已经支付!");
return JSON.toJSONString(map);
}

SortedMap<String, String> retMap = new TreeMap<String, String>();
retMap = PayCommonUtil.pay(orderId, new BigDecimal(order.getPtotal()), order.getRemark(), acc.getOpenId(), request.getRemoteAddr(), SystemManager.getInstance().getSystemSetting().getWww() + "member/webchatPay/success");

if(!StringUtils.isEmpty(retMap.get("error"))){
map.put("error",retMap.get("error"));
return JSON.toJSONString(map);
}

return JSON.toJSONString(retMap);
}

@RequestMapping(value = "http://www.mamicode.com/success")
@ResponseBody
public String success(HttpServletRequest request) throws Exception {
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);
}
String resultXml = new String(outSteam.toByteArray(), "utf-8");
Map<String, String> params = PayCommonUtil.doXMLParse(resultXml);
outSteam.close();
inStream.close();
if (PayCommonUtil.isTenpaySign(params) && "SUCCESS".equals(params.get("return_code")) && "SUCCESS".equals(params.get("result_code"))) {
String orderId = params.get("out_trade_no");
Orderpay orderpay = new Orderpay();
orderpay.setOrderid(orderId);
orderpay.setPaystatus(Orderpay.orderpay_paystatus_n);
orderpay = orderpayService.selectOne(orderpay);

// 获取订单ID
Order order = orderService.selectById(orderId);
if (order == null) {
return "success";
}

// 订单状态不是未支付
if(Order.order_paystatus_y.equals(order.getPaystatus())){
return "success";
}

// 更新订单状态
orderService.orderStatus("WAIT_SELLER_SEND_GOODS",orderpay,order);
return "success";
} else {
// 支付失败
return "fail";
}
}
}


3,页面JS
<script>
$(function () {
$("#btnPay").click(function () {
if (confirm("确认支付?")) {
onBridgeReady();
}
return false;
});
})

function onBridgeReady(){
if (typeof(WeixinJSBridge) == "undefined"){
if( document.addEventListener ){
document.addEventListener(‘WeixinJSBridgeReady‘, onBridgeReady, false);
}else if (document.attachEvent){
document.attachEvent(‘WeixinJSBridgeReady‘, onBridgeReady);
document.attachEvent(‘onWeixinJSBridgeReady‘, onBridgeReady);
}
}

$.ajax({
dataType: "json",
url: "${basepath}/member/webchatPay/pay",
type: "POST",
data: {orderId: "${payInfo.WIDout_trade_no!""}"},
success: function (data) {
if (data.error != null && data.error != "") {
alert(data.error);
return;
}
else {
alert("appId:" + data.appId + ",timeStamp:" + data.timeStamp + ",nonceStr:" + data.nonceStr + ",package:" + data.package + "signType:" + data.signType + ",paySign:" + data.paySign);
// 微信支付
wxPay(data.appId ,data.timeStamp ,data.nonceStr ,data.package ,data.signType ,data.paySign);
}
},
error: function (data) {
alert("支付启动错误");
}
});
}

// 微信支付
function wxPay(appId,timeStamp,nonceStr,package,signType,paySign){
WeixinJSBridge.invoke(
‘getBrandWCPayRequest‘, {
"appId":appId, //公众号名称,由商户传入
"timeStamp":timeStamp, //时间戳,自1970年以来的秒数
"nonceStr":nonceStr, //随机串
"package":package,
"signType":signType, //微信签名方式:
"paySign":paySign //微信签名
},
function(res){
if(res.err_msg == "get_brand_wcpay_request:ok" ) {
window.location.href = "http://www.mamicode.com/${basepath}/member/account/orders";
}else{
alert(‘支付失败‘+res.err_msg);
}
}
);
}
</script>
4,相关配置

  1,微信支付->公众号支付->支付安全目录(注意:如果是ajax调用的话写的是调用的前的页面地址)

  2,公众号设置->功能设置->JS接口安全域名

 

  3,公众号设置->功能设置->网页授权域名

 

微信公众号支付H5-java版代码