微信APP支付(基于Java实现微信APP支付)

步骤:

  • 导入maven依赖
    <!--微信支付-->
    <dependency>
      <groupId>com.github.wxpay</groupId>
      <artifactId>wxpay-sdk</artifactId>
      <version>0.0.3</version>
    </dependency>
  • 微信支付参数配置
import com.github.wxpay.sdk.WXPayConfig;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

/**
 * 微信支付配置(单例)
 */
public class WXConfigUtil implements WXPayConfig {

    private byte[] certData;
    private static WXConfigUtil INSTANCE;

    public static final String APP_ID = "*****";//应用AppID
    public static final String KEY = "******";//商户密钥
    public static final String MCH_ID = "******";//商户号

    public WXConfigUtil() throws Exception {
        String certPath = WXConfigUtil.class.getClassLoader().getResource("").getPath();//从微信商户平台下载的安全证书存放的路径
        File file = new File(certPath+ "apiclient_cert.p12");
        InputStream certStream = new FileInputStream(file);
        this.certData = new byte[(int) file.length()];
        certStream.read(this.certData);
        certStream.close();
    }

    //双重检查加锁
    public static WXConfigUtil getInstance() throws Exception {
        if (INSTANCE == null) {
            synchronized (WXConfigUtil.class) {
                if (INSTANCE == null) {
                    INSTANCE = new WXConfigUtil();
                }
            }
        }
        return INSTANCE;
    }

    @Override
    public String getAppID() {
        return APP_ID;
    }

    //parnerid,商户号
    @Override
    public String getMchID() {
        return MCH_ID;
    }

    @Override
    public String getKey() {
        return KEY;
    }

    @Override
    public InputStream getCertStream() {
        ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);
        return certBis;
    }

    @Override
    public int getHttpConnectTimeoutMs() {
        return 8000;
    }

    @Override
    public int getHttpReadTimeoutMs() {
        return 10000;
    }
}
  • 业务层统一下单以及异步通知后的XML数据处理
import com.aone.app.common.wx.WXConfigUtil;
import com.aone.app.common.wx.WxCfg;
import com.aone.app.service.PayService;
import com.aone.app.service.WXAppPayService;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;

@Service
public class WXAppPayServiceImpl implements WXAppPayService {

