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 = (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 = 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 = 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 = "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 = "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 = "${basepath}/member/account/orders"; }else{ alert('支付失败'+res.err_msg); } } ); } </script>
4,相关配置