针对APP的后台支付代码(微信和支付宝)

Posted llllitm

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了针对APP的后台支付代码(微信和支付宝)相关的知识,希望对你有一定的参考价值。

APP支付:
1.微信支付:
这是app支付时,一个完整的流程
技术分享图片
1.1首先要去微信开放平台注册,并创建APP
技术分享图片
1.2取得微信支付的权限
技术分享图片
1.3 商户平台有公众号平台和APP平台两种,一定要是APP平台,可以在下面这个地方查看
技术分享图片
1.4 我们需要在商户平台和开放平台上获取到以下数据:
开放平台:
APPID、APP_SECRET:见1图。
商户平台:
秘钥(APP_KEY):微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置
商户号(MCH_ID):微信商户平台(pay.weixin.qq.com)-->账户设置-->商户信息-->微信支付商户号
数字证书(微信退款需要使用):微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->证书下载
2.支付宝的操作流程简单,文档清楚(略)
3准备工作结束,我的产品是使用Hbuilder开发的html5的APP,后端是依托于Java Web程序。工作流程参照时序图。主要代码如下,详情见文件
  其中用到一些工具方法  或者客户端创建代码都在链接里面有,我放在了码云上面 https://gitee.com/muziTM/payDemo
  3.1  入口
  
/**
 * 支付类   包含支付宝和微信
 * @author Tianming_Li
 *
 */
@Controller
@RequestMapping("/payController")
public class PayController {
    //订单
    @Autowired
    OrdersService orderService;
    //付费
    @Autowired
    PayService payService;
    //退费
    @Autowired
    RefundService refundService;
    //支付成功回调
    @Autowired
    CallBackService callBackService;
    /**
     * 下单
     * @param outTradeNo
     * @param payType
     * @param request
     * @param response
     * @param modelMap
     * @return
     */
    @RequestMapping("/pay")
    public String pay(@RequestParam(name="outTradeNo") String outTradeNo,@RequestParam(name="payType") String payType,
            HttpServletRequest request,HttpServletResponse response,
            ModelMap modelMap){
        //根据订单号获取到订单信息
        Orders order = orderService.selectOrdersInfoByOutTradeNo(outTradeNo);
        if("wxpay".equals(payType)){
            return payService.wxPay(order, request, response, modelMap);
        }else{
            return payService.aliPay(order);
        }
    }
    /**
     * 退款
     * @param outTradeNo
     * @param payType
     * @param request
     * @param response
     * @return
     */
    @RequestMapping("/refunds")
    public String refunds(@RequestParam(name="outTradeNo") String outTradeNo,@RequestParam(name="payType") String payType,
            HttpServletRequest request,HttpServletResponse response){
        //根据订单号获取到订单信息
        Orders order = orderService.selectOrdersInfoByOutTradeNo(outTradeNo);
        if("wxpay".equals(payType)){
            return refundService.wxRefund(order, request, response);
        }else{
            return refundService.aliRefund(order);
        }
    }
    
    /**
     * 接收微信支付成功通知
     * 
     * @param request
     * @param response
     * @throws IOException
     */

    @RequestMapping(value = "/getWxPayNotify")
    public void getWxPayNotify(HttpServletRequest request, HttpServletResponse response) throws IOException {
        callBackService.wxCallBack(request, response);
    }
    /**
     * 接收支付宝支付成功回调
     * @param request
     * @param response
     * @throws IOException
     */
    @RequestMapping("/getAliPayNotify")
    public void getAliPayNotify(HttpServletRequest request, HttpServletResponse response) throws IOException {
        callBackService.aliCallBack(request, response);
    }
        
}

  3.2 支付代码

 

/**
 * 支付处理
 * @author Tianming_Li
 *
 */
@Service("payService")
public class PayServiceImpl implements PayService {
    
    protected static final Log logger = LogFactory.getLog(PayServiceImpl.class);
    