    private static final Logger logger = LoggerFactory.getLogger("WXAppPayServiceImpl");
    @Autowired
    private WxCfg wxCfg;
    /**
     * 调用官方SDK 获取预支付订单等参数
     * @param type
     * @param out_trade_no
     * @param money
     * @return
     * @throws Exception
     */
    @Override
    public Map<String, String> dounifiedOrder(String type,String out_trade_no,String money) throws Exception {
        Map<String, String> returnMap = new HashMap<>();

        //支付参数
        WXConfigUtil config = new WXConfigUtil();
        WXPay wxpay = new WXPay(config);
        //请求参数封装
        Map<String, String> data = new HashMap<>();
        data.put("appid", config.getAppID());
        data.put("mch_id", config.getMchID());
        data.put("nonce_str", WXPayUtil.generateNonceStr());
        data.put("body", "订单支付");
        data.put("out_trade_no", out_trade_no);
        data.put("total_fee", "1");
        data.put("spbill_create_ip", wxCfg.getIp()); //自己的服务器IP地址
        data.put("notify_url", wxCfg.getAppNotifyUrl());//异步通知地址(请注意必须是外网)
        data.put("trade_type", wxCfg.getAppType());//交易类型
        data.put("attach", type);//附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据
        String s = WXPayUtil.generateSignature(data, config.getKey());  //签名
        data.put("sign", s);//签名

        try {
            //使用官方API请求预付订单
            Map<String, String> response = wxpay.unifiedOrder(data);
            System.out.println(response);
            String returnCode = response.get("return_code");    //获取返回码
            //若返回码为SUCCESS,则会返回一个result_code,再对该result_code进行判断
            if (returnCode.equals("SUCCESS")) {
                //主要返回以下5个参数(必须按照顺序,否则APP报错:-1)
                String resultCode = response.get("result_code");
                returnMap.put("appid", response.get("appid"));
                returnMap.put("noncestr", response.get("nonce_str"));
                if ("SUCCESS".equals(resultCode)) {//resultCode 为SUCCESS,才会返回prepay_id和trade_type
                    returnMap.put("package","Sign=WXPay");
                    returnMap.put("partnerid", response.get("mch_id"));
                    returnMap.put("prepayid", response.get("prepay_id"));
                    returnMap.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));//单位为秒

                    String sign = WXPayUtil.generateSignature(returnMap, config.getKey());// 二次签名
                    returnMap.put("sign",sign); //签名
                    returnMap.put("trade_type", response.get("trade_type"));//获取预支付交易回话标志
                    return returnMap;
                } else {
                    //此时返回没有预付订单的数据
                    return returnMap;
                }
            } else {
                return returnMap;
            }
        } catch (Exception e) {
            System.out.println(e);
            //系统等其他错误的时候
        }
        return returnMap;
    }

    /**
     *
     * @param notifyData 异步通知后的XML数据
     * @return
     */
    @Override
    public String payBack(String notifyData) {
        WXConfigUtil config = null;
        try {
            config = new WXConfigUtil();
        } catch (Exception e) {
            e.printStackTrace();
        }
        WXPay wxpay = new WXPay(config);
        String xmlBack = "";
        Map<String, String> notifyMap = null;
        try {
            notifyMap = WXPayUtil.xmlToMap(notifyData);         // 调用官方SDK转换成map类型数据
            if (wxpay.isPayResultNotifySignatureValid(notifyMap)) {//验证签名是否有效,有效则进一步处理

                String return_code = notifyMap.get("return_code");//状态
                String out_trade_no = notifyMap.get("out_trade_no");//商户订单号
                if (return_code.equals("SUCCESS")) {
                    if (out_trade_no != null) {
                        // 注意特殊情况:订单已经退款,但收到了支付结果成功的通知,不应把商户的订单状态从退款改成支付成功
                        // 注意特殊情况:微信服务端同样的通知可能会多次发送给商户系统,所以数据持久化之前需要检查是否已经处理过了,处理了直接返回成功标志
                        //业务数据持久化
                        System.err.println("支付成功"+"\n");
                        String attach = notifyMap.get("attach");//附加数据,用于区分是那张表订单
                        System.out.print("附加数据类型为:{}"+attach+"\n");
                        if(StringUtils.isEmpty(attach)){
                            logger.info("附加数据类型为:{}", attach);
                        }else{
                            //@TODO 预支付下单后回调的逻辑

                        }
                        logger.info("微信手机支付回调成功订单号:{}", out_trade_no);
                        xmlBack = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
                    } else {
                        logger.info("微信手机支付回调失败订单号:{}", out_trade_no);
                        xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
                    }
                }
                return xmlBack;
            } else {
                // 签名错误,如果数据里没有sign字段,也认为是签名错误
                //失败的数据要不要存储?
                logger.error("手机支付回调通知签名错误");
                xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
                return xmlBack;
            }
        } catch (Exception e) {
            logger.error("手机支付回调通知失败", e);
            xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
        }
        return xmlBack;
    }
}
  • WXCfg中配置的是微信支付的回调地址以及交易类型
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * 微信参数配置中心
 */
@Component
public class WxCfg {

    @Value("${wx.appType}")
    private String appType;//App支付交易类型
    @Value("${wx.appNotifyUrl}")
    private String appNotifyUrl;//App回调地址
    @Value("${wx.h5Type}")
    private String h5Type;//H5支付交易类型
    @Value("${wx.h5NotifyUrl}")
    private String h5NotifyUrl;//H5回调地址
    @Value("${wx.ip}")
    private String ip;//服务器ip
    @Value("${wx.redirect_url}")
    private String redirect_url;//跳转地址

    public String getAppNotifyUrl() {
        return appNotifyUrl;
    }

    public void setAppNotifyUrl(String appNotifyUrl) {
        this.appNotifyUrl = appNotifyUrl;
    }

