java实现微信退款功能
程序员文章站
2024-03-31 12:42:40
微信退款之前需要在常量中配置退款地址,退款的地址必须是可以直接访问的。(之前的申请商户平台及在开放平台申请账号不在描述)在调起之前需要下载商户平台上的证书将其放在项目src...
微信退款之前需要在常量中配置退款地址,退款的地址必须是可以直接访问的。(之前的申请商户平台及在开放平台申请账号不在描述)在调起之前需要下载商户平台上的证书将其放在项目src下。
微信退款回调url :微信官方建议在提交退款申请后进行退款回调url配置,便于通知退款的结果。配置在微信商户平台-》交易中心-》退款配置栏进行退款结果回调通知配置。配置的url必须为可以直接访问的类似付款成功回调url。
配置成功后在回调的url中处理退款后的结果。微信给返回的参数如下:
对于加密信息req_info的解密步骤如下。
解密过程中需要先到oracle官网下载对应java版本的sercity包,然后将下载后的包中两个jar复制到jdk/jre/lib/security/包下并覆盖原jar.另外需要在项目中引入一个bcprov-jdk15on-158.jar
退款部分代码:
// 构造向微信发送参数的实体类 private unifiedorder unifiedorder = new unifiedorder(); // 微信的参数 private weixinconfigutils config = new weixinconfigutils(); public static final string algorithm = "aes/ecb/pkcs7padding"; private refundorder refundorder = new refundorder(); @resource private aesdecodeutil aesdecodeutil; @action("weixinrefund") public string weixinrefund() { try { string out_trade_no = getrequest().getparameter("out_trade_no"); string refund_fee = getrequest().getparameter("refund_fee"); alipay = alipayservice.searchalipaybyouttradeno(out_trade_no); if (alipay != null) { // 参数组 string appid = alipay.getapp_id(); string mch_id = config.mch_id; string nonce_str = randcharsutils.getrandomstring(16); string out_refund_no = uuidutils.getuuid(); integer total_fee = alipay.gettotalfee(); // 构造签名 parameters.put("appid", appid); parameters.put("mch_id", mch_id); parameters.put("nonce_str", nonce_str); parameters.put("out_trade_no", out_trade_no); parameters.put("out_refund_no", out_refund_no); parameters.put("total_fee", total_fee); parameters.put("refund_fee", refund_fee); parameters.put("op_user_id", mch_id); string sign = wxsignutils.createsign("utf-8", parameters); // 向微信发送xml消息 // unifiedorder unifiedorder = new unifiedorder(); unifiedorder.setappid(appid); unifiedorder.setmch_id(mch_id); unifiedorder.setsign(sign); unifiedorder.setnonce_str(nonce_str); unifiedorder.setout_trade_no(out_trade_no); unifiedorder.setout_refund_no(out_refund_no); unifiedorder.settotal_fee(total_fee); unifiedorder.setrefund_fee(integer.valueof(refund_fee)); unifiedorder.setop_user_id(mch_id); string xmlinfo = httpxmlutils.refundxml(unifiedorder); unifiedorder = null; try { closeablehttpresponse response = httputil.post( weixinconstant.refund_url, xmlinfo, true); // 输出退款后的信息 string refundxml = entityutils.tostring(response.getentity(), "utf-8"); map<string, string> refundordermap = httpxmlutils.parserefundxml(refundxml); if (refundordermap.size()>0) { if (refundordermap.get("result_code").equals("success") && refundordermap.get("return_code").equals("success")) { refundorder.setappid(refundordermap.get("appid")); refundorder.setmch_id(refundordermap.get("mch_id")); refundorder.settransaction_id(refundordermap.get("transaction_id")); refundorder.setout_trade_no(refundordermap.get("out_trade_no")); refundorder.setout_refund_no(refundordermap.get("out_refund_no")); refundorder.setrefund_id(refundordermap.get("refund_id")); refundorder.setrefund_fee(integer.valueof(refundordermap.get("refund_fee"))); refundorder.settatol_fee(integer.valueof(refundordermap.get("total_fee"))); refundorder.setrefund_status(weixinrefundstatusconstant.apply_success); refundorderservice.saveorder(refundorder); msg.put("statecode", msgcode.success); msg.put("message ", "退款申请成功"); refundorderservice.saveorder(refundorder); }else { msg.put("statecode", msgcode.error); msg.put("message ", "退款申请失败"); } }else { msg.put("statecode", msgcode.error); msg.put("message ", "退款申请失败"); } try { // 关闭流 entityutils.consume(response.getentity()); } finally { response.close(); } } catch (exception e) { msg.put("statecode", msgcode.sys_error); msg.put("message ", "服务器异常"); } } else { msg.put("statecode", msgcode.error); msg.put("message ", "退款申请失败"); } struts2utils.renderjson(jsonobject.tojsonstring(msg, serializerfeature.disablecircularreferencedetect)); return none; } catch (exception e) { log.error(e.getmessage()); e.printstacktrace(); return "500"; } } /** * 微信退款回调url * */ @action("refundnotifyurl") public string refundnotifyurl() throws ioexception { try { map<string, string> resultmap = jdomparsexmlutils.getweixinresult( struts2utils.getrequest(), struts2utils.getresponse()); if (resultmap.get("return_code").equals("success")) { string reqinfo = resultmap.get("req_info"); string result = aesdecodeutil.decode(reqinfo); map<string, string> resultmaps = httpxmlutils.parserefundnotifyxml(result); refundorder = refundorderservice.getorderbyoutrefundno(resultmaps.get("out_refund_no")); if (resultmaps.get("refund_status").equals("success")){ refundorder.setrefund_status(weixinrefundstatusconstant.refund_success); }else if (resultmaps.get("refund_status").equals("change")) { refundorder.setrefund_status(weixinrefundstatusconstant.refund_fail); }else if (resultmaps.get("refund_status").equals("refundclose")) { refundorder.setrefund_status(weixinrefundstatusconstant.refund_closed); } refundorder.setrefund_rew_account(resultmaps.get("refund_recv_account")); system.out.println(resultmaps.get("refund_recv_account")); refundorderservice.updateorder(refundorder); refundorder = null; unifiedorder.setreturn_code("success"); } unifiedorder.setreturn_code("success"); string refundxml = httpxmlutils.refundxml(unifiedorder); struts2utils.getresponse().getwriter().write(refundxml); struts2utils.getresponse().getwriter().flush(); } catch (exception e) { log.error(e.getmessage()); e.printstacktrace(); return "500"; } return null; }
package com.wellness.platfront.common.weixinutil; import java.text.simpledateformat; import java.util.calendar; import java.util.date; import java.util.random; 生成随机串 /** * nonce_str随即字符串 * @author * @date 2017/08/10 */ public class randcharsutils { private static simpledateformat df = new simpledateformat("yyyymmddhhmmss"); public static string getrandomstring(int length) { //length表示生成字符串的长度 string base = "abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz"; random random = new random(); stringbuffer sb = new stringbuffer(); int number = 0; for (int i = 0; i < length; i++) { number = random.nextint(base.length()); sb.append(base.charat(number)); } return sb.tostring(); } /* * 订单开始交易的时间 */ public static string timestart(){ return df.format(new date()); } /* * 订单开始交易的时间 */ public static string timeexpire(){ calendar now=calendar.getinstance(); now.add(calendar.minute,30); return df.format(now.gettimeinmillis()); } }
生成签名的类
package com.wellness.platfront.common.weixinutil; import java.util.iterator; import java.util.map; import java.util.set; import java.util.sortedmap; /** * 微信支付签名 * @author * @date 2017/08/10 */ public class wxsignutils { /** * 微信支付签名算法sign * @param characterencoding * @param parameters * @return */ @suppresswarnings("rawtypes") public static string createsign(string characterencoding,sortedmap<object,object> parameters){ stringbuffer sb = new stringbuffer(); set es = parameters.entryset();//所有参与传参的参数按照accsii排序(升序) 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=" + weixinconstant.key); string sign = md5util.md5encode(sb.tostring(), characterencoding).touppercase(); return sign; } }
向微信发送消息的类
package com.wellness.platfront.common.weixinutil; import java.io.bufferedreader; import java.io.ioexception; import java.io.inputstream; import java.io.inputstreamreader; import java.io.outputstream; import java.io.outputstreamwriter; import java.io.stringreader; import java.net.httpurlconnection; import java.net.malformedurlexception; import java.net.url; import java.util.hashmap; import java.util.list; import java.util.map; import javax.annotation.resource; import javax.net.ssl.httpsurlconnection; import org.jdom.jdomexception; import org.jdom.input.saxbuilder; import org.xml.sax.inputsource; import com.thoughtworks.xstream.xstream; import com.thoughtworks.xstream.io.xml.domdriver; import com.thoughtworks.xstream.io.xml.xmlfriendlynamecoder; import com.wellness.platfront.business.wechat.service.refundorderservice; import com.wellness.platfront.entity.weixin.transfers; import com.wellness.platfront.entity.weixin.unifiedorder; /** * post提交xml格式的参数 * @author * @date 2017/08/10 */ public class httpxmlutils { @resource private refundorderservice refundorderservice; public static xstream xstream = new xstream(new domdriver("utf-8", new xmlfriendlynamecoder("-_", "_"))); /** * 开始post提交参数到接口 * 并接受返回 * @param url * @param xml * @param method * @param contenttype * @return */ public static string xmlhttpproxy(string url,string xml,string method,string contenttype){ inputstream is = null; outputstreamwriter os = null; try { url _url = new url(url); httpurlconnection conn = (httpurlconnection) _url.openconnection(); conn.setdoinput(true); conn.setdooutput(true); conn.setrequestproperty("content-type", "text/xml"); conn.setrequestproperty("pragma:", "no-cache"); conn.setrequestproperty("cache-control", "no-cache"); conn.setrequestmethod("post"); os = new outputstreamwriter(conn.getoutputstream()); os.write(new string(xml.getbytes(contenttype))); os.flush(); //返回值 is = conn.getinputstream(); return getcontent(is, "utf-8"); } catch (malformedurlexception e) { e.printstacktrace(); } catch (ioexception e) { e.printstacktrace(); } finally{ try { if(os!=null){os.close();} if(is!=null){is.close();} } catch (ioexception e) { e.printstacktrace(); } } return null; } /** * 解析返回的值 * @param is * @param charset * @return */ public static string getcontent(inputstream is, string charset) { string pagestring = null; inputstreamreader isr = null; bufferedreader br = null; stringbuffer sb = null; try { isr = new inputstreamreader(is, charset); br = new bufferedreader(isr); sb = new stringbuffer(); string line = null; while ((line = br.readline()) != null) { sb.append(line + "\n"); } pagestring = sb.tostring(); } catch (exception e) { e.printstacktrace(); } finally { try { if (is != null){ is.close(); } if(isr!=null){ isr.close(); } if(br!=null){ br.close(); } } catch (ioexception e) { e.printstacktrace(); } sb = null; } return pagestring; } /** * 解析申请退款之后微信返回的值并进行存库操作 * @throws ioexception * @throws jdomexception */ public static map<string, string> parserefundxml(string refundxml) throws jdomexception, ioexception{ parsexmlutils.jdomparsexml(refundxml); stringreader read = new stringreader(refundxml); // 创建新的输入源sax 解析器将使用 inputsource 对象来确定如何读取 xml 输入 inputsource source = new inputsource(read); // 创建一个新的saxbuilder saxbuilder sb = new saxbuilder(); // 通过输入源构造一个document org.jdom.document doc; doc = (org.jdom.document) sb.build(source); org.jdom.element root = doc.getrootelement();// 指向根节点 list<org.jdom.element> list = root.getchildren(); map<string, string> refundordermap = new hashmap<string, string>(); if(list!=null&&list.size()>0){ for (org.jdom.element element : list) { refundordermap.put(element.getname(), element.gettext()); } return refundordermap; } return null; } /** * 解析申请退款之后微信退款回调返回的字符串中内容 * @throws ioexception * @throws jdomexception */ public static map<string, string> parserefundnotifyxml(string refundxml) throws jdomexception, ioexception{ parsexmlutils.jdomparsexml(refundxml); stringreader read = new stringreader(refundxml); // 创建新的输入源sax 解析器将使用 inputsource 对象来确定如何读取 xml 输入 inputsource source = new inputsource(read); // 创建一个新的saxbuilder saxbuilder sb = new saxbuilder(); // 通过输入源构造一个document org.jdom.document doc; doc = (org.jdom.document) sb.build(source); org.jdom.element root = doc.getrootelement();// 指向根节点 list<org.jdom.element> list = root.getchildren(); map<string, string> resultmap = new hashmap<>(); if(list!=null&&list.size()>0){ for (org.jdom.element element : list){ resultmap.put(element.getname(), element.gettext()); } return resultmap; } return null; } /** * h5支付时 解析返回的值并返回prepareid * @throws ioexception * @throws jdomexception */ public static map<string, string> geturl(unifiedorder unifiedorder) throws jdomexception, ioexception{ string xmlinfo = httpxmlutils.xmlh5info(unifiedorder); string wxurl = weixinconstant.url; string method = "post"; string weixinpost = httpxmlutils.httpsrequest(wxurl, method, xmlinfo).tostring(); parsexmlutils.jdomparsexml(weixinpost); stringreader read = new stringreader(weixinpost); // 创建新的输入源sax 解析器将使用 inputsource 对象来确定如何读取 xml 输入 inputsource source = new inputsource(read); // 创建一个新的saxbuilder saxbuilder sb = new saxbuilder(); // 通过输入源构造一个document org.jdom.document doc; doc = (org.jdom.document) sb.build(source); org.jdom.element root = doc.getrootelement();// 指向根节点 list<org.jdom.element> list = root.getchildren(); string prepayid =null; map<string, string> msg = new hashmap<string, string>(); if(list!=null&&list.size()>0){ for (org.jdom.element element : list) { msg.put(element.getname(), element.gettext()); } } return msg; } /** * 解析返回的值并返回prepareid * @throws ioexception * @throws jdomexception */ public static string getprepareid(unifiedorder unifiedorder) throws jdomexception, ioexception{ string xmlinfo = httpxmlutils.xmlinfo(unifiedorder); string wxurl = weixinconstant.url; string method = "post"; string weixinpost = httpxmlutils.httpsrequest(wxurl, method, xmlinfo).tostring(); parsexmlutils.jdomparsexml(weixinpost); stringreader read = new stringreader(weixinpost); // 创建新的输入源sax 解析器将使用 inputsource 对象来确定如何读取 xml 输入 inputsource source = new inputsource(read); // 创建一个新的saxbuilder saxbuilder sb = new saxbuilder(); // 通过输入源构造一个document org.jdom.document doc; doc = (org.jdom.document) sb.build(source); org.jdom.element root = doc.getrootelement();// 指向根节点 list<org.jdom.element> list = root.getchildren(); string prepayid =null; if(list!=null&&list.size()>0){ for (org.jdom.element element : list) { if ( "prepay_id".equals(element.getname())) { prepayid= element.gettext(); break; } } } return prepayid; } /** * 向微信发送企业付款请求并解析返回结果 * @throws ioexception * @throws jdomexception */ public static map<string, string> gettransfersmap(transfers transfers) throws jdomexception, ioexception{ string xmlinfo = httpxmlutils.xmltransfer(transfers); string wxurl = weixinconstant.withdraw_url; string method = "post"; string weixinpost = httpxmlutils.httpsrequest(wxurl, method, xmlinfo).tostring(); parsexmlutils.jdomparsexml(weixinpost); stringreader read = new stringreader(weixinpost); // 创建新的输入源sax 解析器将使用 inputsource 对象来确定如何读取 xml 输入 inputsource source = new inputsource(read); // 创建一个新的saxbuilder saxbuilder sb = new saxbuilder(); // 通过输入源构造一个document org.jdom.document doc; doc = (org.jdom.document) sb.build(source); org.jdom.element root = doc.getrootelement();// 指向根节点 list<org.jdom.element> list = root.getchildren(); map<string, string> transfermap=new hashmap<>(); if(list!=null&&list.size()>0){ for (org.jdom.element element : list) { transfermap.put(element.getname(), element.gettext()); } } return transfermap; } /** * 构造退款xml参数 * @param xml * @return */ public static string refundxml(unifiedorder unifiedorder){ xstream.autodetectannotations(true); xstream.alias("xml", unifiedorder.class); return xstream.toxml(unifiedorder); } /** * 构造企业付款xml参数 * @param xml * @return */ public static string transferxml(transfers transfers){ xstream.autodetectannotations(true); xstream.alias("xml", transfers.class); return xstream.toxml(transfers); } /** * 构造xml参数 * @param xml * @return */ public static string xmlinfo(unifiedorder unifiedorder){ if(unifiedorder!=null){ stringbuffer bf = new stringbuffer(); bf.append("<xml>"); bf.append("<appid><![cdata["); bf.append(unifiedorder.getappid()); bf.append("]]></appid>"); bf.append("<mch_id><![cdata["); bf.append(unifiedorder.getmch_id()); bf.append("]]></mch_id>"); bf.append("<nonce_str><![cdata["); bf.append(unifiedorder.getnonce_str()); bf.append("]]></nonce_str>"); bf.append("<sign><![cdata["); bf.append(unifiedorder.getsign()); bf.append("]]></sign>"); bf.append("<body><![cdata["); bf.append(unifiedorder.getbody()); bf.append("]]></body>"); bf.append("<detail><![cdata["); bf.append(unifiedorder.getdetail()); bf.append("]]></detail>"); bf.append("<attach><![cdata["); bf.append(unifiedorder.getattach()); bf.append("]]></attach>"); bf.append("<out_trade_no><![cdata["); bf.append(unifiedorder.getout_trade_no()); bf.append("]]></out_trade_no>"); bf.append("<total_fee><![cdata["); bf.append(unifiedorder.gettotal_fee()); bf.append("]]></total_fee>"); bf.append("<spbill_create_ip><![cdata["); bf.append(unifiedorder.getspbill_create_ip()); bf.append("]]></spbill_create_ip>"); bf.append("<time_start><![cdata["); bf.append(unifiedorder.gettime_start()); bf.append("]]></time_start>"); bf.append("<time_expire><![cdata["); bf.append(unifiedorder.gettime_expire()); bf.append("]]></time_expire>"); bf.append("<notify_url><![cdata["); bf.append(unifiedorder.getnotify_url()); bf.append("]]></notify_url>"); bf.append("<trade_type><![cdata["); bf.append(unifiedorder.gettrade_type()); bf.append("]]></trade_type>"); bf.append("</xml>"); return bf.tostring(); } return ""; } /** * 构造xml参数 * @param xml * @return */ public static string xmlh5info(unifiedorder unifiedorder){ if(unifiedorder!=null){ stringbuffer bf = new stringbuffer(); bf.append("<xml>"); bf.append("<appid><![cdata["); bf.append(unifiedorder.getappid()); bf.append("]]></appid>"); bf.append("<mch_id><![cdata["); bf.append(unifiedorder.getmch_id()); bf.append("]]></mch_id>"); bf.append("<nonce_str><![cdata["); bf.append(unifiedorder.getnonce_str()); bf.append("]]></nonce_str>"); bf.append("<sign><![cdata["); bf.append(unifiedorder.getsign()); bf.append("]]></sign>"); bf.append("<body><![cdata["); bf.append(unifiedorder.getbody()); bf.append("]]></body>"); bf.append("<attach><![cdata["); bf.append(unifiedorder.getattach()); bf.append("]]></attach>"); bf.append("<out_trade_no><![cdata["); bf.append(unifiedorder.getout_trade_no()); bf.append("]]></out_trade_no>"); bf.append("<total_fee><![cdata["); bf.append(unifiedorder.gettotal_fee()); bf.append("]]></total_fee>"); bf.append("<spbill_create_ip><![cdata["); bf.append(unifiedorder.getspbill_create_ip()); bf.append("]]></spbill_create_ip>"); bf.append("<notify_url><![cdata["); bf.append(unifiedorder.getnotify_url()); bf.append("]]></notify_url>"); bf.append("<trade_type><![cdata["); bf.append(unifiedorder.gettrade_type()); bf.append("]]></trade_type>"); bf.append("<scene_info><![cdata["); bf.append(unifiedorder.getscene_info()); bf.append("]]></scene_info>"); bf.append("</xml>"); return bf.tostring(); } return ""; } /** * 构造退款xml参数 * @param xml * @return */ public static string xmltransfer(transfers transfers){ if(transfers!=null){ stringbuffer bf = new stringbuffer(); bf.append("<xml>"); bf.append("<mch_appid><![cdata["); bf.append(transfers.getmch_appid()); bf.append("]]></mch_appid>"); bf.append("<mchid><![cdata["); bf.append(transfers.getmchid()); bf.append("]]></mchid>"); bf.append("<nonce_str><![cdata["); bf.append(transfers.getnonce_str()); bf.append("]]></nonce_str>"); bf.append("<sign><![cdata["); bf.append(transfers.getsign()); bf.append("]]></sign>"); bf.append("<partner_trade_no><![cdata["); bf.append(transfers.getpartner_trade_no()); bf.append("]]></partner_trade_no>"); bf.append("<openid><![cdata["); bf.append(transfers.getopenid()); bf.append("]]></openid>"); bf.append("<check_name><![cdata["); bf.append(transfers.getcheck_name()); bf.append("]]></check_name>"); bf.append("<amount><![cdata["); bf.append(transfers.getamount()); bf.append("]]></amount>"); bf.append("<desc><![cdata["); bf.append(transfers.getdesc()); bf.append("]]></desc>"); bf.append("<spbill_create_ip><![cdata["); bf.append(transfers.getspbill_create_ip()); bf.append("]]></spbill_create_ip>"); bf.append("</xml>"); return bf.tostring(); } return ""; } /** * post请求并得到返回结果 * @param requesturl * @param requestmethod * @param output * @return */ public static string httpsrequest(string requesturl, string requestmethod, string output) { try{ url url = new url(requesturl); httpsurlconnection connection = (httpsurlconnection) url.openconnection(); connection.setdooutput(true); connection.setdoinput(true); connection.setusecaches(false); connection.setrequestmethod(requestmethod); if (null != output) { outputstream outputstream = connection.getoutputstream(); outputstream.write(output.getbytes("utf-8")); outputstream.close(); } // 从输入流读取返回内容 inputstream inputstream = connection.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; connection.disconnect(); return buffer.tostring(); }catch(exception ex){ ex.printstacktrace(); } return ""; } }
加载证书
package com.wellness.platfront.common.weixinutil; import org.apache.http.client.methods.closeablehttpresponse; import org.apache.http.client.methods.httppost; import org.apache.http.entity.stringentity; import org.apache.http.impl.client.httpclients; public class httputil { /** * 发送post请求 * * @param url * 请求地址 * @param outputentity * 发送内容 * @param isloadcert * 是否加载证书 */ public static closeablehttpresponse post(string url, string outputentity, boolean isloadcert) throws exception { httppost httppost = new httppost(url); // 得指明使用utf-8编码,否则到api服务器xml的中文不能被成功识别 httppost.addheader("content-type", "text/xml"); httppost.setentity(new stringentity(outputentity, "utf-8")); if (isloadcert) { // 加载含有证书的http请求 return httpclients.custom().setsslsocketfactory(certutil.initcert()).build().execute(httppost); } else { return httpclients.custom().build().execute(httppost); } } }
加载证书的类
package com.wellness.platfront.common.weixinutil; import java.io.file; import java.io.fileinputstream; import java.security.keystore; import javax.net.ssl.sslcontext; import org.apache.http.conn.ssl.sslconnectionsocketfactory; import org.apache.http.ssl.sslcontexts; /** * 加载证书的类 * @author * @since 2017/08/16 */ @suppresswarnings("deprecation") public class certutil { private static weixinconfigutils config = new weixinconfigutils(); /** * 加载证书 */ public static sslconnectionsocketfactory initcert() throws exception { fileinputstream instream = null; keystore keystore = keystore.getinstance("pkcs12"); instream = new fileinputstream(new file(weixinconstant.path)); keystore.load(instream, config.mch_id.tochararray()); if (null != instream) { instream.close(); } sslcontext sslcontext = sslcontexts.custom().loadkeymaterial(keystore,config.mch_id.tochararray()).build(); sslconnectionsocketfactory sslsf = new sslconnectionsocketfactory(sslcontext, new string[]{"tlsv1"}, null, sslconnectionsocketfactory.browser_compatible_hostname_verifier); return sslsf; } }
解密微信退款中返回相关信息的字符串
package com.wellness.platfront.common.weixinutil; import java.security.security; import javax.crypto.cipher; import javax.crypto.secretkey; import javax.crypto.spec.secretkeyspec; import org.apache.commons.codec.binary.base64; import org.bouncycastle.jce.provider.bouncycastleprovider; import org.springframework.stereotype.service; import com.wellness.platfront.common.wechat.utils.md5; /** * 解密微信退款中返回相关信息的字符串 * @author * @since 2017/09/05 */ @service public class aesdecodeutil { public static final string algorithm = "aes/ecb/pkcs7padding"; public string decode(string reqinfo) throws exception{ try { byte[] decodebase64 = base64.decodebase64(reqinfo); string md5key = md5.md5encode(weixinconstant.key); security.addprovider(new bouncycastleprovider()); cipher cipher = cipher.getinstance(algorithm); secretkey keyspec = new secretkeyspec(md5key.getbytes(), "aes"); //生成加密解密需要的key cipher.init(cipher.decrypt_mode, keyspec); byte[] decoded = cipher.dofinal(decodebase64); string result = new string(decoded, "utf-8"); return result; } catch (exception e) { e.printstacktrace(); } return null; } }
微信解析xml:带有cdata格式的
package com.wellness.platfront.common.weixinutil; import java.io.bytearrayoutputstream; import java.io.ioexception; import java.io.inputstream; import java.io.printwriter; import java.io.stringreader; import java.util.hashmap; import java.util.list; import java.util.map; import javax.servlet.http.httpservletrequest; import javax.servlet.http.httpservletresponse; import org.jdom.document; import org.jdom.element; import org.jdom.jdomexception; import org.jdom.input.saxbuilder; import org.xml.sax.inputsource; import com.wellness.platfront.entity.weixin.unifiedorderresult; import com.wellness.platfront.entity.weixin.wxpayresult; /** * 微信解析xml:带有cdata格式的 * @author * @date 2017/08/10 */ public class jdomparsexmlutils { /** * 1、统一下单获取微信返回 * 解析的时候自动去掉cdma * @param xml */ @suppresswarnings("unchecked") public static unifiedorderresult getunifiedorderresult(string xml){ unifiedorderresult unifieorderresult = new unifiedorderresult(); try { stringreader read = new stringreader(xml); // 创建新的输入源sax 解析器将使用 inputsource 对象来确定如何读取 xml 输入 inputsource source = new inputsource(read); // 创建一个新的saxbuilder saxbuilder sb = new saxbuilder(); // 通过输入源构造一个document document doc; doc = (document) sb.build(source); element root = doc.getrootelement();// 指向根节点 list<element> list = root.getchildren(); if(list!=null&&list.size()>0){ for (element element : list) { system.out.println("key是:"+element.getname()+",值是:"+element.gettext()); if("return_code".equals(element.getname())){ unifieorderresult.setreturn_code(element.gettext()); } if("return_msg".equals(element.getname())){ unifieorderresult.setreturn_msg(element.gettext()); } if("appid".equals(element.getname())){ unifieorderresult.setappid(element.gettext()); } if("mch_id".equals(element.getname())){ unifieorderresult.setmch_id(element.gettext()); } if("nonce_str".equals(element.getname())){ unifieorderresult.setnonce_str(element.gettext()); } if("sign".equals(element.getname())){ unifieorderresult.setsign(element.gettext()); } if("result_code".equals(element.getname())){ unifieorderresult.setresult_code(element.gettext()); } if("prepay_id".equals(element.getname())){ unifieorderresult.setprepay_id(element.gettext()); } if("trade_type".equals(element.getname())){ unifieorderresult.settrade_type(element.gettext()); } } } } catch (jdomexception e) { e.printstacktrace(); } catch (ioexception e) { e.printstacktrace(); }catch (exception e) { e.printstacktrace(); } return unifieorderresult; } /** * 获取微信回调的参数并将xml解析成map * 解析的时候自动去掉cdma * @param xml */ @suppresswarnings("unchecked") public static map<string, string> getweixinresult(httpservletrequest request,httpservletresponse response){ map<string, string> resultmap = new hashmap<>(); try { printwriter writer = response.getwriter(); 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); } outsteam.close(); instream.close(); string result = new string(outsteam.tobytearray(), "utf-8"); stringreader read = new stringreader(result); inputsource source = new inputsource(read); // 创建一个新的saxbuilder saxbuilder sb = new saxbuilder(); // 通过输入源构造一个document document doc; doc = (document) sb.build(source); element root = doc.getrootelement();// 指向根节点 list<element> list = root.getchildren(); if(list!=null&&list.size()>0){ for (element element : list) { resultmap.put(element.getname(), element.gettext()); } } return resultmap; } catch (exception e) { e.printstacktrace(); } return null; } /** * 2、微信回调后参数解析 * 解析的时候自动去掉cdma * @param xml */ @suppresswarnings("unchecked") public static wxpayresult getwxpayresult(string xml){ wxpayresult wxpayresult = new wxpayresult(); try { stringreader read = new stringreader(xml); // 创建新的输入源sax 解析器将使用 inputsource 对象来确定如何读取 xml 输入 inputsource source = new inputsource(read); // 创建一个新的saxbuilder saxbuilder sb = new saxbuilder(); // 通过输入源构造一个document document doc; doc = (document) sb.build(source); element root = doc.getrootelement();// 指向根节点 list<element> list = root.getchildren(); if(list!=null&&list.size()>0){ for (element element : list) { if("return_code".equals(element.getname())){ wxpayresult.setreturn_code(element.gettext()); } if("return_msg".equals(element.getname())){ wxpayresult.setreturn_msg(element.gettext()); } if("appid".equals(element.getname())){ wxpayresult.setappid(element.gettext()); } if("mch_id".equals(element.getname())){ wxpayresult.setmch_id(element.gettext()); } if("nonce_str".equals(element.getname())){ wxpayresult.setnonce_str(element.gettext()); } if("sign".equals(element.getname())){ wxpayresult.setsign(element.gettext()); } if("result_code".equals(element.getname())){ wxpayresult.setresult_code(element.gettext()); } if("return_msg".equals(element.getname())){ wxpayresult.setreturn_msg(element.gettext()); } if("return_msg".equals(element.getname())){ wxpayresult.setreturn_msg(element.gettext()); } if("return_msg".equals(element.getname())){ wxpayresult.setreturn_msg(element.gettext()); } if("return_msg".equals(element.getname())){ wxpayresult.setreturn_msg(element.gettext()); } if("return_msg".equals(element.getname())){ wxpayresult.setreturn_msg(element.gettext()); } if("return_msg".equals(element.getname())){ wxpayresult.setreturn_msg(element.gettext()); } if("return_msg".equals(element.getname())){ wxpayresult.setreturn_msg(element.gettext()); } if("return_msg".equals(element.getname())){ wxpayresult.setreturn_msg(element.gettext()); } } } } catch (jdomexception e) { e.printstacktrace(); } catch (ioexception e) { e.printstacktrace(); }catch (exception e) { e.printstacktrace(); } return wxpayresult; } }
package com.wellness.platfront.common.weixinutil; /** * dom解析 * @author * @date 2017/08/10 */ import java.io.ioexception; import java.io.stringreader; import java.util.iterator; import java.util.list; import org.apache.commons.lang.stringutils; import org.dom4j.document; import org.dom4j.documentexception; import org.dom4j.documenthelper; import org.dom4j.element; import org.dom4j.io.saxreader; import org.jdom.jdomexception; import org.jdom.input.saxbuilder; import org.xml.sax.inputsource; public class parsexmlutils { /** * 1、dom解析 */ @suppresswarnings("rawtypes") public static void beginxmlparse(string xml){ document doc = null; try { doc = documenthelper.parsetext(xml); // 将字符串转为xml element rootelt = doc.getrootelement(); // 获取根节点smsreport system.out.println("根节点是:"+rootelt.getname()); iterator iters = rootelt.elementiterator("sendresp"); // 获取根节点下的子节点sms while (iters.hasnext()) { element recordele1 = (element) iters.next(); iterator iter = recordele1.elementiterator("sms"); while (iter.hasnext()) { element recordele = (element) iter.next(); string phone = recordele.elementtexttrim("phone"); // 拿到sms节点下的子节点stat值 string smsid = recordele.elementtexttrim("smsid"); // 拿到sms节点下的子节点stat值 system.out.println(phone+":"+smsid); } } } catch (documentexception e) { e.printstacktrace(); } catch (exception e) { e.printstacktrace(); } } /** * 2、dom4j解析xml(支持xpath) * 解析的时候自动去掉cdma * @param xml */ public static void xpathparsexml(string xml){ try { stringreader read = new stringreader(xml); saxreader saxreader = new saxreader(); document doc = saxreader.read(read); string xpath ="/xml/appid"; system.out.print(doc.selectsinglenode(xpath).gettext()); } catch (documentexception e) { e.printstacktrace(); } } /** * 3、jdom解析xml * 解析的时候自动去掉cdma * @param xml */ @suppresswarnings("unchecked") public static void jdomparsexml(string xml){ try { stringreader read = new stringreader(xml); // 创建新的输入源sax 解析器将使用 inputsource 对象来确定如何读取 xml 输入 inputsource source = new inputsource(read); // 创建一个新的saxbuilder saxbuilder sb = new saxbuilder(); // 通过输入源构造一个document org.jdom.document doc; doc = (org.jdom.document) sb.build(source); org.jdom.element root = doc.getrootelement();// 指向根节点 list<org.jdom.element> list = root.getchildren(); if(list!=null&&list.size()>0){ for (org.jdom.element element : list) { /*try{ methodname = element.getname(); method m = v.getclass().getmethod("set" + methodname, new class[] { string.class }); if(parseint(methodname)){ m.invoke(v, new object[] { integer.parseint(element.gettext()) }); }else{ m.invoke(v, new object[] { element.gettext() }); } }catch(exception ex){ ex.printstacktrace(); }*/ } } } catch (jdomexception e) { e.printstacktrace(); } catch (ioexception e) { e.printstacktrace(); }catch (exception e) { e.printstacktrace(); } } public static boolean parseint(string key){ if(!stringutils.isempty(key)){ if(key.equals("total_fee")||key.equals("cash_fee")||key.equals("coupon_fee")||key.equals("coupon_count")||key.equals("coupon_fee_0")){ return true; } } return false; } }
微信支付相关的常量
package com.wellness.platfront.common.weixinutil; /** * 微信支付相关的常量 * @author yangfuren * @since 2017/08/16 */ public class weixinconstant { /** * 微信支付api秘钥 */ public static final string key = "eao9gdbk7njqkyevrfb82csputiniwnd"; /** * url */ public static final string url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; /** * 退款url */ public static final string refund_url = "https://api.mch.weixin.qq.com/secapi/pay/refund"; /** * 证书地址 */ public static final string path =""; /** * 付款url */ public static final string withdraw_url="https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers"; }
微信退款状态常量
package com.wellness.platfront.common.weixinutil; /** * 微信退款状态常量 * @author * @since 2017/09/04 */ public class weixinrefundstatusconstant { //退款申请成功 public static final string apply_success="退款申请成功"; //退款申请失败 public static final string apply_fail="退款申请失败"; //退款成功 public static final string refund_success="退款成功"; //退款异常 public static final string refund_fail="退款异常"; //退款关闭 public static final string refund_closed="退款关闭"; }
微信退款订单信息
package com.wellness.platfront.entity.weixin; import java.io.serializable; import java.util.date; import javax.persistence.column; import javax.persistence.entity; import javax.persistence.generatedvalue; import javax.persistence.generationtype; import javax.persistence.id; import javax.persistence.table; /** * 微信退款订单信息 * @author * */ @entity @table(name = "weixin_refund_order") public class refundorder implements serializable{ private static final long serialversionuid = 1l; //退款订单id public integer refundorderid; //微信公众账号 public string appid; //微信商户号 public string mch_id; //微信订单号 public string transaction_id; //商户订单号 public string out_trade_no; //商户退款单号 public string out_refund_no; //微信退款单号 public string refund_id; //退款金额 public integer refund_fee; //订单总价格 public integer tatol_fee; //退款发起时间 public date create_time; //退款状态 申请退款中 申请退款失败 退款成功 退款异常 退款关闭 public string refund_status; //退款退还账户 public string refund_rew_account; //退款完成时间 public date end_time; //订单退还方式 public string refundtype; @id @generatedvalue(strategy = generationtype.auto) @column(name = "refund_order_id", nullable = false) public integer getrefundorderid() { return refundorderid; } public void setrefundorderid(integer refundorderid) { this.refundorderid = refundorderid; } @column(name = "appid", nullable = false) public string getappid() { return appid; } public void setappid(string appid) { this.appid = appid; } @column(name = "mch_id", nullable = false) public string getmch_id() { return mch_id; } public void setmch_id(string mch_id) { this.mch_id = mch_id; } @column(name = "transaction_id", nullable = false) public string gettransaction_id() { return transaction_id; } public void settransaction_id(string transaction_id) { this.transaction_id = transaction_id; } @column(name = "out_trade_no", nullable = false) 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; } @column(name = "out_refund_no", nullable = false) public string getout_refund_no() { return out_refund_no; } public void setout_refund_no(string out_refund_no) { this.out_refund_no = out_refund_no; } @column(name = "refund_id", nullable = false) public string getrefund_id() { return refund_id; } public void setrefund_id(string refund_id) { this.refund_id = refund_id; } @column(name = "refund_fee", nullable = false) public integer getrefund_fee() { return refund_fee; } public void setrefund_fee(integer refund_fee) { this.refund_fee = refund_fee; } @column(name = "tatol_fee", nullable = false) public integer gettatol_fee() { return tatol_fee; } public void settatol_fee(integer tatol_fee) { this.tatol_fee = tatol_fee; } @column(name = "create_time", nullable = false) public date getcreate_time() { return create_time; } public void setcreate_time(date create_time) { this.create_time = create_time; } @column(name = "refund_status", nullable = false) public string getrefund_status() { return refund_status; } public void setrefund_status(string refund_status) { this.refund_status = refund_status; } @column(name = "refund_rew_account") public string getrefund_rew_account() { return refund_rew_account; } public void setrefund_rew_account(string refund_rew_account) { this.refund_rew_account = refund_rew_account; } @column(name = "end_time") public date getend_time() { return end_time; } public void setend_time(date end_time) { this.end_time = end_time; } @column(name = "refund_type") public string getrefundtype() { return refundtype; } public void setrefundtype(string refundtype) { this.refundtype = refundtype; } }
这个实体类中参数和微信官方需要的参数一致
package com.wellness.platfront.entity.weixin; import java.io.serializable; import com.wellness.platfront.entity.member.member; /** * 统一下单提交为微信的参数 * @author * @date 2017年08月11日 */ public class unifiedorder implements serializable{ private static final long serialversionuid = 1l; //微信支付表id private integer weixinid; //微信分配的公众账号id(企业号corpid即为此appid) private string appid; //商户id private string mch_id; //终端设备号(门店号或收银设备id),注意:pc网页或公众号内支付请传"web" private string device_info; //随机字符串:数字+大写字母的组合,32位 private string nonce_str; //签名 private string sign; //商品或支付单简要描述 private string body; //商品名称明细列表 private string detail; //附加参数(例如:用于区别本商户不同的分店) private string attach; //商户系统内部的订单号 private string out_trade_no; //货币类型:符合iso 4217标准的三位字母代码,默认人民币:cny private string fee_type; //总金额 private int total_fee; //app和网页支付提交[用户端ip],native支付填调用微信支付api的机器ip。 private string spbill_create_ip; //订单生成时间,格式为yyyymmddhhmmss, private string time_start; //订单失效时间,格式为yyyymmddhhmmss,最短失效时间间隔必须大于5分钟[支付宝是30分钟,同样30分钟] private string time_expire; //商品标记,代金券或立减优惠功能的参数 private string goods_tag; //接收微信支付异步通知回调地址 private string notify_url; //交易类型:jsapi,native,app h5为 mweb private string trade_type; //trade_type=native,此参数必传。此id为二维码中包含的商品id,商户自行定义。 private string product_id; //no_credit--指定不能使用信用卡支付 private string limit_pay; //trade_type=jsapi,此参数必传,用户在商户appid下的唯一标识 private string openid; //商户内部自己的退款单号 private string out_refund_no; //退款总金额单位为分 private int refund_fee; //操作员的id默认为mch_id private string op_user_id; //微信官方提供的订单号 private string prepayid; //记录所对应的member private member member; //返回给微信的状态码(用于支付回调时) public string return_code; //微信h5支付时候的场景信息官方的信息模板 {"h5_info"://h5支付固定传"h5_info" //{"type":"",//场景类型 "wap_url":"",//wap网站url地址"wap_name": ""//wap 网站名}} public string scene_info; public string getscene_info() { return scene_info; } public void setscene_info(string scene_info) { this.scene_info = scene_info; } public string getreturn_code() { return return_code; } public void setreturn_code(string return_code) { this.return_code = return_code; } public string getappid() { return appid; } public string getmch_id() { return mch_id; } public string getdevice_info() { return device_info; } public string getnonce_str() { return nonce_str; } public string getsign() { return sign; } public string getbody() { return body; } public string getdetail() { return detail; } public string getattach() { return attach; } public string getout_trade_no() { return out_trade_no; } public string getfee_type() { return fee_type; } public int gettotal_fee() { return total_fee; } public string getspbill_create_ip() { return spbill_create_ip; } public string gettime_start() { return time_start; } public string gettime_expire() { return time_expire; } public string getgoods_tag() { return goods_tag; } public string getnotify_url() { return notify_url; } public string gettrade_type() { return trade_type; } public string getproduct_id() { return product_id; } public string getlimit_pay() { return limit_pay; } public string getopenid() { return openid; } public void setappid(string appid) { this.appid = appid; } public void setmch_id(string mch_id) { this.mch_id = mch_id; } public void setdevice_info(string device_info) { this.device_info = device_info; } public void setnonce_str(string nonce_str) { this.nonce_str = nonce_str; } public void setsign(string sign) { this.sign = sign; } public void setbody(string body) { this.body = body; } public void setdetail(string detail) { this.detail = detail; } public void setattach(string attach) { this.attach = attach; } public void setout_trade_no(string out_trade_no) { this.out_trade_no = out_trade_no; } public void setfee_type(string fee_type) { this.fee_type = fee_type; } public void settotal_fee(int total_fee) { this.total_fee = total_fee; } public void setspbill_create_ip(string spbill_create_ip) { this.spbill_create_ip = spbill_create_ip; } public void settime_start(string time_start) { this.time_start = time_start; } public void settime_expire(string time_expire) { this.time_expire = time_expire; } public void setgoods_tag(string goods_tag) { this.goods_tag = goods_tag; } public void setnotify_url(string notify_url) { this.notify_url = notify_url; } public void settrade_type(string trade_type) { this.trade_type = trade_type; } public void setproduct_id(string product_id) { this.product_id = product_id; } public void setlimit_pay(string limit_pay) { this.limit_pay = limit_pay; } public void setopenid(string openid) { this.openid = openid; } public string getout_refund_no() { return out_refund_no; } public void setout_refund_no(string out_refund_no) { this.out_refund_no = out_refund_no; } public int getrefund_fee() { return refund_fee; } public void setrefund_fee(int refund_fee) { this.refund_fee = refund_fee; } public integer getweixinid() { return weixinid; } public void setweixinid(integer weixinid) { this.weixinid = weixinid; } public member getmember() { return member; } public void setmember(member member) { this.member = member; } public string getprepayid() { return prepayid; } public void setprepayid(string prepayid) { this.prepayid = prepayid; } public string getop_user_id() { return op_user_id; } public void setop_user_id(string op_user_id) { this.op_user_id = op_user_id; } }
统一下单微信返回的参数组(xml)
package com.wellness.platfront.entity.weixin; /** * 统一下单微信返回的参数组(xml) * @author * @date 2017年08月11日 */ public class unifiedorderresult { private string appid;//appid private string mch_id;//商家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;//调用接口提交的交易类型,取值如下:jsapi,native,app private string prepay_id;//微信生成的预支付回话标识,用于后续接口调用中使用,该值有效期为2小时 private string code_url;//trade_type为native是有返回,可将该参数值生成二维码展示出来进行扫码支付 private string return_code;//返回状态码success/fail此字段是通信标识,非交易标识,交易是否成功需要查看result_code来判断 private string return_msg;//返回信息 public string getappid() { return appid; } public string getmch_id() { return mch_id; } public string getdevice_info() { return device_info; } public string getnonce_str() { return nonce_str; } public string getsign() { return sign; } public string getresult_code() { return result_code; } public string geterr_code() { return err_code; } public string geterr_code_des() { return err_code_des; } public string gettrade_type() { return trade_type; } public string getprepay_id() { return prepay_id; } public string getcode_url() { return code_url; } public void setappid(string appid) { this.appid = appid; } public void setmch_id(string mch_id) { this.mch_id = mch_id; } public void setdevice_info(string device_info) { this.device_info = device_info; } public void setnonce_str(string nonce_str) { this.nonce_str = nonce_str; } public void setsign(string sign) { this.sign = sign; } public void setresult_code(string result_code) { this.result_code = result_code; } public void seterr_code(string err_code) { this.err_code = err_code; } public void seterr_code_des(string err_code_des) { this.err_code_des = err_code_des; } public void settrade_type(string trade_type) { this.trade_type = trade_type; } public void setprepay_id(string prepay_id) { this.prepay_id = prepay_id; } public void setcode_url(string code_url) { this.code_url = code_url; } public string getreturn_code() { return return_code; } public string getreturn_msg() { return return_msg; } public void setreturn_code(string return_code) { this.return_code = return_code; } public void setreturn_msg(string return_msg) { this.return_msg = return_msg; } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。