    @Override
    public String wxPay(Orders order, HttpServletRequest request, HttpServletResponse response, ModelMap modelMap) {
        BaseDao dao = DaoUtils.getDao("sys");
        StringBuilder sb = new StringBuilder();
        sb.append("SELECT * FROM WX_PAY_CONFIG WHERE YY_ID = ‘");
        sb.append(order.getYyId());
        sb.append("‘");
        //获取到微信配置参数
        WxPayConfig appPayConfig = dao.getObjectBySql(sb.toString(), WxPayConfig.class);
        Map<String, Object> map = new HashMap<String, Object>();
        //初始化一个请求对象
        WxRequestHandler wxRequestHandler = new WxRequestHandler(request, response);
        String payFee = order.getPayMoney();
        int intPayFee = (int) (Float.valueOf(payFee) * 100);
        String nonceStr = WxUtils.getNonceStr();
        String outTradeNo = order.getOutTradeNo();
        String timestamp = WxUtils.getTimeStamp();
        wxRequestHandler.setParameter("appid", appPayConfig.getAppId());//appId
        wxRequestHandler.setParameter("mch_id", appPayConfig.getMchId());//商户号
        wxRequestHandler.setParameter("nonce_str", nonceStr);//随机字符串
        wxRequestHandler.setParameter("body", appPayConfig.getBody());//商品描述
        wxRequestHandler.setParameter("notify_url", appPayConfig.getNotifyUrl());//通知地址
        wxRequestHandler.setParameter("out_trade_no", outTradeNo);
        wxRequestHandler.setParameter("spbill_create_ip", request.getRemoteAddr());
        wxRequestHandler.setParameter("total_fee", String.valueOf(intPayFee));
        wxRequestHandler.setParameter("trade_type", "APP");
         //注意签名生成方式,具体见官方文档
        wxRequestHandler.setParameter("sign", wxRequestHandler.createMD5Sign(appPayConfig.getAppKey()));
        String prepayid;
        try {
            prepayid = wxRequestHandler.sendPrepay();
            if (prepayid != null && !prepayid.equals("")) {
                String signs ="appid=" + appPayConfig.getAppId()
                            + "&noncestr=" + nonceStr
                            + "&package=Sign=WXPay"
                            + "&partnerid="+ appPayConfig.getPartnerId() //商户id
                            + "&prepayid=" + prepayid
                            + "&timestamp=" + timestamp 
                            + "&key=" + appPayConfig.getAppKey();//商户平台---api安全---密钥
                map.put("code", 200);
                map.put("info", "success");
                map.put("prepayid", prepayid);
                map.put("sign", WxUtils.getMD5Encode(signs, "utf8").toUpperCase());
                map.put("appid", appPayConfig.getAppId());
                map.put("timestamp", timestamp); // 等于请求prepayId时的time_start
                map.put("noncestr", nonceStr); // 与请求prepayId时值一致
                map.put("package", "Sign=WXPay"); // 固定常量
                map.put("partnerid", appPayConfig.getPartnerId());//商户id
            } else {
                map.put("code", 400);
                map.put("info", "获取prepayid失败");
            }
        } catch (Exception e) {
            map.put("code", 405);
            map.put("info", "系统异常");
        }

        return JSONUtils.toJSON(map);
    }

    @Override
    public String aliPay(Orders order) {
        //获取配置参数
        BaseDao dao = DaoUtils.getDao("sys");
        StringBuilder sb = new StringBuilder();
        sb.append("SELECT * FROM ALI_PAY_CONFIG WHERE YY_ID = ‘");
        sb.append(order.getYyId());
        sb.append("‘");
        AliPayConfig appPayConfig = dao.getObjectBySql(sb.toString(), AliPayConfig.class);
        
        // 实例化客户端(参数:网关地址、商户appid、商户私钥、格式、编码、支付宝公钥、加密类型),为了取得预付订单信息
        AlipayClient alipayClient = new DefaultAlipayClient(appPayConfig.getUrl(), appPayConfig.getAppId(),
                appPayConfig.getRsaPrivateKey(), appPayConfig.getFormat(), appPayConfig.getCharset(),
                appPayConfig.getPublicKey(), appPayConfig.getSigntype());
        // 实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        // SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        //销售产品码,商家和支付宝签约的产品码,为固定值QUICK_MSECURITY_PAY
        BeanUtils.copy(order, model);//将订单信息复制到model类中
        request.setBizModel(model);
        // 回调地址  指向回调函数  example: https://ip:port/payController/getAliPayNotify.do
        request.setNotifyUrl(appPayConfig.getNotifyUrl()); 
        String orderStr = "";
        try {
            // 这里和普通的接口调用不同,使用的是sdkExecute
            AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
            orderStr = response.getBody();
            logger.info("订单str:" + orderStr);
        } catch (AlipayApiException e) {
            logger.info(e.getMessage());
        }
        return orderStr;
    }

}

 3.2回调代码

@Service("callBackService")
public class CallBackServiceImpl implements CallBackService {
    
    private static final Log LOGGER = LogFactory.getLog(CallBackServiceImpl.class);

