weixin-java-pay实现公众号微信支付与退款

pom.xml 文件
需要在 pom.xml 加入以下依赖!

  <dependency>
        <groupId>com.github.binarywang</groupId>
        <artifactId>weixin-java-pay</artifactId>
        <version>3.0.0</version>
    </dependency>

application.yml 文件
将 application.yml 中修改自己商户平台的信息,以下 keyPath 是证书,可以在微信支付后台下载,指定相关目录即可。


wx:
  pay:
    appId: #微信公众号或者小程序等的appid
    mchId: #微信支付商户号
    mchKey: #微信支付商户密钥
    keyPath: # p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头)
    tradeType: JSAPI  #JSAPI--公众号支付    NATIVE--原生扫码支付   APP--app支付 

假设我们将证书放到 resources 目录下,那写成以下形式即可。

keyPath: classpath:证书名

还需要准备两个配置文件

WechatPayConfig 文件

import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
 
/**
 * @author Gentle
 * @date 2019/05/05
 * 微信支付信息注入bean 中
 */
@Component
public class WeChatPayConfig {
    @Autowired
    private WeChatPayProperties properties;
 
    @Bean
    @ConditionalOnMissingBean
    public WxPayConfig payConfig() {
        WxPayConfig payConfig = new WxPayConfig();
        payConfig.setAppId(this.properties.getAppId());
        payConfig.setMchId(this.properties.getMchId());
        payConfig.setMchKey(this.properties.getMchKey());
        payConfig.setKeyPath(this.properties.getKeyPath());
        payConfig.setTradeType(this.properties.getTradeType());
        payConfig.setNotifyUrl(this.properties.getNotifyUrl());
        return payConfig;
    }
    @Bean
    public WxPayService wxPayService(WxPayConfig payConfig) {
        WxPayService wxPayService = new WxPayServiceImpl();
        wxPayService.setConfig(payConfig);
        return wxPayService;
    }
}

微信支付接口的 Controller

import com.gentle.config.WeChatPayProperties;
import com.gentle.entity.ReturnPayInfoVO;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.util.SignUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
 
import java.math.BigDecimal;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.Map;
 
/**
 * @author : Gentle
 * @date : 2019/5/17 12:11
 * @description:
 */
@RestController
@RequestMapping(value = "/api/client/pay/")
public class WeChatPayController {
 
    @Autowired
    private WxPayService wxPayService;
    @Autowired
    WeChatPayProperties weChatPayProperties;
 
    /**
     * 此处处理订单信息,构建订单数据。
     *
     * 将构建好的支付参数返回到前端,前端调起微信支付
     * @return
     */
    @GetMapping(value = "weChatPay")
    public ReturnPayInfoVO weChatPay() {
        /**
         * 处理内部业务,校验订单等
         */
        final WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest = WxPayUnifiedOrderRequest.newBuilder()
                //调起支付的人的 openId
                .openid("openId")
                //订单编号
                .outTradeNo("我们系统内部订单号")
                //订单金额
                .totalFee(yuanToFee(new BigDecimal(100)))
                //商品描述
                .body("订单信息")
                //获取本地IP
                .spbillCreateIp(InetAddress.getLoopbackAddress().getHostAddress())
                //回调的 URL 地址
                .notifyUrl("http://我们的域名/api/client/pay/weChatPayNotify")
                .build();
        WxPayUnifiedOrderResult wxPayUnifiedOrderResult =null;
        try {
            wxPayUnifiedOrderResult = wxPayService.unifiedOrder(wxPayUnifiedOrderRequest);
        } catch (WxPayException e) {
            e.printStackTrace();
            throw new RuntimeException("微信支付调起失败!");
        }
        //组合参数构建支付
        Map<String, String> paySignInfo = new HashMap<>(5);
        String timeStamp = createTimestamp();
        String nonceStr = String.valueOf(System.currentTimeMillis());
        paySignInfo.put("appId", weChatPayProperties.getAppId());
        paySignInfo.put("nonceStr", nonceStr);
        paySignInfo.put("timeStamp", timeStamp);
        paySignInfo.put("signType", "MD5");
        paySignInfo.put("package", "prepay_id=" + wxPayUnifiedOrderResult.getPrepayId());
        String paySign = SignUtils.createSign(paySignInfo, "MD5", weChatPayProperties.getMchKey(), false);
 
        //组合支付参数
        ReturnPayInfoVO returnPayInfoVO = new ReturnPayInfoVO();
        returnPayInfoVO.setAppId(weChatPayProperties.getAppId());
        returnPayInfoVO.setNonceStr(nonceStr);
        returnPayInfoVO.setPaySign(paySign);
        returnPayInfoVO.setSignType("MD5");
        returnPayInfoVO.setPrepayId(wxPayUnifiedOrderResult.getPrepayId());
        returnPayInfoVO.setTimeStamp(timeStamp);
 
        return returnPayInfoVO;
    }
 
