springboot微信sdk方式进行微信支付

微信支付:
官方文档:https://pay.weixin.qq.com/wiki/doc/api/index.html
第三方SDK:https://github.com/Pay-Group/best-pay-sdk

首先说明一下,微信支付功能接口权限只有微信服务号才拥有。

首先来看一下公众号支付的业务流程图。

springboot微信sdk方式进行微信支付_第1张图片

支付开发中,一般在第10步异步通知成功了,就基本上可以百分百说明支付成功了,可以修改支付状态为已支付。

开发步骤:

1.pom.xml中添加Maven依赖



    cn.springboot
    best-pay-sdk
    1.1.0

2.微信服务号信息配置

package com.wechat.order.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/*微信公众号账号设置*/
@Data//使用了lombok依赖,相当于在代码中getter和setter的作用
@Component
@ConfigurationProperties(prefix = "wechat")//账号信息写在了application.yml中。
public class WeChatAccountConfig {

    private String mpAppId;

    private String mpAppSecret;

    /**
     * 商户号
     */
    private String mchId;

    /**
     * 商户密钥
     */
    private String mchKey;

    /**
     * 商户证书路径
     */
    private String keyPath;

    /**
     * 异步通知路径
     */
    private String notifyUrl;
}
package com.wechat.order.config;

import com.lly835.bestpay.config.WxPayH5Config;
import com.lly835.bestpay.service.impl.BestPayServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

/*微信公众账号支付配置*/
@Component
public class WeChatPayConfig {

    @Autowired
    private WeChatAccountConfig weChatAccountConfig;

    //把你要实例化的对象转化成一个Bean,放在IoC容器中
    @Bean
    public BestPayServiceImpl bestPayService() {

        //支付类, 所有方法都在这个类里
        BestPayServiceImpl bestPayService = new BestPayServiceImpl();
        bestPayService.setWxPayH5Config(wxPayH5Config());
        return bestPayService;
    }

    @Bean
    private WxPayH5Config wxPayH5Config() {
        WxPayH5Config wxPayH5Config = new WxPayH5Config();
        wxPayH5Config.setAppId(weChatAccountConfig.getMpAppId());//设置微信公众号的appid
        wxPayH5Config.setAppSecret(weChatAccountConfig.getMpAppSecret());// 设置微信公众号的app corpSecret
        wxPayH5Config.setMchId(weChatAccountConfig.getMchId());// 设置商户号
        wxPayH5Config.setMchKey(weChatAccountConfig.getMchKey());// 设置商户密钥
        wxPayH5Config.setKeyPath(weChatAccountConfig.getKeyPath());// 设置商户证书路径
        wxPayH5Config.setNotifyUrl(weChatAccountConfig.getNotifyUrl());// 设置支付后异步通知url
        return wxPayH5Config;
    }
}

3.调用方法发起支付

controller

    /**
     * 微信支付发起
     * @param orderId
     * @param returnUrl
     * @return
     */
    @RequestMapping("/create")
    public ModelAndView create(@RequestParam("orderId")String orderId,
                               @RequestParam("returnUrl")String returnUrl,
                               HashMap map){

        //根据订单id查询订单,数据库查询
        OrderDTO orderDTO = orderService.findOne(orderId);
        if(orderDTO == null){//订单不存在抛出错误
            throw new SellException(ResultEnum.ORDER_NOT_EXIST);
        }

        //微信支付
        PayResponse payResponse = wechatPayService.create(orderDTO);

        //携带参数传入网页发起支付的前端模板
        map.put("orderId", orderId);
        map.put("payResponse", payResponse);

        return new ModelAndView("pay/create",map);
    }

service:

    //微信支付发起
    public PayResponse create(OrderDTO orderDTO) {
        PayRequest payRequest = new PayRequest();
        payRequest.setPayTypeEnum(BestPayTypeEnum.WXPAY_H5);//支付方式,微信公众账号支付
        payRequest.setOrderId(orderDTO.getOrderId());//订单号.
        payRequest.setOrderName(payName);//订单名字.
        payRequest.setOrderAmount(orderDTO.getOrderAmount().doubleValue());//订单金额.
        payRequest.setOpenid(orderDTO.getBuyerOpenid());//微信openid, 仅微信支付时需要
        log.info("【微信支付】request={}", JsonUtil.toJson(payRequest));//将payRequest格式化一下,再显示在日志上,便于观看数据
        PayResponse payResponse = bestPayService.pay(payRequest);
        log.info("【微信支付】response={}", JsonUtil.toJson(payResponse));//将payResponse格式化一下,再显示在日志上,便于观看响应后返回的数据);
        return payResponse;
    }

JsonUtil格式转换工具类:

