app用户微信支付-Java后端

本文详细介绍了app用户使用微信支付的Java后端实现步骤,包括接收到用户支付请求后调用微信支付统一下单接口,生成签名,将预付单数据传输给APP,以及如何处理支付通知。关键步骤包括统一下单、支付通知接收,遵循微信支付的交互时序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

app用户微信支付-Java后端

以下是微信官方的交互时序图,统一下单API、支付结果通知API和查询订单API等都涉及签名过程,调用都必须在商户服务器端完成。
在这里插入图片描述
商户系统和微信支付系统主要交互说明:
步骤1:用户在商户APP中选择商品,提交订单,选择微信支付。

步骤2:商户后台收到用户支付单,调用微信支付统一下单接口。

步骤3:统一下单接口返回正常的prepay_id,再按签名规范重新生成签名后,将数据传输给APP。参与签名的字段名为appid,partnerid,prepayid,noncestr,timestamp,package。注意:package的值格式为Sign=WXPay

步骤4:商户APP调起微信支付。

步骤5:商户后台接收支付通知。

下面来看微信接口

微信官方API文档

一、设置必要参数

 public static final String PATERNERKEY = "";//商家的密钥
    public static final String APP_ID = "";//APPID
    public static final String MINI_ID = "";//小程序ID
    public static final String MCH_ID = "";//商户号
    public static final String FEE_TYPE = "CNY";//货币类型,人民币
    private String NOTIFY_URL = "";//程序后台地址
     public static final String TRADE_TYPE = "APP";//支付类型(APP)
    public static final String JSAPI_TRADE_TYPE = "JSAPI";//支付类型(小程序)

二、拉取微信预付单

