微信开发文档地址:https://pay.weixin.qq.com/wiki/doc/api/index.html
接口链接
URL地址:https://api.mch.weixin.qq.com/pay/unifiedorder
是否需要证书
不需要
1 package com.kpcx.pay.weixin; 2 3 import java.io.IOException; 4 import java.net.URLDecoder; 5 import java.util.ResourceBundle; 6 import java.util.SortedMap; 7 import java.util.TreeMap; 8 import javax.servlet.ServletException; 9 import javax.servlet.annotation.WebServlet; 10 import javax.servlet.http.HttpServlet; 11 import javax.servlet.http.HttpServletRequest; 12 import javax.servlet.http.HttpServletResponse; 13 import org.dom4j.DocumentException; 14 import com.alibaba.fastjson.JSONObject; 15 import com.kpcx.controller.NotifyController; 16 import com.kpcx.pay.weixin.entity.OrderCreateRequest; 17 import com.kpcx.util.HttpXmlUtils; 18 import com.kpcx.util.RandCharsUtils; 19 import com.kpcx.util.Tool; 20 import com.kpcx.util.WXSignUtils; 21 22 /** 23 * 微信创建订单接口 24 * 先调用该接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易回话标识后再在APP里面调起支付 25 */ 26 @WebServlet("/create/WxCreate") 27 public class WxOrderCreate extends HttpServlet { 28 private static final long serialVersionUID = 1L; 29 30 31 /** 32 * 微信创建订单接口 33 */ 34 protected void doGet(HttpServletRequest request, HttpServletResponse response) 35 throws ServletException, IOException { 36 // 接受参数 37 String param = URLDecoder.decode(request.getParameter("param"),"UTF-8"); 38 // 转成javabean 39 OrderCreateRequest orderCreate = JSONObject.parseObject(param, OrderCreateRequest.class); 40 NotifyController nController = new NotifyController(); 41 String payMoney = Tool.fenToYuan(orderCreate.getTotal_fee()); 42 //校验订单 43 String checkOrders = nController.checkOrders(orderCreate.getOut_trade_no(), payMoney); 44 JSONObject checkData = JSONObject.parseObject(checkOrders); 45 String code = checkData.getString("Code"); 46 //订单校验通过 47 if(code != null && "0".equals(code)){ 48 // 参数:开始生成签名 49 // 获取配置文件 50 ResourceBundle resource = ResourceBundle.getBundle("weixin"); 51 //随机字符串 52 String nonce_str = RandCharsUtils.getRandomString(16); 53 //订单开始时间 54 String timeStart = RandCharsUtils.timeStart(); 55 //订单结束时间 56 String timeExpire = RandCharsUtils.timeExpire(); 57 58 SortedMap<Object, Object> parameters = new TreeMap<Object, Object>(); 59 parameters.put("appid", resource.getString("appid")); 60 parameters.put("mch_id", resource.getString("mch_id")); 61 parameters.put("nonce_str", nonce_str); 62 parameters.put("body", orderCreate.getBody()); 63 parameters.put("detail", orderCreate.getDetail()); 64 parameters.put("attach", orderCreate.getAttach()); 65 parameters.put("out_trade_no", orderCreate.getOut_trade_no()); 66 parameters.put("total_fee", orderCreate.getTotal_fee()); 67 parameters.put("time_start", timeStart); 68 parameters.put("time_expire", timeExpire); 69 parameters.put("notify_url", resource.getString("notify_url")); 70 parameters.put("trade_type", orderCreate.getTrade_type()); 71 parameters.put("spbill_create_ip", orderCreate.getSpbill_create_ip()); 72 parameters.put("scene_info", orderCreate.getScene_info()); 73 //生成微信签名 74 String sign = WXSignUtils.createSign("UTF-8", parameters); 75 76 // 参数转换成xml格式 77 orderCreate.setAppid(resource.getString("appid")); 78 orderCreate.setMch_id(resource.getString("mch_id")); 79 orderCreate.setNonce_str(nonce_str); 80 orderCreate.setTime_start(timeStart); 81 orderCreate.setTime_expire(timeExpire); 82 orderCreate.setNotify_url(resource.getString("notify_url")); 83 orderCreate.setSign(sign); 84 85 //参数转换成xml格式 86 String xmlInfo = HttpXmlUtils.xmlInfo(orderCreate); 87 String method = "POST"; 88 //请求微信下单 返回值是xml类型的字符串 89 String json = HttpXmlUtils.httpsRequest(resource.getString("wxUrl"), method, xmlInfo).toString(); 90 //xml 转json 91 String result = ""; 92 try { 93 result = Tool.xmlChangeJson(json); 94 } catch (DocumentException e) { 95 // TODO Auto-generated catch block 96 e.printStackTrace(); 97 } 98 JSONObject resultTemp = new JSONObject(); 99 JSONObject object = JSONObject.parseObject(result); 100 if("SUCCESS".equals(object.getString("return_code"))){ 101 object.put("createTime", System.currentTimeMillis()/1000); 102 object.put("package", "Sign=WXPay"); 103 //生成签名给前端 104 SortedMap<Object,Object> parameters1 = new TreeMap<Object,Object>(); 105 parameters1.put("appid", object.getString("appid")); 106 parameters1.put("noncestr", object.getString("nonce_str")); 107 parameters1.put("package",object.getString("package")); 108 parameters1.put("partnerid", object.getString("mch_id")); 109 parameters1.put("prepayid", object.getString("prepay_id")); 110 parameters1.put("timestamp",object.getString("createTime")); 111 sign = WXSignUtils.createSign("UTF-8", parameters1); 112 //转化返回值的格式 113 resultTemp.put("Code", "0"); 114 object.put("sign", sign); 115 resultTemp.put("Result", object); 116 }else{ 117 resultTemp.put("Code", "-1"); 118 resultTemp.put("Result", object); 119 } 120 response.getWriter().write(resultTemp.toJSONString()); 121 //结果返回到filter,记录到日志中 122 request.setAttribute("outStr", resultTemp.toJSONString()); 123 }else{ 124 response.getWriter().write(checkOrders); 125 //结果返回到filter,记录到日志中 126 request.setAttribute("outStr", checkOrders); 127 } 128 129 } 130 131 /** 132 * post方法 133 */ 134 protected void doPost(HttpServletRequest request, HttpServletResponse response) 135 throws ServletException, IOException { 136 // TODO Auto-generated method stub 137 doGet(request, response); 138 } 139 140 }
package com.kpcx.util;
import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.DESKeySpec; import javax.crypto.spec.IvParameterSpec; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.DocumentHelper; import org.dom4j.Element; public class Tool {// 这个方法是将xml字符串转成Json public static String xmlChangeJson(String XML) throws DocumentException { Document document = DocumentHelper.parseText(XML); Element root = document.getRootElement(); Iterator it = root.elementIterator(); String json = "{"; while (it.hasNext()) { Element element = (Element) it.next(); String j = checkChildEle(element); if (j == "") { json += "\"" + element.getName() + "\":\"" + element.getText() + "\","; } else { json += j; } } json = json.substring(0, json.length() - 1); json += "}"; return json; } /** * * 功能描述:金额字符串转换:单位分转成单元 * * @param str * 传入需要转换的金额字符串 * @return 转换后的金额字符串 */ public static String fenToYuan(Object o) { if (o == null) { return "0.00"; } String s = o.toString(); int len = -1; StringBuilder sb = new StringBuilder(); if (s != null && s.trim().length() > 0 && !s.equalsIgnoreCase("null")) { s = removeZero(s); if (s != null && s.trim().length() > 0 && !s.equalsIgnoreCase("null")) { len = s.length(); int tmp = s.indexOf("-"); if (tmp >= 0) { if (len == 2) { sb.append("-0.0").append(s.substring(1)); } else if (len == 3) { sb.append("-0.").append(s.substring(1)); } else { sb.append(s.substring(0, len - 2)).append(".").append(s.substring(len - 2)); } } else { if (len == 1) { sb.append("0.0").append(s); } else if (len == 2) { sb.append("0.").append(s); } else { sb.append(s.substring(0, len - 2)).append(".").append(s.substring(len - 2)); } } } else { sb.append("0.00"); } } else { sb.append("0.00"); } return sb.toString(); } /** * * 功能描述:金额字符串转换:单位元转成单分 * * @param str * 传入需要转换的金额字符串 * @return 转换后的金额字符串 */ public static String yuanToFen(Object o) { if (o == null) return "0"; String s = o.toString(); int posIndex = -1; String str = ""; StringBuilder sb = new StringBuilder(); if (s != null && s.trim().length() > 0 && !s.equalsIgnoreCase("null")) { posIndex = s.indexOf("."); if (posIndex > 0) { int len = s.length(); if (len == posIndex + 1) { str = s.substring(0, posIndex); if (str == "0") { str = ""; } sb.append(str).append("00"); } else if (len == posIndex + 2) { str = s.substring(0, posIndex); if (str == "0") { str = ""; } sb.append(str).append(s.substring(posIndex + 1, posIndex + 2)).append("0"); } else if (len == posIndex + 3) { str = s.substring(0, posIndex); if (str == "0") { str = ""; } sb.append(str).append(s.substring(posIndex + 1, posIndex + 3)); } else { str = s.substring(0, posIndex); if (str == "0") { str = ""; } sb.append(str).append(s.substring(posIndex + 1, posIndex + 3)); } } else { sb.append(s).append("00"); } } else { sb.append("0"); } str = removeZero(sb.toString()); if (str != null && str.trim().length() > 0 && !str.trim().equalsIgnoreCase("null")) { return str; } else { return "0"; } } /** * * 功能描述:去除字符串首部为"0"字符 * * @param str * 传入需要转换的字符串 * @return 转换后的字符串 */ public static String removeZero(String str) { char ch; String result = ""; if (str != null && str.trim().length() > 0 && !str.trim().equalsIgnoreCase("null")) { try { for (int i = 0; i < str.length(); i++) { ch = str.charAt(i); if (ch != '0') { result = str.substring(i); break; } } } catch (Exception e) { result = ""; } } else { result = ""; } return result; } /** * @Title: 获取sign加密时需要的字符串 * @author: Administrator * @param: @param t * @return:String */ public static <T> String getSignParam(T t) throws IllegalArgumentException, IllegalAccessException { List<String> names = new ArrayList<>(); Map<String, Object> maps = new HashMap<>(); // ----------------参数名变小写 升序排序----------------- Class c = t.getClass(); Field[] fs = c.getDeclaredFields(); for (int i = 0; i < fs.length; i++) { Field f = fs[i]; f.setAccessible(true); // 设置些属性是可以访问的 String name = f.getName(); Object val = f.get(t); if (val != null && !"".equals(val) && !"null".equals(val)) { name = name.toLowerCase(); names.add(name); maps.put(name, val); } } Collections.sort(names); StringBuffer strAsc = new StringBuffer();// 按照参数升序后的字符串 for (int i = 0; i < names.size(); i++) { if (i != names.size() - 1) { strAsc.append(names.get(i) + "=" + maps.get(names.get(i)) + "&"); } else { strAsc.append(names.get(i) + "=" + maps.get(names.get(i))); } } return strAsc.toString(); } }
package com.kpcx.pay.weixin.entity; /** * 统一下单提交为微信的参数 * @author iYjrg_xiebin * @date 2015年11月26日上午10:17:06 */ public class OrderCreateRequest { private String appid;//微信分配的公众账号ID(企业号corpid即为此appId),例如:wxd678efh567hg6787 private String mch_id;//商户id private String device_info;//终端设备号(门店号或收银设备ID),注意:PC网页或公众号内支付请传"WEB" private String nonce_str;//随机字符串:数字+大写字母的组合,32位 private String sign;//签名 private String body;//商品或支付单简要描述 private String detail;//商品名称明细列表 private String attach;//附加参数 private String out_trade_no;//商户系统内部的订单号 private String fee_type;//货币类型:符合ISO 4217标准的三位字母代码,默认人民币:CNY private int total_fee;//总金额 private String spbill_create_ip;//APP和网页支付提交[用户端ip],Native支付填调用微信支付API的机器IP。 private String time_start;//订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010 private String time_expire;//订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010;最短失效时间间隔必须大于5分钟[支付宝是30分钟,同样30分钟] private String goods_tag;//商品标记,代金券或立减优惠功能的参数 private String notify_url;//接收微信支付异步通知回调地址 private String trade_type;//交易类型:JSAPI,NATIVE,APP private String product_id;//trade_type=NATIVE,此参数必传。此id为二维码中包含的商品ID,商户自行定义。 private String limit_pay;//no_credit--指定不能使用信用卡支付 private String openid;//trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识 private String scene_info;//上报支付的场景信息 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 getScene_info() { return scene_info; } public void setScene_info(String scene_info) { this.scene_info = scene_info; } }
package com.kpcx.util; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.Random; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * nonce_str随即字符串 * @author iYjrg_xiebin * @date 2015年11月25日下午5:10:32 */ 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()); } public static void main(String[] args) { /*for (int i = 0; i < 10; i++) { System.out.println("第"+i+"次是:"+getRandomString(32)); }*/ System.out.println(getRandomString(16)); // System.out.println("开始时间是:"+timeStart()); // System.out.println("开始时间是:"+timeExpire()); } /** * 获取编码字符集 * @param request * @param response * @return String */ public static String getCharacterEncoding(HttpServletRequest request, HttpServletResponse response) { if(null == request || null == response) { return "gbk"; } String enc = request.getCharacterEncoding(); if(null == enc || "".equals(enc)) { enc = response.getCharacterEncoding(); } if(null == enc || "".equals(enc)) { enc = "gbk"; } return enc; } }
package com.kpcx.util; import java.util.Iterator; import java.util.Map; import java.util.ResourceBundle; import java.util.Set; import java.util.SortedMap; import com.kpcx.pay.weixin.entity.NotifyResult; /** * 微信支付签名 * @author iYjrg_xiebin * @date 2015年11月25日下午4:47:07 */ public class WXSignUtils { //http://mch.weixin.qq.com/wiki/doc/api/index.php?chapter=4_3 //商户Key:改成公司申请的即可 //32位密码设置地址:http://www.sexauth.com/ jdex1hvufnm1sdcb0e81t36k0d0f15nc static ResourceBundle rb = ResourceBundle.getBundle("weixin"); private static String Key = rb.getString("key"); /** * 微信支付签名算法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=" + Key); // System.out.println("字符串拼接后是:"+sb.toString()); String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase(); return sign; } /** * @Title: 签名算法方法 * @author: Administrator * @param: @param characterEncoding 字符编码 * @param: @param notifyResult 回调参数实体类 * @return:String */ public static String createSign(String characterEncoding,NotifyResult notifyResult) throws IllegalArgumentException, IllegalAccessException{ StringBuffer sb = new StringBuffer(); String getValue = ""; try { getValue = Tool.getSignParam(notifyResult); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } sb.append(getValue); sb.append("&key=" + Key); // System.out.println("字符串拼接后是:"+sb.toString()); String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase(); return sign; } }
package com.kpcx.util; 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.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import javax.net.ssl.HttpsURLConnection; import com.kpcx.pay.weixin.entity.OrderCreateRequest; import com.kpcx.pay.weixin.entity.OrderRefundCondition; import net.sf.json.JSONObject; /** * post提交xml格式的参数 * @author 孟丛丛 * @date 2015年11月25日下午3:33:38 */ public class HttpXmlUtils { /** * 开始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; } /** * 构造xml参数 * @param xml * @return */ public static String xmlInfo(OrderCreateRequest orderCreate){ //构造xml参数的时候,至少又是个必传参数 /* * <xml> <appid>wx2421b1c4370ec43b</appid> <attach>支付测试</attach> <body>JSAPI支付测试</body> <mch_id>10000100</mch_id> <nonce_str>1add1a30ac87aa2db72f57a2375d8fec</nonce_str> <notify_url>http://wxpay.weixin.qq.com/pub_v2/pay/notify.v2.php</notify_url> <openid>oUpF8uMuAJO_M2pxb1Q9zNjWeS6o</openid> <out_trade_no>1415659990</out_trade_no> <spbill_create_ip>14.23.150.211</spbill_create_ip> <total_fee>1</total_fee> <trade_type>JSAPI</trade_type> <sign>0CB01533B8C1EF103065174F50BCA001</sign> </xml> */ if(orderCreate!=null){ StringBuffer bf = new StringBuffer(); bf.append("<xml>"); bf.append("<appid><![CDATA["); bf.append(orderCreate.getAppid()); bf.append("]]></appid>"); bf.append("<mch_id><![CDATA["); bf.append(orderCreate.getMch_id()); bf.append("]]></mch_id>"); bf.append("<nonce_str><![CDATA["); bf.append(orderCreate.getNonce_str()); bf.append("]]></nonce_str>"); bf.append("<sign><![CDATA["); bf.append(orderCreate.getSign()); bf.append("]]></sign>"); bf.append("<body><![CDATA["); bf.append(orderCreate.getBody()); bf.append("]]></body>"); bf.append("<detail><![CDATA["); bf.append(orderCreate.getDetail()); bf.append("]]></detail>"); bf.append("<attach><![CDATA["); bf.append(orderCreate.getAttach()); bf.append("]]></attach>"); bf.append("<out_trade_no><![CDATA["); bf.append(orderCreate.getOut_trade_no()); bf.append("]]></out_trade_no>"); bf.append("<total_fee><![CDATA["); bf.append(orderCreate.getTotal_fee()); bf.append("]]></total_fee>"); bf.append("<spbill_create_ip><![CDATA["); bf.append(orderCreate.getSpbill_create_ip()); bf.append("]]></spbill_create_ip>"); bf.append("<time_start><![CDATA["); bf.append(orderCreate.getTime_start()); bf.append("]]></time_start>"); bf.append("<time_expire><![CDATA["); bf.append(orderCreate.getTime_expire()); bf.append("]]></time_expire>"); bf.append("<notify_url><![CDATA["); bf.append(orderCreate.getNotify_url()); bf.append("]]></notify_url>"); bf.append("<trade_type><![CDATA["); bf.append(orderCreate.getTrade_type()); bf.append("]]></trade_type>"); bf.append("</xml>"); return bf.toString(); } return ""; } /** * @Title: 查询订单请求参数转xml * @param: @param json */ public static String toXml(JSONObject json){ if(json!=null){ StringBuffer bf = new StringBuffer(); bf.append("<xml>"); bf.append("<appid><![CDATA["); bf.append(json.getString("appid")); bf.append("]]></appid>"); bf.append("<mch_id><![CDATA["); bf.append(json.getString("mch_id")); bf.append("]]></mch_id>"); bf.append("<nonce_str><![CDATA["); bf.append(json.getString("nonce_str")); bf.append("]]></nonce_str>"); bf.append("<sign><![CDATA["); bf.append(json.getString("sign")); bf.append("]]></sign>"); bf.append("<out_trade_no><![CDATA["); bf.append(json.getString("out_trade_no")); bf.append("]]></out_trade_no>"); bf.append("</xml>"); return bf.toString(); } return ""; } /** * @Title: 退款接口请求数据转成xml方法 * @author: gaohaijun * @param: @param orderRefund 退款接口参数实体类 * @return:String * @date:2017年6月19日上午9:14:01 */ public static String RefundXmlInfo(OrderRefundCondition orderRefund){ if(orderRefund != null){ StringBuffer bf = new StringBuffer(); bf.append("<xml>"); bf.append("<appid><![CDATA["); bf.append(orderRefund.getAppid()); bf.append("]]></appid>"); bf.append("<mch_id><![CDATA["); bf.append(orderRefund.getMch_id()); bf.append("]]></mch_id>"); bf.append("<nonce_str><![CDATA["); bf.append(orderRefund.getNonce_str()); bf.append("]]></nonce_str>"); bf.append("<out_refund_no><![CDATA["); bf.append(orderRefund.getOut_refund_no()); bf.append("]]></out_refund_no>"); bf.append("<out_trade_no><![CDATA["); bf.append(orderRefund.getOut_trade_no()); bf.append("]]></out_trade_no>"); bf.append("<refund_fee><![CDATA["); bf.append(orderRefund.getRefund_fee()); bf.append("]]></refund_fee>"); bf.append("<total_fee><![CDATA["); bf.append(orderRefund.getTotal_fee()); bf.append("]]></total_fee>"); bf.append("<refund_desc><![CDATA["); bf.append(orderRefund.getRefund_desc()); bf.append("]]></refund_desc>"); bf.append("<sign><![CDATA["); bf.append(orderRefund.getSign()); bf.append("]]></sign>"); 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 ""; } /** * 回调后将结果返回给微信 * @param return_code * @param return_msg * @return */ public static String backWeixin(String return_code,String return_msg){ try{ StringBuffer bf = new StringBuffer(); bf.append("<xml>"); bf.append("<return_code><![CDATA["); bf.append(return_code); bf.append("]]></return_code>"); bf.append("<return_msg><![CDATA["); bf.append(return_msg); bf.append("]]></return_msg>"); bf.append("</xml>"); return bf.toString(); }catch(Exception ex){ ex.printStackTrace(); } return ""; } /** * @Title: 查询对账订单请求参数转xml * @param: @param json */ public static String toBillXml(JSONObject json){ if(json!=null){ StringBuffer bf = new StringBuffer(); bf.append("<xml>"); bf.append("<appid><![CDATA["); bf.append(json.getString("appid")); bf.append("]]></appid>"); bf.append("<mch_id><![CDATA["); bf.append(json.getString("mch_id")); bf.append("]]></mch_id>"); bf.append("<nonce_str><![CDATA["); bf.append(json.getString("nonce_str")); bf.append("]]></nonce_str>"); bf.append("<sign><![CDATA["); bf.append(json.getString("sign")); bf.append("]]></sign>"); bf.append("<bill_date><![CDATA["); bf.append(json.getString("bill_date")); bf.append("]]></bill_date>"); bf.append("<bill_type><![CDATA["); bf.append(json.getString("bill_type")); bf.append("]]></bill_type>"); bf.append("</xml>"); return bf.toString(); } return ""; } }
二、微信回调
package com.kpcx.pay.weixin; import java.io.BufferedReader; import java.io.IOException; import java.io.PrintWriter; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.ResourceBundle; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringUtils; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.log4j.MDC; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.kpcx.controller.NotifyController; import com.kpcx.controller.RefundController; import com.kpcx.pay.weixin.entity.NotifyResult; import com.kpcx.service.PaymentService; import com.kpcx.service.impl.PaymentServiceImpl; import com.kpcx.util.HttpXmlUtils; import com.kpcx.util.JdomParseXmlUtils; import com.kpcx.util.MybatisUtil; import com.kpcx.util.Tool; import com.kpcx.util.WXSignUtils; import net.sf.json.JSONObject; /** * 微信支付回调接口 * * @author 孟丛丛 支付成功后,微信会回调我们把支付结果和用户信息发给我们 */ @WebServlet("/WxOrderNotify") public class WxOrderNotifyNew extends HttpServlet { private static final long serialVersionUID = 1L; ResourceBundle resource = ResourceBundle.getBundle("jkUrl"); /** * */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { NotifyController nController = new NotifyController(); Logger logger = LoggerFactory.getLogger(getClass()); PaymentService paymentService = new PaymentServiceImpl(); try { BufferedReader reader = request.getReader(); String line = ""; StringBuffer inputString = new StringBuffer(); try { PrintWriter writer = response.getWriter(); while ((line = reader.readLine()) != null) { inputString.append(line); } if (reader != null) { reader.close(); } logger.info("------------------------[微信回调]接收到的报文-----" + inputString.toString() + "----------------------"); if (!StringUtils.isEmpty(inputString.toString())) { NotifyResult notifyResult = JdomParseXmlUtils.getWXPayResult(inputString.toString()); String wxSign = notifyResult.getSign(); notifyResult.setSign(null); if ("SUCCESS".equals(notifyResult.getReturn_code()) && "SUCCESS".equals(notifyResult.getResult_code())) { // 查询订单详情 String ticketType = JSONObject.fromObject(notifyResult.getAttach()).getString("ticketType"); com.alibaba.fastjson.JSONObject orders = nController.OrderDetail(notifyResult.getOut_trade_no(),Integer.parseInt(ticketType)); if (!"0".equals(orders.getString("Code"))) { // 查不到这个订单 writer.write(HttpXmlUtils.backWeixin("FAIL", "无该订单信息")); } else { // 如果回调成功,进行服务器端订单处理 /** * 一系列的判断处理 * 1、查看该订单是否是自己的单子 * 2、查看该订单的支付状态是否是未支付 * 3、查看该订单的金额和支付宝返回的金额是否一致 * 4、保存支付数据 * 5、更新支付状态 * 6、判断完成、插完支付数据自己想要做的操作 * 注意:4、5部要加同步锁,防止几个回调同时对数据的操作 * */ logger.info("返回微信标志---" + HttpXmlUtils.backWeixin("SUCCESS", "OK")); writer.write(HttpXmlUtils.backWeixin("SUCCESS", "OK")); } else { writer.write(HttpXmlUtils.backWeixin("FAIL", "签名失败")); logger.info("-------微信反校验签名【失败】"); } } } else { writer.write(HttpXmlUtils.backWeixin("FAIL", notifyResult.getReturn_msg())); } if (writer != null) { writer.close(); } } else { writer.write(HttpXmlUtils.backWeixin("FAIL", "未获取到微信返回的结果")); } } catch (Exception e) { e.printStackTrace(); } } catch (Exception ex) { ex.printStackTrace(); } } /** * post请求 */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); } }
1 package com.kpcx.util; 2 3 import java.io.IOException; 4 import java.io.StringReader; 5 import java.util.List; 6 import org.jdom.Document; 7 import org.jdom.Element; 8 import org.jdom.JDOMException; 9 import org.jdom.input.SAXBuilder; 10 import org.xml.sax.InputSource; 11 import com.kpcx.pay.weixin.entity.OrderCreateResponse; 12 import com.kpcx.pay.weixin.entity.NotifyResult; 13 14 15 16 /** 17 * 微信解析xml:带有CDATA格式的 18 * @author iYjrg_xiebin 19 * @date 2015年11月26日上午10:18:07 20 */ 21 public class JdomParseXmlUtils { 22 23 /** 24 * 1、统一下单获取微信返回 25 * 解析的时候自动去掉CDMA 26 * @param xml 27 */ 28 @SuppressWarnings("unchecked") 29 public static OrderCreateResponse getUnifiedorderResult(String xml){ 30 OrderCreateResponse unifieorderResult = new OrderCreateResponse(); 31 try { 32 StringReader read = new StringReader(xml); 33 // 创建新的输入源SAX 解析器将使用 InputSource 对象来确定如何读取 XML 输入 34 InputSource source = new InputSource(read); 35 // 创建一个新的SAXBuilder 36 SAXBuilder sb = new SAXBuilder(); 37 // 通过输入源构造一个Document 38 Document doc; 39 doc = (Document) sb.build(source); 40 41 Element root = doc.getRootElement();// 指向根节点 42 List<Element> list = root.getChildren(); 43 44 if(list!=null&&list.size()>0){ 45 for (Element element : list) { 46 47 48 if("return_code".equals(element.getName())){ 49 unifieorderResult.setReturn_code(element.getText()); 50 } 51 52 if("return_msg".equals(element.getName())){ 53 unifieorderResult.setReturn_msg(element.getText()); 54 } 55 56 if("appid".equals(element.getName())){ 57 unifieorderResult.setAppid(element.getText()); 58 } 59 60 61 if("mch_id".equals(element.getName())){ 62 unifieorderResult.setMch_id(element.getText()); 63 } 64 65 if("nonce_str".equals(element.getName())){ 66 unifieorderResult.setNonce_str(element.getText()); 67 } 68 69 if("sign".equals(element.getName())){ 70 unifieorderResult.setSign(element.getText()); 71 } 72 73 if("result_code".equals(element.getName())){ 74 unifieorderResult.setResult_code(element.getText()); 75 } 76 77 if("prepay_id".equals(element.getName())){ 78 unifieorderResult.setPrepay_id(element.getText()); 79 } 80 81 if("trade_type".equals(element.getName())){ 82 unifieorderResult.setTrade_type(element.getText()); 83 } 84 } 85 } 86 87 } catch (JDOMException e) { 88 e.printStackTrace(); 89 } catch (IOException e) { 90 e.printStackTrace(); 91 }catch (Exception e) { 92 e.printStackTrace(); 93 } 94 95 return unifieorderResult; 96 } 97 98 99 /** 100 * 2、微信回调后参数解析 101 * 解析的时候自动去掉CDMA 102 * @param xml 103 */ 104 @SuppressWarnings("unchecked") 105 public static NotifyResult getWXPayResult(String xml){ 106 NotifyResult wXPayResult = new NotifyResult(); 107 try { 108 StringReader read = new StringReader(xml); 109 // 创建新的输入源SAX 解析器将使用 InputSource 对象来确定如何读取 XML 输入 110 InputSource source = new InputSource(read); 111 // 创建一个新的SAXBuilder 112 SAXBuilder sb = new SAXBuilder(); 113 // 通过输入源构造一个Document 114 Document doc; 115 doc = (Document) sb.build(source); 116 117 Element root = doc.getRootElement();// 指向根节点 118 List<Element> list = root.getChildren(); 119 120 if(list!=null&&list.size()>0){ 121 for (Element element : list) { 122 123 if("appid".equals(element.getName())){ 124 wXPayResult.setAppid(element.getText()); 125 }else if("attach".equals(element.getName())){ 126 wXPayResult.setAttach(element.getText()); 127 }else if("bank_type".equals(element.getName())){ 128 wXPayResult.setBank_type(element.getText()); 129 }else if("cash_fee".equals(element.getName())){ 130 wXPayResult.setCash_fee(element.getText()); 131 }else if("fee_type".equals(element.getName())){ 132 wXPayResult.setFee_type(element.getText()); 133 }else if("is_subscribe".equals(element.getName())){ 134 wXPayResult.setIs_subscribe(element.getText()); 135 }else if("mch_id".equals(element.getName())){ 136 wXPayResult.setMch_id(element.getText()); 137 }else if("nonce_str".equals(element.getName())){ 138 wXPayResult.setNonce_str(element.getText()); 139 }else if("openid".equals(element.getName())){ 140 wXPayResult.setOpenid(element.getText()); 141 }else if("out_trade_no".equals(element.getName())){ 142 wXPayResult.setOut_trade_no(element.getText()); 143 }else if("result_code".equals(element.getName())){ 144 wXPayResult.setResult_code(element.getText()); 145 }else if("return_code".equals(element.getName())){ 146 wXPayResult.setReturn_code(element.getText()); 147 }else if("sign".equals(element.getName())){ 148 wXPayResult.setSign(element.getText()); 149 }else if("time_end".equals(element.getName())){ 150 wXPayResult.setTime_end(element.getText()); 151 }else if("total_fee".equals(element.getName())){ 152 wXPayResult.setTotal_fee(element.getText()); 153 }else if("trade_type".equals(element.getName())){ 154 wXPayResult.setTrade_type(element.getText()); 155 }else if("transaction_id".equals(element.getName())){ 156 wXPayResult.setTransaction_id(element.getText()); 157 }else if("device_info".equals(element.getName())){ 158 wXPayResult.setDevice_info(element.getText()); 159 }else if("err_code".equals(element.getName())){ 160 wXPayResult.setErr_code(element.getText()); 161 }else if("err_code_des".equals(element.getName())){ 162 wXPayResult.setErr_code_des(element.getText()); 163 }else if("cash_fee_type".equals(element.getName())){ 164 wXPayResult.setCash_fee_type(element.getText()); 165 }else if("coupon_fee".equals(element.getName())){ 166 wXPayResult.setCoupon_fee(element.getText()); 167 }else if("coupon_count".equals(element.getName())){ 168 wXPayResult.setCoupon_count(element.getText()); 169 } 170 171 } 172 } 173 174 } catch (JDOMException e) { 175 e.printStackTrace(); 176 } catch (IOException e) { 177 e.printStackTrace(); 178 }catch (Exception e) { 179 e.printStackTrace(); 180 } 181 182 return wXPayResult; 183 } 184 185 }