    /**
     *
     * @param xmlData 微信返回的流
     * @return
     */
    @RequestMapping(value = "weChatPayNotify",method = {RequestMethod.GET,RequestMethod.POST})
    public String weChatNotify(@RequestBody String xmlData){
 
        try {
            final WxPayOrderNotifyResult notifyResult = this.wxPayService.parseOrderNotifyResult(xmlData);
            //这里是存储我们发起支付时订单号的信息,所以取出来
            notifyResult.getOutTradeNo();
            /**
             * 系统内部业务,修改订单状态之类的
             */
            //成功后回调微信信息
            return WxPayNotifyResponse.success("回调成功!");
        } catch (WxPayException e) {
            e.printStackTrace();
            return WxPayNotifyResponse.fail("回调有误!");
        }
    }
    /**
     * 1 块钱转为 100 分
     * 元转分
     *
     * @param bigDecimal 钱数目
     * @return 分
     */
    private int yuanToFee(BigDecimal bigDecimal) {
        return bigDecimal.multiply(new BigDecimal(100)).intValue();
    }
    /**
     * 时间
     *
     * @return 时间戳
     */
    private String createTimestamp() {
        return Long.toString(System.currentTimeMillis() / 1000);
    }
}

上述代码便是位置支付的调起信息和支付成功后回调的处理逻辑了,可以对代码进行适当的修改,便可使用。

微信退款实现:
以下便是微信退款的实现,代码也相对简单,修改以下便可使用,当然要各种参数校验等,否则可能会出现被人恶意调起的可能

import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
 
import java.math.BigDecimal;
 
/**
 * @author : Gentle
 * @date : 2019/5/17 12:38
 * @description:
 */
@RestController
@RequestMapping(value = "/api/client/refund/")
@Slf4j
public class WeChatRefundController {
 
    private static final String REFUND_SUCCESS = "SUCCESS";
 
    @Autowired
    private WxPayService wxPayService;
 
    @PostMapping(value = "weChatRefund")
    public String refund() {
        //申请退款
        WxPayRefundRequest refundInfo = WxPayRefundRequest.newBuilder()
                //订单号
                .outTradeNo("自己系统订单号")
                //退款订单号
                .outRefundNo("自己系统订单号")
                //金额
                .totalFee(yuanToFee(new BigDecimal(100)))
                //退款金额
                .refundFee(yuanToFee(new BigDecimal(100)))
                //todo 回调地址
                .notifyUrl("http://我们系统的域名/api/client/refund/refundNotify")
                .build();
        WxPayRefundResult wxPayRefundResult;
        try {
            wxPayRefundResult = wxPayService.refund(refundInfo);
            //判断退款信息是否正确
            if (REFUND_SUCCESS.equals(wxPayRefundResult.getReturnCode())
                    && REFUND_SUCCESS.equals(wxPayRefundResult.getResultCode())) {
                /**
                 * 系统内部业务逻辑
                 */
                return "正在退款中。。";
            }
        } catch (WxPayException e) {
            log.error("微信退款接口错误信息= {}", e);
        }
 
        return "退款失败";
    }
 
 
    /**
     * 仅支持一次性退款,多次退款需要修改逻辑
     * @param xmlData 微信返回的流数据
     * @return
     */
    @RequestMapping(value = "refundNotify",method = {RequestMethod.GET,RequestMethod.POST})
    public String refundNotify(@RequestBody String xmlData) {
 
        WxPayRefundNotifyResult wxPayRefundNotifyResult;
        try {
            wxPayRefundNotifyResult = wxPayService.parseRefundNotifyResult(xmlData);
        } catch (WxPayException e) {
            log.error("退款失败,失败信息:{}", e);
            return WxPayNotifyResponse.fail("退款失败");
        }
        //判断你返回状态信息是否正确
        if (REFUND_SUCCESS.equals(wxPayRefundNotifyResult.getReturnCode())) {
            WxPayRefundNotifyResult.ReqInfo reqInfo = wxPayRefundNotifyResult.getReqInfo();
            //判断退款状态
            if (REFUND_SUCCESS.equals(reqInfo.getRefundStatus())) {
                //内部订单号
                String outTradeNo = reqInfo.getOutTradeNo();
                /**
                 * 一、可能会重复回调,需要做防重判断
                 * 二、处理我们系统内部业务,做修改订单状态,释放资源等!
                 */
                return WxPayNotifyResponse.success("退款成功!");
            }
        }
        return WxPayNotifyResponse.fail("回调有误!");
    }
    /**
     * 1 块钱转为 100 分
     * 元转分
     *
     * @param bigDecimal 钱数目
     * @return 分
     */
    private int yuanToFee(BigDecimal bigDecimal) {
        return bigDecimal.multiply(new BigDecimal(100)).intValue();
    }
    /**
     * 时间
     *
     * @return 时间戳
     */
    private String createTimestamp() {
        return Long.toString(System.currentTimeMillis() / 1000);
    }
}