public Map wechatPay(Map inDTO){
	Map outDTO=new HashMap();//创建返回对象
	//.......省略参数校验
	/*主要参数有:
	* total_fee 金额,传入单位(元)
	* userId  程序用户ID,用于记录订单
	* buyType  购买类型 ,可不用
	* buyGoodsId 商品ID,自定义
	* body 商品描述
	* attach 附加数据
	*/
	 // 1.0 拼凑需要的参数
        String appid = APP_ID; // 应用ID
        String mch_id = MCH_ID; // 商户号
        String nonce_str = WXPayUtil.generateNonceStr(); // 生成随机数
        String body = inDTO.get("body") == null ? "":inDTO.get("body").toString();//商品描述
        String attach = inDTO.get("attach") == null ? "":inDTO.get("attach").toString();//附加数据
        String out_trade_no = WXPayUtil.generateNonceStr(); // 生成商户订单号
        String fee_type = FEE_TYPE;//货币类型
        Double totalFee=Double.parseDouble(inDTO.get("total_fee").toString());
        Long total_Fee= new Double(totalFee * 100.0).longValue();
        String total_fee = String.valueOf(total_Fee) ;//总金额(分)
        String spbill_create_ip = "127.0.0.1"; //终端IP
        String notify_url = NOTIFY_URL+"/wxNotify";//通知地址,用于接收微信支付回调
        String trade_type = TRADE_TYPE; //交易类型
        //签名	sign  后面追加
        // 2.0 生成map集合
        SortedMap<String, String> packageParams = new TreeMap<String, String>();
        packageParams.put("appid", appid); // 应用ID
        packageParams.put("mch_id", mch_id); // 商户号
        packageParams.put("attach", attach); // 商户号
        packageParams.put("nonce_str", nonce_str); // 生成随机数
        packageParams.put("out_trade_no", out_trade_no); // 生成商户订单号
        packageParams.put("total_fee", total_fee); // 总金额	(分)
        packageParams.put("body", body); // 商品描述
        packageParams.put("fee_type", fee_type); // 货币类型
        packageParams.put("notify_url", notify_url); // 通知地址
        packageParams.put("trade_type", trade_type); // 交易类型
        packageParams.put("spbill_create_ip", spbill_create_ip); // 终端IP
        Map<String, String> returnMap = new HashMap<>();
         try {
            // 3.0 利用上面的参数,先去生成自己的签名
            String sign = WXPayUtil.createSign(packageParams,PATERNERKEY);
//            String sign = WXPayUtil.createSign(packageParams,getSignkey());
            // 4.0 将签名再放回map中,它也是一个参数
            packageParams.put("sign", sign);
            // 5.0将当前的map结合转化成xml格式
            String xml = WXPayUtil.mapToXml(packageParams);
            logger.info(xml);
          // 6.0获取需要发送的url地址
            String wxUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder"; // 获取微信统一下单的api接口
         //String wxUrl = "https://api.mch.weixin.qq.com/sandboxnew/pay/unifiedorder"; // 微信沙盒测试模式,金额固定为 101分
            // 7,向微信发送请求
            String returnXml = CertHttpUtil.postData(wxUrl, xml);
             // 8,将微信返回的xml结果转成map格式
            returnMap = WXPayUtil.xmlToMap(returnXml);
            if("SUCCESS".equals(returnMap.get("return_code"))){
            //再次加密sign,为确保加密一致,故后端加密后返回前端
            	long timestamp=  WXPayUtil.getCurrentTimestamp();//时间戳
                String noncestr = WXPayUtil.generateNonceStr();//随机字符串
                String sign1= getSign(returnMap.get("prepay_id"),String.valueOf(timestamp),noncestr);
                returnMap.put("nonce_str",noncestr);
                returnMap.put("sign",sign1);
                returnMap.put("timestamp",String.valueOf(timestamp));
                outDTO.put("returnMap",returnMap);//返回调取微信APP所需的参数
                outDTO.put("out_trade_no",out_trade_no);//上面生成的商户订单号
                 outDTO.put("res","success")
                 /*这里可以先创建一条订单信息,
                 *01:已支付;02:已取消;03:待支付。
                 *支付类型暂定为03:待支付,因为用户取消支付,后端不会收到回调数据,
                 *所以暂定为待支付,等到收到回调数据后再修改支付状态。
                 */
            }else{
                logger.error("获取prepay_id失败");
                //定义返回信息
                outDTO.put("res","获取prepay_id失败")
            }
            }catch (Exception e){
			//省略
        }
        return outDTO;

三、商户APP调起微信支付,此为前端操作,后端不做说明
四、商户后端接收微信支付通知

@RequestMapping("/wxNotify")
    @ResponseBody
    public void wxNotify(HttpServletRequest request, HttpServletResponse response){
        try {
            String returnXml = reciverWx(request); // 接收到异步的参数
            logger.info("***********************微信异步通知**************************");
            logger.info(returnXml);
            Map<String, String> returnMap = WXPayUtil.xmlToMap(returnXml);// 解析xml成map
            // 过滤空 设置 TreeMap
            SortedMap<String, String> packageParams = new TreeMap<String, String>();
            Iterator it = returnMap.keySet().iterator();
            while (it.hasNext())
            {
                String parameter = (String) it.next();
                String parameterValue = returnMap.get(parameter);
                String v = "";
                if (null != parameterValue)
                {
                    v = parameterValue.trim();
                }
                packageParams.put(parameter, v);
            }
            // 判断签名是否正确
            String resXml = "";
            if (WXPayUtil.isSignatureValid(packageParams,PATERNERKEY)) {
                if ("SUCCESS".equals(packageParams.get("return_code"))) {
                  // 返回成功,获取订单号,获取金额
                  String out_trade_no = packageParams.get("out_trade_no"); // 商户订单号
                  String total_fee = packageParams.get("total_fee");
                  //再获取系统中储存的订单信息
                  /*
                  *查询系统中储存的订单信息,略
                  */
                  //进行比对
                  if(订单号一致&&金额一致){
                  /*
				   *这里写支付成功后的业务代码,别忘了把前面设置的待支付状态,改为已支付!!
				   */
                  	logger.info("***********************微信异步通知-成功**************************");
                        resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                            + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
                  }else{
                    resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                            + "<return_msg><![CDATA[参数错误]]></return_msg>" + "</xml> ";
                   }
                 } else {// 如果微信返回支付失败,将错误信息返回给微信
                    resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                            + "<return_msg><![CDATA[交易失败]]></return_msg>" + "</xml> ";
                }
            }else{
                resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                        + "<return_msg><![CDATA[通知签名验证失败]]></return_msg>" + "</xml> ";
            }  
           // 处理业务完毕,将业务结果通知给微信
            // ------------------------------
            BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
            out.write(resXml.getBytes());
            out.flush();
            out.close();
        }catch (Exception e){
            e.getMessage();
        }

    }  
    /**
     * 接收微信的异步通知
     *
     * @throws IOException
     */
    public static String reciverWx(HttpServletRequest request) throws IOException
    {
        InputStream inputStream;
        StringBuffer sb = new StringBuffer();
        inputStream = request.getInputStream();
        String s;
        BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
        while ((s = in.readLine()) != null)
        {
            sb.append(s);
        }
        in.close();
        inputStream.close();
        return sb.toString();
    }     

注:代码中所用到的工具类(WXPayUtil),均为微信原生代码。微信官方API文档---->SDK和DEMO下载

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值