微信小程序集成b2b交易代码 Published on Apr 21, 2025 in 随笔 with 0 comment vue: ``` // 微信支付,将参数传后端获取数据掉起微信支付 wxPayOrder(orderData).then(response => { let params = response.data wx.requestCommonPayment({ signData: params.signData, mode: params.mode, paySig: params.paySig, signature: params.signature, success(res) { console.log('支付成功', res); this.paySuccess() }, fail(res) { console.log('支付失败,res', res); uni.showToast({ title: '支付失败,如果您已支付,请勿反复支付', icon: 'none' }) } }); ``` java ``` //微信支付下单统一参数封装 Map payParams = Maps.newHashMapWithExpectedSize(CommonConstants.INTEGER_TYPE.TYPE_EIGHT); payParams.put("mchid", wxConfig.getB2bMchId()); payParams.put("description", request.getOrderName()); payParams.put("out_trade_no", DateUtil.getDateline() + "b2b" + request.getOutTradeNo()); Map outTradeNoParams = Maps.newHashMapWithExpectedSize(CommonConstants.INTEGER_TYPE.TYPE_ONE); outTradeNoParams.put("out_trade_no", request.getOutTradeNo()); payParams.put("attach", JsonUtils.toJsonString(outTradeNoParams)); Map amountMap = Maps.newHashMapWithExpectedSize(CommonConstants.INTEGER_TYPE.TYPE_ONE); amountMap.put("order_amount", MoneyUtils.yuanToFen(request.getFee())); payParams.put("amount", amountMap); payParams.put("env", 0); String uri = "requestCommonPayment"; String url2 = uri + "&" + JSON.toJSONString(payParams); Map connect = remoteConnectService.queryConnect( LoginHelper.getUserId() + "", SourceEnum.WECHAT_MP_OPEN_ID.name() ); if (connect == null) { log.error("未获取到用户{}:{}登录信息", LoginHelper.getUserId() + "", SourceEnum.WECHAT_MP_OPEN_ID.name()); return null; } String paramsStr = JSON.toJSONString(payParams); log.info("统一下单API,支付参数:{}", paramsStr); PayResponse payResponse = new PayResponse(); payResponse.setSignData(paramsStr); payResponse.setMode(wxConfig.getB2bMode()); payResponse.setPaySig(HmacSha256Util.hmacSha256Hex(wxConfig.getB2bAppKey(), url2)); payResponse.setSignature(HmacSha256Util.hmacSha256Hex(connect.get("sessionKey").toString(), paramsStr)); log.info("统一下单最后返回支付参数:{}", JSON.toJSONString(payResponse)); ``` 编码工具类: ``` package com.honghan.common.core.utils; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; public class HmacSha256Util { public static String hmacSha256Hex(String key, String data) { try { Mac sha256Hmac = Mac.getInstance("HmacSHA256"); SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256"); sha256Hmac.init(secretKey); byte[] hashBytes = sha256Hmac.doFinal(data.getBytes(StandardCharsets.UTF_8)); return bytesToHex(hashBytes); } catch (NoSuchAlgorithmException | InvalidKeyException e) { throw new RuntimeException("Error while generating HMAC-SHA256", e); } } private static String bytesToHex(byte[] bytes) { StringBuilder hexString = new StringBuilder(); for (byte b : bytes) { String hex = Integer.toHexString(0xff & b); if (hex.length() == 1) hexString.append('0'); hexString.append(hex); } return hexString.toString(); } // Example usage: public static void main(String[] args) { String sessionKey = "yourSessionKey"; String signData = "yourSignData"; String signature = hmacSha256Hex(sessionKey, signData); System.out.println("Signature: " + signature); } } ``` b2b支付回调通知已经请求加解密方法: ``` package com.honghan.trade.controller.pay; import cn.hutool.core.date.DateTime; import cn.hutool.core.net.URLDecoder; import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.TypeReference; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.honghan.common.core.constant.CommonConstants; import com.honghan.common.core.constant.Constants; import com.honghan.common.core.domain.ResultResponse; import com.honghan.common.core.enums.OrderStatus; import com.honghan.common.core.exception.ServiceException; import com.honghan.common.core.utils.HttpUtils; import com.honghan.common.core.utils.TimeUtils; import com.honghan.common.core.utils.ajax.AjaxUtils; import com.honghan.common.core.utils.copy.CopyUtils; import com.honghan.mall.api.RemoteProductSkuStockService; import com.honghan.site.api.RemoteCompanyService; import com.honghan.store.api.RemoteStoreOrderService; import com.honghan.store.api.RemoteStoreStockService; import com.honghan.system.api.RemoteSysConfigService; import com.honghan.trade.api.call.PaySuccessCallback; import com.honghan.trade.api.call.ResultWechatBack; import com.honghan.trade.api.domain.PaymentSuccessParamsVO; import com.honghan.trade.api.domain.TradeOrder; import com.honghan.trade.api.domain.pay.PayResponse; import com.honghan.trade.config.pay.config.WxConfig; import com.honghan.trade.config.pay.sign.WechatPayValidator; import com.honghan.trade.domain.vo.TradeOrderVO; import com.honghan.trade.payment.RefundLogService; import com.honghan.trade.payment.entity.RefundLog; import com.honghan.trade.payment.entity.enums.PaymentMethodEnum; import com.honghan.trade.payment.param.PaymentSuccessParams; import com.honghan.trade.service.*; import com.honghan.trade.service.pay.AliPayService; import com.honghan.trade.service.pay.call.OrderPayCallback; import com.wechat.pay.contrib.apache.httpclient.auth.Verifier; import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.util.crypto.PKCS7Encoder; import org.apache.commons.lang3.StringUtils; import org.apache.dubbo.config.annotation.DubboReference; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.BufferedReader; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.text.SimpleDateFormat; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; /** * 订单回调 */ @Slf4j @RestController @RequestMapping("/order/notify") public class TradeOrderNotifyController { private final ReentrantLock lock = new ReentrantLock(); @Resource private TradeOrderService tradeOrderService; @Resource private TradeOrderProductService tradeOrderProductService; @Resource private TradeMessageService tradeMessageService; @Resource private IBillOrderService billOrderService; @Resource private ISubOrderService subOrderService; @Resource private PaySuccessCallback paySuccessCallback; @Resource private AliPayService aliPayService; @Resource private TradeMatchService tradeMatchService; @Resource private TradeMatchDetailService tradeMatchDetailService; @Resource private WxConfig wxConfig; @Resource private Verifier verifier; @Resource private IPaymentOrderService paymentOrderService; @Resource private OrderPayCallback orderPayCallback; @DubboReference private RemoteCompanyService companyService; @DubboReference private RemoteStoreStockService remoteStoreStockService; @DubboReference private RemoteCompanyService remoteCompanyService; @DubboReference private RemoteSysConfigService remoteSysConfigService; @DubboReference private RemoteStoreOrderService remoteStoreOrderService; @DubboReference private RemoteProductSkuStockService remoteProductSkuStockService; /** * 退款日志 */ @Autowired private RefundLogService refundLogService; /** * 支付宝回调接口 */ @PostMapping("/alipayNotify") public void aliPayNotify(HttpServletRequest request, HttpServletResponse response) { ResultResponse result = aliPayService.asyncNotify(request, paySuccessCallback); if (result.getCode() == Constants.SUCCESS) { AjaxUtils.renderText(response, CommonConstants.SUCCESS); } else { AjaxUtils.renderText(response, CommonConstants.FAIL); } } /** * 微信回调接口 */ @PostMapping("/wxPayNotify") public Map wxPayNotify(HttpServletRequest request, HttpServletResponse response) { String orderNo = ""; try { //处理通知参数 String body = HttpUtils.readData(request); log.info("微信支付回调参数:{}", body); //转换为Map Map bodyMap = JSONObject.parseObject(body, new TypeReference>() { }); //微信的通知ID(通知的唯一ID) String notifyId = bodyMap.get("id").toString(); //构造验证签名信息 WechatPayValidator wxCheckSign = new WechatPayValidator(verifier, notifyId, body); if (!wxCheckSign.validate(request)) { return ResultWechatBack.falseMsg(response); } if (lock.tryLock(6, TimeUnit.SECONDS)) { //解密resource中的通知数据 String resource = bodyMap.get("resource").toString(); Map resourceMap = WechatPayValidator.decryptFromResource(resource, wxConfig.getApiV3Key(), 1); //解密后返回相关订单详情 log.info("微信支付回调解密后返回相关订单详情---{}", resourceMap); orderNo = resourceMap.get("out_trade_no").toString(); String transactionId = resourceMap.get("transaction_id").toString(); String tradeState = resourceMap.get("trade_state").toString(); if (StringUtils.equals(WxConfig.SUCCESS, tradeState)) { String _payTime = resourceMap.get("success_time").toString(); DateTime dateTime = new DateTime(_payTime); //转换成Date对象 Date timeDate = dateTime.toJdkDate(); String payParamStr = resourceMap.get("attach").toString(); String payParamJson = URLDecoder.decode(payParamStr, StandardCharsets.UTF_8); //PayParam payParam = JSONUtil.toBean(payParamJson, PayParam.class); String tradeNo_ = resourceMap.get("transaction_id").toString(); Double totalAmount = null; PaymentSuccessParams paymentSuccessParams = new PaymentSuccessParams( PaymentMethodEnum.WECHAT.name(), tradeNo_, totalAmount, null ); paySuccessCallback.doWhilePaySuccess(CopyUtils.copy(paymentSuccessParams, PaymentSuccessParamsVO.class), orderNo, transactionId, timeDate); // if(orderNo.startsWith("Y")) { // //购物车下的订单 // List subOrder = subOrderService.getOrderNos(orderNo); // List orderNoList = subOrder.stream().map(SubOrder::getCarOrderNo).collect(Collectors.toList()); // List tradeOrders = tradeOrderService.getByPayOrder(orderNoList); // for (TradeOrder tradeOrder : tradeOrders) { // if (tradeOrder.getType().equals(OrderType.MALL.getValue())) { // Asserts.isTrue(tradeOrder.getStatus().equals(OrderStatus.CONFIRMED.getValue()), "订单状态不是待付款状态!"); // tradeOrder.setStatus(OrderStatus.PAYED.getValue()); // } else if (tradeOrder.getType().equals(OrderType.MALL_MATCH.getValue())) { // Asserts.isTrue(tradeOrder.getStatus().equals(OrderStatus.CONFIRMED.getValue()), "订单状态不是待付款状态!"); // tradeOrder.setStatus(OrderStatus.COUNT.getValue()); // } // tradeOrder.setPayTime(TimeUtils.getNowDate()); // orderPayCallback.paySuccess(orderNo, transactionId, tradeOrder); // } // }else if (orderNo.startsWith("W") || orderNo.startsWith("F")) { // PaymentOrder payMentOrder = paymentOrderService.queryOrderNo(orderNo); // Asserts.isTrue(payMentOrder.getStatus().equals(0), "付款单状态不是待付款状态!"); // TradeOrder tradeOrder = tradeOrderService.getById(payMentOrder.getOriginalOrderId()); // payMentOrder.setPayType(tradeOrder.getPayType()); // payMentOrder.setStatus(PaymentStatusEnum.FINISH.getValue()); // payMentOrder.setPayTime(TimeUtils.getNowDate()); // payMentOrder.setPayNo(transactionId); // boolean updateById = paymentOrderService.updateById(payMentOrder); // if (updateById) { // Integer total = payMentOrder.getTotal(); // List paymentOrders = paymentOrderService.queryOriginalOrderId(payMentOrder.getOriginalOrderId(), null); // long payAmountNum = paymentOrders.stream().filter(paymentOrder-> paymentOrder.getStatus() == 1).count(); // //付款方式 1 先款后货 2 先付订金 后付尾款 3 先货后款 // if(total == 1 && payMentOrder.getPaymentType() == 3) { // //付完钱直接完成 // tradeOrder.setStatus(OrderStatus.COUNT.getValue()); // }else if(total == 2){ // if(payMentOrder.getRemark().equals(PaymentPayTypeEnum.FIRST_PAYMENT.getValue())){ // tradeOrder.setIfPickUp(1); // tradeOrder.setStatus(OrderStatus.PART_PAYED.getValue()); // } else { // tradeOrder.setStatus(OrderStatus.COUNT.getValue()); // } // }else { // tradeOrder.setIfPickUp(1); // tradeOrder.setStatus(OrderStatus.COUNT.getValue()); // } // boolean paymentUpdateById = tradeOrderService.updateById(tradeOrder); // if(paymentUpdateById){ // tradeOrderProductService.batchUpdateProductSaleNum(tradeOrder.getId()); // } // } // }else { // LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); // queryWrapper.eq(TradeOrder::getIdentifier, orderNo); // queryWrapper.last("LIMIT 1"); // TradeOrder tradeOrder = tradeOrderService.getOne(queryWrapper); // Asserts.isTrue(tradeOrder.getStatus().equals(OrderStatus.CONFIRMED.getValue()), "订单状态不是待付款状态!"); // tradeOrder.setIfPickUp(1); // tradeOrder.setStatus(OrderStatus.PAYED.getValue()); // orderPayCallback.paySuccess(orderNo, transactionId, tradeOrder); // } //成功应答 响应微信 log.info("微信支付回调成功----商户订单号:{}", orderNo); return ResultWechatBack.trueMsg(response); } else { log.warn("微信支付回调状态并不是SUCCESS:{}", resourceMap); return ResultWechatBack.falseMsg(response); } } } catch (Exception e) { log.error("微信支付回调处理失败, orderNo = " + orderNo, e); return ResultWechatBack.falseMsg(response); } finally { //要主动释放锁 lock.unlock(); } return ResultWechatBack.trueMsg(response); } private static final String TOKEN = "xxx"; // Token private static final String ENCODING_AES_KEY = "xxx"; // EncodingAESKey private static final String APPID = "xxx"; // 小程序Appid /** * 微信消息推送 */ @RequestMapping("/callback") public void callback(HttpServletRequest request, HttpServletResponse httpServletResponse) throws IOException { // 从 URL 参数中获取 String signature = request.getParameter("signature"); String timestamp = request.getParameter("timestamp"); String nonce = request.getParameter("nonce"); String echostr = request.getParameter("echostr"); if (StringUtils.isNotBlank(echostr) && checkSignature(signature, timestamp, nonce)) { // 返回 echostr 表示验证通过 httpServletResponse.getWriter().write(echostr); return null; } String msgSignature = request.getParameter("msg_signature"); String encryptType = request.getParameter("encrypt_type"); // "aes" 是加密类型 // 打印请求的 URL 参数 System.out.println("signature: " + signature); System.out.println("timestamp: " + timestamp); System.out.println("nonce: " + nonce); System.out.println("msg_signature: " + msgSignature); System.out.println("encrypt_type: " + encryptType); // 从请求体中获取 JSON 数据(Encrypt 字段) StringBuilder body = new StringBuilder(); try (BufferedReader reader = request.getReader()) { String line; while ((line = reader.readLine()) != null) { body.append(line); } } String jsonBody = body.toString(); System.out.println("Request Body (JSON): " + jsonBody); // 解析 JSON 数据中的 Encrypt 字段 String encrypt = parseEncryptField(jsonBody); System.out.println("Encrypt: " + encrypt); // 校验 msg_signature 签名是否正确 if (!checkMsgSignature(msgSignature, timestamp, nonce, encrypt)) { return ResponseEntity.status(400).body("Signature verification failed!"); } // 解密消息体中的 Encrypt 内容 String decryptedMessage = decryptMessage(encrypt); // 解密消息 System.out.println("Decrypted message: " + decryptedMessage); cn.hutool.json.JSONObject entries = JSONUtil.parseObj(decryptedMessage); if (!entries.getStr("appid").equals(APPID)) { throw new RuntimeException("AppId 不匹配,非法请求"); } entries = entries.getJSONObject("msg"); String event = entries.getStr("Event"); if (event.equalsIgnoreCase("retail_pay_notify")) { String orderNo = ""; String transactionId = entries.getStr("order_id").toString(); String tradeState = entries.getStr("pay_status").toString(); if (StringUtils.equalsIgnoreCase("ORDER_PAY_SUCC", tradeState)) { String _payTime = entries.getStr("pay_time").toString(); DateTime dateTime = new DateTime(_payTime); //转换成Date对象 Date timeDate = dateTime.toJdkDate(); String payParamStr = entries.getStr("attach").toString(); orderNo = JSONUtil.parseObj(payParamStr).getStr("out_trade_no"); if (orderNo.contains("b2b")) { orderNo = orderNo.split("b2b")[1]; } String tradeNo_ = entries.getStr("order_id").toString(); Double totalAmount = null; PaymentSuccessParams paymentSuccessParams = new PaymentSuccessParams( PaymentMethodEnum.WECHAT.name(), tradeNo_, totalAmount, null ); try { paySuccessCallback.doWhilePaySuccess(CopyUtils.copy(paymentSuccessParams, PaymentSuccessParamsVO.class), orderNo, transactionId, timeDate); } catch (Exception e) { log.error("微信支付回调处理失败, orderNo = " + orderNo, e); } //成功应答 响应微信 log.info("微信支付回调成功----商户订单号:{}", orderNo); } else { log.warn("微信支付回调状态并不是SUCCESS:{}", tradeState); } } else if (event.equalsIgnoreCase("retail_refund_notify")) { String orderNo = ""; String transactionId = entries.getStr("order_id").toString(); String refundId = entries.getStr("refund_id").toString(); orderNo = entries.getStr("out_trade_no"); if (orderNo.contains("b2b")) { orderNo = orderNo.split("b2b")[1]; } String outRefundNo = entries.getStr("out_refund_no").toString();//商户退款单号 String refundStatus = entries.getStr("refund_status").toString();//微信退款状态 if (StringUtils.isNotBlank(refundStatus) && StringUtils.equalsIgnoreCase("REFUND_SUCC", refundStatus)) { TradeOrderVO tradeOrderVO = tradeOrderService.selectVoByOutRefundNo(outRefundNo); if (Objects.isNull(tradeOrderVO)) { log.warn("微信该笔订单号商家不存在,退款订单号:{}", outRefundNo); new ServiceException("微信该笔订单号商家不存在,退款订单号:" + outRefundNo); } String successTime = entries.getStr("refund_time").toString();//微信退款成功时间 TradeOrder tradeOrder = new TradeOrder(); tradeOrder.setId(tradeOrderVO.getId()); tradeOrder.setStatus(OrderStatus.CANCELLED.getValue()); try { if (StringUtils.isNotBlank(successTime)) { SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); Date date = formatter.parse(successTime); Date refundSuccessTime = TimeUtils.parseDate(TimeUtils.format(date, CommonConstants.DATE.FORMAT_DEFAULT), CommonConstants.DATE.FORMAT_DEFAULT); tradeOrder.setRefundTime(refundSuccessTime); } else { tradeOrder.setRefundTime(TimeUtils.getNowDate()); } } catch (Exception e) { log.error("商城订单-微信退款回调处理失败, orderNo = " + orderNo, e); } tradeOrderService.updateById(tradeOrder); log.info("商城订单微信退款回调成功success----商户订单号:{}", orderNo); RefundLog refundLog = refundLogService.getOne(new LambdaQueryWrapper().eq(RefundLog::getPaymentReceivableNo, transactionId)); if (refundLog != null) { refundLog.setIsRefund(true); refundLog.setReceivableNo(refundId); refundLogService.saveOrUpdate(refundLog); } } } // 处理解密后的消息逻辑(根据需求) // String responseMessage = "{\"demo_resp\":\"good luck\"}"; // 构造回包 // String response = createResponse(responseMessage); httpServletResponse.getWriter().write("success"); } /** * 验证微信签名 * * @param signature 微信传来的签名 * @param timestamp 微信传来的时间戳 * @param nonce 微信传来的随机数 * @return 是否是合法请求 */ public static boolean checkSignature(String signature, String timestamp, String nonce) { try { String[] arr = new String[]{TOKEN, timestamp, nonce}; // 1. 字典序排序 Arrays.sort(arr); // 2. 拼接成一个字符串 StringBuilder content = new StringBuilder(); for (String s : arr) { content.append(s); } // 3. SHA1加密 MessageDigest md = MessageDigest.getInstance("SHA-1"); byte[] digest = md.digest(content.toString().getBytes()); // 4. 转成十六进制字符串 StringBuilder hexStr = new StringBuilder(); for (byte b : digest) { String shaHex = Integer.toHexString(b & 0xFF); if (shaHex.length() < 2) { hexStr.append(0); } hexStr.append(shaHex); } // 5. 比较签名 return hexStr.toString().equals(signature); } catch (Exception e) { e.printStackTrace(); return false; } } /** * 解析请求体中的 Encrypt 字段 */ private String parseEncryptField(String jsonBody) { try { JSONObject jsonObject = JSON.parseObject(jsonBody); return jsonObject.getString("Encrypt"); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 校验 msg_signature 签名 */ private boolean checkMsgSignature(String signature, String timestamp, String nonce, String encrypt) { try { String[] arr = new String[]{encrypt, timestamp, nonce, TOKEN}; Arrays.sort(arr); StringBuilder sb = new StringBuilder(); for (String str : arr) { sb.append(str); } MessageDigest md = MessageDigest.getInstance("SHA-1"); byte[] digest = md.digest(sb.toString().getBytes()); StringBuilder hexStr = new StringBuilder(); for (byte b : digest) { String shaHex = Integer.toHexString(b & 0xFF); if (shaHex.length() < 2) { hexStr.append(0); } hexStr.append(shaHex); } return hexStr.toString().equals(signature); } catch (Exception e) { e.printStackTrace(); return false; } } /** * 解密消息体中的 Encrypt 内容 */ private String decryptMessage(String encrypt) { try { // 1. Base64 解密 Encrypt 字段 byte[] encryptedBytes = Base64.getDecoder().decode(encrypt); // 2. 获取 AESKey byte[] aesKeyBytes = Base64.getDecoder().decode(ENCODING_AES_KEY + "="); SecretKeySpec secretKey = new SecretKeySpec(aesKeyBytes, "AES"); IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKeyBytes, 0, 16)); // 使用前16字节作为 IV // 3. AES 解密 Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); cipher.init(Cipher.DECRYPT_MODE, secretKey, iv); byte[] decrypted = cipher.doFinal(encryptedBytes); // 4.去除补位字符 decrypted = PKCS7Encoder.decode(decrypted); // 5. 拆解结构 random(16B) + msg_len(4B) + msg + appid ByteBuffer byteBuffer = ByteBuffer.wrap(decrypted); // 读取 random byte[] randomBytes = new byte[16]; byteBuffer.get(randomBytes); String randomStr = new String(randomBytes, StandardCharsets.UTF_8); // 读取 msg_len(4 字节,网络字节序,大端) int msgLen = byteBuffer.getInt(); // 读取 msg byte[] msgBytes = new byte[msgLen]; byteBuffer.get(msgBytes); String msg = new String(msgBytes, StandardCharsets.UTF_8); // 读取 appid byte[] appIdBytes = new byte[byteBuffer.remaining()]; byteBuffer.get(appIdBytes); String appId = new String(appIdBytes, StandardCharsets.UTF_8); // 5. 将解密后的数据以 JSON 格式返回 JSONObject jsonResponse = new JSONObject(); jsonResponse.put("random", randomStr); jsonResponse.put("msg_len", msgLen); jsonResponse.put("msg", msg); jsonResponse.put("appid", appId); return jsonResponse.toString(); // 返回 JSON 格式字符串 } catch (Exception e) { e.printStackTrace(); return null; } } /** * 构造回包并加密 */ private String createResponse(String message) { try { // 1. 构造 FullStr String randomStr = generateRandomString(16); // 随机生成16字节 byte[] msgBytes = message.getBytes("UTF-8"); // 2. 构造消息头:random(16B) + msg_len(4B) + msg byte[] msgLenBytes = intToByteArray(msgBytes.length); // 长度占4字节 byte[] fullMessage = new byte[randomStr.length() + 4 + msgBytes.length]; // 拼接消息 System.arraycopy(randomStr.getBytes("UTF-8"), 0, fullMessage, 0, randomStr.length()); System.arraycopy(msgLenBytes, 0, fullMessage, randomStr.length(), msgLenBytes.length); System.arraycopy(msgBytes, 0, fullMessage, randomStr.length() + 4, msgBytes.length); // 3. 用 AES 加密消息 byte[] encryptedMessage = encryptWithAES(fullMessage); // 4. Base64 编码加密结果 String encrypt = Base64.getEncoder().encodeToString(encryptedMessage); // 5. 生成签名 String msgSignature = generateMsgSignature(encrypt); // 6. 构造回包 long timeStamp = System.currentTimeMillis() / 1000; // 当前时间戳,单位秒 int nonce = new Random().nextInt(Integer.MAX_VALUE); // 随机生成一个 nonce // 7. 构造回包 return "{\"Encrypt\": \"" + encrypt + "\", \"MsgSignature\": \"" + msgSignature + "\", \"TimeStamp\": " + timeStamp + ", \"Nonce\": " + nonce + "}"; } catch (Exception e) { e.printStackTrace(); return "{\"error\":\"Failed to create response\"}"; } } /** * AES 加密 */ private byte[] encryptWithAES(byte[] data) throws Exception { byte[] aesKeyBytes = Base64.getDecoder().decode(ENCODING_AES_KEY + "="); Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); SecretKeySpec secretKey = new SecretKeySpec(aesKeyBytes, "AES"); IvParameterSpec iv = new IvParameterSpec(aesKeyBytes, 0, 16); // 使用前16字节作为 IV cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv); // 使用空的 16 字节偏移量 return cipher.doFinal(data); } /** * 生成消息签名 */ private String generateMsgSignature(String encrypt) throws Exception { String[] arr = new String[]{"1713424427", "415670741", TOKEN, encrypt}; Arrays.sort(arr); StringBuilder sb = new StringBuilder(); for (String str : arr) { sb.append(str); } MessageDigest md = MessageDigest.getInstance("SHA-1"); byte[] digest = md.digest(sb.toString().getBytes()); StringBuilder hexStr = new StringBuilder(); for (byte b : digest) { String shaHex = Integer.toHexString(b & 0xFF); if (shaHex.length() < 2) { hexStr.append(0); } hexStr.append(shaHex); } return hexStr.toString(); } // 将整数转化为网络字节序的4字节 private byte[] intToByteArray(int num) { return new byte[]{ (byte) (num >>> 24), (byte) (num >>> 16), (byte) (num >>> 8), (byte) num }; } /** * 生成固定长度的随机字符串 */ private String generateRandomString(int length) { StringBuilder sb = new StringBuilder(); String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; Random random = new Random(); for (int i = 0; i < length; i++) { sb.append(chars.charAt(random.nextInt(chars.length()))); } return sb.toString(); } } ``` 本文由 admin 创作,采用 知识共享署名4.0 国际许可协议进行许可。本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名。