- // api支付拼包------------------------------------------------------------------------------
- RequestHandler reqHandler = new RequestHandler(request, response);
- // TenpayHttpClient httpClient = new TenpayHttpClient();
- // TreeMap<String, String> outParams = new TreeMap<String,String>();
- // 初始化
- reqHandler.init();
- reqHandler.init(APP_ID,APP_SECRET, APP_KEY,PARTNER_KEY);
- // 当前时间 yyyyMMddHHmmss
- String currTime = TenpayUtil.getCurrTime();
- // 8位日期
- String strTime = currTime.substring(8, currTime.length());
- // 四位随机数
- String strRandom = TenpayUtil.buildRandom(4) + "";
- // 10位序列号,可以自行调整。
- String strReq = strTime + strRandom;
- // 订单号,此处用时间加随机数生成,商户根据自己情况调整,只要保持全局唯一就行
- String out_trade_no = strReq;
- // 设置package订单参数
- SortedMap<String, String> packageParams = new TreeMap<String, String>();
- packageParams.put("bank_type", "WX"); // 支付类型
- packageParams.put("body", "商品名称"); // 商品描述
- packageParams.put("fee_type", "1"); // 银行币种
- packageParams.put("input_charset", "UTF-8"); // 字符集
- packageParams.put("notify_url", "通知地址,接收交易结果,并进行业务处理,例如:http://abc.com/buy/buy.do"); // 通知地址
- packageParams.put("out_trade_no", out_trade_no); // 商户订单号
- packageParams.put("partner", PARTNER_ID); // 设置商户号
- packageParams.put("total_fee", "交易金额"); // 商品总金额,以分为单位
- packageParams.put("spbill_create_ip", request.getRemoteAddr()); // 订单生成的机器IP,指用户浏览器端IP
- // 获取package包
- String packageValue = reqHandler.genPackage(packageParams);
- String noncestr = Sha1Util.getNonceStr();
- String timestamp = Sha1Util.getTimeStamp();
- // 设置支付参数
- SortedMap<String, String> signParams = new TreeMap<String, String>();
- signParams.put("appid", appid);
- signParams.put("noncestr", noncestr);
- signParams.put("package", packageValue);
- signParams.put("timestamp", timestamp);
- signParams.put("appkey", appkey);
- // 生成支付签名,要采用URLENCODER的原始值进行SHA1算法!
- String sign = Sha1Util.createSHA1Sign(signParams);
- // 增加非参与签名的额外参数
- signParams.put("paySign", sign);
- signParams.put("signType", "SHA1");
- // ------------------------------------微信js
- // api支付拼包结束------------------------------------
- // --------------------------------本地系统生成订单-------------------------------------
- //
- // --------------------------------生成完成---------------------------------------------
- request.setAttribute("appid", appid);
- request.setAttribute("timestamp", timestamp);
- request.setAttribute("noncestr", noncestr);
- request.setAttribute("package", packageValue);
- request.setAttribute("paysign", sign);
- request.setAttribute("czje", czje);
英文全大写带下划线的,各位申请微信支付的时候都会给你的。
注意:微信demo里面RequestHandler 在设置商户key和appkey有点问题,ResponseHandler连postData都没获取到,下面把我修正后的贴出来做参考(注:其它java类没什么问题)
RequestHandler:
- package com.zk.common.wxpay;
- import java.io.UnsupportedEncodingException;
- import java.net.URLEncoder;
- import java.util.Iterator;
- import java.util.Map;
- import java.util.Set;
- import java.util.SortedMap;
- import java.util.TreeMap;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import com.zk.common.wxpay.util.MD5Util;
- import com.zk.common.wxpay.util.TenpayUtil;
- /*
- '微信支付服务器签名支付请求请求类
- '============================================================================
- 'api说明:
- 'init(app_id, app_secret, partner_key, app_key);
- '初始化函数,默认给一些参数赋值,如cmdno,date等。
- 'setKey(key_)'设置商户密钥
- 'getLasterrCode(),获取最后错误号
- 'GetToken();获取Token
- 'getTokenReal();Token过期后实时获取Token
- 'createMd5Sign(signParams);生成Md5签名
- 'genPackage(packageParams);获取package包
- 'createSHA1Sign(signParams);创建签名SHA1
- 'sendPrepay(packageParams);提交预支付
- 'getDebugInfo(),获取debug信息
- '============================================================================
- '*/
- public class RequestHandler {
- /** Token获取网关地址地址 */
- private String tokenUrl;
- /** 预支付网关url地址 */
- private String gateUrl;
- /** 查询支付通知网关URL */
- private String notifyUrl;
- /** 商户参数 */
- private String appid;
- private String appkey;
- private String partnerkey;
- private String appsecret;
- private String key;
- /** 请求的参数 */
- private SortedMap parameters;
- /** Token */
- private String Token;
- private String charset;
- /** debug信息 */
- private String debugInfo;
- private String last_errcode;
- private HttpServletRequest request;
- private HttpServletResponse response;
- /**
- * 初始构造函数。
- *
- * @return
- */
- public RequestHandler(HttpServletRequest request,
- HttpServletResponse response) {
- this.last_errcode = "0";
- this.request = request;
- this.response = response;
- this.charset = "GBK";
- this.parameters = new TreeMap();
- // 验证notify支付订单网关
- notifyUrl = "https://gw.tenpay.com/gateway/simpleverifynotifyid.xml";
- }
- /**
- * 初始化函数。
- */
- public void init(String app_id, String app_secret, String app_key,
- String partner_key) {
- this.last_errcode = "0";
- this.Token = "token_";
- this.debugInfo = "";
- this.appkey = app_key;
- this.appid = app_id;
- this.partnerkey = partner_key;
- this.key = partner_key;//原demo没有,手动加上
- this.appsecret = app_secret;
- }
- public void init() {
- }
- /**
- * 获取最后错误号
- */
- public String getLasterrCode() {
- return last_errcode;
- }
- /**
- *获取入口地址,不包含参数值
- */
- public String getGateUrl() {
- return gateUrl;
- }
- /**
- * 获取参数值
- *
- * @param parameter
- * 参数名称
- * @return String
- */
- public String getParameter(String parameter) {
- String s = (String) this.parameters.get(parameter);
- return (null == s) ? "" : s;
- }
- //设置密钥
- public void setKey(String key) {
- this.partnerkey = key;
- }
- //设置微信密钥
- public void setAppKey(String key){
- this.appkey = key;
- }
- // 特殊字符处理
- public String UrlEncode(String src) throws UnsupportedEncodingException {
- return URLEncoder.encode(src, this.charset).replace("+", "%20");
- }
- // 获取package的签名包
- public String genPackage(SortedMap<String, String> packageParams)
- throws UnsupportedEncodingException {
- String sign = createSign(packageParams);
- 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();
- sb.append(k + "=" + UrlEncode(v) + "&");
- }
- // 去掉最后一个&
- String packageValue = sb.append("sign=" + sign).toString();
- System.out.println("packageValue=" + packageValue);
- return packageValue;
- }
- /**
- * 创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
- */
- public String createSign(SortedMap<String, String> packageParams) {
- 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 (null != v && !"".equals(v) && !"sign".equals(k)
- && !"key".equals(k)) {
- sb.append(k + "=" + v + "&");
- }
- }
- sb.append("key=" + this.getKey());
- System.out.println("md5 sb:" + sb);
- String sign = MD5Util.MD5Encode(sb.toString(), this.charset)
- .toUpperCase();
- return sign;
- }
- /**
- * 创建package签名
- */
- public boolean createMd5Sign(String signParams) {
- StringBuffer sb = new StringBuffer();
- Set es = this.parameters.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 + "&");
- }
- }
- // 算出摘要
- String enc = TenpayUtil.getCharacterEncoding(this.request,
- this.response);
- String sign = MD5Util.MD5Encode(sb.toString(), enc).toLowerCase();
- String tenpaySign = this.getParameter("sign").toLowerCase();
- // debug信息
- this.setDebugInfo(sb.toString() + " => sign:" + sign + " tenpaySign:"
- + tenpaySign);
- return tenpaySign.equals(sign);
- }
- //输出XML
- public String parseXML() {
- StringBuffer sb = new StringBuffer();
- sb.append("<xml>");
- Set es = this.parameters.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(null != v && !"".equals(v) && !"appkey".equals(k)) {
- sb.append("<" + k +">" + getParameter(k) + "</" + k + ">\n");
- }
- }
- sb.append("</xml>");
- return sb.toString();
- }
- /**
- * 设置debug信息
- */
- protected void setDebugInfo(String debugInfo) {
- this.debugInfo = debugInfo;
- }
- public void setPartnerkey(String partnerkey) {
- this.partnerkey = partnerkey;
- }
- public String getDebugInfo() {
- return debugInfo;
- }
- public String getKey() {
- return key;
- }
- }
ResponseHandler:
- package com.zk.common.wxpay;
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.io.PrintWriter;
- import java.io.Reader;
- import java.io.UnsupportedEncodingException;
- import java.util.ArrayList;
- import java.util.Iterator;
- import java.util.Map;
- import java.util.Set;
- import java.util.SortedMap;
- import java.util.TreeMap;
- import com.zk.common.Parameters;
- import com.zk.common.wxpay.util.Sha1Util;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import org.dom4j.Document;
- import org.dom4j.DocumentHelper;
- import org.dom4j.Element;
- import org.jdom.JDOMException;
- import com.sun.org.apache.xalan.internal.xsltc.runtime.Hashtable;
- import com.zk.common.wxpay.util.MD5Util;
- import com.zk.common.wxpay.util.TenpayUtil;
- import com.zk.common.wxpay.util.XMLUtil;
- /**
- * 微信支付服务器签名支付请求应答类 api说明: getKey()/setKey(),获取/设置密钥
- * getParameter()/setParameter(),获取/设置参数值 getAllParameters(),获取所有参数
- * isTenpaySign(),是否财付通签名,true:是 false:否 getDebugInfo(),获取debug信息
- */
- public class ResponseHandler {
- private static final String appkey = APP_KEY;
- /** 密钥 */
- private String key;
- /** 应答的参数 */
- private SortedMap parameters;
- /** debug信息 */
- private String debugInfo;
- private HttpServletRequest request;
- private HttpServletResponse response;
- private String uriEncoding;
- private Hashtable xmlMap;
- private SortedMap smap;
- public SortedMap getSmap() {
- return smap;
- }
- private String k;
- /**
- * 构造函数
- *
- * @param request
- * @param response
- */
- public ResponseHandler(HttpServletRequest request,
- HttpServletResponse response) {
- this.request = request;
- this.response = response;
- this.smap = new TreeMap<String, String>();
- this.key = "";
- this.parameters = new TreeMap();
- this.debugInfo = "";
- this.uriEncoding = "";
- Map m = this.request.getParameterMap();
- Iterator it = m.keySet().iterator();
- while (it.hasNext()) {
- String k = (String) it.next();
- String v = ((String[]) m.get(k))[0];
- this.setParameter(k, v);
- }
- BufferedReader reader =null;
- try{
- reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
- StringBuilder sb = new StringBuilder();
- String line = null;
- while ((line = reader.readLine()) != null) {
- sb.append(line);
- }
- Document doc = DocumentHelper.parseText(sb.toString());
- Element root = doc.getRootElement();
- for (Iterator iterator = root.elementIterator(); iterator.hasNext();) {
- Element e = (Element) iterator.next();
- smap.put(e.getName(), e.getText());
- }
- }catch (Exception e) {
- // TODO: handle exception
- e.printStackTrace();
- }
- }
- /**
- * 获取密钥
- */
- public String getKey() {
- return key;
- }
- /**
- * 设置密钥
- */
- public void setKey(String key) {
- this.key = key;
- }
- /**
- * 获取参数值
- *
- * @param parameter
- * 参数名称
- * @return String
- */
- public String getParameter(String parameter) {
- String s = (String) this.parameters.get(parameter);
- return (null == s) ? "" : s;
- }
- /**
- * 设置参数值
- *
- * @param parameter
- * 参数名称
- * @param parameterValue
- * 参数值
- */
- public void setParameter(String parameter, String parameterValue) {
- String v = "";
- if (null != parameterValue) {
- v = parameterValue.trim();
- }
- this.parameters.put(parameter, v);
- }
- /**
- * 返回所有的参数
- *
- * @return SortedMap
- */
- public SortedMap getAllParameters() {
- return this.parameters;
- }
- public void doParse(String xmlContent) throws JDOMException, IOException {
- this.parameters.clear();
- // 解析xml,得到map
- Map m = XMLUtil.doXMLParse(xmlContent);
- // 设置参数
- Iterator it = m.keySet().iterator();
- while (it.hasNext()) {
- String k = (String) it.next();
- String v = (String) m.get(k);
- this.setParameter(k, v);
- }
- }
- /**
- * 是否财付通签名,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
- *
- * @return boolean
- */
- public boolean isValidSign() {
- StringBuffer sb = new StringBuffer();
- Set es = this.parameters.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=" + this.getKey());
- // 算出摘要
- String enc = TenpayUtil.getCharacterEncoding(this.request,
- this.response);
- String sign = MD5Util.MD5Encode(sb.toString(), enc).toLowerCase();
- String ValidSign = this.getParameter("sign").toLowerCase();
- // debug信息
- this.setDebugInfo(sb.toString() + " => sign:" + sign + " ValidSign:"
- + ValidSign);
- System.out.println("财付通签名:"+this.getDebugInfo());
- return ValidSign.equals(sign);
- }
- /**
- * 判断微信签名
- */
- public boolean isWXsign() {
- StringBuffer sb = new StringBuffer();
- String keys = "";
- SortedMap<String, String> signParams = new TreeMap<String, String>();
- Set es = this.smap.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 (k != "SignMethod" && k != "AppSignature") {
- signParams.put(k.toLowerCase(), v);
- }
- }
- signParams.put("appkey", this.appkey);
- Set set = signParams.entrySet();
- Iterator pit = set.iterator();
- while (pit.hasNext()) {
- Map.Entry entry = (Map.Entry) pit.next();
- String k = (String) entry.getKey();
- String v = (String) entry.getValue();
- if (sb.length() == 0) {
- sb.append(k + "=" + v);
- } else {
- sb.append("&" + k + "=" + v);
- }
- }
- String sign = Sha1Util.getSha1(sb.toString()).toString().toLowerCase();
- this.setDebugInfo(sb.toString() + " => SHA1 sign:" + sign);
- return sign.equals(this.smap.get("AppSignature"));
- }
- // 判断微信维权签名
- public boolean isWXsignfeedback() {
- StringBuffer sb = new StringBuffer();
- Hashtable signMap = new Hashtable();
- Set es = this.parameters.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 (k != "SignMethod" && k != "AppSignature") {
- sb.append(k + "=" + v + "&");
- }
- }
- signMap.put("appkey", this.appkey);
- // ArrayList akeys = new ArrayList();
- // akeys.Sort();
- while (it.hasNext()) {
- String v = k;
- if (sb.length() == 0) {
- sb.append(k + "=" + v);
- } else {
- sb.append("&" + k + "=" + v);
- }
- }
- String sign = Sha1Util.getSha1(sb.toString()).toString().toLowerCase();
- this.setDebugInfo(sb.toString() + " => SHA1 sign:" + sign);
- return sign.equals(this.smap.get("AppSignature"));
- }
- /**
- * 返回处理结果给财付通服务器。
- *
- * @param msg
- * Success or fail
- * @throws IOException
- */
- public void sendToCFT(String msg) throws IOException {
- String strHtml = msg;
- PrintWriter out = this.getHttpServletResponse().getWriter();
- out.println(strHtml);
- out.flush();
- out.close();
- }
- /**
- * 获取uri编码
- *
- * @return String
- */
- public String getUriEncoding() {
- return uriEncoding;
- }
- /**
- * 设置uri编码
- *
- * @param uriEncoding
- * @throws UnsupportedEncodingException
- */
- public void setUriEncoding(String uriEncoding)
- throws UnsupportedEncodingException {
- if (!"".equals(uriEncoding.trim())) {
- this.uriEncoding = uriEncoding;
- // 编码转换
- String enc = TenpayUtil.getCharacterEncoding(request, response);
- Iterator it = this.parameters.keySet().iterator();
- while (it.hasNext()) {
- String k = (String) it.next();
- String v = this.getParameter(k);
- v = new String(v.getBytes(uriEncoding.trim()), enc);
- this.setParameter(k, v);
- }
- }
- }
- /**
- * 获取debug信息
- */
- public String getDebugInfo() {
- return debugInfo;
- }
- /**
- * 设置debug信息
- */
- protected void setDebugInfo(String debugInfo) {
- this.debugInfo = debugInfo;
- }
- protected HttpServletRequest getHttpServletRequest() {
- return this.request;
- }
- protected HttpServletResponse getHttpServletResponse() {
- return this.response;
- }
- }
2.Jsapi调用
在第一步中已拼好包放入request中了,第二部js调用微信api,看代码:
- <script type="text/javascript">
- function callpay(){
- WeixinJSBridge.invoke('getBrandWCPayRequest',{
- "appId" : "${appid}","timeStamp" : "${timestamp}", "nonceStr" : "${noncestr}", "package" : "${package}","signType" : "SHA1", "paySign" : "${paysign}"
- },function(res){
- WeixinJSBridge.log(res.err_msg);
- if(res.err_msg == "get_brand_wcpay_request:ok"){
- alert("微信支付成功");
- }else if(res.err_msg == "get_brand_wcpay_request:cancel"){
- alert("用户取消支付");
- }else{
- alert("支付失败");
- }
- });
- }
- </script>
点击支付按钮,调用callpay 即可。
3.微信支付后的通知接口
支付成功了,微信根据你提供的notify_url,来通知你支付成功与否,虽然js里知道了结果,但这里需要正式通知,并处理业务,下面是我的代码片段:
- System.out.println("-----------------微信支付来消息啦--------------------------");
- ResponseHandler resHandler = new ResponseHandler(request,response);
- resHandler.setKey(PARTNER_KEY);
- if (resHandler.isValidSign() == true) {
- if (resHandler.isWXsign() == true) {
- // 商户订单号
- String out_trade_no = resHandler
- .getParameter("out_trade_no");
- // 财付通订单号
- String transaction_id = resHandler
- .getParameter("transaction_id");
- // 金额,以分为单位
- String total_fee = resHandler.getParameter("total_fee");
- // 如果有使用折扣券,discount有值,total_fee+discount=原请求的total_fee
- String discount = resHandler.getParameter("discount");
- // 支付结果
- String trade_state = resHandler
- .getParameter("trade_state");
- System.out.println("支付的订单号:" + out_trade_no);
- // 判断签名及结果
- if ("0".equals(trade_state)) {
- System.out.println("哈哈,微信支付成功了");
- // ------------------------------
- // 即时到账处理业务开始
- // ------------------------------
- // 处理数据库逻辑
- // 注意交易单不要重复处理
- // 注意判断返回金额
- // ------------------------------
- // 即时到账处理业务完毕
- // ------------------------------
- System.out.println("success 后台通知成功");
- // 给财付通系统发送成功信息,财付通系统收到此结果后不再进行后续通知
- resHandler.sendToCFT("success");
- } else {// sha1签名失败
- System.out.println("fail -SHA1 failed");
- resHandler.sendToCFT("fail");
- }
- } else {// MD5签名失败
- System.out.println("fail -Md5 failed");
- }
- }