首页 > 其他分享 >SpringBoot集成微信APP支付

SpringBoot集成微信APP支付

时间:2024-05-10 16:37:03浏览次数:24  
标签:pay String 微信 APP private new import com SpringBoot

目录

废话不多说,先上代码

  • application-dev.yml
#支付
pay:
  # 支付回调通知地址
  notifyUrl: 别想C 填自己的
  #  微信App支付
  weChat: 别想C 填自己的
    # 微信支付AppID
    applyAppId: 别想C 填自己的
    # 微信支付商户号
    mchId: 别想C 填自己的
    # 微信支付API密钥
    apiV3Key: 别想C 填自己的
    # 微信支付证书序列号
    mchSerialNo: 别想C 填自己的
    # 微信支付证书私钥路径 ssl
    privateKeyPath: C:\Users\dzx\Desktop\yiNong\ssl\apiclient_key.pem
    # 微信支付接口域名地址
    domain: https://api.mch.weixin.qq.com
  • QuickStart
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

/**
 * APP 支付
 */
@Configuration
@Data
public class QuickStart {
    /**
     * applyAppId
     */
    @Value("${pay.weChat.applyAppId}")
    private String appid;
    /**
     * 商户号
     */
    @Value("${pay.weChat.mchId}")
    private String merchantId;
    /**
     * 商户API私钥路径
     */
    @Value("${pay.weChat.privateKeyPath}")
    private String privateKeyPath;
    /**
     * 商户证书序列号
     */
    @Value("${pay.weChat.mchSerialNo}")
    private String merchantSerialNumber;
    /**
     * 商户APIV3密钥
     */
    @Value("${pay.weChat.apiV3Key}")
    private String apiV3Key;

    @Value("${pay.notifyUrl}")
    private String notifyUrl;
}
  • 接收数据的实体
    Resource
import lombok.Data;

@Data
public class Resource {
    private String algorithm;
    private String ciphertext;
    private String associated_data;
    private String original_type;
    private String nonce;
}

PayNotifyParams

import lombok.Data;

@Data
public class PayNotifyParams {
    private String id;
    private String create_time;
    private String event_type;
    private String resource_type;
    private Resource resource;
    private String summary;
}

上业务代码

  • WeChatService
import com.ynjs.common.pay.weChat.app.PayNotifyParams;

import java.util.Map;

public interface WeChatService {
    /**
     * 调用统一下单API
     *
     * @param orderId
     * @return
     * @throws Exception
     */
    String appPay(String orderId) throws Exception;

    /**
     * 支付成功通知
     *
     * @param payNotifyParams
     * @return
     */
    Map<String, String> payNotify(PayNotifyParams payNotifyParams);

}
  • WeChatServiceImpl
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.google.gson.Gson;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.service.payments.app.AppServiceExtension;
import com.wechat.pay.java.service.payments.app.model.Amount;
import com.wechat.pay.java.service.payments.app.model.PrepayRequest;
import com.wechat.pay.java.service.payments.app.model.PrepayWithRequestPaymentResponse;
import com.ynjs.common.exception.CustomException;
import com.ynjs.common.pay.weChat.app.PayNotifyParams;
import com.ynjs.common.pay.weChat.app.QuickStart;
import com.ynjs.mapper.CrmUserOrderMapper;
import com.ynjs.mapper.DevIotClusterMapper;
import com.ynjs.pojo.CrmUserOrder;
import com.ynjs.pojo.DevIotCluster;
import com.ynjs.service.WeChatService;
import lombok.extern.log4j.Log4j2;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.security.GeneralSecurityException;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;


@Log4j2
@Service
public class WeChatServiceImpl implements WeChatService {
    @Resource
    private CrmUserOrderMapper crmUserOrderMapper;
    @Resource
    private QuickStart quickStart;
    @Resource
    private CloseableHttpClient httpClient;
    @Resource
    private DevIotClusterMapper devIotClusterMapper;

