目录
2.3 返回前端参数(这个参数是感觉uniapp来的 可能其他的会不一样所以注意了)
下面会有几期关于app微信支付的经验分享
微信支付功能已通过测试可以使用 可能一些设计不合理 欢迎提出更好的方案 让我们改进





- <!--mybatis-puls-->
- <dependency>
- <groupId>com.baomidou</groupId>
- <artifactId>mybatis-plus-boot-starter</artifactId>
- <version>3.4.3.4</version>
- </dependency>
- <dependency>
- <groupId>com.baomidou</groupId>
- <artifactId>mybatis-plus-extension</artifactId>
- <version>3.4.3.4</version>
- </dependency>
- <!--mybatis-plus代码生成器-->
- <dependency>
- <groupId>com.baomidou</groupId>
- <artifactId>mybatis-plus-generator</artifactId>
- <version>3.2.0</version>
- </dependency>
- <!--spring data redis依赖-->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-redis</artifactId>
- </dependency>
- <!-- springcache-->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-cache</artifactId>
- </dependency>
- <!--微信支付 -->
- <dependency>
- <groupId>com.github.wechatpay-apiv3</groupId>
- <artifactId>wechatpay-apache-httpclient</artifactId>
- <version>0.4.2</version>
- </dependency>
- <!--hutool工具类 -->
- <dependency>
- <groupId>cn.hutool</groupId>
- <artifactId>hutool-all</artifactId>
- <version>5.7.6</version>
- </dependency>
- <!--参数校验 -->
- <dependency>
- <groupId>org.hibernate</groupId>
- <artifactId>hibernate-validator</artifactId>
- <version>6.0.1.Final</version>
- </dependency>
- <dependency>
- <groupId>org.glassfish</groupId>
- <artifactId>jakarta.el</artifactId>
- <version>3.0.3</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-validation</artifactId>
- </dependency>
- package com.yqs.Enum;
-
- /**
- *微信支付 api调用接口
- * @author zhangjunrong
- * @date 2022/5/9 19:57
- */
- public enum WxApiType {
- /** 下单API */
- CREATE_ORDER("https://api.mch.weixin.qq.com/v3/pay/transactions/app"),
-
- /** 查询支付订单API ONE{}=>outTradeNo – 商户订单号 系统生 TOW{}=>mchId商户的商户号,由微信支付生成并下发。 */
- QUERY_CREATE_ORDER("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{}?mchid={}"),
-
- /** 查询退款订单API {}=>outRefundNo 商户退款单号*/
- QUERY_REFUND_ORDER("https://api.mch.weixin.qq.com/v3/refund/domestic/refunds/{}"),
-
- /** 关闭订单API {}=>outTradeNo 商户订单号*/
- CLOSE_ORDER("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{}/close"),
-
- /** 申请退款API {}=>outTradeNo 商户订单号*/
- REFUND_ORDER("https://api.mch.weixin.qq.com/v3/refund/domestic/refunds"),
-
- /** 申请交易账单API {}=>bill_date 账单日期 格式yyyy-MM-DD仅支持三个月内的账单下载申请*/
- TRADE_BILLS("https://api.mch.weixin.qq.com/v3/bill/tradebill?bill_date={}"),
-
- /** 申请资金账单API {}=>bill_date 账单日期 格式yyyy-MM-DD仅支持三个月内的账单下载申请*/
- FUND_FLOW_BILLS("https://api.mch.weixin.qq.com/v3/bill/fundflowbill?bill_date={}");
-
- private final String value;
-
- WxApiType(String value) {
- this.value = value;
- }
-
- public String getValue() {
- return value;
- }
- }
- package com.yqs.Enum;
-
- /**
- * @Description 微信支付状态
- * @Author 小乌龟
- * @Date 2022/5/14 10:56
- */
- public enum WxPayStatusEnum {
- /** 未支付 */
- NOTPAY(0,"NOTPAY"),
-
- /** 支付成功 */
- SUCCESS(1,"SUCCESS"),
-
- /** 转入退款 */
- REFUND(2,"REFUND"),
-
- /** 已关闭 */
- CLOSED(3,"CLOSED"),
- /** 退款处理中 */
- REF_PROCESSING(0,"PROCESSING"),
- /** 退款成功 */
- REF_SUCCESS(1,"SUCCESS"),
- /** 退款已关闭 */
- REF_CLOSED(2,"CLOSED"),
- /** 退款异常 */
- REF_ABNORMAL(3,"ABNORMAL");
-
-
-
-
- private final Integer code;
- private final String value;
-
- WxPayStatusEnum(Integer code,String value) {
- this.code=code;
- this.value = value;
- }
-
- public Integer getCode() {
- return code;
- }
-
- public String getValue() {
- return value;
- }
-
- /**
- *退款状态 转换 String => int
- * @param value 退款String
- * @return Integer
- * @author zhangjunrong
- * @date 2022/5/19 13:47
- */
- public static Integer getCode(String value){
- switch(value){
- case "PROCESSING":
- return REF_PROCESSING.code;
- case "SUCCESS":
- return REF_SUCCESS.code;
- case "CLOSED":
- return REF_CLOSED.code;
- default:
- return REF_ABNORMAL.code;
- }
- }
- }
- package com.yqs.constant.wechatPay;
-
- /**
- *微信支付HTTP请求头相关常量
- * @author zhangjunrong
- * @return
- */
- public final class WechatPayHttpHeaders {
- //请求头配置
- public static final String ACCEPT = "Accept";
-
- public static final String CONTENT_TYPE = "Content-type";
-
- public static final String APPLICATION_JSON = "application/json";
-
- public static final String APPLICATION_JSON_UTF = "application/json; charset=utf-8";
- /**
- *微信回调参数==>微信序列号
- */
- public static final String WECHATPAY_SERIAL = "Wechatpay-Serial";
- /**
- *微信回调参数==>应答随机串
- */
- public static final String WECHATPAY_NONCE="Wechatpay-Nonce";
- /**
- *微信回调参数==>应答时间戳
- */
- public static final String WECHATPAY_TIMESTAMP="Wechatpay-Timestamp";
- /**
- *微信回调参数==>应答签名
- */
- public static final String WECHATPAY_SIGNATURE="Wechatpay-Signature";
-
- private WechatPayHttpHeaders() {
- // Don't allow instantiation
- }
-
- }
- package com.yqs.constant.wechatPay;
-
- /**
- * @Description 微信支付参数
- * @Author 小乌龟
- * @Date 2022/5/4 8:44
- */
- public class WXOrderConstant {
-
- /**
- *应用ID
- */
- public final static String APPID ="appid";
-
- /**
- *直连商户号
- */
- public final static String MCHID ="mchid";
-
- /**
- *用户支付状态
- */
- public final static String TRADE_STATE ="trade_state";
-
- /**
- *用户退款状态
- */
- public final static String STATUS ="status";
-
-
- /**
- *商品描述
- */
- public final static String DESCRIPTION ="description";
-
- /**
- *通知地址
- */
- public final static String NOTIFY_URL ="notify_url";
-
- /**
- *预支付交易会话标识
- */
- public final static String PREPAY_ID ="prepay_id";
-
- /**
- *商户订单号
- */
- public final static String OUT_TRADE_NO ="out_trade_no";
-
- /**
- *商户退款单号
- */
- public final static String OUT_REFUND_NO ="out_refund_no";
-
- /**
- *微信支付系统生成的订单号
- */
- public final static String TRANSACTION_ID ="transaction_id";
-
- /**
- *微信支付系统生成的订单号
- */
- public final static String REFUND_ID ="refund_id";
- /**
- *订单金额
- */
- public final static String AMOUNT ="amount";
- /**
- *总金额 下单时系统计算金额 单位为分
- */
- public final static String AMOUNT_TOTAL ="total";
-
- /**
- *总金额 退款时 退款金额
- */
- public final static String AMOUNT_REFUND ="refund";
-
- /**
- *总金额 退款时 币种
- */
- public final static String AMOUNT_CURRENCY ="currency";
-
- /**
- *用户支付金额
- */
- public final static String AMOUNT_PAYER_TOTAL ="payer_total";
- /**
- *优惠功能
- */
- public final static String PROMOTION_DETAIL ="promotion_detail";
- /**
- *优惠类型
- */
- public final static String PROMOTION_DETAIL_TYPE ="type";
- /**
- * 微信优惠 CASH:充值型代金券
- */
- public final static String WX_DISCOUNT_TYPE="CASH";
-
- /**
- *下单回调给微信支付成功信息
- */
- public final static String WX_BACK_OK="SUCCESS";
-
- /**
- *退款回调 退款状态
- */
- public final static String REFUND_STATUS="refund_status";
-
-
- /**
- *微信回调 通知数据
- */
- public final static String RESOURCE="resource";
-
- /**
- *微信账单类型 交易账单
- */
- public final static String TRADE_BILL="tradebill";
- /**
- *微信账单类型 资金账单
- */
- public final static String FUND_FLOW_BILL="fundflowbill";
- /**
- *微信账单下载地址
- */
- public final static String DOWNLOAD_URL="download_url";
-
- /**
- *微信回调 通知数据=>数据密文
- */
- public final static String RESOURCE_CIPHERTEXT="ciphertext";
-
- /**
- *微信回调 通知数据=>附加数据
- */
- public final static String RESOURCE_ASSOCIATED_DATA="associated_data";
-
- /**
- *微信回调 通知数据=>随机串
- */
- public final static String RESOURCE_NONCE="nonce";
-
-
-
-
- }
- /**
- * @Description
- * @Author 小乌龟
- * @Date 2022/4/13 19:49
- */
- @Data
- @AllArgsConstructor
- @NoArgsConstructor
- @ApiModel(value="前端=>微信创建订单", description="")
- public class ToCreatOrderVO {
-
- @ApiModelProperty(value = "订单号")
- @NotBlank
- String outTradeNo;
-
- @ApiModelProperty(value = "金额")
- @NotBlank
- String total;
-
- @ApiModelProperty(value = "订单描述")
- @NotBlank
- String description;
- }
- //1.数据库查询配置参数
- @Override
- @Cacheable(key = "'config'")
- public ToolWxConfig find() {
- ToolWxConfig wxConfig = toolWxConfigMapper.selectById(1L);
- return wxConfig;
- }
- //2.微信下单
- @Override
- public ReCreatOrderVO createOrder(ToolWxConfig wxConfig, ToCreatOrderVO toCreatOrderVO) {
- try {
- //1.请求配置参数
- HttpPost httpPost = new HttpPost(WxApiType.CREATE_ORDER.getValue());
- //格式配置
- httpPost.addHeader(WechatPayHttpHeaders.ACCEPT, WechatPayHttpHeaders.APPLICATION_JSON);
- httpPost.addHeader(WechatPayHttpHeaders.CONTENT_TYPE, WechatPayHttpHeaders.APPLICATION_JSON_UTF);
- //2.读取privateKey私钥
- PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(wxConfig.getPrivateKey().getBytes(StandardCharsets.UTF_8)));
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- ObjectMapper objectMapper = new ObjectMapper();
- //3.配置下单参数
- ObjectNode rootNode = objectMapper.createObjectNode();
- rootNode.put(WXOrderConstant.MCHID, wxConfig.getMchId())
- .put(WXOrderConstant.APPID, wxConfig.getAppId())
- .put(WXOrderConstant.DESCRIPTION, toCreatOrderVO.getDescription())
- .put(WXOrderConstant.NOTIFY_URL, wxConfig.getCreNotifyUrl())
- .put(WXOrderConstant.OUT_TRADE_NO, toCreatOrderVO.getOutTradeNo());
- rootNode.putObject(WXOrderConstant.AMOUNT)
- //total 微信需要int类型 为了不丢失精度 单位为分
- .put(WXOrderConstant.AMOUNT_TOTAL, new BigDecimal(toCreatOrderVO.getTotal()).movePointRight(SystemConstant.NUM_TWO).intValue());
- log.warn("金额" + new BigDecimal(toCreatOrderVO.getTotal()).movePointRight(SystemConstant.NUM_TWO).intValue());
- objectMapper.writeValue(bos, rootNode);
- //4.调用微信下单接口
- httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
- //接口返回值 申请获取prepay_id
- CloseableHttpResponse response = WxPayUtil.getHttpClient(wxConfig, WxPayUtil.getVerifier(wxConfig)).execute(httpPost);
- //预支付交易会话标识 prepay_id
- String bodyAsString = EntityUtils.toString(response.getEntity());
- //5.APP调起支付API 构造签名串
- String timestamp = DateUtil.currentSeconds() + "";
- String nonce = RandomUtil.randomString(SystemConstant.NUM_32);
- StringBuilder builder = new StringBuilder();
- //应用id
- builder.append(wxConfig.getAppId()).append("\n");
- //时间戳
- builder.append(timestamp).append("\n");
- //随机字符串
- builder.append(nonce).append("\n");
- //预支付交易会话标识 prepay_id 通过bodyAsString获取 prepay_id
- JsonNode node = objectMapper.readTree(bodyAsString);
- builder.append(node.get(WXOrderConstant.PREPAY_ID).textValue()).append("\n");
- String prepayId = node.get(WXOrderConstant.PREPAY_ID).textValue();
- //6.计算签名
- String sign = WxPayUtil.sign(builder.toString().getBytes(StandardCharsets.UTF_8), merchantPrivateKey);
- //todo 测试签名是否成功
- System.err.println(sign);
- //7.返回参数 让前端调微信支付
- return new ReCreatOrderVO(wxConfig.getAppId(), prepayId, wxConfig.getMchId(), wxConfig.getWxPackage(), nonce, timestamp, sign);
- } catch (Exception e) {
- log.error(toCreatOrderVO.getOutTradeNo() + "订单下单失败");
- //下单失败抛异常
- throw new YqsException(MessageEnum.NOT_ACCEPTABLE.getCode(), "下单失败 重新尝试付款");
- }
- }
- /**
- * @author 小乌龟
- */
- @Data
- @AllArgsConstructor
- @NoArgsConstructor
- @EqualsAndHashCode(callSuper = false)
- @ApiModel(value="微信创建订单", description="")
- public class ReCreatOrderVO {
- //uniapp需要参数
- // "appid": "wx499********7c70e", // 微信开放平台 - 应用 - AppId,注意和微信小程序、公众号 AppId 可能不一致
- // "noncestr": "c5sEwbaNPiXAF3iv", // 随机字符串
- // "package": "Sign=WXPay", // 固定值
- // "partnerid": "148*****52", // 微信支付商户号
- // "prepayid": "wx202254********************fbe90000", // 统一下单订单号
- // "timestamp": 1597935292, // 时间戳(单位:秒)
- // "sign": "A842B45937F6EFF60DEC7A2EAA52D5A0" // 签名,这里用的 MD5/RSA 签名
-
-
- @ApiModelProperty(value = "appid")
- private String appId;
-
- @ApiModelProperty(value = "统一下单订单号 prepayid ")
- private String prepayId;
-
- @ApiModelProperty(value = "微信支付商户号")
- private String partnerId;
-
- @ApiModelProperty(value = "订单详情扩展字符串")
- private String wxPackage;
-
- @ApiModelProperty(value = "随机字符串")
- private String wxNonce;
-
- @ApiModelProperty(value = "时间戳")
- private String wxTimestamp;
-
- @ApiModelProperty(value = "签名")
- private String wxSign;
-
- }
- @PostMapping("/toWxPayApp")
- @ApiOperation("微信支付")
- @RequiresAuthentication
- public ResultResponse<ReCreatOrderVO> toWxPayApp(@ApiParam("订单信息") @RequestBody @Valid ToCreatOrderVO toCreatOrderVO, BindingResult br) {
- return process(() -> iToolWxConfigService.createOrder(iToolWxConfigService.find(), toCreatOrderVO), br);
- }