• 微信支付 APP端 后端 第一弹 微信下单


    目录

    工程总介绍:

    第一弹: 微信 支付下单

    展示结果截图

    1.配置说明

    1.1数据库设计 需要拿到微信官方给的一些参数

     1.2用到的jar包

    1.3信支付接口请求状态枚举

    1.3.1接口请求

    1.3.2状态

    1.4 微信参数常量配置

    1.4.1微信支付HTTP请求头相关常量

    1.4.2 微信支付参数 常量

    2.APP下单

    2.1创建订单VO

    2.2 微信下单service

    2.3 返回前端参数(这个参数是感觉uniapp来的 可能其他的会不一样所以注意了)

    3.3 controller


    工程总介绍:

    下面会有几期关于app微信支付的经验分享 

    微信支付功能已通过测试可以使用 可能一些设计不合理 欢迎提出更好的方案 让我们改进

    第一弹: 微信 支付下单

    展示结果截图

    1.配置说明

    1.1数据库设计 需要拿到微信官方给的一些参数

     1.2用到的jar包

    1. <!--mybatis-puls-->
    2. <dependency>
    3. <groupId>com.baomidou</groupId>
    4. <artifactId>mybatis-plus-boot-starter</artifactId>
    5. <version>3.4.3.4</version>
    6. </dependency>
    7. <dependency>
    8. <groupId>com.baomidou</groupId>
    9. <artifactId>mybatis-plus-extension</artifactId>
    10. <version>3.4.3.4</version>
    11. </dependency>
    12. <!--mybatis-plus代码生成器-->
    13. <dependency>
    14. <groupId>com.baomidou</groupId>
    15. <artifactId>mybatis-plus-generator</artifactId>
    16. <version>3.2.0</version>
    17. </dependency>
    18. <!--spring data redis依赖-->
    19. <dependency>
    20. <groupId>org.springframework.boot</groupId>
    21. <artifactId>spring-boot-starter-data-redis</artifactId>
    22. </dependency>
    23. <!-- springcache-->
    24. <dependency>
    25. <groupId>org.springframework.boot</groupId>
    26. <artifactId>spring-boot-starter-cache</artifactId>
    27. </dependency>
    28. <!--微信支付 -->
    29. <dependency>
    30. <groupId>com.github.wechatpay-apiv3</groupId>
    31. <artifactId>wechatpay-apache-httpclient</artifactId>
    32. <version>0.4.2</version>
    33. </dependency>
    34. <!--hutool工具类 -->
    35. <dependency>
    36. <groupId>cn.hutool</groupId>
    37. <artifactId>hutool-all</artifactId>
    38. <version>5.7.6</version>
    39. </dependency>
    40. <!--参数校验 -->
    41. <dependency>
    42. <groupId>org.hibernate</groupId>
    43. <artifactId>hibernate-validator</artifactId>
    44. <version>6.0.1.Final</version>
    45. </dependency>
    46. <dependency>
    47. <groupId>org.glassfish</groupId>
    48. <artifactId>jakarta.el</artifactId>
    49. <version>3.0.3</version>
    50. </dependency>
    51. <dependency>
    52. <groupId>org.springframework.boot</groupId>
    53. <artifactId>spring-boot-starter-validation</artifactId>
    54. </dependency>

    1.3信支付接口请求状态枚举

    1.3.1接口请求

    1. package com.yqs.Enum;
    2. /**
    3. *微信支付 api调用接口
    4. * @author zhangjunrong
    5. * @date 2022/5/9 19:57
    6. */
    7. public enum WxApiType {
    8. /** 下单API */
    9. CREATE_ORDER("https://api.mch.weixin.qq.com/v3/pay/transactions/app"),
    10. /** 查询支付订单API ONE{}=>outTradeNo – 商户订单号 系统生 TOW{}=>mchId商户的商户号,由微信支付生成并下发。 */
    11. QUERY_CREATE_ORDER("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{}?mchid={}"),
    12. /** 查询退款订单API {}=>outRefundNo 商户退款单号*/
    13. QUERY_REFUND_ORDER("https://api.mch.weixin.qq.com/v3/refund/domestic/refunds/{}"),
    14. /** 关闭订单API {}=>outTradeNo 商户订单号*/
    15. CLOSE_ORDER("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{}/close"),
    16. /** 申请退款API {}=>outTradeNo 商户订单号*/
    17. REFUND_ORDER("https://api.mch.weixin.qq.com/v3/refund/domestic/refunds"),
    18. /** 申请交易账单API {}=>bill_date 账单日期 格式yyyy-MM-DD仅支持三个月内的账单下载申请*/
    19. TRADE_BILLS("https://api.mch.weixin.qq.com/v3/bill/tradebill?bill_date={}"),
    20. /** 申请资金账单API {}=>bill_date 账单日期 格式yyyy-MM-DD仅支持三个月内的账单下载申请*/
    21. FUND_FLOW_BILLS("https://api.mch.weixin.qq.com/v3/bill/fundflowbill?bill_date={}");
    22. private final String value;
    23. WxApiType(String value) {
    24. this.value = value;
    25. }
    26. public String getValue() {
    27. return value;
    28. }
    29. }

    1.3.2状态

    1. package com.yqs.Enum;
    2. /**
    3. * @Description 微信支付状态
    4. * @Author 小乌龟
    5. * @Date 2022/5/14 10:56
    6. */
    7. public enum WxPayStatusEnum {
    8. /** 未支付 */
    9. NOTPAY(0,"NOTPAY"),
    10. /** 支付成功 */
    11. SUCCESS(1,"SUCCESS"),
    12. /** 转入退款 */
    13. REFUND(2,"REFUND"),
    14. /** 已关闭 */
    15. CLOSED(3,"CLOSED"),
    16. /** 退款处理中 */
    17. REF_PROCESSING(0,"PROCESSING"),
    18. /** 退款成功 */
    19. REF_SUCCESS(1,"SUCCESS"),
    20. /** 退款已关闭 */
    21. REF_CLOSED(2,"CLOSED"),
    22. /** 退款异常 */
    23. REF_ABNORMAL(3,"ABNORMAL");
    24. private final Integer code;
    25. private final String value;
    26. WxPayStatusEnum(Integer code,String value) {
    27. this.code=code;
    28. this.value = value;
    29. }
    30. public Integer getCode() {
    31. return code;
    32. }
    33. public String getValue() {
    34. return value;
    35. }
    36. /**
    37. *退款状态 转换 String => int
    38. * @param value 退款String
    39. * @return Integer
    40. * @author zhangjunrong
    41. * @date 2022/5/19 13:47
    42. */
    43. public static Integer getCode(String value){
    44. switch(value){
    45. case "PROCESSING":
    46. return REF_PROCESSING.code;
    47. case "SUCCESS":
    48. return REF_SUCCESS.code;
    49. case "CLOSED":
    50. return REF_CLOSED.code;
    51. default:
    52. return REF_ABNORMAL.code;
    53. }
    54. }
    55. }

    1.4 微信参数常量配置

    1.4.1微信支付HTTP请求头相关常量

    1. package com.yqs.constant.wechatPay;
    2. /**
    3. *微信支付HTTP请求头相关常量
    4. * @author zhangjunrong
    5. * @return
    6. */
    7. public final class WechatPayHttpHeaders {
    8. //请求头配置
    9. public static final String ACCEPT = "Accept";
    10. public static final String CONTENT_TYPE = "Content-type";
    11. public static final String APPLICATION_JSON = "application/json";
    12. public static final String APPLICATION_JSON_UTF = "application/json; charset=utf-8";
    13. /**
    14. *微信回调参数==>微信序列号
    15. */
    16. public static final String WECHATPAY_SERIAL = "Wechatpay-Serial";
    17. /**
    18. *微信回调参数==>应答随机串
    19. */
    20. public static final String WECHATPAY_NONCE="Wechatpay-Nonce";
    21. /**
    22. *微信回调参数==>应答时间戳
    23. */
    24. public static final String WECHATPAY_TIMESTAMP="Wechatpay-Timestamp";
    25. /**
    26. *微信回调参数==>应答签名
    27. */
    28. public static final String WECHATPAY_SIGNATURE="Wechatpay-Signature";
    29. private WechatPayHttpHeaders() {
    30. // Don't allow instantiation
    31. }
    32. }

    1.4.2 微信支付参数 常量

    1. package com.yqs.constant.wechatPay;
    2. /**
    3. * @Description 微信支付参数
    4. * @Author 小乌龟
    5. * @Date 2022/5/4 8:44
    6. */
    7. public class WXOrderConstant {
    8. /**
    9. *应用ID
    10. */
    11. public final static String APPID ="appid";
    12. /**
    13. *直连商户号
    14. */
    15. public final static String MCHID ="mchid";
    16. /**
    17. *用户支付状态
    18. */
    19. public final static String TRADE_STATE ="trade_state";
    20. /**
    21. *用户退款状态
    22. */
    23. public final static String STATUS ="status";
    24. /**
    25. *商品描述
    26. */
    27. public final static String DESCRIPTION ="description";
    28. /**
    29. *通知地址
    30. */
    31. public final static String NOTIFY_URL ="notify_url";
    32. /**
    33. *预支付交易会话标识
    34. */
    35. public final static String PREPAY_ID ="prepay_id";
    36. /**
    37. *商户订单号
    38. */
    39. public final static String OUT_TRADE_NO ="out_trade_no";
    40. /**
    41. *商户退款单号
    42. */
    43. public final static String OUT_REFUND_NO ="out_refund_no";
    44. /**
    45. *微信支付系统生成的订单号
    46. */
    47. public final static String TRANSACTION_ID ="transaction_id";
    48. /**
    49. *微信支付系统生成的订单号
    50. */
    51. public final static String REFUND_ID ="refund_id";
    52. /**
    53. *订单金额
    54. */
    55. public final static String AMOUNT ="amount";
    56. /**
    57. *总金额 下单时系统计算金额 单位为分
    58. */
    59. public final static String AMOUNT_TOTAL ="total";
    60. /**
    61. *总金额 退款时 退款金额
    62. */
    63. public final static String AMOUNT_REFUND ="refund";
    64. /**
    65. *总金额 退款时 币种
    66. */
    67. public final static String AMOUNT_CURRENCY ="currency";
    68. /**
    69. *用户支付金额
    70. */
    71. public final static String AMOUNT_PAYER_TOTAL ="payer_total";
    72. /**
    73. *优惠功能
    74. */
    75. public final static String PROMOTION_DETAIL ="promotion_detail";
    76. /**
    77. *优惠类型
    78. */
    79. public final static String PROMOTION_DETAIL_TYPE ="type";
    80. /**
    81. * 微信优惠 CASH:充值型代金券
    82. */
    83. public final static String WX_DISCOUNT_TYPE="CASH";
    84. /**
    85. *下单回调给微信支付成功信息
    86. */
    87. public final static String WX_BACK_OK="SUCCESS";
    88. /**
    89. *退款回调 退款状态
    90. */
    91. public final static String REFUND_STATUS="refund_status";
    92. /**
    93. *微信回调 通知数据
    94. */
    95. public final static String RESOURCE="resource";
    96. /**
    97. *微信账单类型 交易账单
    98. */
    99. public final static String TRADE_BILL="tradebill";
    100. /**
    101. *微信账单类型 资金账单
    102. */
    103. public final static String FUND_FLOW_BILL="fundflowbill";
    104. /**
    105. *微信账单下载地址
    106. */
    107. public final static String DOWNLOAD_URL="download_url";
    108. /**
    109. *微信回调 通知数据=>数据密文
    110. */
    111. public final static String RESOURCE_CIPHERTEXT="ciphertext";
    112. /**
    113. *微信回调 通知数据=>附加数据
    114. */
    115. public final static String RESOURCE_ASSOCIATED_DATA="associated_data";
    116. /**
    117. *微信回调 通知数据=>随机串
    118. */
    119. public final static String RESOURCE_NONCE="nonce";
    120. }

    2.APP下单

    2.1创建订单VO

    1. /**
    2. * @Description
    3. * @Author 小乌龟
    4. * @Date 2022/4/13 19:49
    5. */
    6. @Data
    7. @AllArgsConstructor
    8. @NoArgsConstructor
    9. @ApiModel(value="前端=>微信创建订单", description="")
    10. public class ToCreatOrderVO {
    11. @ApiModelProperty(value = "订单号")
    12. @NotBlank
    13. String outTradeNo;
    14. @ApiModelProperty(value = "金额")
    15. @NotBlank
    16. String total;
    17. @ApiModelProperty(value = "订单描述")
    18. @NotBlank
    19. String description;
    20. }

    2.2 微信下单service

    1. //1.数据库查询配置参数
    2. @Override
    3. @Cacheable(key = "'config'")
    4. public ToolWxConfig find() {
    5. ToolWxConfig wxConfig = toolWxConfigMapper.selectById(1L);
    6. return wxConfig;
    7. }
    8. //2.微信下单
    9. @Override
    10. public ReCreatOrderVO createOrder(ToolWxConfig wxConfig, ToCreatOrderVO toCreatOrderVO) {
    11. try {
    12. //1.请求配置参数
    13. HttpPost httpPost = new HttpPost(WxApiType.CREATE_ORDER.getValue());
    14. //格式配置
    15. httpPost.addHeader(WechatPayHttpHeaders.ACCEPT, WechatPayHttpHeaders.APPLICATION_JSON);
    16. httpPost.addHeader(WechatPayHttpHeaders.CONTENT_TYPE, WechatPayHttpHeaders.APPLICATION_JSON_UTF);
    17. //2.读取privateKey私钥
    18. PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(wxConfig.getPrivateKey().getBytes(StandardCharsets.UTF_8)));
    19. ByteArrayOutputStream bos = new ByteArrayOutputStream();
    20. ObjectMapper objectMapper = new ObjectMapper();
    21. //3.配置下单参数
    22. ObjectNode rootNode = objectMapper.createObjectNode();
    23. rootNode.put(WXOrderConstant.MCHID, wxConfig.getMchId())
    24. .put(WXOrderConstant.APPID, wxConfig.getAppId())
    25. .put(WXOrderConstant.DESCRIPTION, toCreatOrderVO.getDescription())
    26. .put(WXOrderConstant.NOTIFY_URL, wxConfig.getCreNotifyUrl())
    27. .put(WXOrderConstant.OUT_TRADE_NO, toCreatOrderVO.getOutTradeNo());
    28. rootNode.putObject(WXOrderConstant.AMOUNT)
    29. //total 微信需要int类型 为了不丢失精度 单位为分
    30. .put(WXOrderConstant.AMOUNT_TOTAL, new BigDecimal(toCreatOrderVO.getTotal()).movePointRight(SystemConstant.NUM_TWO).intValue());
    31. log.warn("金额" + new BigDecimal(toCreatOrderVO.getTotal()).movePointRight(SystemConstant.NUM_TWO).intValue());
    32. objectMapper.writeValue(bos, rootNode);
    33. //4.调用微信下单接口
    34. httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
    35. //接口返回值 申请获取prepay_id
    36. CloseableHttpResponse response = WxPayUtil.getHttpClient(wxConfig, WxPayUtil.getVerifier(wxConfig)).execute(httpPost);
    37. //预支付交易会话标识 prepay_id
    38. String bodyAsString = EntityUtils.toString(response.getEntity());
    39. //5.APP调起支付API 构造签名串
    40. String timestamp = DateUtil.currentSeconds() + "";
    41. String nonce = RandomUtil.randomString(SystemConstant.NUM_32);
    42. StringBuilder builder = new StringBuilder();
    43. //应用id
    44. builder.append(wxConfig.getAppId()).append("\n");
    45. //时间戳
    46. builder.append(timestamp).append("\n");
    47. //随机字符串
    48. builder.append(nonce).append("\n");
    49. //预支付交易会话标识 prepay_id 通过bodyAsString获取 prepay_id
    50. JsonNode node = objectMapper.readTree(bodyAsString);
    51. builder.append(node.get(WXOrderConstant.PREPAY_ID).textValue()).append("\n");
    52. String prepayId = node.get(WXOrderConstant.PREPAY_ID).textValue();
    53. //6.计算签名
    54. String sign = WxPayUtil.sign(builder.toString().getBytes(StandardCharsets.UTF_8), merchantPrivateKey);
    55. //todo 测试签名是否成功
    56. System.err.println(sign);
    57. //7.返回参数 让前端调微信支付
    58. return new ReCreatOrderVO(wxConfig.getAppId(), prepayId, wxConfig.getMchId(), wxConfig.getWxPackage(), nonce, timestamp, sign);
    59. } catch (Exception e) {
    60. log.error(toCreatOrderVO.getOutTradeNo() + "订单下单失败");
    61. //下单失败抛异常
    62. throw new YqsException(MessageEnum.NOT_ACCEPTABLE.getCode(), "下单失败 重新尝试付款");
    63. }
    64. }

    2.3 返回前端参数(这个参数是感觉uniapp来的 可能其他的会不一样所以注意了)

    1. /**
    2. * @author 小乌龟
    3. */
    4. @Data
    5. @AllArgsConstructor
    6. @NoArgsConstructor
    7. @EqualsAndHashCode(callSuper = false)
    8. @ApiModel(value="微信创建订单", description="")
    9. public class ReCreatOrderVO {
    10. //uniapp需要参数
    11. // "appid": "wx499********7c70e", // 微信开放平台 - 应用 - AppId,注意和微信小程序、公众号 AppId 可能不一致
    12. // "noncestr": "c5sEwbaNPiXAF3iv", // 随机字符串
    13. // "package": "Sign=WXPay", // 固定值
    14. // "partnerid": "148*****52", // 微信支付商户号
    15. // "prepayid": "wx202254********************fbe90000", // 统一下单订单号
    16. // "timestamp": 1597935292, // 时间戳(单位:秒)
    17. // "sign": "A842B45937F6EFF60DEC7A2EAA52D5A0" // 签名,这里用的 MD5/RSA 签名
    18. @ApiModelProperty(value = "appid")
    19. private String appId;
    20. @ApiModelProperty(value = "统一下单订单号 prepayid ")
    21. private String prepayId;
    22. @ApiModelProperty(value = "微信支付商户号")
    23. private String partnerId;
    24. @ApiModelProperty(value = "订单详情扩展字符串")
    25. private String wxPackage;
    26. @ApiModelProperty(value = "随机字符串")
    27. private String wxNonce;
    28. @ApiModelProperty(value = "时间戳")
    29. private String wxTimestamp;
    30. @ApiModelProperty(value = "签名")
    31. private String wxSign;
    32. }

    3.3 controller

    1. @PostMapping("/toWxPayApp")
    2. @ApiOperation("微信支付")
    3. @RequiresAuthentication
    4. public ResultResponse<ReCreatOrderVO> toWxPayApp(@ApiParam("订单信息") @RequestBody @Valid ToCreatOrderVO toCreatOrderVO, BindingResult br) {
    5. return process(() -> iToolWxConfigService.createOrder(iToolWxConfigService.find(), toCreatOrderVO), br);
    6. }

  • 相关阅读:
    where条件中有权限校验的自定义函数优化方法
    2、 MongoDB应用与开发
    图搜索算法详解
    Java对象内存布局和对象头
    marquee标签的用法
    ms-sql server sql 把逗号分隔的字符串分开
    SpringBoot整合redis的基本操作
    python 中导出requirements.txt 的几种方法
    Weblogic管理控制台未授权远程命令执行漏洞(CVE-2020-14882,CVE-2020-14883)
    内卷时代,扫地机器人何时能成为刚需?
  • 原文地址:https://blog.csdn.net/Little___Turtle/article/details/125520005