    public String getH5NotifyUrl() {
        return h5NotifyUrl;
    }

    public void setH5NotifyUrl(String h5NotifyUrl) {
        this.h5NotifyUrl = h5NotifyUrl;
    }

    public String getAppType() {
        return appType;
    }

    public void setAppType(String appType) {
        this.appType = appType;
    }

    public String getH5Type() {
        return h5Type;
    }

    public void setH5Type(String h5Type) {
        this.h5Type = h5Type;
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public String getRedirect_url() {
        return redirect_url;
    }

    public void setRedirect_url(String redirect_url) {
        this.redirect_url = redirect_url;
    }
}
  • 控制层下单接口以及回调接口
import com.aone.app.service.WXAppPayService;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

@RestController
@RequestMapping("pay")
@Api("App支付")
public class PayAppController {

    @Autowired
    private WXAppPayService wxAppPayService;

    /**
     *
     * App支付统一下单
     * @param out_trade_no  订单号
     * @param total_fee      支付金额
     * @param type          0:预约订单1:专家保证金2:即时咨询订单
     * @return
     * @throws Exception
     */
    @PostMapping("order")
    public Map<String, String> order(@RequestParam(value = "type") String  type,@RequestParam(value = "out_trade_no") String out_trade_no,@RequestParam(value = "total_fee") String total_fee)throws Exception{
        return wxAppPayService.dounifiedOrder(type,out_trade_no,total_fee);
    }

    /**
     *   微信支付异步结果通知
     */
    @RequestMapping(value = "wxPayNotify", method = {RequestMethod.GET, RequestMethod.POST})
    public String wxPayNotify(HttpServletRequest request, HttpServletResponse response) {
        System.out.print("微信回调开始"+"\n");
        String resXml = "";
        try {
            InputStream inputStream = request.getInputStream();
            //将InputStream转换成xmlString
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            StringBuilder sb = new StringBuilder();
            String line = null;
            try {
                while ((line = reader.readLine()) != null) {
                    sb.append(line + "\n");
                }
            } catch (IOException e) {
                System.out.println(e.getMessage());
            } finally {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            resXml = sb.toString();
            String result = wxAppPayService.payBack(resXml);
            System.out.print("微信回调结束"+"\n");
            return result;
        } catch (Exception e) {
            System.out.println("微信手机支付失败:" + e.getMessage());
            String result = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
            return result;
        }
    }

}
  • 下单封装的Map中封装参数服务器IP写死可能会报错,提供获取服务器IP工具类
import javax.servlet.http.HttpServletRequest;

/**
 * 获取服务器IP工具类
 */
public class IpAddr {

