Java 微信支付 步骤 以及代码

用于个人记录,以防后续用到,也希望能帮助到更多的小伙伴

微信支付步骤及代码:

  • 1、商户生成订单

  • 2、商户调用微信下单接口,获取预交易的链接

  • 3、商户将链接生成二维码图片,展示给用户;

  • 4、支付结果通知:

    • 微信异步通知商户支付结果,商户告知微信支付接收情况

    • 商户如果没有收到通知,可以调用接口,查询支付状态

  • 5、如果支付成功,发货,修改订单状态

 

微信支付官方文档:https://pay.weixin.qq.com/index.php/core/home/login?return_url=%2F

用到的是:Native支付, 就是扫码支付

参数以及返回值 具体去官网查看

以下是具体步骤以及代码 还有 需要注意的几个点和坑:

官网下载 : wx-sdk 打成jar包 引入maven

命令:mvn source:jar install -Dmaven.test.skip=true 或者 用maven插件

1.application中加入:

ly:
  pay:
    wx:
      appID: wx*********
      mchID: ********
      key: *******
      payType: NATIVE

2.配置类:

package com.leyou.order.config;

import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayConfigImpl;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class PayConfiguration {

    @Bean
    @ConfigurationProperties(prefix = "ly.pay.wx")
    public WXPayConfigImpl payConfig(){
        return new WXPayConfigImpl();
    }


    /**
     * 注册WXPay对象
     * @param payConfig 支付相关配置
     * @return WXPay对象
     * @throws Exception 连结WX失败时用到
     */
    @Bean
    public WXPay wxPay(WXPayConfigImpl payConfig) throws Exception {
        return new WXPay(payConfig);
    }
}

================以下开始生成支付二维码并且给前台返回=============================

3.订单生成以后 传入一个 orderId (订单ID)到后台 , 进入支付界面生成二维码

payHelper 工具类:

package com.leyou.order.utils;

import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayConfigImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

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

/**
 * 支付的工具类
 */
@Slf4j
@Component //加入spring 容器
public class PayHelper {

    @Autowired
    private WXPay wxPay;

    @Autowired
    private WXPayConfigImpl wxPayConfig;


    /**
     * 创建微信支付订单
     * @param body
     * @param orderId
     * @param totalFee
     * @return
     */
    public String createOrder(String body,Long orderId,Long totalFee){
        Map map = new HashMap<>();
//        商品描述
        map.put("body",body);
//        本系统的订单号
        map.put("out_trade_no",orderId.toString());
//        订单的支付金额
        map.put("total_fee",totalFee.toString());
//        终端id
        map.put("spbill_create_ip","IP地址例127.0.0.1需要修改");
//        通知地址
        map.put("notify_url","网关getway地址/api/pay/wxnotify");
//        交易类型
        map.put("trade_type","NATIVE");
        try{
            Map result = wxPay.unifiedOrder(map);
            log.info("【微信支付】result:{}",result);
            // 校验业务状态
            checkResultCode(result);
//          codeurl用来生成二维码
            String codeUrl = result.get("code_url");
            log.info("【微信支付】codeUrl:{}",codeUrl);
            return codeUrl;
        }catch(Exception e){
            e.printStackTrace();
            log.error("【微信支付】微信支付业务失败");
            throw  new RuntimeException("微信支付失败");
        }
    }

    public void checkResultCode(Map result) {
        // 检查业务状态
        String resultCode = result.get("result_code");
        if ("FAIL".equals(resultCode)) {
            log.error("【微信支付】微信支付业务失败,错误码:{},原因:{}", result.get("err_code"), result.get("err_code_des"));
            throw new RuntimeException("【微信支付】微信支付业务失败");
        }
    }
}

 

 

controller:

@GetMapping("/url/{id}")
public ResponseEntity getCodeUrl(@PathVariable(name = "id")Long orderId){
    return ResponseEntity.ok(orderService.getCodeUrl(orderId));
}

Service :

    @Autowired
    private PayHelper payHelper;
    @Autowired
    private StringRedisTemplate redisTemplate;

    private String PRE_FIX = "ly:order:pay:id:";
    /**
     * 获取连接
     * @param orderId
     * @return
     */
    public String getCodeUrl(Long orderId) {
        String redisKey = PRE_FIX + orderId;
        String codeUrl = redisTemplate.opsForValue().get(redisKey);
        if(!StringUtils.isEmpty(codeUrl)){
            return codeUrl;
        }
        TbOrder tbOrder = tbOrderService.getById(orderId);
//        实付金额,为了测试改成1分 ,应该写为 实付金额从数据库中查取
        Long actualFee = 1L;//tbOrder.getActualFee();
        String body = "商城支付";
//        用户微信支付的url
        codeUrl = payHelper.createOrder(body, orderId, actualFee);
//        codeurl有2小时的有效期,需要放入redis ,并设置过期时长
        redisTemplate.opsForValue().set(redisKey,codeUrl,2, TimeUnit.HOURS);
        //给用户返回 codeUrl 就是二维码
        return codeUrl;
    }