/**
 * 把对象转换成json格式,便于观看
 */
public class JsonUtil {

    public static String toJson(Object object) {
        GsonBuilder gsonBuilder = new GsonBuilder();
        gsonBuilder.setPrettyPrinting();
        Gson gson = gsonBuilder.create();
        return gson.toJson(object);
    }
}
4.在static文件夹下编写微信内H5调起支付的前端代码pay.html(可以从微信支付官方文档中拷贝代码),检测是否可以支付, 此步骤可省略。
ps:为什么把支付的前端代码写在后台中?
如果放在前端的话,加入几个地方或几个模块都可以发起微信支付,每次发起都要调用这个前端代码,

这个前端代码就要写好几次。如果放在后端的话,只要给个请求,就可以直接调用这段代码。

5.对支付的前端代码动态注入参数以发起支付。
这里我们用到模板技术。

(1)在pom.xml中引入freemarker依赖

       
       
            org.springframework.boot
            spring-boot-starter-freemarker
       

(2)把controller中发起支付的方法返回类型改为ModelAndView,return new ModelAndView("path",model);//path为模板存放的路径,不包括模板后缀名。这里model我们采用Map类型,把payResponse和returnUrl携带过去。
(3)在相应的地方,创建模板文件xx.ftl。如我上述步骤的path为pay/create,则我在resources/templates目录下创建文件夹pay,在pay目录下再创建create.ftl文件。
(4)修改pay.html成模板,参数动态注入。${xxxx}

(5)模板中,支付后进行跳转到returnUrl。

create.ftl模板:

6.填写微信支付的支付授权目录。
比如我的前端支付代码访问路径是http://xxxxx(网站根路径)/sell/pay.html。

支付授权目录就写http://xxxxx(网站根路径)/sell/

7.微信异步通知,并在相应的controller中进行支付状态修改。
依靠前端返回的支付成功来判断成功并不安全,容易被篡改。必须依靠后端异步通知来判断是否已支付成功
(1)验证签名,支付状态
(2)校验支付金额与订单金额是否一致,2个金额相减小于0.01即认为相等。
(3)修改订单支付状态

service:

   /*微信支付异步通知*/
    @Override
    public PayResponse notify(String notifyData) {
        //1. 验证签名
        //2. 支付的状态
        //3. 支付金额
        //4. 支付人(下单人 == 支付人)

        PayResponse payResponse = bestPayService.asyncNotify(notifyData);
        log.info("【微信支付】异步通知, payResponse={}", JsonUtil.toJson(payResponse));

        //查询订单
        OrderDTO orderDTO = orderService.findOne(payResponse.getOrderId());

        //判断订单是否存在
        if (orderDTO == null) {
            log.error("【微信支付】异步通知, 订单不存在, orderId={}", payResponse.getOrderId());
            throw new SellException(ResultEnum.ORDER_NOT_EXIST);
        }

        //判断金额是否一致(0.10   0.1)
        if (!MathUtil.equals(payResponse.getOrderAmount(), orderDTO.getOrderAmount().doubleValue())) {
            log.error("【微信支付】异步通知, 订单金额不一致, orderId={}, 微信通知金额={}, 系统金额={}",
                    payResponse.getOrderId(),
                    payResponse.getOrderAmount(),
                    orderDTO.getOrderAmount());
            throw new SellException(ResultEnum.WXPAY_NOTIFY_MONEY_VERIFY_ERROR);
        }

        //修改订单的支付状态
        orderService.paid(orderDTO);

        return payResponse;
    }

controller:

    /**
     * 微信异步通知
     * @param notifyData
     */
    @PostMapping("/notify")
    public ModelAndView notify(@RequestBody String notifyData) {
        wechatPayService.notify(notifyData);

        //返回给微信处理结果
        return new ModelAndView("pay/success");
    }
}

success.ftl异步通知成功模板:


    
    

8.微信退款
(1)设置退款人,退款金额,退款方式
(2)退款

service:

   /**
     * 退款
     * @param orderDTO
     */
    @Override
    public RefundResponse refund(OrderDTO orderDTO) {
        RefundRequest refundRequest = new RefundRequest();
        refundRequest.setOrderId(orderDTO.getOrderId());
        refundRequest.setOrderAmount(orderDTO.getOrderAmount().doubleValue());
        refundRequest.setPayTypeEnum(BestPayTypeEnum.WXPAY_H5);
        log.info("【微信退款】request={}", JsonUtil.toJson(refundRequest));

        RefundResponse refundResponse = bestPayService.refund(refundRequest);
        log.info("【微信退款】response={}", JsonUtil.toJson(refundResponse));

        return refundResponse;
    }
}


你可能感兴趣的:(微信)