zoukankan      html  css  js  c++  java
  • springboot接入微信app支付

    一:集成步骤

    1.引入依赖:

    <dependency>
      <groupId>com.github.wxpay</groupId>
      <artifactId>wxpay-sdk</artifactId>
      <version>0.0.3</version>
    </dependency>
    

    2.微信app支付参数配置:

    #服务器域名地址
    server.service-domain = http://127.0.0.1:8080
    
    #微信app支付
    pay.wxpay.app.appID = "你的appid"
    pay.wxpay.app.mchID = "你的商户id"
    pay.wxpay.app.key = "你的api秘钥,不是appSecret"
    #从微信商户平台下载的安全证书存放的路径、我放在resources下面,切记一定要看看target目录下的class文件下有没有打包apiclient_cert.p12文件
    pay.wxpay.app.certPath = static/cert/wxpay/apiclient_cert.p12
    #微信支付成功的异步通知接口
    pay.wxpay.app.payNotifyUrl=${server.service-domain}/api/wxPay/notify
    

    3.定义配置类:

    package com.annaru.upms.payment.config;
    
    import com.github.wxpay.sdk.WXPayConfig;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.stereotype.Component;
    
    import java.io.InputStream;
    
    /**
     * 配置我们自己的信息
     */
    @Component
    @ConfigurationProperties(prefix = "pay.wxpay.app")
    public class WxPayAppConfig implements WXPayConfig {
        /**
         * appID
         */
        private String appID;
    
        /**
         * 商户号
         */
        private String mchID;
    
        /**
         * API 密钥
         */
        private String key;
    
        /**
         * API证书绝对路径 (本项目放在了 resources/cert/wxpay/apiclient_cert.p12")
         */
        private String certPath;
    
        /**
         * HTTP(S) 连接超时时间,单位毫秒
         */
        private int httpConnectTimeoutMs = 8000;
    
        /**
         * HTTP(S) 读数据超时时间,单位毫秒
         */
        private int httpReadTimeoutMs = 10000;
    
        /**
         * 微信支付异步通知地址
         */
        private String payNotifyUrl;
    
        /**
         * 微信退款异步通知地址
         */
        private String refundNotifyUrl;
    
        /**
         * 获取商户证书内容(这里证书需要到微信商户平台进行下载)
         *
         * @return 商户证书内容
         */
        @Override
        public InputStream getCertStream() {
            InputStream certStream  =getClass().getClassLoader().getResourceAsStream(certPath);
            return certStream;
        }
    
        public String getAppID() {
            return appID;
        }
    
        public void setAppID(String appID) {
            this.appID = appID;
        }
    
        public String getMchID() {
            return mchID;
        }
    
        public void setMchID(String mchID) {
            this.mchID = mchID;
        }
    
        public String getKey() {
            return key;
        }
    
        public void setKey(String key) {
            this.key = key;
        }
    
        public String getCertPath() {
            return certPath;
        }
    
        public void setCertPath(String certPath) {
            this.certPath = certPath;
        }
    
        public int getHttpConnectTimeoutMs() {
            return httpConnectTimeoutMs;
        }
    
        public void setHttpConnectTimeoutMs(int httpConnectTimeoutMs) {
            this.httpConnectTimeoutMs = httpConnectTimeoutMs;
        }
    
        public int getHttpReadTimeoutMs() {
            return httpReadTimeoutMs;
        }
    
        public void setHttpReadTimeoutMs(int httpReadTimeoutMs) {
            this.httpReadTimeoutMs = httpReadTimeoutMs;
        }
    
        public String getPayNotifyUrl() {
            return payNotifyUrl;
        }
    
        public void setPayNotifyUrl(String payNotifyUrl) {
            this.payNotifyUrl = payNotifyUrl;
        }
    
        public String getRefundNotifyUrl() {
            return refundNotifyUrl;
        }
    
        public void setRefundNotifyUrl(String refundNotifyUrl) {
            this.refundNotifyUrl = refundNotifyUrl;
        }
    }
    

    4. 定义controller:

    在调用微信服务接口进行统一下单之前,

    1、为保证安全性,建议验证数据库是否存在订单号对应的订单。

    package com.annaru.upms.payment.controller;
    
    import com.annaru.common.result.ResultMap;
    import com.annaru.upms.payment.service.WxPayService;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    import io.swagger.annotations.ApiParam;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.servlet.http.HttpServletRequest;
    
    @Api(tags = "微信支付接口管理")
    @RestController
    @RequestMapping("/wxPay")
    public class WxPayController{
    
        @Autowired
        private WxPayService wxPayService;
    
        /**
         * 统一下单接口
         */
        @ApiOperation(value = "统一下单", notes = "统一下单")
        @GetMapping("/unifiedOrder")
        public ResultMap unifiedOrder(
            @ApiParam(value = "订单号") @RequestParam String orderNo,
            @ApiParam(value = "订单金额") @RequestParam double amount,
            @ApiParam(value = "商品名称") @RequestParam String body,
                                      HttpServletRequest request) {
            try {
                // 1、验证订单是否存在
                
                // 2、开始微信支付统一下单
                ResultMap resultMap = wxPayService.unifiedOrder(orderNo, orderNo, body);
                return resultMap;//系统通用的返回结果集,见文章末尾
            } catch (Exception e) {
                logger.error(e.getMessage());
                return ResultMap.error("运行异常,请联系管理员");
            }
        }
        
        /**
         * 微信支付异步通知
         */
        @RequestMapping(value = "/notify")
        public String payNotify(HttpServletRequest request) {
            InputStream is = null;
            String xmlBack = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[报文为空]]></return_msg></xml> ";
            try {
                is = request.getInputStream();
                // 将InputStream转换成String
                BufferedReader reader = new BufferedReader(new InputStreamReader(is));
                StringBuilder sb = new StringBuilder();
                String line = null;
                while ((line = reader.readLine()) != null) {
                    sb.append(line + "\n");
                }
                xmlBack = wxPayService.notify(sb.toString());
            } catch (Exception e) {
                logger.error("微信手机支付回调通知失败:", e);
            } finally {
                if (is != null) {
                    try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return xmlBack;
        }
        
        @ApiOperation(value = "退款", notes = "退款")
        @PostMapping("/refund")
        public ResultMap refund(@ApiParam(value = "订单号") @RequestParam String orderNo,
                                @ApiParam(value = "退款金额") @RequestParam double amount,
                                @ApiParam(value = "退款原因") @RequestParam(required = false) String refundReason){
    
            return wxPayService.refund(orderNo, amount, refundReason);
        }
    
    }
    

    5、定义service接口:

    package com.annaru.upms.payment.service;
    
    import com.annaru.common.result.ResultMap;
    
    /**
     * 微信支付服务接口
     */
    public interface WxPayService {
    
        /**
         * @Description: 微信支付统一下单
         * @param orderNo: 订单编号
         * @param amount: 实际支付金额
         * @param body: 订单描述
         * @Author: 
         * @Date: 2019/8/1
         * @return
         */
        ResultMap unifiedOrder(String orderNo, double amount, String body) ;
    
        /**
         * @Description: 订单支付异步通知
         * @param notifyStr: 微信异步通知消息字符串
         * @Author: 
         * @Date: 2019/8/1
         * @return 
         */
        String notify(String notifyStr) throws Exception;
        
        /**
         * @Description: 退款
         * @param orderNo: 订单编号
         * @param amount: 实际支付金额
         * @param refundReason: 退款原因
         * @Author: XCK
         * @Date: 2019/8/6
         * @return
         */
        ResultMap refund(String orderNo, double amount, String refundReason);
    
    }
    
    

    6、service实现类

    package com.annaru.upms.payment.service.impl;
    
    import com.alibaba.dubbo.config.annotation.Reference;
    import com.annaru.common.result.ResultMap;
    import com.annaru.common.util.HttpContextUtils;
    import com.annaru.upms.payment.config.WxPayAppConfig;
    import com.annaru.upms.payment.service.WxPayService;
    import com.annaru.upms.service.IOrderPaymentService;
    import com.github.wxpay.sdk.WXPay;
    import com.github.wxpay.sdk.WXPayUtil;
    import org.apache.commons.lang3.StringUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import java.util.HashMap;
    import java.util.Map;
    
    @Service
    public class WxPayServiceImpl implements WxPayService {
        private final Logger logger = LoggerFactory.getLogger(WxPayServiceImpl.class);
    
        @Reference
        private IOrderPaymentService orderPaymentService;
        @Autowired
        private WxPayAppConfig wxPayAppConfig;
    
        @Override
        public ResultMap unifiedOrder(String orderNo, double amount, String body) {
            Map<String, String> returnMap = new HashMap<>();
            Map<String, String> responseMap = new HashMap<>();
            Map<String, String> requestMap = new HashMap<>();
            try {
                WXPay wxpay = new WXPay(wxPayAppConfig);
                requestMap.put("body", body);                                     // 商品描述
                requestMap.put("out_trade_no", orderNo);                          // 商户订单号
                requestMap.put("total_fee", String.valueOf((int)(amount*100)));   // 总金额
                requestMap.put("spbill_create_ip", HttpContextUtils.getIpAddr()); // 终端IP
                requestMap.put("trade_type", "APP");                              // App支付类型
                requestMap.put("notify_url", wxPayAppConfig.getPayNotifyUrl());   // 接收微信支付异步通知回调地址
                Map<String, String> resultMap = wxpay.unifiedOrder(requestMap);
                //获取返回码
                String returnCode = resultMap.get("return_code");
                String returnMsg = resultMap.get("return_msg");
                //若返回码为SUCCESS,则会返回一个result_code,再对该result_code进行判断
                if ("SUCCESS".equals(returnCode)) {
                    String resultCode = resultMap.get("result_code");
                    String errCodeDes = resultMap.get("err_code_des");
                    if ("SUCCESS".equals(resultCode)) {
                        responseMap = resultMap;
                    }
                }
                if (responseMap == null || responseMap.isEmpty()) {
                    return ResultMap.error("获取预支付交易会话标识失败");
                }
                // 3、签名生成算法
                Long time = System.currentTimeMillis() / 1000;
                String timestamp = time.toString();
                returnMap.put("appid", wxPayAppConfig.getAppID());
                returnMap.put("partnerid", wxPayAppConfig.getMchID());
                returnMap.put("prepayid", responseMap.get("prepay_id"));
                returnMap.put("noncestr", responseMap.get("nonce_str"));
                returnMap.put("timestamp", timestamp);
                returnMap.put("package", "Sign=WXPay");
                returnMap.put("sign", WXPayUtil.generateSignature(returnMap, wxPayAppConfig.getKey()));//微信支付签名
                return ResultMap.ok().put("data", returnMap);
            } catch (Exception e) {
                logger.error("订单号:{},错误信息:{}", orderNo, e.getMessage());
                return ResultMap.error("微信支付统一下单失败");
            }
        }
    
        @Override
        public String notify(String notifyStr) {
            String xmlBack = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[报文为空]]></return_msg></xml> ";
            try {
                // 转换成map
                Map<String, String> resultMap = WXPayUtil.xmlToMap(notifyStr);
                WXPay wxpayApp = new WXPay(wxPayAppConfig);
                if (wxpayApp.isPayResultNotifySignatureValid(resultMap)) {
                    String returnCode = resultMap.get("return_code");  //状态
                    String outTradeNo = resultMap.get("out_trade_no");//商户订单号
                    String transactionId = resultMap.get("transaction_id");
                    if (returnCode.equals("SUCCESS")) {
                        if (StringUtils.isNotBlank(outTradeNo)) {
                            /**
                             * 注意!!!
                             * 请根据业务流程,修改数据库订单支付状态,和其他数据的相应状态
                             *
                             */
                            logger.info("微信手机支付回调成功,订单号:{}", outTradeNo);
                            xmlBack = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return xmlBack;
        }
        
         @Override
        public ResultMap refund(String orderNo, double amount, String refundReason){
    
            if(StringUtils.isBlank(orderNo)){
                return ResultMap.error("订单编号不能为空");
            }
            if(amount <= 0){
                return ResultMap.error("退款金额必须大于0");
            }
    
            Map<String, String> responseMap = new HashMap<>();
            Map<String, String> requestMap = new HashMap<>();
            WXPay wxpay = new WXPay(wxPayAppConfig);
            requestMap.put("out_trade_no", orderNo);
            requestMap.put("out_refund_no", UUIDGenerator.getOrderNo());
            requestMap.put("total_fee", "订单支付时的总金额,需要从数据库查");
            requestMap.put("refund_fee", String.valueOf((int)(amount*100)));//所需退款金额
            requestMap.put("refund_desc", refundReason);
            try {
                responseMap = wxpay.refund(requestMap);
            } catch (Exception e) {
                e.printStackTrace();
            }
            String return_code = responseMap.get("return_code");   //返回状态码
            String return_msg = responseMap.get("return_msg");     //返回信息
            if ("SUCCESS".equals(return_code)) {
                String result_code = responseMap.get("result_code");       //业务结果
                String err_code_des = responseMap.get("err_code_des");     //错误代码描述
                if ("SUCCESS".equals(result_code)) {
                    //表示退款申请接受成功,结果通过退款查询接口查询
                    //修改用户订单状态为退款申请中或已退款。退款异步通知根据需求,可选
                    //
                    return ResultMap.ok("退款申请成功");
                } else {
                    logger.info("订单号:{}错误信息:{}", orderNo, err_code_des);
                    return ResultMap.error(err_code_des);
                }
            } else {
                logger.info("订单号:{}错误信息:{}", orderNo, return_msg);
                return ResultMap.error(return_msg);
            }
        }
    
    }
    
    

    7、定义通用返回结果集 ResultMap

    package com.annaru.common.result;
    
    import org.apache.http.HttpStatus;
    
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * @Description 通用返回结果集
     * @Author 
     * @Date 2018/6/12 15:13
     */
    public class ResultMap extends HashMap<String, Object> {
        public ResultMap() {
            put("state", true);
            put("code", 0);
            put("msg", "success");
        }
    
        public static ResultMap error(int code, String msg) {
            ResultMap r = new ResultMap();
            r.put("state", false);
            r.put("code", code);
            r.put("msg", msg);
            return r;
        }
    
        public static ResultMap error(String msg) {
            return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, msg);
        }
    
        public static ResultMap error() {
            return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, "未知异常,请联系管理员");
        }
    
        public static ResultMap ok(String msg) {
            ResultMap r = new ResultMap();
            r.put("msg", msg);
            return r;
        }
    
        public static ResultMap ok(Map<String, Object> par) {
            ResultMap r = new ResultMap();
            r.putAll(par);
            return r;
        }
    
        public static ResultMap ok() {
            return new ResultMap();
        }
    
        public ResultMap put(String key, Object value) {
            super.put(key, value);
            return this;
        }
    
    }
    

     转自:https://www.cnblogs.com/apes-book/p/11404289.html

     
     
  • 相关阅读:
    小程序携带参数转发
    小程序开发过程中问题终结
    在小程序中使用md5处理需要加密的字符串(含中文的字符串)
    php 字符串的处理
    PHP 数组(array)
    php数学运算
    php 单双引号的区别
    PHP 结构控制 if else / switch / while / do while
    JavaScript best practices JS最佳实践
    java入门概念梳理总结
  • 原文地址:https://www.cnblogs.com/javalinux/p/14760198.html
Copyright © 2011-2022 走看看