以上生成二维码 ==========================================================================

用户扫完二维码以后会有一个回调地址进入回调方法中

=====================

以下有一个注意事项:

@RestController
@PostMapping(value = "/wxnotify",produces = "application/xml")


   com.fasterxml.jackson.dataformat
   jackson-dataformat-xml
   2.9.6

1.回调到后台的数据是 xml 格式 所以我们这里要把xml 格式转化为对象map结构,需要配置 以上就是配置 需要引入坐标

2.返回也是 xml 这里用map 会自动转化成xml格式返回到前台

======================

以下回调以后的方法:

package com.leyou.order.controller;

import com.leyou.order.service.PayService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

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

@RestController
@RequestMapping("/pay")
public class PayController {

    @Autowired
    private PayService payService;
    /**
     * 接收 微信支付发来的回调
     * produces 说明request中的参数的媒体类型
     * 现在 媒体类型是 xml
     * @param map
     */
    @PostMapping(value = "/wxnotify",produces = "application/xml")
    public Map wxPayNotify(@RequestBody Map map){

            payService.wxPayNotify(map);

        //
        //
        //  
        //  
        //
            Map returnMap = new HashMap<>();
            returnMap.put("return_code","SUCCESS");
            returnMap.put("return_msg","OK");
            return returnMap;

    }
}

 

 

回调以后的Service:

package com.leyou.order.service;

import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayConstants;
import com.leyou.common.Exceptions.LyException;
import com.leyou.common.enums.ExceptionEnums;
import com.leyou.order.entity.TbOrder;
import com.leyou.order.enums.OrderStatusEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Map;

@Slf4j
@Service
public class PayService {
    @Autowired
    private TbOrderService tbOrderService;
    @Autowired
    private WXPay wxPay;
    /**
     * 接收微信支付的回调处理方法
     * 从参数中获取 orderid,和 用户支付金额
     * 和自己数据库的订单数据进行比对
     * 如果正确就直接返回
     * 如果不对,直接抛出异常
     * @param map
     */
    public void wxPayNotify(Map map) {
        if(map.get("result_code") == null || !map.get("result_code").equals(WXPayConstants.SUCCESS)){
            throw new LyException(ExceptionEnums.INVALID_NOTIFY_PARAM);
        }
        try {
            boolean bWeiChat = wxPay.isPayResultNotifySignatureValid(map);
        } catch (Exception e) {
            throw new LyException(ExceptionEnums.INVALID_NOTIFY_PARAM);
        }
//      本系统的订单号
        String orderId = map.get("out_trade_no");
//        用户支付的总金额
        String userPayTotal = map.get("total_fee");
        Long userPayTotalLong = Long.valueOf(userPayTotal);
//        查询数据库中的order信息
        Long orderIdLong = Long.valueOf(orderId);
        TbOrder tbOrder = tbOrderService.getById(orderIdLong);
//        订单的状态
        Integer status = tbOrder.getStatus();
//        订单的实付金额
        Long actualFee = tbOrder.getActualFee();
//        订单当前已经不是 未支付状态了
        if(status.intValue() != OrderStatusEnum.INIT.value().intValue()){
            return ;
        }
        //            用户的支付金额不一致,这里为了测试 把代码注掉,上线加上判断金额是否一致
//        if(actualFee.longValue() != userPayTotalLong.longValue()){
//
//            log.error("【微信支付】用户的付款金额不对!!");
//            throw new LyException(ExceptionEnums.INVALID_NOTIFY_PARAM);
//        }
//        支付成功后,修改状态,修改为 已支付,待发货
        tbOrderService.updateOrderStatusForPaySuccess(orderIdLong);
    }
}

 

修改订单状态:已经支付成功,将未支付改成已支付状态

package com.leyou.order.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.leyou.order.entity.TbOrder;
import com.leyou.order.enums.OrderStatusEnum;
import com.leyou.order.mapper.TbOrderMapper;
import com.leyou.order.service.TbOrderService;
import org.springframework.stereotype.Service;

/**
 * 

* 服务实现类 *

* * @author HM * @since 2019-10-15 */ @Service public class TbOrderServiceImpl extends ServiceImpl implements TbOrderService { /** * 把订单的状态改为 已支付 * @param orderId * @return */ @Override public void updateOrderStatusForPaySuccess(Long orderId) { // update tb_order set status =2 where order_id=? and status=1 UpdateWrapper updateWrapper = new UpdateWrapper<>(); updateWrapper.lambda().eq(TbOrder::getOrderId,orderId); updateWrapper.lambda().eq(TbOrder::getStatus, OrderStatusEnum.INIT.value()); updateWrapper.lambda().set(TbOrder::getStatus,OrderStatusEnum.PAY_UP.value()); this.update(updateWrapper); } }

====================================

注意事项:

update tb_order set status =2 where order_id=? and status=1

幂等

不写后面 and status=1 的话,状态会出问题,

本身已经是发货,但是执行了错误的sql 会把状态改回到2 这样会 重复发货

====================================

 

 

 

 

 

 

 

 

你可能感兴趣的:(java)