模拟 微信支付回调

场景

微信支付需要配置回调地址。当用户发起微信支付,点击付款成功后,微信会调用应用程序配置好的URL直接,意思是说支付成功了。在这个回调成功的方法里面,应用程序可以处理自己的业务逻辑。如修改订单状态,减少库存等。

存在问题

开发环境,IP多为内网IP,不是公网IP,这样微信回调是回调不回来的。当然也可以通过反向代理ngrok结合nginx来搞。

这里主要是通过程序,用redis句柄来模拟各个环境的微信支付回调。

核心代码

CallBakController

package com.weixin.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.weixin.bean.CallBack;
import com.weixin.config.WeixinConfig;
import com.weixin.redis.WeixinCallBackRedisDbManager;
import com.weixin.util.OrderUtils;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.net.UnknownHostException;
import java.util.List;
import java.util.Map;

/**
 * Created by wangshuang on 17/4/6.
 */
@Controller
@RequestMapping("/weixin")
public class CallBakController {

    @Autowired
    private WeixinCallBackRedisDbManager weixinCallBackRedisDbManager;

    @RequestMapping(value = "/pay/callback", method = RequestMethod.POST)
    @ResponseBody
    public JSONObject getTeachersByCategory(@RequestParam(required = true) String orderNo) {

        JSONObject returnObj = new JSONObject();

        CallBack callBack = new CallBack();

        if(StringUtils.isEmpty(orderNo)){
            returnObj.put("status", "10001");
            returnObj.put("msg", "订单编号不能为空");
            return returnObj;
        }

        int overTime = 30; // 设置过期时间
        List packageParams = null;

        try {

            // 获取微信回调信息
            if(weixinCallBackRedisDbManager.checkCallBackKey(orderNo)){

                callBack = weixinCallBackRedisDbManager.getCallBackInfo(orderNo);

            }

            if(null == callBack){
                returnObj.put("status", "10001");
                returnObj.put("msg", "未匹配订单编号");
                return returnObj;
            }

            packageParams = OrderUtils.CallBakInfo(
                    callBack.getOut_trade_no(),
                    callBack.getTotal_fee(),
                    callBack.getTrade_type(),
                    callBack.getOpenid(),
                    callBack.getAppid(),
                    callBack.getMch_id(),
                    overTime,
                    callBack.getTransaction_id());

            String sign = OrderUtils.genWeixinSign(packageParams, WeixinConfig.GZH_KEY);
            packageParams.add(new NameValuePair("sign", sign));
            String params = OrderUtils.toXml(packageParams);
            Map paramsMap = OrderUtils.sendWeixinPost(params);

            returnObj = (JSONObject) JSON.toJSON(paramsMap);
            return returnObj;

        } catch (UnknownHostException e) {
            returnObj.put("status", "500");
            returnObj.put("msg", "访问无效");
            return returnObj;
        } catch (Exception e) {
            returnObj.put("status", "500");
            returnObj.put("msg", "模拟微信支付回调失败");
            return returnObj;
        }


    }

}

CallBack回调返回参数封装

package com.weixin.bean;

/**
 * Created by wangshuang on 17/4/7.
 */
public class CallBack {

    //公众号ID
    private String appid;
    //付款银行
    private String bank_type;
    //现金支付金额
    private String cash_fee;
    //货币种类
    private String fee_type;
    //是否关注公众账号
    private String is_subscribe;
    //商户号
    private String mch_id;
    //随机字符串
    private String nonce_str;
    //openid
    private String openid;
    //商户订单号
    private String out_trade_no;
    //业务结果
    private String result_code;
    //返回状态码
    private String return_code;
    //支付完成时间
    private String time_end;
    //总金额
    private String total_fee;
    //交易类型
    private String trade_type;
    //微信支付订单号
    private String transaction_id;
    //签名
    private String sign;

    此处get/set方法省略。。。
}

发送POST请求给应用程序

/**
     * 发送微信请求 sendWeixinPost:
     *
     * @author sid
     * @param xml
     * @return
     */
    public static Map sendWeixinPost(String xml) {

        PostMethod post = new PostMethod(WeixinConfig.USERVICE_URL);
        post.setRequestHeader("Pragma:", "no-cache");
        post.setRequestHeader("Cache-Control", "no-cache");
        post.setRequestHeader("Content-Type", "text/xml");

        post.setRequestBody(xml);
        try {
            String res = HttpClientUtil.httpRequest(post);
            // 获取微信POST过来反馈信息
            Map params = XmlConverUtil.xmltoMap(res);
            return params;
        } catch (ConnectTimeoutException e) {
            e.printStackTrace();
        } catch (HttpException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

redis 具体操作类

package com.weixin.redis;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.weixin.bean.CallBack;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;


/**
 * Created by wangshuang on 17/4/7.
 */
@Repository
public class WeixinCallBackRedisDbManager {

    @Autowired
    JedisPool jedisPool;

    /**
     * 用户信息过期时间:半小时
     */
    private static int EXPIRE_TIME = 60 * 30;

    // 微信回调key
    private static final String WEI_XIN_CALL_BACK = "WEI_XIN_CALL_BACK" + ":";

    // 保存微信回调数据
    public void saveCallBackInfo(CallBack callBack, String orderNo) {

        Jedis jedis = jedisPool.getResource();

        String key = WEI_XIN_CALL_BACK + orderNo;

        String weixinInfo = JSONObject.toJSONString(callBack);

        jedis.set(key, weixinInfo);

        jedis.expire(key, EXPIRE_TIME);

        jedis.close();
    }

    // 判断微信回调key是否存在
    public boolean checkCallBackKey(String orderNo){

        Jedis jedis = jedisPool.getResource();

        String key = WEI_XIN_CALL_BACK + orderNo;

        boolean flag = jedis.exists(key);

        jedis.close();

        return flag;

    }

    // 获取微信回调数据
    public CallBack getCallBackInfo(String orderNo){

        Jedis jedis = jedisPool.getResource();

        String key = WEI_XIN_CALL_BACK + orderNo;

        CallBack callback = (CallBack) JSON.parseObject(jedis.get(key), CallBack.class);

        jedis.close();

        return callback;

    }

}

读取配置文件工具类

package com.weixin.util;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

/**
 * Created by wangshuang on 17/4/6.
 */
public class ConfigUtil {

    static Properties properties=new Properties();

    private static void load(){
        InputStream is= ConfigUtil.class.getResourceAsStream("/application.properties");
        try {
            properties.load(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static  String getProperty(String key){
        String value= properties.getProperty(key);
        if(value==null){
            load();
            value= properties.getProperty(key);
        }
        return value;
    }

    public static int getIntProperty(String key){
        String value=getProperty(key);
        if(value==null)return 0;
        return Integer.parseInt(value.trim());
    }


    public static void main(String[] args) {
        System.out.println(ConfigUtil.getProperty("uServiceUrl"));
    }

}

说明:

  • 项目工程代码已经全部开源,可以下载下来直接运行,保密原则,微信相关的appId和macId已经全部注释掉。只需要替换成自己微信公众号的相应值即可。
  • uServiceUrl需要配置成自己应用的回调地址

开源地址:https://github.com/wangxiaoda513/weixinCallBak
谢谢大家,互相学习,互相进步。

你可能感兴趣的:(模拟 微信支付回调)