    public static final String SUCCESS = "SUCCESS";

    @SuppressWarnings("unchecked")
    @Override
    public void wxCallBack(HttpServletRequest request, HttpServletResponse response) throws IOException {
        PrintWriter writer = response.getWriter();
        InputStream inputstream = request.getInputStream();
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        byte[] b = new byte[1024];
        int len = 0;
        while((len = inputstream.read(b))!= -1){
            outputStream.write(b, 0, len);
        }
        String result = new String(outputStream.toByteArray(), "utf-8");
        inputstream.close();
        outputStream.close();
        Map<String, String> map = null;
        //解析微信通知返回的信息
        try {
            map = WxUtils.doXMLParse(result);
        } catch (JDOMException e) {
            LOGGER.info("微信回调失败:"+e.getMessage());
        }    
        // 若支付成功,则告知微信服务器收到通知
        if (SUCCESS.equals(map.get("return_code")) && SUCCESS.equals(map.get("result_code"))) {
                
            /**
             * ...
             * 回调业务
             */
            
            //微信会一直调用接口,直到我们返回SUCCESS
            String notifyStr = WxUtils.setXML(SUCCESS, "");
            writer.write(notifyStr);
            writer.flush();
        }
    }

    @Override
    public void aliCallBack(HttpServletRequest request, HttpServletResponse response) throws IOException {
        LOGGER.info("进入支付宝回调");
        // 获取支付宝GET过来反馈信息
        String reqWay = "";
        if ("GET".equals(request.getMethod())) {
            reqWay = "GET";
        }
        Map<String, String> params = new HashMap<String, String>();
        Map<?, ?> requestParams = request.getParameterMap();
        for (Iterator<?> iter = requestParams.keySet().iterator(); iter.hasNext();) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            // 乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
            if ("GET".equals(reqWay)) {
                try {
                    valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
                } catch (UnsupportedEncodingException e) {
                    LOGGER.info("不支持的编码:" + e.getMessage());
                }
            }
            params.put(name, valueStr);
        }
        String tradeNo = request.getParameter("trade_no"); // 支付宝交易号
        String tradeStatus = request.getParameter("trade_status"); // 支付状态
        String outTradeNo = request.getParameter("out_trade_no"); // 系统订单号
        String sellerId = request.getParameter("seller_id"); // 商户号

        LOGGER.info("支付宝交易号:" + tradeNo + ", 返回状态:" + tradeStatus + ",订单号  :" + outTradeNo);
        Map<String, Object> map = new HashMap<String, Object>();
        String result = "";
        try {
            if ("TRADE_SUCCESS".equals(tradeStatus)) {
                /**
                 * ...
                 * 回调业务
                 */
            } else {
                result = "fail";// 为了保证不重复回调
            }
        } catch (Exception e) {
            result = "fail";
        }
        map.put(result, result);
        AliUtils.renderText(response, result);

    }

}

3.4 微信退费的时候需要证书,密码默认是商户号,由于项目中使用了多个微信商户号,因此有多个证书,路径和密码放在了数据库中

public class WxRequestHandler{
/**
     * 退费
     * @return
     */
    public Map<String,String> sendWxChanel(String filePath,String pwd) throws Exception{
        Map<String,String> map =null;
        Set es=this.getAllParameters().entrySet();
        Iterator it=es.iterator();
        StringBuilder sb = new StringBuilder("<xml>");
        while(it.hasNext()){
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            sb.append("<"+k+">"+v+"</"+k+">");
        }
        sb.append("</xml>");
        String params=sb.substring(0);
        String requestUrl = this.getGateUrl();
        TenpayHttpClient httpClient = new TenpayHttpClient();
        httpClient.setReqContent(requestUrl);
        String resContent = "";
        //filepath 文件路径 pwd 密码
        if (httpClient.callHttpPost(requestUrl, params,true,filePath,pwd)) {
            resContent = httpClient.getResContent();
            map=WxUtils.doXMLParse(resContent);
        }
        return map;
    }

}

 

 

以上是关于针对APP的后台支付代码(微信和支付宝)的主要内容,如果未能解决你的问题,请参考以下文章

app微信支付宝支付后台的插件模式+回调通过spring广播处理后续业务(已亲测可用)

当微信和支付宝遇上友盟

微信和支付宝实现

微信和支付宝支付模式详解及实现二

iOS 微信和支付宝关于回调处理

Android应用跳转到微信和支付宝扫一扫