案例相关代码已经发布到 GitHub 和码云上,如有兴趣可以下载学习!
GitHub:
https://github.com/LuckyToMeet-Dian-N/WeChat-Demo/tree/master/wechat-pay-demo
码云:
https://gitee.com/reway_wen/WeChat-Demo/tree/master/wechat-pay-demo

总结:
上述便是微信支付和微信退款的实现!代码不难,只是开发资质倒是个问题。如果有资质的话,那这篇文章可能给到您一些帮助。

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
注意要点: 1,Topay里面的参数要填好:appid,appsecret,mch_id,partnerkey,spbill_create_ip 2,openid 需要微信授权获取到 3,每次支付orderNo要不同 openid参考实例: 1,授权链接地址:https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxba3445566677&redirect_uri=http://www.acc.com/weixin/pay/paydispatcher&response_type=code&scope=snsapi_userinfo&state=123#wechat_redirect 2,转向处理地址:通过第一个链接微信会把code传过来,之前参数获取就行 @RequestMapping(value = "/paydispatcher", method = { RequestMethod.GET }) public void payDispatcher(HttpServletRequest request, HttpServletResponse response) throws Exception { String code = request.getParameter("code"); String msg=""; if(code==null||code.equals("")){ msg="获取微信Code失败!"; request.setAttribute("msg" ,msg); request.getRequestDispatcher("/jsp/login.jsp").forward(request,response); }else{ WeixinUtil util = new WeixinUtil(); UserAccessToken token = (UserAccessToken) request.getSession().getAttribute("UserAccessToken"); if(null==token){ token = util.getAccessToken3(Constants.APPID, Constants.SECRET,code); request.getSession().setAttribute("UserAccessToken",token); } request.setAttribute("openid", token.getOpenid()); request.setAttribute("accessToken", token.getAccessToken()); request.setAttribute("refreshToken", token.getRefreshToken()); request.setAttribute("expiresIn", token.getExpiresIn()); request.getRequestDispatcher("/pay/index.jsp").forward(request,response); } } // 获取用户openid accesstoken public static UserAccessToken getAccessToken3(String appid , String appsecret,String code) { UserAccessToken accessToken = null; String requestUrl = Constants.GET_OPENID_ACCESSTOKEN_URL.replace("APPID" , appid).replace("APPSECRET" , appsecret).replace("CODE" , code); String json = httpRequest(requestUrl , "GET" , null); JSONObject jsonObject = JSONObject.fromObject(json); // 如果请求成功 if (null != jsonObject) { try { accessToken = new UserAccessToken(); accessToken.setAccessToken(jsonObject.getString("access_token")); accessToken.setRefreshToken(jsonObject.getString("refresh_token")); accessToken.setExpiresIn(jsonObject.getInt("expires_in")); accessToken.setOpenid(jsonObject.getString("openid")); accessToken.setScope(jsonObject.getString("scope")); } catch (Exception e) { accessToken = null; // 获取token失败 System.out.println("获取token失败 errcode:{} errmsg:{}"); } } return accessToken; }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值