赞
踩
申请应用号:appid
申请商户号:mchid
设置APIV3密钥:apiV3Key
下载并配置商户证书,商户证书序列号:mchSerialNo ;商户API私钥路径:privateKey
需要后端完成的一共有三个接口
1,拿到订单参数后,向微信发送请求支付消息,把拿到的参数返回给前端,用于用户付款
2,前端输入密码后,微信会异步回调一个接口,成功扣款后做对应业务处理
3,查询支付结果返回给前端
- <!--微信小程序支付-->
- <dependency>
- <groupId>com.github.wechatpay-apiv3</groupId>
- <artifactId>wechatpay-apache-httpclient</artifactId>
- <version>0.4.9</version>
- </dependency>
- # 微信
- wx:
- # 小程序支付
- pay:
- # 应用号
- appId: ********
- # 商户号
- mchId: ********
- # 商户APIV3密钥(32位)
- apiV3Key: ********************************
- # 商户证书序列号
- mchSerialNo: ****************
- # 支付成功回调 url 需要公网可访问
- notifyUrl: http://改成自己的回调地址/system/order/wechatPayCallback
- # 退款成功回调 url 需要公网可访问
- refundNotifyUrl: http://改成自己的回调地址/system/order/wechatRefundBack
- # 商户API私钥路径 【证书路径】
- privateKey: "**********"
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- @Data
- @Component
- public class WeChatToolConfig {
- /**
- * 应用id
- */
- @Value("${wx.pay.appId}")
- private String appId;
-
- /**
- * 商户id
- */
- @Value("${wx.pay.mchId}")
- private String mchId;
-
- /**
- * 商户APIV3密钥
- */
- @Value("${wx.pay.apiV3Key}")
- private String apiV3Key;
-
- /**
- * 商户证书序列号
- */
- @Value("${wx.pay.mchSerialNo}")
- private String mchSerialNo;
-
- /**
- * 商户私钥
- */
- @Value("${wx.pay.privateKey}")
- private String privateKey;
-
- /**
- * 支付成功回调url
- */
- @Value("${wx.pay.notifyUrl}")
- private String notifyUrl;
-
- /**
- * 退款成功回调url
- */
- @Value("${wx.pay.refundNotifyUrl}")
- private String refundNotifyUrl;
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- public enum WxApiTypeEnum {
- /**
- * 小程序 下单API
- */
- CREATE_ORDER("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi"),
-
- /**
- * 申请退款API 通过 outTradeNo 商户订单号 退单
- */
- REFUND_ORDER("https://api.mch.weixin.qq.com/v3/refund/domestic/refunds"),
-
- /**
- * 查询支付订单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"),
-
- /**
- * 货物录入
- */
- GOOD_ENTERING("https://api.weixin.qq.com/wxa/sec/order/upload_shipping_info?access_token={}"),
-
- /**
- * 接口调用凭证
- */
- API_VOUCHER("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={}&secret={}");
-
- private final String value;
-
- WxApiTypeEnum(String value) {
- this.value = value;
- }
-
- public String getValue() {
- return value;
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- public 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
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- public class WeChatUtil {
- private static final Logger log = LoggerFactory.getLogger(WeChatUtil.class);
- /**
- * 签名生成 计算签名
- *
- * @param message 签名体
- * @param privateKey 商户私钥
- * @return String
- */
- public static String sign(byte[] message, PrivateKey privateKey) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException {
- Signature sign = Signature.getInstance("SHA256withRSA");
- sign.initSign(privateKey);
- sign.update(message);
- return Base64.getEncoder().encodeToString(sign.sign());
- }
-
- /**
- * 构造HttpClient 实现 微信申请接口 调用功能
- *
- * @param verifier 微信验签器
- * @return CloseableHttpClient
- */
- public static CloseableHttpClient getHttpClient(WeChatToolConfig config, Verifier verifier) {
- PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(config.getPrivateKey().getBytes(StandardCharsets.UTF_8)));
- // 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签
- WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
- .withMerchant(config.getMchId(), config.getMchSerialNo(), merchantPrivateKey)
- .withValidator(new WechatPay2Validator(verifier));
- return builder.build();
- }
-
- /**
- * 构造HttpClient 实现 微信申请接口 调用功能 不用微信签名认证 账单申请中可用到
- *
- * @param verifier 微信验签器
- * @return CloseableHttpClient
- */
- public static CloseableHttpClient getHttpClientNoSign(WeChatToolConfig config, Verifier verifier) {
- PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(config.getPrivateKey().getBytes(StandardCharsets.UTF_8)));
- // 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签
- WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
- .withMerchant(config.getMchId(), config.getMchSerialNo(), merchantPrivateKey)
- .withValidator(new WechatPay2Validator(verifier))
- .withValidator(response -> true);
- return builder.build();
- }
-
- /**
- * 获取验证功能
- *
- * @return Verifier 微信验签器
- */
- public static Verifier getVerifier(WeChatToolConfig config) {
- try {
- PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(config.getPrivateKey().getBytes(StandardCharsets.UTF_8)));
- // 定时更新平台证书功能
- // 获取证书管理器实例
- CertificatesManager certificatesManager = CertificatesManager.getInstance();
- // 向证书管理器增加需要自动更新平台证书的商户信息
- certificatesManager.putMerchant(config.getMchId(), new WechatPay2Credentials(config.getMchId(),
- new PrivateKeySigner(config.getMchSerialNo(), merchantPrivateKey)), config.getApiV3Key().getBytes(StandardCharsets.UTF_8));
- // 从证书管理器中获取verifier=>验签器
- return certificatesManager.getVerifier(config.getMchId());
- } catch (Exception e) {
- log.warn("验证出错");
- throw new CustomException("微信证书出错 联系客服");
- }
- }
-
-
- /**
- * 回调验证
- *
- * @param request 微信回调请求
- * @return String
- */
- public static Notification verifyBack(HttpServletRequest request, WeChatToolConfig config) throws IOException, ValidationException, ParseException {
- // 应答报文主体
- BufferedReader br = request.getReader();
- String str;
- StringBuilder builder = new StringBuilder();
- while ((str = br.readLine()) != null) {
- builder.append(str);
- }
- // 构建request,传入必要参数
- // 参数 1.微信序列号 2.应答随机串 3.应答时间戳 4.应答签名 5.应答报文主体
- NotificationRequest notificationRequest = new NotificationRequest.Builder()
- .withSerialNumber(request.getHeader(WechatPayHttpHeaders.WECHATPAY_SERIAL))
- .withNonce(request.getHeader(WechatPayHttpHeaders.WECHATPAY_NONCE))
- .withTimestamp(request.getHeader(WechatPayHttpHeaders.WECHATPAY_TIMESTAMP))
- .withSignature(request.getHeader(WechatPayHttpHeaders.WECHATPAY_SIGNATURE))
- .withBody(builder.toString())
- .build();
- NotificationHandler handler = new NotificationHandler(WeChatUtil.getVerifier(config), config.getApiV3Key().getBytes(StandardCharsets.UTF_8));
- // 验签和解析请求体
- log.info("验签和解析请求体==============================开始验证==============================");
- return handler.parse(notificationRequest);
- }
-
- /**
- * 验证用户支付金额 场景 微信回调验证
- *
- * @param jsonObject 微信回调json 返回参数
- * @param total 数据库记录金额
- * @return Boolean
- */
- public static Boolean verifyMoney(JSONObject jsonObject, Integer total) {
- // 总金额计数值 用户支付计算
- int userPayTotal = WeChatPayParam.NUM_ZERO;
- // 1.验证订单金额
- // 用户支付金额
- int payerTotal = (int) jsonObject.getJSONObject(WeChatPayParam.AMOUNT).get(WeChatPayParam.AMOUNT_PAYER_TOTAL);
- userPayTotal += payerTotal;
- // CASH充值型代金券 要加上优惠金额 银行优惠 获取
- // 排空 如果没有优惠则跳过
- if (!ObjectUtil.isEmpty(jsonObject.get(WeChatPayParam.PROMOTION_DETAIL))) {
- JSONArray jsonArray = jsonObject.getJSONArray(WeChatPayParam.PROMOTION_DETAIL);
- for (Object object : jsonArray) {
- JSONObject json = (JSONObject) object;
- // 如果优惠类型为CASH 则要和 用户支付金额 累加
- if (WeChatPayParam.WX_DISCOUNT_TYPE.equals(json.get(WeChatPayParam.PROMOTION_DETAIL_TYPE).toString())) {
- userPayTotal += (int) json.get(WeChatPayParam.AMOUNT);
- }
- }
- }
- // 2.总金额 预支付时的 金额 与 total 用户支付金额
- // 微信端返回的支付总金额
- int wxTotal = (int) jsonObject.getJSONObject(WeChatPayParam.AMOUNT).get(WeChatPayParam.AMOUNT_TOTAL);
- // 校验通知的信息是否与商户侧的信息一致,防止数据泄露导致出现“假通知”,造成资金损失。
- log.info("微信回调金额===比较=== " + "微信端返回的支付总金额" + jsonObject.getJSONObject(WeChatPayParam.AMOUNT).get(WeChatPayParam.AMOUNT_TOTAL) + "================用户支付总金额计算" + userPayTotal);
- return wxTotal == userPayTotal && total == wxTotal;
- }
-
-
- /**
- * 获取接口调用凭证
- */
- public static JSONObject getAccessToken(WeChatToolConfig config) throws Exception {
- log.info("initAccessToken:开始运行...");
- // 获取secret
- String secret = WxMaConfiguration.getMaService(config.getAppId()).getWxMaConfig().getSecret();
- // 获取url
- String url = StrFormatter.format(WxApiTypeEnum.API_VOUCHER.getValue(), config.getAppId(), secret);
- return getBodyAsJsonByGet(url, config);
- }
-
- /**
- * 调用微信支付 get请求 统一配置
- * 要微信签名认证
- *
- * @param url 请求url
- * @return JSONObject
- */
- public static JSONObject getBodyAsJsonByGet(String url, WeChatToolConfig config) throws IOException {
- // 1.构造httpGet请求
- HttpGet httpGet = new HttpGet(url);
- httpGet.addHeader(WechatPayHttpHeaders.ACCEPT, WechatPayHttpHeaders.APPLICATION_JSON);
- // 2.调起微信查询订单接口
- CloseableHttpResponse response = WeChatUtil.getHttpClient(config, WeChatUtil.getVerifier(config)).execute(httpGet);
- // 3.返回结果信息
- String bodyAsString = EntityUtils.toString(response.getEntity());
- // 转为JSON格式返回
- return JSON.parseObject(bodyAsString);
- }
-
- /**
- * 调用微信支付 post请求 统一配置
- * 要微信签名认证
- *
- * @param url 请求url
- * @param requestParam 请求参数
- * @param config 基本配置
- * @return JSONObject
- */
- public static JSONObject getBodyAsJsonByPost(String url, JSONObject requestParam, WeChatToolConfig config) throws Exception {
- // 1.设置请求url和请求头
- HttpPost httpPost = new HttpPost(url);
- httpPost.addHeader(WechatPayHttpHeaders.ACCEPT, WechatPayHttpHeaders.APPLICATION_JSON);
- httpPost.addHeader(WechatPayHttpHeaders.CONTENT_TYPE, WechatPayHttpHeaders.APPLICATION_JSON_UTF);
-
- // 2.传入参数
- String jsonString = JSON.toJSONString(requestParam);
- httpPost.setEntity(new StringEntity(jsonString, StandardCharsets.UTF_8));
-
- // 3.调用接口 获取预支付交易会话标识 prepay_id
- CloseableHttpResponse response = WeChatUtil.getHttpClient(config, WeChatUtil.getVerifier(config)).execute(httpPost);
-
- // 4.获取返回值 转为JSON
- String bodyAsString = EntityUtils.toString(response.getEntity());
- return JSON.parseObject(bodyAsString);
- }
-
-
- /**
- * 获取签名
- *
- * @param appId appId
- * @param timestamp 时间戳
- * @param nonce 随机字符串
- * @param wxPackage 订单详情扩展字符串
- * @param privateKey 商户私钥
- */
- public static String getSign(String appId, String timestamp, String nonce, String wxPackage, String privateKey) throws Exception {
- // APP调起支付API 构造签名串
- // 应用id
- String builder = appId + "\n" +
- // 时间戳
- timestamp + "\n" +
- // 随机字符串
- nonce + "\n" +
- // 预支付交易会话标识 prepay_id=wx201410272009395522657a690389285100 必须以此格式
- wxPackage + "\n";
-
- // 读取privateKey商户私钥
- PrivateKey merchantPrivateKey = PemUtils.getPrivateKey(privateKey);
- // 计算签名
- return WeChatUtil.sign(builder.getBytes(StandardCharsets.UTF_8), merchantPrivateKey);
- }
-
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- public class WeChatPayParam {
-
- /**
- * 应用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 PAYER = "payer";
-
- /**
- * 用户在直连商户appid下的唯一标识。 下单前需获取到用户的Openid
- */
- public final static String OPENID = "openid";
-
- /**
- * 总金额 退款时 退款金额
- */
- 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";
-
- /**
- * 发货信息 状态码
- */
- public final static String ERR_CODE = "errcode";
-
- /**
- * 发货信息 状态信息
- */
- public final static String ERR_MSG = "errmsg";
-
-
- /**
- * 请求支付 错误状态码
- */
- public final static String CODE = "code";
-
- /**
- * 请求支付 状态信息
- */
- public final static String MESSAGE = "message";
-
- /**
- * 固定支付参数 package
- */
- public final static String WX_PACKAGE = "prepay_id=";
-
- /**
- * 币种 RMB
- */
- public final static String CURRENCY_RMB = "CNY";
-
- /**
- * 支付成功
- */
- public final static String PAY_SUCCESS = "支付成功";
- /**
- * 退款成功
- */
- public final static String REFUND_SUCCESS = "退款成功";
-
- /**
- * 订单单号类型
- */
- public final static String ORDER_NUMBER_TYPE = "order_number_type";
-
- /**
- * 商品信息
- */
- public final static String ITEM_DESC = "item_desc";
-
- /**
- * 订单
- */
- public final static String ORDER_KEY = "order_key";
-
- /**
- * 物流模式
- */
- public final static String LOGISTICS_TYPE = "logistics_type";
-
- /**
- * 发货模式
- */
- public final static String DELIVERY_MODE = "delivery_mode";
-
- /**
- * 物流信息列表
- */
- public final static String SHIPPING_LIST = "shipping_list";
-
- /**
- * 上传时间
- */
- public final static String UPLOAD_TIME = "upload_time";
-
- /**
- * 获取到的凭证
- */
- public final static String ACCESS_TOKEN = "access_token";
-
-
- /**
- * 数字 0~11
- */
- public final static int NUM_NEGATIVE_ONE = -1;
- public final static int NUM_ZERO = 0;
- public final static int NUM_ONE = 1;
- public final static int NUM_TWO = 2;
- public final static int NUM_THREE = 3;
- public final static int NUM_FOUR = 4;
- public final static int NUM_FIVE = 5;
- public final static int NUM_SIX = 6;
- public final static int NUM_SEVEN = 7;
- public final static int NUM_EIGHT = 8;
- public final static int NUM_NINE = 9;
- public final static int NUM_TEN = 10;
- public final static int NUM_ELEVEN = 11;
- public final static int NUM_15 = 15;
- public final static int NUM_16 = 16;
- public final static int NUM_19 = 19;
- public final static int NUM_TWENTY = 20;
- public final static int NUM_30 = 30;
- public final static int NUM_32 = 32;
- public final static int NUM_50 = 50;
- public final static int NUM_60 = 60;
- public final static int NUM_64 = 64;
- public final static int NUM_90 = 90;
- public final static int NUM_100 = 100;
- public final static int NUM_200 = 200;
- public final static int NUM_1024 = 1024;
- public final static int NUM_5000 = 5000;
- public final static int NUM_24_time = 86400; // 60*60*60*24 一天
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- @Autowired
- private WaybillService waybillService;
-
- /**
- * 微信请求下单支付
- *
- * @param waybillId 运单id
- * @return 付款所需参数
- */
- @RepeatSubmit
- @GetMapping("/weChatCreateOrder/{waybillId}")
- @Operation(summary = "微信请求下单支付")
- public AjaxResult<CreateOrderVo> weChatCreateOrder(@PathVariable("waybillId") String waybillId) {
- return waybillService.weChatCreateOrder(waybillId);
- }
- @Data
- @AllArgsConstructor
- @NoArgsConstructor
- @EqualsAndHashCode(callSuper = false)
- public class CreateOrderVo implements Serializable {
-
- // 微信小程序需要参数
- // "appId": "wx499********7c70e", // 微信开放平台 - 应用 - AppId,注意和微信小程序、公众号 AppId 可能不一致
- // "timeStamp": 1597935292, // 时间戳(单位:秒)
- // "nonceStr": "c5sEwbaNPiXAF3iv", // 随机字符串
- // "package": "wx202254********************fbe90000", // 小程序下单接口返回的prepay_id参数值,提交格式如:prepay_id=***;示例值:prepay_id=wx201410272009395522657a690389285100
- // "signType": "RSA" 签名类型,默认为RSA,仅支持RSA。
- // "paySign": "A842B45937F6EFF60DEC7A2EAA52D5A0" // 签名,这里用的 MD5/RSA 签名
-
- @Serial
- private static final long serialVersionUID = 1L;
-
- /**
- * 时间戳
- */
- @Schema(description = "时间戳")
- private String timeStamp;
-
- /**
- * 随机字符串
- */
- @Schema(description = "随机字符串")
- private String nonceStr;
-
- /**
- * 订单详情扩展字符串 package
- */
- @Schema(description = "订单详情扩展字符串 package")
- private String wxPackage;
-
- /**
- * 签名方式
- */
- @Schema(description = "签名方式")
- private String signType;
-
- /**
- * 签名
- */
- @Schema(description = "签名")
- private String paySign;
-
- /**
- * 运单号
- */
- @Schema(description = "运单号")
- private String outTradeNo;
-
-
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- // 第三节中保存的微信配置信息 注入进来
- @Autowired
- private WeChatToolConfig config;
-
- @Autowired
- private PayService payService;
-
- /**
- * 微信请求下单支付
- *
- * @param waybillId 运单id
- * @return 付款所需参数
- */
- @Override
- public AjaxResult<CreateOrderVo> weChatCreateOrder(String waybillId) {
- // 查询运单
- Waybill waybill = getById(waybillId, "运单id不存在");
- // 调用微信请求下单接口
- int total = waybill.getGoodTotalPrice().multiply(new BigDecimal("100.00")).intValue();
- // 获取付款所需参数
- CreateOrderVo createOrder = payService.createPayOrder(waybill.getGoodName(), waybillId, waybill.getOpenId(), total, config);
- log.info("支付返回" + createOrder);
- return AjaxResult.success(createOrder);
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- /**
- * 小程序请求下单
- *
- * @param description 商品描述
- * @param outTradeNo 商户订单号
- * @param openId appid下的唯一标识
- * @param total 总金额
- * @param config 基本配置
- * @return 小程序下单前端Vo
- */
- @Override
- public CreateOrderVo createPayOrder(String description, String outTradeNo, String openId, int total, WeChatToolConfig config) {
- // 配置下单参数
- JSONObject requestParam = new JSONObject();
- // 商户id
- requestParam.put(WeChatPayParam.MCHID, config.getMchId());
- // 应用id
- requestParam.put(WeChatPayParam.APPID, config.getAppId());
- // 商品描述
- requestParam.put(WeChatPayParam.DESCRIPTION, description);
- // 回调地址
- requestParam.put(WeChatPayParam.NOTIFY_URL, config.getNotifyUrl());
- // 订单号
- requestParam.put(WeChatPayParam.OUT_TRADE_NO, outTradeNo);
- // 金额
- JSONObject amount = new JSONObject();
- // 金额 单位 分
- amount.put(WeChatPayParam.AMOUNT_TOTAL, "dev".equals(SpringUtils.getActiveProfile()) ? 1 : total);
- // 货币类型 人民币
- amount.put(WeChatPayParam.AMOUNT_CURRENCY, WeChatPayParam.CURRENCY_RMB);
- // 金额
- requestParam.put(WeChatPayParam.AMOUNT, amount);
-
- // 支付者
- JSONObject payer = new JSONObject();
- // 微信登录时生成的openid,创建订单时存入订单中
- payer.put(WeChatPayParam.OPENID, openId);
- // 支付者
- requestParam.put(WeChatPayParam.PAYER, payer);
-
- try {
- // 调用post请求
- JSONObject jsonObject = WeChatUtil.getBodyAsJsonByPost(WxApiTypeEnum.CREATE_ORDER.getValue(), requestParam, config);
- // 异常情况
- if (Objects.nonNull(jsonObject.get(WeChatPayParam.CODE))) {
- throw new CustomException(jsonObject.get(WeChatPayParam.MESSAGE).toString());
- }
- // 时间戳
- String timestamp = String.valueOf(DateUtil.currentSeconds());
- // 随机字符串
- String nonce = RandomUtil.randomString(WeChatPayParam.NUM_32);
- // 订单详情扩展字符串 prepay_id=wx201410272009395522657a690389285100 必须以此格式
- String wxPackage = WeChatPayParam.WX_PACKAGE + jsonObject.get(WeChatPayParam.PREPAY_ID);
- // 获取签名
- String sign = WeChatUtil.getSign(config.getAppId(), timestamp, nonce, wxPackage, config.getPrivateKey());
-
- return new CreateOrderVo(timestamp, nonce, wxPackage, "RSA", sign, outTradeNo);
- } catch (Exception e) {
- log.error("请求下单失败:" + outTradeNo);
- log.error(e.getMessage());
- throw new CustomException("请求下单失败:" + e.getMessage());
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- /**
- * 支付回调给微信确认
- */
- @Operation(summary = "支付回调给微信确认")
- @IgnoreAuth
- @PostMapping("/wechatPayCallback")
- public Map<String, String> wechatCallback(HttpServletRequest request) {
- Map<String, String> result = new HashMap<>(WeChatPayParam.NUM_TWO);
- // 判断支付是否成功
- if (waybillService.verifyCreateOrder(request)) {
- result.put(WeChatPayParam.CODE, WeChatPayParam.WX_BACK_OK);
- } else {
- result.put(WeChatPayParam.CODE, "FAIL");
- result.put(WeChatPayParam.MESSAGE, "失败");
- }
- return result;
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- /**
- * 微信支付回调验证判定 核对成功 数据异步入库
- */
- @Override
- @Transactional
- public Boolean verifyCreateOrder(HttpServletRequest request) {
- log.info("===================================进入微信支付回调核对订单中========================================");
- // 获取微信通知详情
- JSONObject decryptData = payService.getDecryptData(request, config);
-
- // 获取运单号
- String waybillId = decryptData.get(WeChatPayParam.OUT_TRADE_NO).toString();
-
- // 获取微信支付生成的订单号
- String transactionId = decryptData.get(WeChatPayParam.TRANSACTION_ID).toString();
-
- log.info(decryptData.get(WeChatPayParam.OUT_TRADE_NO).toString() + "订单回调信息记录:订单状态:" + waybillId);
-
- // 判断支付是否成功
- if (StrUtil.equals(WeChatPayParam.WX_BACK_OK, decryptData.get(WeChatPayParam.TRADE_STATE).toString())) {
- // 查询运单
- Waybill waybill = getById(waybillId, "运单id不存在");
- // 判断金额是否与数据库一致
- if (WeChatUtil.verifyMoney(decryptData, getAmountByOrderNo(waybillId))) {
- // 修改订单状态,保存微信支付订单号
- updateStatus(waybill, transactionId);
- // 判断发货是否成功
- if (payService.verifyDeliverGood(waybill.getGoodName(), waybill.getOpenId(), transactionId, config)) {
- // 修改发货状态 确认
- updateDeliverGood(waybill, ShipmentEnum.OK);
- } else {
- // 修改发货状态 未确认
- updateDeliverGood(waybill, ShipmentEnum.NOT);
- }
- return true;
- }
- }
- return false;
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- /**
- * 获取通知
- *
- * @param request 请求
- * @param config 微信配置
- * @return 通知详情
- */
- @Override
- public JSONObject getDecryptData(HttpServletRequest request, WeChatToolConfig config) {
- try {
- // 解析微信通知
- Notification notification = WeChatUtil.verifyBack(request, config);
- // 获取通知简要说明
- String summary = notification.getSummary();
- // 判断支付状态
- if (WeChatPayParam.PAY_SUCCESS.equals(summary) || WeChatPayParam.REFUND_SUCCESS.equals(summary)) {
- // 返回详情信息
- return JSON.parseObject(notification.getDecryptData());
- } else {
- // 支付失败
- throw new CustomException(summary);
- }
- } catch (Exception e) {
- log.error("回调失败验证" + e);
- e.printStackTrace();
- throw new CustomException("支付回调失败:" + e.getMessage());
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- /**
- * 判断发货是否成功
- *
- * @param description 商品描述
- * @param openId appid下的唯一标识
- * @param transactionId 微信支付生成订单号
- * @param config 基本配置
- * @return 是否成功
- */
- @Override
- public Boolean verifyDeliverGood(String description, String openId, String transactionId, WeChatToolConfig config) {
- try {
- // 获取接口调用凭证
- JSONObject jsonObject = WeChatUtil.getAccessToken(config);
- // 异常情况
- if (Objects.nonNull(jsonObject.get(WeChatPayParam.CODE))) {
- throw new CustomException(jsonObject.get(WeChatPayParam.MESSAGE).toString());
- }
- String accessToken = jsonObject.get(WeChatPayParam.ACCESS_TOKEN).toString();
-
- // 构建请求参数
- JSONObject requestParam = new JSONObject();
-
- // 订单
- JSONObject orderKey = new JSONObject();
- orderKey.put(WeChatPayParam.ORDER_NUMBER_TYPE, OrderNumberTypeEnum.WECHAT.getCode());
- orderKey.put(WeChatPayParam.TRANSACTION_ID, transactionId);
- requestParam.put(WeChatPayParam.ORDER_KEY, orderKey);
- // 物流模式 用户自提
- requestParam.put(WeChatPayParam.LOGISTICS_TYPE, LogisticsTypeEnum.VIRTUAL.getCode());
- // 发货模式 统一发货
- requestParam.put(WeChatPayParam.DELIVERY_MODE, DeliveryModeEnum.UNIFIED_DELIVERY.getCode());
- // 物流信息列表
- List<JSONObject> shippingLists = new ArrayList<>();
- Map<String, Object> map = new HashMap<>();
- map.put(WeChatPayParam.ITEM_DESC, description);
- shippingLists.add(new JSONObject(map));
- requestParam.put(WeChatPayParam.SHIPPING_LIST, shippingLists);
- // 上传时间
- requestParam.put(WeChatPayParam.UPLOAD_TIME, new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ").format(new Date()));
- // 支付者
- JSONObject payer = new JSONObject();
- // 微信登录时生成的openid,创建订单时存入订单中
- payer.put(WeChatPayParam.OPENID, openId);
- requestParam.put(WeChatPayParam.PAYER, payer);
- // 设置请求url
- String url = StrFormatter.format(WxApiTypeEnum.GOOD_ENTERING.getValue(), accessToken);
- // 发送请求
- JSONObject object = WeChatUtil.getBodyAsJsonByPost(url, requestParam, config);
- // 发货失败
- if (!object.get(WeChatPayParam.ERR_CODE).equals(WeChatPayParam.NUM_ZERO)) {
- log.error("发货失败:" + object.get(WeChatPayParam.ERR_CODE) + " " + object.get(WeChatPayParam.ERR_MSG));
- return false;
- }
- } catch (Exception e) {
- e.printStackTrace();
- throw new CustomException(e.getMessage());
- }
- return true;
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- /**
- * 更新订单,运单状态 已完成
- *
- * @param waybill 运单
- * @param transactionId 微信支付订单号
- */
- public void updateStatus(Waybill waybill, String transactionId) {
- // 修改运单状态
- waybill.setWaybillStatus(WaybillStatusEnum.COMPLETED);
- waybill.setPayId(transactionId);
- updateById(waybill);
-
- // 新增散户流水
- individualAddFlow(waybill);
-
- // 查询订单
- final OrderService orderService = SpringUtils.getBean(OrderService.class);
- LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<>();
- queryWrapper.eq(Order::getId, waybill.getOrderId());
- Order order = orderService.getOne(queryWrapper);
-
- // 修改订单状态
- LambdaUpdateWrapper<Order> orderWrapper = new LambdaUpdateWrapper<>();
- orderWrapper.eq(Order::getId, waybill.getOrderId());
- orderWrapper.set(Order::getOrderStatus, OrderStatusEnum.COMPLETED);
- orderWrapper.set(Order::getGoodWeight, waybill.getNetWeight());
- orderWrapper.set(Order::getGoodTotalPrice, waybill.getNetWeight().multiply(order.getGoodPrice()));
- orderService.update(orderWrapper);
- }
-
- /**
- * 修改运单确认发货
- *
- * @param waybill 运单
- * @param shipment 确认发货枚举
- */
- private void updateDeliverGood(JkwlWaybill waybill, ShipmentEnum shipment) {
- waybill.setShipment(shipment);
- updateById(waybill);
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- /**
- * 查询微信支付订单状态
- *
- * @param waybillId 运单id
- */
- @GetMapping("/getPayOrder/{waybillId}")
- @Operation(summary = "查询微信支付订单状态")
- public AjaxResult<Void> getPayOrder(@PathVariable("waybillId") String waybillId) {
- return waybillService.getPayOrder(waybillId);
- }
- /**
- * 查询微信支付是否成功
- *
- * @param waybillId 运单id
- */
- @Override
- public AjaxResult<Void> getPayOrder(String waybillId) {
- try {
- // 查询微信支付信息
- JSONObject jsonObject = payService.getPayState(waybillId, config);
- // 返回查单结果信息
- final String res = jsonObject.get(WeChatPayParam.TRADE_STATE).toString();
- // 支付成功
- if (WeChatPayParam.WX_BACK_OK.equals(res)) {
- // 根据业务 该干嘛干嘛
- // 例: 修改订单
- // updateStatus(orderId);
- return AjaxResult.success("SUCCESS");
- } catch (Exception e) {
- log.error("支付查单失败" + orderId);
- e.printStackTrace();
- }
- return AjaxResult.error();
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- /**
- * 获取支付状态
- *
- * @param waybillId 运单id
- * @param config 配置
- * @return 状态详情
- */
- @Override
- public JSONObject getPayState(String waybillId, WeChatToolConfig config) throws IOException {
- // 查单 微信接口 编辑 微信订单号 + 商户号
- String url = StrFormatter.format(WxApiTypeEnum.QUERY_CREATE_ORDER.getValue(), waybillId, config.getMchId());
- // 调用微信接口
- JSONObject jsonObject = WeChatUtil.getBodyAsJsonByGet(url, config);
- // 异常情况
- if (Objects.nonNull(jsonObject.get(WeChatPayParam.CODE))) {
- throw new CustomException(jsonObject.get(WeChatPayParam.MESSAGE).toString());
- }
- return jsonObject;
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- /**
- * 微信退款
- *
- * @param waybillId 运单id
- */
- @RepeatSubmit
- @GetMapping("/weChatRefundOrder/{waybillId}/{amount}")
- @Operation(summary = "微信退款")
- @IgnoreAuth
- public AjaxResult<Void> weChatRefundOrder(@PathVariable("waybillId") String waybillId, @PathVariable("amount") int amount) {
- return waybillService.weChatRefundOrder(waybillId, amount);
- }
- /**
- * 微信退款
- *
- * @param waybillId 运单id
- */
- @Override
- public AjaxResult<Void> weChatRefundOrder(String waybillId, int amount) {
- // 非开发环境 输入多少退多少
- if (!"dev".equals(SpringUtils.getActiveProfile())) {
- // 从数据库获取运单退款金额
- amount = getAmountByOrderNo(waybillId);
- }
- // 调用微信退款接口
- JSONObject jsonObject = payService.refundOrder(waybillId, amount, config);
- // 获取微信退款状态
- String status = jsonObject.get(WeChatPayParam.STATUS).toString();
-
- return switch (status) {
- // 退款关闭
- case "CLOSED" -> AjaxResult.success("退款关闭");
- // 退款处理中
- case "PROCESSING" -> AjaxResult.success("退款处理中 请稍后");
- // 退款成功
- case "SUCCESS" -> {
- // 可拓展 退款成功后进行的操作 例:修改订单退款订单,运单状态 微信退款入数据库
- // updateStatus(orderId);
- yield AjaxResult.success("退款申请成功 注意退款查收");
- }
- // 退款异常
- default -> AjaxResult.error("退款账户异常 请联系管理人员");
- };
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- /**
- * 微信退款
- *
- * @param waybillId 运单id
- * @param refundAmount 退款金额
- * @param config 配置
- * @return 状态详情
- */
- @Override
- public JSONObject refundOrder(String waybillId, Integer refundAmount, WeChatToolConfig config) {
- // 配置参数
- JSONObject requestParam = new JSONObject();
- // 商户订单号 orderId
- requestParam.put(WeChatPayParam.OUT_TRADE_NO, waybillId);
- // 商户退款单号
- requestParam.put(WeChatPayParam.OUT_REFUND_NO, waybillId);
- // 退款回调地址
- requestParam.put(WeChatPayParam.NOTIFY_URL, config.getRefundNotifyUrl());
- // 金额信息 amount (单位都是分)
- JSONObject amount = new JSONObject();
- // 原订单金额 total
- amount.put(WeChatPayParam.AMOUNT_TOTAL, refundAmount);
- // 退款金额 refund
- amount.put(WeChatPayParam.AMOUNT_REFUND, refundAmount);
- // 退款币种 CNY 人民币
- amount.put(WeChatPayParam.AMOUNT_CURRENCY, WeChatPayParam.CURRENCY_RMB);
- // 金额信息 amount: 原订单金额 total 退款金额 refund (单位都是分)
- requestParam.put(WeChatPayParam.AMOUNT, amount);
-
- try {
- // 调用请求接口
- JSONObject jsonObject = WeChatUtil.getBodyAsJsonByPost(WxApiTypeEnum.REFUND_ORDER.getValue(), requestParam, config);
- // 异常情况
- if (Objects.nonNull(jsonObject.get(WeChatPayParam.CODE))) {
- throw new CustomException(jsonObject.get(WeChatPayParam.MESSAGE).toString());
- }
- log.info("微信申请退款返回结果" + "response:" + jsonObject);
- return jsonObject;
- } catch (Exception e) {
- log.info("微信退款" + waybillId + "失败");
- e.printStackTrace();
- throw new CustomException("退款失败:" + e.getMessage());
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- /**
- * 微信退款回调接口
- */
- @IgnoreAuth
- @Operation(summary = "微信退款回调接口")
- @PostMapping("/wechatRefundBack")
- public Map<String, String> wechatRefundBack(HttpServletRequest request) {
- Map<String, String> result = new HashMap<>(WeChatPayParam.NUM_TWO);
- // 根据退款返回结果 更新订单状态 返回结果
- if (waybillService.verifyRefundOrder(request)) {
- log.info("==============================微信退款成功订单=====================================");
- result.put(WeChatPayParam.CODE, WeChatPayParam.WX_BACK_OK);
- } else {
- result.put(WeChatPayParam.CODE, "FAIL");
- result.put(WeChatPayParam.MESSAGE, "失败");
- }
- return result;
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- @Override
- public Boolean verifyRefundOrder(HttpServletRequest request) {
- // 获取微信通知详情
- JSONObject decryptData = jkwlPayService.getDecryptData(request, config);
- // 商户退款单号
- String outRefundNo = decryptData.get(WeChatPayParam.OUT_REFUND_NO).toString();
-
- log.info("微信退款成功订单:" + outRefundNo);
-
- // 退款状态
- String refundStatus = decryptData.get(WeChatPayParam.REFUND_STATUS).toString();
- // 数据库核对 如果退款状态已退款说明已处理 直接返回即可
- if (WaybillStatusEnum.CANCELED.equals(getStatus(outRefundNo))) {
- return true;
- }
- return switch (refundStatus) {
- // 退款关闭
- case "CLOSED" -> Boolean.FALSE;
- // 退款成功
- case "SUCCESS" -> {
- // 修改订单退款订单,运单状态 微信退款入数据库
- // updateStatus(outRefundNo);
- yield Boolean.TRUE;
- }
- // 退款异常
- default -> Boolean.FALSE;
- };
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- /**
- * 查询退款订单
- *
- * @param waybillId 运单id
- */
- @Operation(summary = "查询退款订单")
- @GetMapping("/getRefundOrder/{waybillId}")
- public AjaxResult<Void> getRefundOrder(@PathVariable("waybillId") String waybillId) {
- return waybillService.getRefundOrder(waybillId);
- }
- /**
- * 查询退款订单
- *
- * @param waybillId 运单id
- */
- @Override
- public AjaxResult<Void> getRefundOrder(String waybillId) {
- try {
- // 调用微信查询退款订单接口
- JSONObject jsonObject = payService.getRefundState(waybillId, config);
- // 获取退款状态
- String string = jsonObject.get(WeChatPayParam.STATUS).toString();
-
- return switch (string) {
- // 退款关闭
- case "CLOSED" -> AjaxResult.success("退款关闭");
- // 退款处理中
- case "PROCESSING" -> AjaxResult.success("退款处理中 请稍后");
- // 退款成功
- case "SUCCESS" -> AjaxResult.success("退款申请成功 注意退款查收");
- // 退款异常
- default -> AjaxResult.error("退款账户异常 请联系管理人员");
- };
- } catch (Exception e) {
- log.error("支付查单失败" + waybillId);
- e.printStackTrace();
- }
- return AjaxResult.error();
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- /**
- * 获取退款状态
- *
- * @param waybillId 运单id
- * @param config 配置
- * @return 状态详情
- */
- @Override
- public JSONObject getRefundState(String waybillId, WeChatToolConfig config) throws IOException {
- // 查单 微信接口 拼接url
- String url = StrFormatter.format(WxApiTypeEnum.QUERY_REFUND_ORDER.getValue(), waybillId);
- // 调用微信接口
- JSONObject jsonObject = WeChatUtil.getBodyAsJsonByGet(url, config);
- // 异常情况
- if (Objects.nonNull(jsonObject.get(WeChatPayParam.CODE))) {
- throw new CustomException(jsonObject.get(WeChatPayParam.MESSAGE).toString());
- }
- return jsonObject;
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。