    /**
     * 支付成功通知
     *
     * @param orderId
     * @return
     */
    public String appPay(String orderId) {
        if (StrUtil.isBlank(orderId)) {
            throw new CustomException("订单不能为空");
        }
        CrmUserOrder cuo = crmUserOrderMapper.getUsOrderInfo(orderId);
        if (Objects.isNull(cuo)) {
            throw new CustomException("找不到该订单!");
        }
        CrmUserOrder crmUserOrder = crmUserOrderMapper.finishOrder(orderId);
        Integer payState = crmUserOrder.getPAY_STATE();
        if (payState == 1) {
            throw new CustomException("该订单已支付,请勿重复支付");
        }
        // 使用自动更新平台证书的RSA配置
        // 一个商户号只能初始化一个配置,否则会因为重复的下载任务报错
        Config config = new RSAAutoCertificateConfig.Builder()
                .merchantId(quickStart.getMerchantId())
                .privateKeyFromPath(quickStart.getPrivateKeyPath())
                .merchantSerialNumber(quickStart.getMerchantSerialNumber())
                .apiV3Key(quickStart.getApiV3Key())
                .build();
        // 构建service
        AppServiceExtension service = new AppServiceExtension.Builder().config(config).build();
        // request.setXxx(val)设置所需参数,具体参数可见Request定义
        PrepayRequest request = new PrepayRequest();
        BigDecimal payAmount = cuo.getPAY_AMOUNT();
        BigDecimal multiply = payAmount.multiply(new BigDecimal("100")); //乘
        Amount amount = new Amount();
        amount.setTotal(multiply.intValue());    // 金额(以分为单位)
        amount.setCurrency("CNY");
        request.setAmount(amount);
        request.setAppid(quickStart.getAppid());
        request.setMchid(quickStart.getMerchantId());
        request.setDescription("渔浪浪平台充值");
        request.setAttach(crmUserOrder.getIOT_CODE() + "-" + cuo.getRECHARGE());
        request.setNotifyUrl(quickStart.getNotifyUrl() + "/api/appapi/WeChatAppNotify");
        request.setOutTradeNo(orderId);
        // 调用下单方法,得到应答
        PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);
        response.getNonceStr();
        Gson gson = new Gson();
        return gson.toJson(response);
    }

    /**
     * 支付成功后回调通知
     *
     * @return
     */
    public Map<String, String> payNotify(PayNotifyParams payNotifyParams) {
        Map<String, String> res = new HashMap<>();
        try {
            String json = new AesUtil(quickStart.getApiV3Key().getBytes()).decryptToString(
                    payNotifyParams.getResource().getAssociated_data().getBytes(),
                    payNotifyParams.getResource().getNonce().getBytes(),
                    payNotifyParams.getResource().getCiphertext());
            String outTradeNo = JSON.parseObject(json, Map.class).get("out_trade_no").toString();
            String attach = JSON.parseObject(json, Map.class).get("attach").toString();
            String amount = JSON.parseObject(json, Map.class).get("amount").toString();
            String total = JSON.parseObject(amount, Map.class).get("total").toString();
            // 金额单位为分
            BigDecimal totalBig = new BigDecimal(total);
            LocalDateTime now = LocalDateTime.now();
            CrmUserOrder cuo = new CrmUserOrder();
            cuo.setOutTradeNo(outTradeNo);
            cuo.setTransactionId(JSON.parseObject(json, Map.class).get("transaction_id").toString());
            cuo.setCashFee(totalBig.divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP));
            cuo.setPAY_STATE(1);
            cuo.setORDER_ID(outTradeNo);
            cuo.setMEAL_EX(attach);
            cuo.setROW_DATE_UPDATE(now);
            int update = crmUserOrderMapper.UpdateOrder(cuo);
            if (update > 0) {
                CrmUserOrder order = crmUserOrderMapper.finishOrder(outTradeNo);
                Integer recharge = order.getRECHARGE();// 充值天数
                String iotCode = order.getIOT_CODE(); // 充值的SN设备
                DevIotCluster cluster = devIotClusterMapper.getCluster(iotCode);
                Duration duration = Duration.between(now, cluster.getDUE_DATE());
                long days = duration.toDays();
                if (days < 0) {
                    days = 0;
                }
                LocalDateTime timestamp = now.plusDays(recharge + days + 1);
                DevIotCluster dic = new DevIotCluster();
                dic.setDUE_DATE(timestamp);
                dic.setIOT_CODE(iotCode);
                dic.setROW_DATE_UPDATE(now);
                int 充值结果 = devIotClusterMapper.upByIotCode(dic);
                if (充值结果 > 0) {
                    res.put("code", JSON.parseObject(json, Map.class).get("trade_state").toString());
                    res.put("message", JSON.parseObject(json, Map.class).get("trade_state_desc").toString());
                }
            }
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
            res.put("code", "FAIL");
            res.put("message", "失败");
        }
        return res;
    }

    /**
     * 商户订单号查询订单
     *
     * @throws Exception
     */
    public void queryOrder(String orderId) throws Exception {
        //请求URL
        URIBuilder uriBuilder = new URIBuilder("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/" + orderId);
        uriBuilder.setParameter("mchid", quickStart.getMerchantId());
        //完成签名并执行请求
        HttpGet httpGet = new HttpGet(uriBuilder.build());
        httpGet.addHeader("Accept", "application/json");
        CloseableHttpResponse response = httpClient.execute(httpGet);
        try {
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == 200) {
                System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
            } else if (statusCode == 204) {
                System.out.println("success");
            } else {
                System.out.println("failed,resp code = " + statusCode + ",return body = " + EntityUtils.toString(response.getEntity()));
                throw new IOException("request failed");
            }
        } finally {
            response.close();
        }
    }

    /**
     * 关闭订单
     *
     * @throws Exception
     */
    public void closeOrder(String orderId) throws Exception {
        //请求URL
        HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/" + orderId + "/close");
        //请求body参数
        String reqdata = "{\"mchid\": \"" + quickStart.getMerchantId() + "\"}";
        StringEntity entity = new StringEntity(reqdata, "utf-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept", "application/json");
        //完成签名并执行请求
        CloseableHttpResponse response = httpClient.execute(httpPost);
        try {
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == 200) {
                System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
            } else if (statusCode == 204) {
                System.out.println("success");
            } else {
                System.out.println("failed,resp code = " + statusCode + ",return body = " + EntityUtils.toString(response.getEntity()));
                throw new IOException("request failed");
            }
        } finally {
            response.close();
        }
    }
}

