1.首先我们先下载微信支付的服务器端demo
2.个文件作用介绍
index.jsp 下单 payRequest.jsp 获取微信支付prepay_id等。
重点我说说这个payNotifyUrl.jsp
- <%@ page language="java" contentType="text/html; charset=GBK" pageEncoding="GBK"%>
- <%@ page import="com.tenpay.RequestHandler" %>
- <%@ page import="com.tenpay.ResponseHandler" %>
- <%@ page import="com.tenpay.client.ClientResponseHandler" %>
- <%@ page import="com.tenpay.client.TenpayHttpClient" %>
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
- <%
- //---------------------------------------------------------
- //财付通支付通知(后台通知)示例,商户按照此文档进行开发即可
- //---------------------------------------------------------
- //商户号
- String partner = "1900000109";
-
- //密钥
- String key = "8934e7d15453e97507ef794cf7b0519d";
-
- //创建支付应答对象
- ResponseHandler resHandler = new ResponseHandler(request, response);
- resHandler.setKey(key);
-
- //判断签名
- if(resHandler.isTenpaySign()) {
-
- //通知id
- String notify_id = resHandler.getParameter("notify_id");
-
- //创建请求对象
- RequestHandler queryReq = new RequestHandler(null, null);
- //通信对象
- TenpayHttpClient httpClient = new TenpayHttpClient();
- //应答对象
- ClientResponseHandler queryRes = new ClientResponseHandler();
-
- //通过通知ID查询,确保通知来至财付通
- queryReq.init();
- queryReq.setKey(key);
- queryReq.setGateUrl("https://gw.tenpay.com/gateway/verifynotifyid.xml");
- queryReq.setParameter("partner", partner);
- queryReq.setParameter("notify_id", notify_id);
-
- //通信对象
- httpClient.setTimeOut(5);
- //设置请求内容
- httpClient.setReqContent(queryReq.getRequestURL());
- System.out.println("queryReq:" + queryReq.getRequestURL());
- //后台调用
- if(httpClient.call()) {
- //设置结果参数
- queryRes.setContent(httpClient.getResContent());
- System.out.println("queryRes:" + httpClient.getResContent());
- queryRes.setKey(key);
-
-
- //获取返回参数
- String retcode = queryRes.getParameter("retcode");
- String trade_state = queryRes.getParameter("trade_state");
-
- String trade_mode = queryRes.getParameter("trade_mode");
-
- //判断签名及结果
- if(queryRes.isTenpaySign()&& "0".equals(retcode) && "0".equals(trade_state) && "1".equals(trade_mode)) {
- System.out.println("订单查询成功");
- //取结果参数做业务处理
- System.out.println("out_trade_no:" + queryRes.getParameter("out_trade_no")+
- " transaction_id:" + queryRes.getParameter("transaction_id"));
- System.out.println("trade_state:" + queryRes.getParameter("trade_state")+
- " total_fee:" + queryRes.getParameter("total_fee"));
- //如果有使用折扣券,discount有值,total_fee+discount=原请求的total_fee
- System.out.println("discount:" + queryRes.getParameter("discount")+
- " time_end:" + queryRes.getParameter("time_end"));
- //------------------------------
- //处理业务开始
- //------------------------------
-
- //处理数据库逻辑
- //注意交易单不要重复处理
- //注意判断返回金额
-
- //------------------------------
- //处理业务完毕
- //------------------------------
- resHandler.sendToCFT("Success");
- }
- else{
- //错误时,返回结果未签名,记录retcode、retmsg看失败详情。
- System.out.println("查询验证签名失败或业务错误");
- System.out.println("retcode:" + queryRes.getParameter("retcode")+
- " retmsg:" + queryRes.getParameter("retmsg"));
- }
-
- } else {
-
- System.out.println("后台调用通信失败");
-
- System.out.println(httpClient.getResponseCode());
- System.out.println(httpClient.getErrInfo());
- //有可能因为网络原因,请求已经处理,但未收到应答。
- }
- }
- else{
- System.out.println("通知签名验证失败");
- }
-
- %>
-
就是上面的这代码。完全没有用。查看sdk源码才知道 这个异步回调是接收微信发送的所有参数,然后排序 加密 验签。 最坑的是 微信 的参数根本不是通过的参数返回的。而是通过的流。所以这个太坑了。下面我把我修改过的源码发出来 帮助大家解决回调问题。
首先是控制器
- /**
- * 异步回调接口
- * @param request
- * @param response
- * @throws Exception
- */
- @RequestMapping(value="/weixin_parent_notify.do",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();
-
- SortedMap<String,String> map = WXRequestUtil.doXMLParseWithSorted(sb.toString());//接受微信的通知参数
- Map<String,String> return_data = new HashMap<String,String>();
-
- //创建支付应答对象
- ResponseHandler resHandler = new ResponseHandler(request, response);
-
- resHandler.setAllparamenters(map);
- resHandler.setKey(ConstantUtil.PARTNER_KEY[0]);
-
- //判断签名
- if(resHandler.isTenpaySign()){
- if(!map.get("return_code").toString().equals("SUCCESS")){
- return_data.put("return_code", "FAIL");
- return_data.put("return_msg", "return_code不正确");
- }else{
- if(!map.get("result_code").toString().equals("SUCCESS")){
- return_data.put("return_code", "FAIL");
- return_data.put("return_msg", "result_code不正确");
- }
-
-
-
- String out_trade_no = map.get("out_trade_no").toString();
- String time_end = map.get("time_end").toString();
- BigDecimal total_fee = new BigDecimal(map.get("total_fee").toString());
- //付款完成后,支付宝系统发送该交易状态通知
- System.out.println("交易成功");
- Map order = orderdao.PaymentEndGetOrderInfo(out_trade_no);
-
- if(order == null){
- System.out.println("订单不存在");
- return_data.put("return_code", "FAIL");
- return_data.put("return_msg", "订单不存在");
- return WXRequestUtil.GetMapToXML(return_data);
- }
-
- int order_type = (int) order.get("order_type");
- boolean payment_status = (boolean) order.get("payment_status");
- int supplier_id = (int) order.get("supplier_id");
-
- BigDecimal p = new BigDecimal("100");
- BigDecimal amount = (BigDecimal) order.get("amount");
-
- amount = amount.multiply(p);
-
- //如果订单已经支付返回错误
- if(payment_status){
- System.out.println("订单已经支付");
- return_data.put("return_code", "SUCCESS");
- return_data.put("return_msg", "OK");
- return WXRequestUtil.GetMapToXML(return_data);
- }
-
-
- //如果支付金额不等于订单金额返回错误
- if(amount.compareTo(total_fee)!=0){
- System.out.println("资金异常");
- return_data.put("return_code", "FAIL");
- return_data.put("return_msg", "金额异常");
- return WXRequestUtil.GetMapToXML(return_data);
- }
-
- //更新订单信息
- if(orderdao.PaymentEndUpdateOrder(out_trade_no, time_end)){
- System.out.println("更新订单成功");
- //如果该订单是幼儿产品 并且 存在代理
- if(order_type == 2){
- if(supplier_id != 0){
- Map su = userdao.getSupplierInfo(supplier_id);
- String phone = (String) su.get("phone_number");
- String nickname = (String) su.get("nickname");
- String app_token = (String) su.get("app_token");
-
- String content = "【三盛科创】尊敬的"+ nickname +"您好。您在我们平台出售的商品有新用户下单。请您点击该链接查看发货信息。"+Config.WEB_SERVER+"/order/SupplierOrderInfo.do?order_number="+out_trade_no+"&sid="+app_token+".请您务必妥善包管。";
- MessageUtil.SendMessage(phone,content);
- }
- }else{
- orderdao.UpdateOrderStatus(out_trade_no, 3);//更新订单为已完成
- }
-
- return_data.put("return_code", "SUCCESS");
- return_data.put("return_msg", "OK");
- return WXRequestUtil.GetMapToXML(return_data);
- }else{
- return_data.put("return_code", "FAIL");
- return_data.put("return_msg", "更新订单失败");
- return WXRequestUtil.GetMapToXML(return_data);
- }
- }
- }else{
- return_data.put("return_code", "FAIL");
- return_data.put("return_msg", "签名错误");
- }
-
- String xml = WXRequestUtil.GetMapToXML(return_data);
- return xml;
- }
微信工具类WXRequestUtil.java
- package com.tenpay.util;
-
- import java.io.BufferedReader;
- import java.io.ByteArrayInputStream;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.io.OutputStream;
- import java.net.ConnectException;
- import java.net.HttpURLConnection;
- import java.net.InetAddress;
- import java.net.URL;
- import java.security.KeyStore;
- import java.util.Date;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Map;
- import java.util.SortedMap;
- import java.util.TreeMap;
-
- import javax.net.ssl.SSLContext;
-
- import org.apache.http.Consts;
- import org.apache.http.HttpEntity;
- import org.apache.http.client.methods.CloseableHttpResponse;
- import org.apache.http.client.methods.HttpPost;
- import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
- import org.apache.http.conn.ssl.SSLContexts;
- import org.apache.http.entity.StringEntity;
- import org.apache.http.impl.client.CloseableHttpClient;
- import org.apache.http.impl.client.HttpClients;
- import org.apache.http.util.EntityUtils;
- import org.glassfish.jersey.internal.util.Base64;
- import org.jdom.Document;
- import org.jdom.Element;
- import org.jdom.input.SAXBuilder;
-
- import com.zhiweism.util.MD5;
- import com.zhiweism.util.Util;
-
- /*
- * 用户发起统一下单请求
- * 作者:董志平
- * 用于发起微信扫码支付接口
- */
- public class WXRequestUtil {
- private static String WXSign = null;
- // //测试
- public static void main(String[] args) {
- //Map<String,String> res = SendPayment("苹果","20170106113325",1,0);
- }
-
- /*
- * 发起支付请求
- * body 商品描述
- * out_trade_no 订单号
- * total_fee 订单金额 单位 元
- * product_id 商品ID
- */
- public static Map<String,String> SendPayment(String body,String out_trade_no,double total_fee,int app_type){
- String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
- String xml = WXParamGenerate(body,out_trade_no,total_fee,app_type);
- String res = httpsRequest(url,"POST",xml);
- Map<String,String> data = null;
- try {
- data = doXMLParse(res);
- } catch (Exception e) {
- data = null;
- }
- return data;
- }
-
-
- /**
- * 获取签名
- * @return
- */
- public static String getWXSign() {
- return WXSign;
- }
-
- /**
- * 获得随机字符串
- *
- */
- public static String NonceStr(){
- String res = Base64.encodeAsString(Math.random()+"::"+new Date().toString()).substring(0, 30);
- return res;
- }
-
- /**
- * 获取时间戳
- */
- public static String GetTimeStamp(){
- int t = (int)(System.currentTimeMillis()/1000);
- return t+"";
- }
-
-
- /**
- * 获取用户的ip
- *
- */
- public static String GetIp() {
- InetAddress ia=null;
- try {
- ia=InetAddress.getLocalHost();
- String localip=ia.getHostAddress();
- return localip;
- } catch (Exception e) {
- return null;
- }
- }
-
- /**
- * 获取签名
- *
- */
- public static String GetSign(Map<String,String> param,int app_type){
- String StringA = Util.formatUrlMap(param, false, false);
- String stringSignTemp = MD5.md5(StringA+"&key="+ConstantUtil.PARTNER_KEY[app_type]).toUpperCase();
- return stringSignTemp;
- }
-
- /**
- *
- * 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();
- }
-
-
- //微信统一下单参数设置
- public static String WXParamGenerate(String description,String out_trade_no,double total_fee,int app_type){
- int fee = (int)(total_fee * 100.00);
- Map<String,String> param = new HashMap<String,String>();
- param.put("appid", ConstantUtil.APP_ID[app_type]);
- param.put("mch_id", ConstantUtil.PARTNER[app_type]);
- param.put("nonce_str",NonceStr());
- param.put("body",description);
- param.put("out_trade_no",out_trade_no);
- param.put("total_fee", fee+"");
- param.put("spbill_create_ip", GetIp());
- param.put("notify_url", ConstantUtil.WEIXIN_NOTIFY[app_type]);
- param.put("trade_type", "APP");
-
- WXSign = GetSign(param,app_type);
-
- param.put("sign", WXSign);
- return GetMapToXML(param);
- }
-
- //发起微信支付请求
- public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {
- try {
- URL url = new URL(requestUrl);
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-
- conn.setDoOutput(true);
- conn.setDoInput(true);
- conn.setUseCaches(false);
- // 设置请求方式(GET/POST)
- conn.setRequestMethod(requestMethod);
- conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
- // 当outputStr不为null时向输出流写数据
- if (null != outputStr) {
- OutputStream outputStream = conn.getOutputStream();
- // 注意编码格式
- outputStream.write(outputStr.getBytes("UTF-8"));
- outputStream.close();
- }
- // 从输入流读取返回内容
- InputStream inputStream = conn.getInputStream();
- InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
- BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
- String str = null;
- StringBuffer buffer = new StringBuffer();
- while ((str = bufferedReader.readLine()) != null) {
- buffer.append(str);
- }
- // 释放资源
- bufferedReader.close();
- inputStreamReader.close();
- inputStream.close();
- inputStream = null;
- conn.disconnect();
- return buffer.toString();
- } catch (ConnectException ce) {
- System.out.println("连接超时:{}"+ ce);
- } catch (Exception e) {
- System.out.println("https请求异常:{}"+ e);
- }
- return null;
- }
-
- //退款的请求方法
- public static String httpsRequest2(String requestMethod, String outputStr) throws Exception {
- KeyStore keyStore = KeyStore.getInstance("PKCS12");
- StringBuilder res = new StringBuilder("");
- FileInputStream instream = new FileInputStream(new File("/home/apiclient_cert.p12"));
- try {
- keyStore.load(instream, "".toCharArray());
- } finally {
- instream.close();
- }
-
- // Trust own CA and all self-signed certs
- SSLContext sslcontext = SSLContexts.custom()
- .loadKeyMaterial(keyStore, "1313329201".toCharArray())
- .build();
- SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
- sslcontext,
- new String[] { "TLSv1" },
- null,
- SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
- CloseableHttpClient httpclient = HttpClients.custom()
- .setSSLSocketFactory(sslsf)
- .build();
- try {
-
- HttpPost httpost = new HttpPost("https://api.mch.weixin.qq.com/secapi/pay/refund");
- httpost.addHeader("Connection", "keep-alive");
- httpost.addHeader("Accept", "*/*");
- httpost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
- httpost.addHeader("Host", "api.mch.weixin.qq.com");
- httpost.addHeader("X-Requested-With", "XMLHttpRequest");
- httpost.addHeader("Cache-Control", "max-age=0");
- httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
- StringEntity entity2 = new StringEntity(outputStr ,Consts.UTF_8);
- httpost.setEntity(entity2);
- System.out.println("executing request" + httpost.getRequestLine());
-
- CloseableHttpResponse response = httpclient.execute(httpost);
-
- try {
- HttpEntity entity = response.getEntity();
-
- System.out.println("----------------------------------------");
- System.out.println(response.getStatusLine());
- if (entity != null) {
- System.out.println("Response content length: " + entity.getContentLength());
- BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));
- String text = "";
- res.append(text);
- while ((text = bufferedReader.readLine()) != null) {
- res.append(text);
- System.out.println(text);
- }
-
- }
- EntityUtils.consume(entity);
- } finally {
- response.close();
- }
- } finally {
- httpclient.close();
- }
- return res.toString();
-
- }
-
- //xml解析
- public static Map<String, String> doXMLParse(String strxml) throws Exception {
- strxml = strxml.replaceFirst("encoding=".*"", "encoding="UTF-8"");
- if(null == strxml || "".equals(strxml)) {
- return null;
- }
-
- Map<String,String> m = new HashMap<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;
- }
-
- //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();
- }
- }
修改微信ResponseHandler.java
- package com.tenpay;
-
-
- import java.io.IOException;
- import java.io.PrintWriter;
- import java.io.UnsupportedEncodingException;
- import java.util.Iterator;
- import java.util.Map;
- import java.util.Set;
- import java.util.SortedMap;
- import java.util.TreeMap;
-
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
-
- import com.tenpay.util.MD5Util;
- import com.tenpay.util.TenpayUtil;
-
- /**
- *
- * @author miklchen
- *
- */
- public class ResponseHandler {
-
- private String key;
-
-
- private SortedMap parameters;
-
-
- private String debugInfo;
-
- private HttpServletRequest request;
-
- private HttpServletResponse response;
-
- private String uriEncoding;
-
- /**
- *
- * @param request
- * @param response
- */
- public ResponseHandler(HttpServletRequest request,
- HttpServletResponse response) {
- this.request = request;
- this.response = response;
-
- this.key = "";
- this.parameters = new TreeMap();
- this.debugInfo = "";
-
- this.uriEncoding = "";
- }
-
- /**
- */
- public String getKey() {
- return key;
- }
-
- /**
- *
- */
- public void setKey(String key) {
- this.key = key;
- }
-
- /**
- *ֵ
- * @param parameter
- * @return String
- */
- public String getParameter(String parameter) {
- String s = (String)this.parameters.get(parameter);
- return (null == s) ? "" : s;
- }
-
- /**
- * @param parameter
- * @param parameterValueֵ
- */
- public void setParameter(String parameter, String parameterValue) {
- String v = "";
- if(null != parameterValue) {
- v = parameterValue.trim();
- }
-
- this.parameters.put(parameter, v);
- }
-
- /**
- *
- * @return SortedMap
- */
- public SortedMap getAllParameters() {
- return this.parameters;
- }
-
- public void setAllparamenters(SortedMap map){
- this.parameters = map;
- }
-
- /**
- * 微信异步回调签名
- * @return boolean
- */
- public boolean isTenpaySign() {
- StringBuffer sb = new StringBuffer();
- Set es = this.parameters.entrySet();
- Iterator it = es.iterator();
- while(it.hasNext()) {
- Map.Entry entry = (Map.Entry)it.next();
- String k = (String)entry.getKey();
- String v = (String)entry.getValue();
- if(!"sign".equals(k) && null != v && !"".equals(v)) {
- sb.append(k + "=" + v + "&");
- }
- }
-
- sb.append("key="+this.getKey());
- String enc = TenpayUtil.getCharacterEncoding(this.request, this.response);
- String sign = MD5Util.MD5Encode(sb.toString(), enc).toLowerCase();
-
- String tenpaySign = this.getParameter("sign").toLowerCase();
-
- System.out.println("sign:"+sign+" tenpaysign:"+tenpaySign);
-
- return tenpaySign.equals(sign);
- }
-
- /**
- *
- * @throws IOException
- */
- public void sendToCFT(String msg) throws IOException {
- String strHtml = msg;
- PrintWriter out = this.getHttpServletResponse().getWriter();
- out.println(strHtml);
- out.flush();
- out.close();
-
- }
-
- /**
- *
- * @return String
- */
- public String getUriEncoding() {
- return uriEncoding;
- }
-
- /**
- * @param uriEncoding
- * @throws UnsupportedEncodingException
- */
- public void setUriEncoding(String uriEncoding)
- throws UnsupportedEncodingException {
- if (!"".equals(uriEncoding.trim())) {
- this.uriEncoding = uriEncoding;
-
-
- String enc = TenpayUtil.getCharacterEncoding(request, response);
- Iterator it = this.parameters.keySet().iterator();
- while (it.hasNext()) {
- String k = (String) it.next();
- String v = this.getParameter(k);
- v = new String(v.getBytes(uriEncoding.trim()), enc);
- this.setParameter(k, v);
- }
- }
- }
-
- /**
-
- */
- public String getDebugInfo() {
- return debugInfo;
- }
-
- /**
- *
- */
- protected void setDebugInfo(String debugInfo) {
- this.debugInfo = debugInfo;
- }
-
- protected HttpServletRequest getHttpServletRequest() {
- return this.request;
- }
-
- protected HttpServletResponse getHttpServletResponse() {
- return this.response;
- }
-
- }
试试是不是已经可以发起异步回调了。记得key 在 微信支付 -》API安全 下面设置。