news 2026/5/12 17:38:19

HTTP方式和MQ方式实现回调通知

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
HTTP方式和MQ方式实现回调通知

HTTP方式

首先提供一个bean给springboot,

@Configuration public class OKHttpClientConfig { @Bean public OkHttpClient httpClient() { return new OkHttpClient(); } }

然后借助okHTTP发送http请求。

@Slf4j @Service public class GroupBuyNotifyService { @Resource private OkHttpClient okHttpClient; public String groupBuyNotify(String apiUrl, String notifyRequestDTOJSON) throws Exception { try { // 1. 构建参数 MediaType mediaType = MediaType.parse("application/json"); RequestBody body = RequestBody.create(mediaType, notifyRequestDTOJSON); Request request = new Request.Builder() .url(apiUrl) .post(body) .addHeader("content-type", "application/json") .build(); // 2. 调用接口 Response response = okHttpClient.newCall(request).execute(); // 3. 返回结果 return response.body().string(); } catch (Exception e) { log.error("拼团回调 HTTP 接口服务异常 {}", apiUrl, e); throw new AppException(ResponseCode.HTTP_EXCEPTION); } } }

考虑到应用场景可能是集群部署,使用Redisson加锁,确保不会重复发送。

@Service public class TradePort implements ITradePort { @Resource private GroupBuyNotifyService groupBuyNotifyService; @Resource private IRedisService redisService; @Override public String groupBuyNotify(NotifyTaskEntity notifyTask) throws Exception { RLock lock = redisService.getLock(notifyTask.lockKey()); try { if (lock.tryLock(3, 0, TimeUnit.SECONDS)) { try { // 无效的 notifyUrl 则直接返回成功 if (StringUtils.isBlank(notifyTask.getNotifyUrl()) || "暂无".equals(notifyTask.getNotifyUrl())) { return NotifyTaskHTTPEnumVO.SUCCESS.getCode(); } return groupBuyNotifyService.groupBuyNotify(notifyTask.getNotifyUrl(), notifyTask.getParameterJson()); } finally { if (lock.isLocked() && lock.isHeldByCurrentThread()) { lock.unlock(); } } } return NotifyTaskHTTPEnumVO.NULL.getCode(); } catch (Exception e) { Thread.currentThread().interrupt(); return NotifyTaskHTTPEnumVO.NULL.getCode(); } } }

说到集群情况,不由关联到幂等性问题,常见的做法是在数据库解决,譬如给每一条消息一个唯一标识,或者是将id设为主键,不许重复插入;在高并发的情况下也可以如上使用Redisson锁解决。

MQ方式

这里用的是Rocketmq的方式发送回调消息,首先在yaml文件中配置好

# RocketMQ rocketmq: name-server: 127.0.0.1:9876 producer: group: group_buy_producer group-buy-mq: topic: group_buy_topic tags: team_success: team_success team_refund: team_refund

然后在publisher类中发送消息

@Slf4j @Component public class EventPublisher { @Autowired private RocketMQTemplate rocketMQTemplate; @Value("${group-buy-mq.topic}") private String topic; public void publish(String tag, String message) { try { // RocketMQ: topic:tag String destination = topic + ":" + tag; rocketMQTemplate.convertAndSend(destination, message); } catch (Exception e) { log.error("发送MQ消息失败 team_success message:{}", message, e); throw e; } } }

然后按以下格式配一个或多个listener类,负责接收消息。

@Slf4j @Component @RocketMQMessageListener( topic = "${group-buy-mq.topic}", // Topic selectorExpression = "team_success", // Tag(相当于 routingKey) consumerGroup = "team_success_consumer_group" // 消费组 ) public class TeamSuccessTopicListener implements RocketMQListener<String> { @Override public void onMessage(String message) { log.info("接收消息:{}", message); } }

Rocketmq和Rabbitmq的优劣对比

  • RocketMQ 使用 Java 语言开发
  • 顺序消息、事务消息、消息过滤、定时消息等。顺序消息、事务消息、消息过滤、定时消息,丰富的特性尽可能多地提供思路及解决方案
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/12 17:37:18

把注意力收回到自己身上的庖丁解牛

它的本质是&#xff1a;**将原本耗散在 外部不可控变量&#xff08;他人评价、社会比较、宏观焦虑、八卦新闻&#xff09;上的 CPU 算力 和 内存带宽&#xff0c;强制重定向回 内部可控进程&#xff08;自身技能、身体健康、情绪管理、当下行动&#xff09;。这是一种 从“观察…

作者头像 李华
网站建设 2026/5/12 17:33:59

通用ERP和垂直ERP在服装行业谁更香?

在挑选ERP时&#xff0c;很多企业都会面临一个经典难题&#xff1a;是用用友、金蝶这类通用型大厂的产品&#xff0c;还是选丽晶、艾格文这类垂直深耕服装行业的专业系统&#xff1f;这个问题的答案&#xff0c;取决于你对“全业务流程数字化转型”的定义有多深。通用ERP的优势…

作者头像 李华
网站建设 2026/5/12 17:33:25

【数据科学】【会计学】第十一篇 综合会计领域

鉴证会计领域的各类函数、算法和规则。这些内容涵盖了审计风险模型、审计抽样方法、财务舞弊检测、数据分析算法、平展账期方法以及鉴证业务框架等多个方面。 编号 类型 会计领域 函数/算法/规则逐步推理思考的数学方程式表达 参数列表及参数的数学特征和数据结构 法律法规…

作者头像 李华
网站建设 2026/5/12 17:30:15

AI写教材神器来袭!一键生成教材,轻松解决低查重难题!

许多教材编写者常常感到遗憾&#xff0c;他们花费大量时间和精力打磨正文内容&#xff0c;却因为缺乏配套资源而影响了教学效果。设计课后练习时&#xff0c;常常难以找到合适的题型&#xff1b;想制作生动的教学课件时&#xff0c;又缺乏相关的技术支持&#xff1b;需要进行深…

作者头像 李华