    public static String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("PRoxy-Client-IP");
        }
        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

}

主要用于安卓APP微信支付,IOS微信支付可能是需要交钱,太贵了,所以IOS的微信支付提供外链接使用H5进行支付。

原文地址:https://www.cnblogs.com/LJing21/p/11221184.html

时间: 2024-11-09 07:33:25

微信APP支付(基于Java实现微信APP支付)的相关文章

支付宝APP支付(基于Java实现支付宝APP支付)

贴一下支付核心代码,以供后续参考: 业务层 import com.alipay.api.AlipayApiException; import com.alipay.api.AlipayClient; import com.alipay.api.DefaultAlipayClient; import com.alipay.api.domain.AlipayTradeAppPayModel; import com.alipay.api.internal.util.AlipaySignature; i

基于java的微信公众号二次开发视频教程

详情请交流  QQ  709639943 00.基于java的微信公众号二次开发视频教程 00.leetcode 算法 面试 00.北风网 零基础到数据(大数据)分析专家-首席分析师 00.快速上手JMeter 00.Jmeter 00.2017年Java web开发工程师成长之路 00.R语言速成实战 00.R语言数据分析实战 00.Python+Django+Ansible Playbook自动化运维项目实战 00.Java深入微服务原理改造房产销售平台 00.Python3入门机器学习 经

带领技术小白入门——基于java的微信公众号开发(包括服务器配置、java web项目搭建、tomcat手动发布web项目、微信开发所需的url和token验证)

微信公众号对于每个人来说都不陌生,但是许多人都不清楚是怎么开发的.身为技术小白的我,在闲暇之余研究了一下基于java的微信公众号开发.下面就是我的实现步骤,写的略显粗糙,希望大家多多提议! 一.申请服务器 1.我购买的是阿里云服务器,购买后要设置一下服务器密码,默认用户名是administrator,购买好后如下: 2.申请好后,copy一下此服务器的IP地址(公有),在本地ping一下看看是否可用,j键盘Win+R,输入cmd,输入ping+IP回车,如下即为成功: 二.配置服务器 1.下载远

wemall app中基于Java获取和保存图片的代码

wemall-mobile是基于WeMall的android app商城,只需要在原商城目录下上传接口文件即可完成服务端的配置,客户端可定制修改.分享其中关于 保存正在下载的图片URL集合和图片三种获取方式管理者,网络URL获取.内存缓存获取.外部文件缓存获取的代码供技术员学习参考使用. package com.inuoer.util; import java.lang.ref.SoftReference; import java.util.HashMap; import java.util.H

微信支付之扫码支付(java版 native原生支付)

本文直接从代码调用微信扫码支付讲起.账号配置,参数生成等请参考官方文档:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_1 微信扫码支付.简单来说,就是你把微信支付需要的信息,生成到二维码图片中.通过微信扫一扫,发起支付.我们需要做的就是二件事: 一是:按照微信扫码支付规则生成二维码信息. 二是:微信没有提供生成二维码图片的接口.需要我们自己把二维码信息生成到二维码图片中. 1.模式选择: 微信扫码支付,有两种模式,文档中有

小黑式烂代码之微信APP支付 + 退款(JAVA实现)

首先,你得先有微信开发平台账号密码还需要开通应用,然后还有微信服务商平台商户版账号(这些我都是给产品经理拿的) 其次我认为你先去看一看微信开发平台的文档!  https://pay.weixin.qq.com/wiki/doc/api/index.html 这里有很多种支付,我就采用APP支付来说了(会了APP支付其实H5支付都差不多的!) 进来后是这样的,随便看看'APP支付那几篇文章'讲的流程!,看完后知道大概了就可以看看'API列表了' 我们后台开发需要关注的就是这三个API了! 1 /*

APP支付微信支付,Java后台开发

记录微信支付的开发过程 附上开发文档:https://pay.weixin.qq.com/wiki/doc/api/index.html 统一下单,完成微信支付共需要两个接口 第一个:拉取微信预付单 第二个:微信异步通知 前期准备,都是产品或者其他人员来准备的,我们需要的东西有, 商户appid 商户号 服务器异步通知路径(开发人员) 密钥(AppSecret) 统一下单接口链接:https://api.mch.weixin.qq.com/pay/unifiedorder 需要在微信商户平台设置

微信支付之扫码、APP、小程序支付接入详解

做电商平台的小伙伴都知道,支付服务是必不可少的一部分,今天我们开始就说说支付服务的接入及实现.目前在国内,几乎90%中小公司的支付系统都离不开微信支付和支付宝支付.那么大家要思考了,为什么微信支付和支付宝支付能作为大多数公司接入的首选呢?其实这个问题大多小伙伴应该是很清楚的,说白了就是人家有庞大的用户流量,目前微信在国内的用户已突破10亿,支付宝也接近8亿左右,如此庞大的用户群体,你还会选择其他的第三方支付(微博钱包.财付通.快钱等)吗,作为普通客户,大家都希望能方便快捷,谁会为了在一个平台买点

APP怎样接入支付宝或微信支付?

转自  https://www.zhihu.com/question/27246921 作者:Wang Fei链接:https://www.zhihu.com/question/27246921/answer/42729752来源:知乎著作权归作者所有,转载请联系作者获得授权. 1.首先,你要有一间五证齐全的公司 2.然后用这些材料,去支付宝注册一个商家账户(审核周期大概5个工作日),或者微信的开发者账号(审核周期大概5个工作日,300元费用),或者银联.paypal(这俩个我不太熟悉) 3.然