java微信公众号支付示例详解
程序员文章站
2022-07-08 18:06:59
本文实例为大家分享了java微信公众号支付示例代码,供大家参考,具体内容如下开始之前,先准备好:appid、商家号、商户密匙。工具类:md5util.javapackage com.yiexpress...
本文实例为大家分享了java微信公众号支付示例代码,供大家参考,具体内容如下
开始之前,先准备好:appid、商家号、商户密匙。
工具类:
md5util.java
package com.yiexpress.core.utils.wechat; import java.security.messagedigest; /** * md5工具类 */ public class md5util { public final static string md5(string s) { char hexdigits[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; try { byte[] btinput = s.getbytes(); messagedigest mdinst = messagedigest.getinstance("md5"); mdinst.update(btinput); byte[] md = mdinst.digest(); int j = md.length; char str[] = new char[j * 2]; int k = 0; for (int i = 0; i < j; i++) { byte byte0 = md[i]; str[k++] = hexdigits[byte0 >>> 4 & 0xf]; str[k++] = hexdigits[byte0 & 0xf]; } string md5str = new string(str); return md5str; } catch (exception e) { e.printstacktrace(); return null; } } }
saputils.java
package com.yiexpress.core.utils; import java.lang.reflect.*; import java.util.list; import java.io.ioexception; import java.io.stringwriter; import org.dom4j.document; import org.dom4j.documenthelper; import org.dom4j.element; import org.dom4j.io.outputformat; import org.dom4j.io.xmlwriter; import org.slf4j.logger; import org.slf4j.loggerfactory; import org.springframework.util.stringutils; public class saputils { private static final logger logger = loggerfactory.getlogger(saputils.class); /** 根据反射对javabean转成xml文件的格式 * 以类名为第一标签,所有属性作为第二节点,并放入对应的值,如果属性为空 就不放入该熟悉 * @param dto 传入的对象 * @param operationname 操作名称 * @return */ public static string formattoxml(object dto,string operationname){ logger.info("解析当前类{}为指定的xml文档格式的数据",dto.getclass().getname()); logger.info("当前的同步方法是,{}",operationname); string result = null; field fields[]=dto.getclass().getdeclaredfields();//dto 是实体类名称 //documenthelper提供了创建document对象的方法 document document = documenthelper.createdocument(); //添加节点信息 string classname=dto.getclass().getname(); // 操作的名称 element rootelement = document.addelement(operationname); try { field.setaccessible(fields, true); for (int i = 0; i < fields.length; i++) { //添加节点信息 if(!stringutils.isempty(fields[i].get(dto))){ class<?> type = fields[i].gettype(); // 如果是list if(type == list.class){ string listname = fields[i].getname(); createelement(rootelement, fields[i].get(dto),listname); } else{ element element = rootelement.addelement(fields[i].getname()); element.settext((string) fields[i].get(dto)); } } } // 设置xml文档格式 outputformat outputformat = outputformat.createprettyprint(); // 设置xml编码方式,即是用指定的编码方式保存xml文档到字符串(string),这里也可以指定为gbk或是iso8859-1 outputformat.setencoding("utf-8"); // outputformat.setsuppressdeclaration(true); //是否生产xml头 outputformat.setindent(true); //设置是否缩进 outputformat.setindent(" "); //以四个空格方式实现缩进 outputformat.setnewlines(true); //设置是否换行 stringwriter stringwriter =null; // writer filewriter =null; // xmlwriter是用来把xml文档写入字符串的(工具) xmlwriter xmlwriter = null; try { // stringwriter字符串是用来保存xml文档的 stringwriter = new stringwriter(); // filewriter = new filewriter("d:\\modu11le.xml"); // xmlwriter是用来把xml文档写入字符串的(工具) xmlwriter = new xmlwriter(stringwriter, outputformat); // 把创建好的xml文档写入字符串 xmlwriter.write(document); //filewriter.write(stringwriter.tostring()); result=stringwriter.tostring(); } catch (ioexception e) { logger.error("写入数据失败"); throw new runtimeexception("写入数据失败"+e); }finally{ try { if(xmlwriter!=null){ xmlwriter.flush(); xmlwriter.close(); } /* if(filewriter!=null){ filewriter.flush(); filewriter.close(); }*/ } catch (ioexception e) { logger.error("关闭输出流出错"); throw new runtimeexception("关闭输出流出错"+e); } } } catch (exception e) { logger.error("添加xml的节点失败"+e); } logger.error("转换xml结束"); return result; } /** * 添加类中的list * @param element * @param object * @param name * @return * @throws illegalargumentexception * @throws illegalaccessexception */ public static element createelement(element element ,object object,string name ) throws illegalargumentexception, illegalaccessexception{ element nameelement = element.addelement(name); list info = (list)object; for(int j= 0;j<info.size();j++){ // 添加row的标签 element rowelement = nameelement.addelement("row"); // 添加 对象的熟悉 field fields[]=info.get(j).getclass().getdeclaredfields();//dto 是实体类名称 field.setaccessible(fields, true); for (int i = 0; i < fields.length; i++) { //添加节点信息 if(!stringutils.isempty(fields[i].get(info.get(j)))){ element childelement = rowelement.addelement(fields[i].getname()); childelement.settext((string) fields[i].get(info.get(j))); } } } return element; } }
unifiedorderrequest.java
package com.yiexpress.core.utils.wechat; public class unifiedorderrequest { private string appid;// 公众账号id private string mch_id;//商户号 private string device_info; //设备号 否 private string nonce_str;//随机字符串 private string sign;//签名 private string sign_type;//签名类型 private string body;//商品描述 private string detail;//商品详情 private string attach;//附加数据 private string out_trade_no;//商户订单号 private string fee_type;//标价币种 private string total_fee;//标价金额 private string spbill_create_ip;//终端ip private string time_start;//交易起始时间 private string time_expire;//交易结束时间 private string goods_tag;//订单优惠标记 private string notify_url;//通知地址 private string trade_type;//交易类型 private string product_id;//商品id private string limit_pay;//指定支付方式 private string openid;//用户标识 public string getappid() { return appid; } public void setappid(string appid) { this.appid = appid; } public string getmch_id() { return mch_id; } public void setmch_id(string mch_id) { this.mch_id = mch_id; } public string getdevice_info() { return device_info; } public void setdevice_info(string device_info) { this.device_info = device_info; } public string getnonce_str() { return nonce_str; } public void setnonce_str(string nonce_str) { this.nonce_str = nonce_str; } public string getsign() { return sign; } public void setsign(string sign) { this.sign = sign; } public string getsign_type() { return sign_type; } public void setsign_type(string sign_type) { this.sign_type = sign_type; } public string getbody() { return body; } public void setbody(string body) { this.body = body; } public string getdetail() { return detail; } public void setdetail(string detail) { this.detail = detail; } public string getattach() { return attach; } public void setattach(string attach) { this.attach = attach; } public string getout_trade_no() { return out_trade_no; } public void setout_trade_no(string out_trade_no) { this.out_trade_no = out_trade_no; } public string getfee_type() { return fee_type; } public void setfee_type(string fee_type) { this.fee_type = fee_type; } public string gettotal_fee() { return total_fee; } public void settotal_fee(string total_fee) { this.total_fee = total_fee; } public string getspbill_create_ip() { return spbill_create_ip; } public void setspbill_create_ip(string spbill_create_ip) { this.spbill_create_ip = spbill_create_ip; } public string gettime_start() { return time_start; } public void settime_start(string time_start) { this.time_start = time_start; } public string gettime_expire() { return time_expire; } public void settime_expire(string time_expire) { this.time_expire = time_expire; } public string getgoods_tag() { return goods_tag; } public void setgoods_tag(string goods_tag) { this.goods_tag = goods_tag; } public string getnotify_url() { return notify_url; } public void setnotify_url(string notify_url) { this.notify_url = notify_url; } public string gettrade_type() { return trade_type; } public void settrade_type(string trade_type) { this.trade_type = trade_type; } public string getproduct_id() { return product_id; } public void setproduct_id(string product_id) { this.product_id = product_id; } public string getlimit_pay() { return limit_pay; } public void setlimit_pay(string limit_pay) { this.limit_pay = limit_pay; } public string getopenid() { return openid; } public void setopenid(string openid) { this.openid = openid; } }
unifiedorderrespose.java
package com.yiexpress.core.utils.wechat; public class unifiedorderrespose { private string return_code; //返回状态码 private string return_msg; //返回信息 private string appid; //公众账号id private string mch_id; //商户号 private string device_info; //设备号 private string nonce_str; //随机字符串 private string sign; //签名 private string result_code; //业务结果 private string err_code; //错误代码 private string err_code_des; //错误代码描述 private string trade_type; //交易类型 private string prepay_id; //预支付交易会话标识 private string code_url; //二维码链接 public string getreturn_code() { return return_code; } public void setreturn_code(string return_code) { this.return_code = return_code; } public string getreturn_msg() { return return_msg; } public void setreturn_msg(string return_msg) { this.return_msg = return_msg; } public string getappid() { return appid; } public void setappid(string appid) { this.appid = appid; } public string getmch_id() { return mch_id; } public void setmch_id(string mch_id) { this.mch_id = mch_id; } public string getdevice_info() { return device_info; } public void setdevice_info(string device_info) { this.device_info = device_info; } public string getnonce_str() { return nonce_str; } public void setnonce_str(string nonce_str) { this.nonce_str = nonce_str; } public string getsign() { return sign; } public void setsign(string sign) { this.sign = sign; } public string getresult_code() { return result_code; } public void setresult_code(string result_code) { this.result_code = result_code; } public string geterr_code() { return err_code; } public void seterr_code(string err_code) { this.err_code = err_code; } public string geterr_code_des() { return err_code_des; } public void seterr_code_des(string err_code_des) { this.err_code_des = err_code_des; } public string gettrade_type() { return trade_type; } public void settrade_type(string trade_type) { this.trade_type = trade_type; } public string getprepay_id() { return prepay_id; } public void setprepay_id(string prepay_id) { this.prepay_id = prepay_id; } public string getcode_url() { return code_url; } public void setcode_url(string code_url) { this.code_url = code_url; } }
wxpayconstants.java
package com.yiexpress.core.utils.wechat; public class wxpayconstants { public enum signtype { md5, hmacsha256 } public static final string fail = "fail"; public static final string success = "success"; public static final string hmacsha256 = "hmac-sha256"; public static final string md5 = "md5"; public static final string field_sign = "sign"; public static final string field_sign_type = "sign_type"; }
wxpayutil.java
package com.yiexpress.core.utils.wechat; import java.io.bufferedoutputstream; import java.io.bufferedreader; import java.io.bytearrayinputstream; import java.io.inputstream; import java.io.inputstreamreader; import java.io.stringwriter; import java.io.writer; import java.net.httpurlconnection; import java.net.url; import java.util.*; import java.security.messagedigest; import org.w3c.dom.node; import org.w3c.dom.nodelist; import com.yiexpress.core.utils.saputils; import com.yiexpress.core.utils.xmlutil; import com.yiexpress.core.utils.wechat.wxpayconstants.signtype; import javax.crypto.mac; import javax.crypto.spec.secretkeyspec; import javax.xml.parsers.documentbuilder; import javax.xml.parsers.documentbuilderfactory; import javax.xml.transform.outputkeys; import javax.xml.transform.transformer; import javax.xml.transform.transformerfactory; import javax.xml.transform.dom.domsource; import javax.xml.transform.stream.streamresult; import org.jdom2.document; import org.jdom2.element; import org.jdom2.input.saxbuilder; import org.slf4j.logger; import org.slf4j.loggerfactory; /** * 支付工具类 */ public class wxpayutil { private static logger log = loggerfactory.getlogger(wxpayutil.class); /** * 生成订单对象信息 * @param orderid 订单号 * @param appid 微信appid * @param mch_id 微信分配的商户id * @param body 支付介绍主体 * @param price 支付价格(放大100倍) * @param spbill_create_ip 终端ip * @param notify_url 异步直接结果通知接口地址 * @param noncestr * @return */ public static map<string,object> createorderinfo(map<string, string> requestmap,string shopkey) { //生成订单对象 unifiedorderrequest unifiedorderrequest = new unifiedorderrequest(); unifiedorderrequest.setappid(requestmap.get("appid"));//公众账号id unifiedorderrequest.setbody(requestmap.get("body"));//商品描述 unifiedorderrequest.setmch_id(requestmap.get("mch_id"));//商户号 unifiedorderrequest.setnonce_str(requestmap.get("noncestr"));//随机字符串 unifiedorderrequest.setnotify_url(requestmap.get("notify_url"));//通知地址 unifiedorderrequest.setopenid(requestmap.get("userweixinopenid")); unifiedorderrequest.setdetail(requestmap.get("detail"));//详情 unifiedorderrequest.setout_trade_no(requestmap.get("out_trade_no"));//商户订单号 unifiedorderrequest.setspbill_create_ip(requestmap.get("spbill_create_ip"));//终端ip unifiedorderrequest.settotal_fee(requestmap.get("paymoney")); //金额需要扩大100倍:1代表支付时是0.01 unifiedorderrequest.settrade_type("jsapi");//jsapi--公众号支付、native--原生扫码支付、app--app支付 sortedmap<string, string> packageparams = new treemap<string, string>(); packageparams.put("appid", unifiedorderrequest.getappid()); packageparams.put("body", unifiedorderrequest.getbody()); packageparams.put("mch_id", unifiedorderrequest.getmch_id()); packageparams.put("nonce_str", unifiedorderrequest.getnonce_str()); packageparams.put("notify_url", unifiedorderrequest.getnotify_url()); packageparams.put("openid", unifiedorderrequest.getopenid()); packageparams.put("detail", unifiedorderrequest.getdetail()); packageparams.put("out_trade_no", unifiedorderrequest.getout_trade_no()); packageparams.put("spbill_create_ip", unifiedorderrequest.getspbill_create_ip()); packageparams.put("total_fee", unifiedorderrequest.gettotal_fee()); packageparams.put("trade_type", unifiedorderrequest.gettrade_type()); try { unifiedorderrequest.setsign(generatesignature(packageparams,shopkey));//签名 } catch (exception e) { e.printstacktrace(); } //将订单对象转为xml格式 string orderstr=saputils.formattoxml(unifiedorderrequest,"xml").replace("<?xml version=\"1.0\" encoding=\"utf-8\"?>",""); log.debug("封装好的统一下单请求数据:"+orderstr.replace("__", "_")); map<string,object> responsemap = new hashmap<string,object>(); responsemap.put("orderinfo_tostring", orderstr.replace("__", "_")); responsemap.put("unifiedorderrequest",unifiedorderrequest); return responsemap; } public static void main(string[] args) { // unifiedorderrequest ut=new unifiedorderrequest(); // ut.setappid("wx1234156789"); // ut.setbody("内容body"); // ut.setmch_id("商户号"); // ut.setnonce_str("随机字符串"); // ut.setnotify_url("回调地址"); // ut.setopenid("openid"); // ut.setdetail("详情"); // ut.setout_trade_no("订单号"); // ut.setspbill_create_ip("终端ip"); // ut.settotal_fee("金额"); // ut.settrade_type("调用类型jsapi"); // system.out.println("---"+saputils.formattoxml(ut,"xml")+"---"); // unifiedorderrequest unifiedorderrequest = new unifiedorderrequest(); // unifiedorderrequest.setappid("dsfsdf");//公众账号id // unifiedorderrequest.setbody("sdfsdf");//商品描述 // unifiedorderrequest.setmch_id("sdfsd");//商户号 // unifiedorderrequest.setnonce_str("dfsd");//随机字符串 // unifiedorderrequest.setnotify_url("sdfdsf");//通知地址 // unifiedorderrequest.setopenid("sdfsdf"); // // unifiedorderrequest.settrade_type("jsapi");//jsapi--公众号支付、native--原生扫码支付、app--app支付 // // system.out.println("---"+saputils.formattoxml(unifiedorderrequest,"xml").replace("<?xml version=\"1.0\" encoding=\"utf-8\"?>","")+"---"); // string str="<xml><appid>dsfsdf</appid><mch_id>sdfsd</mch_id><nonce_str>dfsd</nonce_str><body>sdfsdf</body><notify_url>sdfdsf</notify_url><trade_type>jsapi</trade_type><openid>sdfsdf</openid></xml>"; // unifiedorderrequest s=saputils.getbeanbyxml(str,unifiedorderrequest.class); // system.out.println(s.getappid()+"---"+s.getmch_id()+"--"+s.getfee_type()); } /** * 生成签名 * @param appid_value * @param mch_id_value * @param productid * @param nonce_str_value * @param trade_type * @param notify_url * @param spbill_create_ip * @param total_fee * @param out_trade_no * @return */ private static string createsign(unifiedorderrequest unifiedorderrequest,string shopkey) { //根据规则创建可排序的map集合 sortedmap<string, string> packageparams = new treemap<string, string>(); packageparams.put("appid", unifiedorderrequest.getappid()); packageparams.put("body", unifiedorderrequest.getbody()); packageparams.put("mch_id", unifiedorderrequest.getmch_id()); packageparams.put("nonce_str", unifiedorderrequest.getnonce_str()); packageparams.put("notify_url", unifiedorderrequest.getnotify_url()); packageparams.put("out_trade_no", unifiedorderrequest.getout_trade_no()); packageparams.put("spbill_create_ip", unifiedorderrequest.getspbill_create_ip()); packageparams.put("trade_type", unifiedorderrequest.gettrade_type()); packageparams.put("total_fee", unifiedorderrequest.gettotal_fee()); 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 + "&"); } } //第二步拼接key,key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->api安全-->密钥设置 sb.append("key="+shopkey); string sign = md5util.md5(sb.tostring()).touppercase();//md5加密 log.error("方式一生成的签名="+sign); return sign; } //xml解析 public static sortedmap<string, string> doxmlparsewithsorted(string strxml) throws exception { strxml = strxml.replacefirst("encoding=\".*\"", "encoding=\"utf-8\""); if(null == strxml || "".equals(strxml)) { return null; } sortedmap<string,string> m = new treemap<string,string>(); 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; } public 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(); } /** * 调统一下单api * @param orderinfo * @return */ public static unifiedorderrespose httporder(string orderinfo,int index) { //统一下单接口地址 自动适应 1中国境内 2东南亚 3其他 string[] urllist={"https://api.mch.weixin.qq.com/pay/unifiedorder","https://apihk.mch.weixin.qq.com/pay/unifiedorder" ,"https://apius.mch.weixin.qq.com/pay/unifiedorder "}; //string url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; try { httpurlconnection conn = (httpurlconnection) new url(urllist[index]).openconnection(); //加入数据 conn.setrequestmethod("post"); conn.setdooutput(true); bufferedoutputstream buffoutstr = new bufferedoutputstream(conn.getoutputstream()); buffoutstr.write(orderinfo.getbytes("utf-8")); buffoutstr.flush(); buffoutstr.close(); //获取输入流 bufferedreader reader = new bufferedreader(new inputstreamreader(conn.getinputstream(), "utf-8")); string line = null; stringbuffer sb = new stringbuffer(); while((line = reader.readline())!= null){ sb.append(line); } //xml转对象 unifiedorderrespose unifiedorderrespose =xmlutil.getbeanbyxml(sb.tostring(),unifiedorderrespose.class); return unifiedorderrespose; } catch (exception e) { e.printstacktrace(); } return null; } /** * xml格式字符串转换为map * * @param strxml xml字符串 * @return xml数据转换后的map * @throws exception */ public static map<string, string> xmltomap(string strxml) throws exception { try { map<string, string> data = new hashmap<string, string>(); documentbuilderfactory documentbuilderfactory = documentbuilderfactory.newinstance(); documentbuilder documentbuilder = documentbuilderfactory.newdocumentbuilder(); inputstream stream = new bytearrayinputstream(strxml.getbytes("utf-8")); org.w3c.dom.document doc = documentbuilder.parse(stream); doc.getdocumentelement().normalize(); nodelist nodelist = doc.getdocumentelement().getchildnodes(); for (int idx = 0; idx < nodelist.getlength(); ++idx) { node node = nodelist.item(idx); if (node.getnodetype() == node.element_node) { org.w3c.dom.element element = (org.w3c.dom.element) node; data.put(element.getnodename(), element.gettextcontent()); } } try { stream.close(); } catch (exception ex) { // do nothing } return data; } catch (exception ex) { wxpayutil.getlogger().warn("invalid xml, can not convert to map. error message: {}. xml content: {}", ex.getmessage(), strxml); throw ex; } } /** * 将map转换为xml格式的字符串 * * @param data map类型数据 * @return xml格式的字符串 * @throws exception */ public static string maptoxml(map<string, string> data) throws exception { documentbuilderfactory documentbuilderfactory = documentbuilderfactory.newinstance(); documentbuilder documentbuilder= documentbuilderfactory.newdocumentbuilder(); org.w3c.dom.document document = documentbuilder.newdocument(); org.w3c.dom.element root = document.createelement("xml"); document.appendchild(root); for (string key: data.keyset()) { string value = data.get(key); if (value == null) { value = ""; } value = value.trim(); org.w3c.dom.element filed = document.createelement(key); filed.appendchild(document.createtextnode(value)); root.appendchild(filed); } transformerfactory tf = transformerfactory.newinstance(); transformer transformer = tf.newtransformer(); domsource source = new domsource(document); transformer.setoutputproperty(outputkeys.encoding, "utf-8"); transformer.setoutputproperty(outputkeys.indent, "yes"); stringwriter writer = new stringwriter(); streamresult result = new streamresult(writer); transformer.transform(source, result); string output = writer.getbuffer().tostring(); //.replaceall("\n|\r", ""); try { writer.close(); } catch (exception ex) { } return output; } /** * 生成带有 sign 的 xml 格式字符串 * * @param data map类型数据 * @param key api密钥 * @return 含有sign字段的xml */ public static string generatesignedxml(final map<string, string> data, string key) throws exception { return generatesignedxml(data, key, signtype.md5); } /** * 生成带有 sign 的 xml 格式字符串 * * @param data map类型数据 * @param key api密钥 * @param signtype 签名类型 * @return 含有sign字段的xml */ public static string generatesignedxml(final map<string, string> data, string key, signtype signtype) throws exception { string sign = generatesignature(data, key, signtype); data.put(wxpayconstants.field_sign, sign); return maptoxml(data); } /** * 判断签名是否正确 * * @param xmlstr xml格式数据 * @param key api密钥 * @return 签名是否正确 * @throws exception */ public static boolean issignaturevalid(string xmlstr, string key) throws exception { map<string, string> data = xmltomap(xmlstr); if (!data.containskey(wxpayconstants.field_sign) ) { return false; } string sign = data.get(wxpayconstants.field_sign); return generatesignature(data, key).equals(sign); } /** * 判断签名是否正确,必须包含sign字段,否则返回false。使用md5签名。 * * @param data map类型数据 * @param key api密钥 * @return 签名是否正确 * @throws exception */ public static boolean issignaturevalid(map<string, string> data, string key) throws exception { return issignaturevalid(data, key, signtype.md5); } /** * 判断签名是否正确,必须包含sign字段,否则返回false。 * * @param data map类型数据 * @param key api密钥 * @param signtype 签名方式 * @return 签名是否正确 * @throws exception */ public static boolean issignaturevalid(map<string, string> data, string key, signtype signtype) throws exception { if (!data.containskey(wxpayconstants.field_sign) ) { return false; } string sign = data.get(wxpayconstants.field_sign); return generatesignature(data, key, signtype).equals(sign); } /** * 生成签名 * * @param data 待签名数据 * @param key api密钥 * @return 签名 */ public static string generatesignature(final map<string, string> data, string key) throws exception { return generatesignature(data, key, signtype.md5); } /** * 生成签名. 注意,若含有sign_type字段,必须和signtype参数保持一致。 * * @param data 待签名数据 * @param key api密钥 * @param signtype 签名方式 * @return 签名 */ public static string generatesignature(final map<string, string> data, string key, signtype signtype) throws exception { set<string> keyset = data.keyset(); string[] keyarray = keyset.toarray(new string[keyset.size()]); arrays.sort(keyarray); stringbuilder sb = new stringbuilder(); for (string k : keyarray) { if (k.equals(wxpayconstants.field_sign)) { continue; } if (data.get(k).trim().length() > 0) // 参数值为空,则不参与签名 sb.append(k).append("=").append(data.get(k).trim()).append("&"); } sb.append("key=").append(key); if (signtype.md5.equals(signtype)) { return md5(sb.tostring()).touppercase(); } else if (signtype.hmacsha256.equals(signtype)) { return hmacsha256(sb.tostring(), key); } else { log.error("获取签名失败,失败原因:"+string.format("invalid sign_type: %s", signtype)); throw new exception(string.format("invalid sign_type: %s", signtype)); } } /** * 获取随机字符串 nonce str * @return string 随机字符串 */ public static string generatenoncestr() { return uuid.randomuuid().tostring().replaceall("-", "").substring(0, 32); } /** * map转xml数据 */ public static string getmaptoxml(map<string,string> param){ stringbuffer sb = new stringbuffer(); sb.append("<xml>"); for (map.entry<string,string> entry : param.entryset()) { sb.append("<"+ entry.getkey() +">"); sb.append(entry.getvalue()); sb.append("</"+ entry.getkey() +">"); } sb.append("</xml>"); return sb.tostring(); } /** * 生成 md5 * @param data 待处理数据 * @return md5结果 */ public static string md5(string data) throws exception { java.security.messagedigest md = messagedigest.getinstance("md5"); byte[] array = md.digest(data.getbytes("utf-8")); stringbuilder sb = new stringbuilder(); for (byte item : array) { sb.append(integer.tohexstring((item & 0xff) | 0x100).substring(1, 3)); } return sb.tostring().touppercase(); } /** * 生成 hmacsha256 * @param data 待处理数据 * @param key 密钥 * @return 加密结果 * @throws exception */ public static string hmacsha256(string data, string key) throws exception { mac sha256_hmac = mac.getinstance("hmacsha256"); secretkeyspec secret_key = new secretkeyspec(key.getbytes("utf-8"), "hmacsha256"); sha256_hmac.init(secret_key); byte[] array = sha256_hmac.dofinal(data.getbytes("utf-8")); stringbuilder sb = new stringbuilder(); for (byte item : array) { sb.append(integer.tohexstring((item & 0xff) | 0x100).substring(1, 3)); } return sb.tostring().touppercase(); } /** * 日志 * @return */ public static logger getlogger() { logger logger = loggerfactory.getlogger("wxpay java sdk"); return logger; } /** * 获取当前时间戳,单位秒 * @return */ public static long getcurrenttimestamp() { return system.currenttimemillis()/1000; } /** * 获取当前时间戳,单位毫秒 * @return */ public static long getcurrenttimestampms() { return system.currenttimemillis(); } /** * 生成 uuid, 即用来标识一笔单,也用做 nonce_str * @return */ public static string generateuuid() { return uuid.randomuuid().tostring().replaceall("-", "").substring(0, 32); } /** * 支付签名 * @param timestamp * @param noncestr * @param packages * @return * @throws unsupportedencodingexception */ public static string paysign(string timestamp, string noncestr,string packages,string appid){ map<string, string> paras = new hashmap<string, string>(); paras.put("appid", appid); paras.put("timestamp", timestamp); paras.put("noncestr", noncestr); paras.put("package", packages); paras.put("signtype", "md5"); stringbuffer sb = new stringbuffer(); set es = paras.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 + "&"); } } string sign = md5util.md5(sb.tostring()).touppercase();//md5加密 return sign; } }
xmlutil.java
package com.yiexpress.core.utils; import java.io.stringreader; import java.lang.reflect.field; import java.util.date; import org.dom4j.document; import org.dom4j.element; import org.dom4j.io.saxreader; import org.xml.sax.inputsource; public class xmlutil{ /** * json 数据转换对象 * * @param element * 要转换的element数据 * @param pojo * 要转换的目标对象类型 * @return 转换的目标对象 * @throws exception * 转换失败 */ @suppresswarnings("rawtypes") public static object fromxmltobean(element rootelt, class pojo) throws exception{ // 首先得到pojo所定义的字段 field[] fields = pojo.getdeclaredfields(); // 根据传入的class动态生成pojo对象 object obj = pojo.newinstance(); for (field field : fields) { // 设置字段可访问(必须,否则报错) field.setaccessible(true); // 得到字段的属性名 string name = field.getname(); // 这一段的作用是如果字段在element中不存在会抛出异常,如果出异常,则跳过。 try { rootelt.elementtexttrim(name); } catch (exception ex) { continue; } if (rootelt.elementtexttrim(name) != null && !"".equals(rootelt.elementtexttrim(name))) { // 根据字段的类型将值转化为相应的类型,并设置到生成的对象中。 if (field.gettype().equals(long.class) || field.gettype().equals(long.class)) { field.set(obj, long.parselong(rootelt.elementtexttrim(name))); } else if (field.gettype().equals(string.class)) { field.set(obj, rootelt.elementtexttrim(name)); } else if (field.gettype().equals(double.class) || field.gettype().equals(double.class)) { field.set(obj, double.parsedouble(rootelt.elementtexttrim(name))); } else if (field.gettype().equals(integer.class) || field.gettype().equals(int.class)) { field.set(obj, integer.parseint(rootelt.elementtexttrim(name))); } else if (field.gettype().equals(java.util.date.class)) { field.set(obj, date.parse(rootelt.elementtexttrim(name))); } else { continue; } } } return obj; } /** * 把xml格式转化为指定对象 * * @param xml * @return */ @suppresswarnings("unchecked") public static <t> t getbeanbyxml(string xml, class<t> valuetype) { t person = null; inputsource in = new inputsource(new stringreader(xml)); in.setencoding("utf-8"); saxreader reader = new saxreader(); document document; try { document = reader.read(in); element root = document.getrootelement(); person = (t) xmlutil.fromxmltobean(root, valuetype); } catch (exception e) { // todo auto-generated catch block e.printstacktrace(); system.out.println("数据解析错误"); } return person; } }
获取预支付id和签名的controller
package com.yiexpress.jerry.controller.ewe.wechat; import java.util.hashmap; import java.util.map; import java.util.sortedmap; import java.util.treemap; import javax.servlet.http.httpservletrequest; import org.slf4j.logger; import org.slf4j.loggerfactory; import org.springframework.stereotype.controller; import org.springframework.web.bind.annotation.requestmapping; import org.springframework.web.bind.annotation.requestparam; import org.springframework.web.bind.annotation.responsebody; import com.yiexpress.core.utils.wechat.unifiedorderrequest; import com.yiexpress.core.utils.wechat.unifiedorderrespose; import com.yiexpress.core.utils.wechat.wxpayutil; /** * 微信支付controller */ @controller @requestmapping(value = "/wxpay") public class wxpaycontroller{ private static final logger logger = loggerfactory.getlogger(wxpaycontroller.class); private string appid="公总号 appid";//公总号 appid private string mchid="商家号";//商家号 private string apikey="商户密匙";//商户密匙 /** * 获取终端ip * @param request * @return */ public static string getipaddr(httpservletrequest request) { string ip = request.getheader( " x-forwarded-for " ); if (ip == null || ip.length() == 0 || " unknown " .equalsignorecase(ip)) { ip = request.getheader( " proxy-client-ip " ); } if (ip == null || ip.length() == 0 || " unknown " .equalsignorecase(ip)) { ip = request.getheader( " wl-proxy-client-ip " ); } if (ip == null || ip.length() == 0 || " unknown " .equalsignorecase(ip)) { ip = request.getremoteaddr(); } return ip; } /** * 支付初始化 返回预支付id、签名等信息 * @param paymoney * @return map * result -1 */ @requestmapping("/topayinit") @responsebody public map<string,object> topay(httpservletrequest request,@requestparam(value="paymoney",required=true)float paymoney,@requestparam(value="openid",required=true) string openid,@requestparam(value="orderid",required=true)string orderid){ map<string,object> map = new hashmap<>(); //订单号 目前生产的随机数 后面放入指定系统唯一的单号 //判断单号是否存在 string noncestr = wxpayutil.generatenoncestr(); map<string,string> requestmap = new hashmap<string, string>(); requestmap.put("appid",appid); requestmap.put("userweixinopenid",openid); //之前使用etca单号作为商户订单号,现在改为自动生成的账单号 2018-10-25 peter //requestmap.put("out_trade_no",aushipmentbrief.getshipmentreference()); requestmap.put("out_trade_no","订单号"); requestmap.put("mch_id",mchid); //计算金额 微信支付的金额的单位是分,例如:实际支付1.23元,传入参数就是123 int money=0; try { money=(int)(paymoney*100); } catch (exception e) { map.put("result",-1); map.put("msg","金额格式不正确"); return map; } requestmap.put("paymoney",money+""); requestmap.put("spbill_create_ip", getipaddr(request)); requestmap.put("notify_url","回调地址"); requestmap.put("noncestr", noncestr); requestmap.put("body","微信下单账单支付"); requestmap.put("detail","散客下单账单支付"); map<string,object> requestinfo = wxpayutil.createorderinfo(requestmap,apikey); string orderinfo_tostring = (string) requestinfo.get("orderinfo_tostring"); logger.debug("request 请求字符串:"+orderinfo_tostring); //判断返回码 unifiedorderrespose orderresponse = wxpayutil.httporder(orderinfo_tostring,0);// 调用统一下单接口 //判断超时的情况 if(orderresponse==null || orderresponse.getreturn_code()==null || ("success".equals(orderresponse.getreturn_code()) && (orderresponse.geterr_code()==null || "systemerror".equals(orderresponse.geterr_code())))){ orderresponse = wxpayutil.httporder(orderinfo_tostring,1); if(orderresponse==null || orderresponse.getreturn_code()==null || ("success".equals(orderresponse.getreturn_code()) && (orderresponse.geterr_code()==null || "systemerror".equals(orderresponse.geterr_code())))){ orderresponse = wxpayutil.httporder(orderinfo_tostring,2); } } logger.debug("response 返回字段:==》{}",orderresponse); //根据微信文档return_code 和result_code都为success的时候才会返回code_url if(null!=orderresponse && "success".equals(orderresponse.getreturn_code()) && "success".equals(orderresponse.getresult_code())){ string timestamp = string.valueof(wxpayutil.getcurrenttimestamp()); map.put("timestamp",timestamp); map.put("noncestr",noncestr); unifiedorderrequest unifiedorderrequest = (unifiedorderrequest) requestinfo.get("unifiedorderrequest"); map.put("unifiedorderrequest",unifiedorderrequest); sortedmap<string, string> packageparams = new treemap<string, string>(); packageparams.put("appid",appid); packageparams.put("signtype","md5"); packageparams.put("noncestr", noncestr); packageparams.put("timestamp", timestamp); string packages = "prepay_id="+orderresponse.getprepay_id(); packageparams.put("package",packages); string sign = null; try { //生成签名 sign = wxpayutil.generatesignature(packageparams,apikey); } catch (exception e) { map.put("result",-1); map.put("msg","支付签名信息异常"); e.printstacktrace(); } if(sign!=null && !"".equals(sign)){ logger.debug("------------支付签名:"+sign+"-------------------"); map.put("paysign",sign); map.put("result",1); map.put("appid",appid); }else{ map.put("result",-1); map.put("msg","支付签名信息异常"); } map.put("prepay_id",orderresponse.getprepay_id()); return map; }else{ //不成功 if(orderresponse!=null){ string text = "调用微信支付出错,返回状态码:"+orderresponse.getreturn_code()+",返回信息:"+orderresponse.getreturn_msg(); if(orderresponse.geterr_code()!=null && !"".equals(orderresponse.geterr_code())){ text = text +",错误码:"+orderresponse.geterr_code()+",错误描述:"+orderresponse.geterr_code_des(); } logger.error(text); }else{ logger.error("返回值 orderresponse对象为空"); } map.put("result",-1); map.put("msg","支付环境异常,请稍后再试"); return map; } } }
jsp代码
<script type="text/javascript"> //点击支付按钮 开始支付 function topay(){ //初步判断数据 var openid=$("#openid").val(); var paymoney=$("#paymoney").val(); $.ajax({ url : "${pagecontext.request.contextpath}/topayinit", type:"post", datatype : 'json', data:{ paymoney:paymoney, openid:openid, orderid:"订单号" }, success : function(result) { if(result.result==1){ var paysign = result.paysign; var prepay_id = result.prepay_id; var noncestr = result.noncestr; var timestamp = result.timestamp; var unifiedorderrequest = result.unifiedorderrequest; var spbill_create_ip = unifiedorderrequest.spbill_create_ip; var detail = unifiedorderrequest.detail; var out_trade_no = unifiedorderrequest.out_trade_no; var appid=result.appid; onbridgeready(paysign,prepay_id,noncestr,timestamp,appid); }else{ alert("失败"); } }, error : function(data, status, e) { // 服务器响应失败时的处理函数 alert("数据异常,支付失败", 'error'); } }); } //调起公众号支付 function onbridgeready(paysign,prepay_id,noncestr,timestamp,appid){ weixinjsbridge.invoke( 'getbrandwcpayrequest', { "appid":appid, //appid "timestamp":timestamp, "noncestr":noncestr, //随机串 "package":"prepay_id="+prepay_id, "signtype":"md5", "paysign":paysign //微信签名 }, function(res){ // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。 if(res.err_msg == "get_brand_wcpay_request:ok" ) { alert("支付完成", 'success'); }else if(res.err_msg == "get_brand_wcpay_request:cancel" ) { alert("取消支付", 'success'); }else if(res.err_msg == "get_brand_wcpay_request:fail"){ alert("支付失败", 'success'); } } ); } </script>
定义微信支付成功回调接口apiaupostcontroller.java
package com.yiexpress.api.controller.ewe.aupost; import java.util.hashmap; import java.util.map; import javax.annotation.resource; import javax.servlet.servletinputstream; import javax.servlet.http.httpservletrequest; import javax.servlet.http.httpservletresponse; import org.apache.commons.collections.maputils; import org.slf4j.logger; import org.slf4j.loggerfactory; import org.springframework.beans.factory.annotation.value; import org.springframework.http.converter.json.mappingjackson2httpmessageconverter; import org.springframework.stereotype.controller; import org.springframework.web.bind.annotation.requestmapping; import org.springframework.web.bind.annotation.responsebody; import com.yiexpress.core.utils.wechat.wxpayutil; @controller @requestmapping("/api") public class apiaupostcontroller { private static final logger logger=loggerfactory.getlogger(apiaupostcontroller.class); @resource(name = "jacksonbean") private mappingjackson2httpmessageconverter jackson; private string apikey="商户密匙";//商户密匙 /** * 异步回调接口 * @param request * @param response * @throws exception */ @requestmapping(value="/paymentnotice",produces="text/html;charset=utf-8") @responsebody public string weixinparentnotifypage(httpservletrequest request,httpservletresponse response) throws exception{ servletinputstream instream = request.getinputstream(); stringbuffer sb = new stringbuffer(); int len = -1; byte[] buffer = new byte[1024]; while((len = instream.read(buffer)) != -1){ sb.append(new string(buffer,0,len)); } instream.close(); map<string,string> map = wxpayutil.xmltomap(sb.tostring());//接受微信的回调的通知参数 map<string,string> return_data = new hashmap<string,string>(); //判断签名是否正确 if(wxpayutil.issignaturevalid(map,apikey)){ if(map.get("return_code").tostring().equals("fail")){ return_data.put("return_code", "fail"); return_data.put("return_msg", map.get("return_msg")); }else { string return_code=maputils.getstring(map,"return_code"); string result_code=maputils.getstring(map,"result_code"); if(return_code!=null && "success".equals(return_code) && result_code!=null && "success".equals(result_code)){ string out_trade_no =maputils.getstring(map,"out_trade_no");//系统订单号 //支付成功,可以自定义新逻辑 } } }else{ return_data.put("return_code", "fail"); return_data.put("return_msg", "签名错误"); } string xml = wxpayutil.getmaptoxml(return_data); logger.error("支付通知回调结果:"+xml); return xml; } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: JAVA实现MQTT客户端订阅消息并消费