import com.ynjs.common.pay.weChat.app.PayNotifyParams;
import com.ynjs.common.result.Result;
import com.ynjs.service.WeChatService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.log4j.Log4j2;
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 javax.annotation.Resource;

@Log4j2
@RestController
@RequestMapping("/appapi")
@Api(tags = "WX APP支付")
public class WeChatPayController {
    @Resource
    private WeChatService weChatService;

    /**
     * 微信APP支付 /api/wechat_pay/app/GetAppParams
     *
     * @param orderId
     * @return
     * @throws Exception
     */
    @PostMapping("/GetAppParams")
    @ApiOperation("调用统一下单API")
    public Result AppPay(String orderId) throws Exception {
        //调用微信服务获取App支付参数
        return Result.success(weChatService.appPay(orderId));
    }


    @PostMapping("/WeChatAppNotify")
    @ApiOperation("支付成功通知")
    public Result weChatAppNotify(@RequestBody PayNotifyParams payNotifyParams) {
        return Result.success(weChatService.payNotify(payNotifyParams));
    }
}

建议自己也看看官方文档,光C解决不了小问题。懂的吧

代码随着微信支付的迭代可能会有啥问题,及时评论!

标签:pay,String,微信,APP,private,new,import,com,SpringBoot
From: https://www.cnblogs.com/Aurora-dzx/p/18184733

相关文章

  • h5使用js拉起微信支付
    近期,业务需求对接了微信支付,做个总结。web网页想要拉起微信支付,有两种方法:H5下单支付,JSAPI支付。首先纯前端做不了微信支付,必须配合后端才能通过微信的下单请求。接下来说说这两种方法的区别。H5微信下单支付这种支付方式是用户在浏览器端打开网页,通过下单等操作,与后端交互......
  • windows服务器部署springboot项目
    @目录方法一使用cmd命令运行方法二将项目配置成服务运行部署第一步:编写xml文件执行命令生成一个服务删除这个服务如有问题可在评论区发表。方法一使用cmd命令运行java-jartestboot.jar输入java-jar直接将jar包拖进去,然后按enter(回车)就好了。如果失败,那就是jar......
  • app测试注意点
    业务测试方面:1功能性2安装与卸载3软件更新升级4登录测试5离线测试6UI界面7安全性测试8兼容性(操作系统、屏幕尺寸、分辨率)9消息推送10前后台切换11网络环境(WIFI、2G、3G、4G、无网路)12异常中断13性能测试1、安装、卸载测试:1)、下载apk文件后,在真机环境下进行安装、......
  • uniapp 周选择范围时间
      css使用点击查看下载css库css自定义的样式:/*亮高*/.box-blue{background-color:#409EFF;color:white;border-radius:10rpx;}/*中间连接背景颜色*/.bg-light-blue{width:80rpx;height:80rpx;background-color:#e7f2ff......
  • SpringBoot读取Resources下的文件
    packagecom.qzsl.dp.utils;importorg.springframework.beans.factory.annotation.Qualifier;importorg.springframework.core.io.Resource;importorg.springframework.core.io.ResourceLoader;importorg.springframework.stereotype.Component;importorg.springfr......
  • springboot JunitTest
    junit测试参考官方文档:https://docs.spring.io/spring-boot/docs/2.0.4.RELEASE/reference/html/boot-features-testing.html1.对springboot框架的项目进行测试,需要引入测试包<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boo......
  • SpringBoot中全部注解归纳解释
    https://blog.csdn.net/weixin_55772633/article/details/131882825https://www.cnblogs.com/jingzh/p/14620211.html1springboot注解1.1引言1.2基本注解1.3JPA注解1.4SpringMVC相关注解1.5全局异常处理1.6项目中具体配置解析和使用环境1.7Lombok注解1.8数......
  • SpringBoot+使用过滤器链执行风控决策
    风控流程下单前进行风控校验//1.begin---风控处理---前置处理{黑白名单校验}RiskControlRuleEnumcontrolRuleEnum=riskControlHandlerService.preHandle(mappingObj.getMerchantGoodsType(),thatUser);if(controlRuleEnum!=null){log......
  • 小程序直接生成鸿蒙App的方法
    今天来聊聊纯血鸿蒙,这个一直处于风口浪尖的技术话题。操作系统作为软件生态系统的基石,始终是全球科技领域竞争的制高点。鸿蒙操作系统(HarmonyOS)的出现,不仅代表了中国在该领域的技术突破,也展现了国内技术的不懈追求。自从2019年首次公开亮相再到即将面世的纯血鸿蒙OS,凭借其创新的......
  • 使用微信文件助手跨平台互联网互传文件
    微信的文件助手有下面这些版本:网页版https://filehelper.weixin.qq.com/移动版PC版https://weixin.qq.com/这些之间都是可以互传文件的。这样一台机器登录文件传输助手网页版,一台机器登录PC版本的微信,两台互联网上的机器互传文件就可以实现了。从网上看,2021年12月31日......