spring-bus消息总线的使用

news2024/11/16 12:00:42

文章目录

  • 依赖
  • bus应用
    • 接口
    • 用到的封装参数类
  • 接收的应用
    • 监听器
    • 定义的事件类
  • 使用bus
    • 定义bus远程调用
    • A应用数据更新后通过bus数据同步给B应用

依赖

   <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-bus-amqp</artifactId>
    </dependency>

bus应用

  • 类似于生产者

接口

  • 供内部其他应用使用,远程调用该接口实现各应用之间数据同步
  • 参数1定义事件,参数2定义操作具体crud,参数3定义传参数据,参数4定义给哪个应用(nacos注册的应用名)同步数据
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.xyc.sms.common.bus.events.DataSyncEventEnum;
import com.xyc.sms.common.bus.events.DataSyncEventFactory;
import com.xyc.sms.common.bus.events.DataSyncOperateTypeEnum;
import com.xyc.sms.common.entity.Result;
import org.springframework.cloud.bus.ServiceMatcher;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;

/**
 * 数据同步通知事件控制器,该事件主要用于平台中常规的数据同步通知,
 * 需要用于其他功能请新增类
 * 需要增加同步的方式请在{@link DataSyncEventEnum}增加事件枚举
 * 同时在{@link com.xyc.sms.common.bus.events.dataSync}下增加事件类,新增的事件类需要继承{@link com.xyc.sms.common.bus.events.DataSyncEvent}
 */
@RestController
@RequestMapping("/default")
public class DataSyncNotifyEventController {

    private static final Log logger = LogFactory.get();

    @Resource
    private ServiceMatcher busServiceMatcher;
    @Resource
    private ApplicationEventPublisher applicationEventPublisher;

    /**
     * 发布数据同步通知事件
     *
     * @param eventEnum   事件枚举,可通过枚举找到对应的事件类
     * @param operateType 操作类型枚举
     * @param obj         需要处理的消息
     * @param destination 目的地,为null则是广播给所有该事件的监听器
     * @return 发布结果
     */
    @PostMapping("/publish/{eventEnum}/{operateType}")
    public Result publishDataSyncNotifyEvent(@PathVariable("eventEnum") DataSyncEventEnum eventEnum,
                                             @PathVariable("operateType") DataSyncOperateTypeEnum operateType,
                                             @RequestBody Object obj,
                                             @RequestParam(value = "destination", required = false) String destination) {
        try {
            applicationEventPublisher.publishEvent(DataSyncEventFactory.getInstanceForEvent(
                    eventEnum,
                    operateType,
                    obj,
                    busServiceMatcher.getServiceId(),
                    destination));
            return Result.returnSuccessWithMsg("success");
        } catch (Exception e) {
            logger.error(e);
            return Result.returnFail(e.getMessage());
        }
    }
}
  • 事件工厂类
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;

public class DataSyncEventFactory {

    private static final ObjectMapper OM = new ObjectMapper();

    /**
     * 通过事件的类模板获取构造器并调用,生成事件的实体类
     *
     * @param operateType        操作类型
     * @param source             事件原数据
     * @param originService      原服务
     * @param destinationService 目标服务
     * @return 事件实体类
     * @throws NoSuchMethodException     通过类模板无法找到相应的构造方法所抛出的异常
     * @throws InvocationTargetException 构造器创建实例可能出现的调用目标异常
     * @throws InstantiationException    构造器创建实例可能出现的实例化异常
     * @throws IllegalAccessException    构造器创建实例可能出现的无法访问异常
     * @throws IOException               json转化出现IO的异常
     * @throws ClassNotFoundException    通过类名{@link DataSyncEventEnum#getEventClassName()}没有找到对应类
     */
    public static DataSyncEvent<?> getInstanceForEvent(DataSyncEventEnum eventEnum,
                                                       DataSyncOperateTypeEnum operateType,
                                                       Object source,
                                                       String originService,
                                                       String destinationService)
            throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException, ClassNotFoundException {
        Constructor<?>[] constructors = DataSyncEventFactory.getEventClass(eventEnum).getDeclaredConstructors();
        Constructor<?> constructor = Arrays.stream(constructors).filter(c -> c.getParameterCount() == 4).findFirst().orElseThrow(
                NoSuchMethodException::new);
        // 值转化
        Object o = OM.readValue(OM.writeValueAsString(source), constructor.getParameterTypes()[1]);
        return (DataSyncEvent<?>) constructor.newInstance(operateType, o, originService, destinationService);
    }

    private static Class<?> getEventClass(DataSyncEventEnum eventEnum) throws ClassNotFoundException {
        return Class.forName(eventEnum.getEventClassName());
    }
}

用到的封装参数类

在这里插入图片描述

  • 定义各事件的枚举(只定义全类限定名称)
public enum DataSyncEventEnum {

    /**
     * 黑名单同步,参数为事件的类型名,注意需要使用全限定类名
     * @see com.xyc.sms.common.bus.events.dataSync.BlackListSyncEvent
     */
    BLACKLIST_SYN("com.xyc.sms.common.bus.events.dataSync.BlackListSyncEvent"),
    /**
     * 路由同步
     * @see com.xyc.sms.common.bus.events.dataSync.RouteSyncEvent
     */
    ROUTE_SYN("com.xyc.sms.common.bus.events.dataSync.RouteSyncEvent");

    /**
     * 事件类型名
     * @see DataSyncEvent 该抽象类的实现类
     */
    private final String eventClassName;

    DataSyncEventEnum(String eventClassName) {
        this.eventClassName = eventClassName;
    }

    public String getEventClassName() {
        return eventClassName;
    }
}
  • 定义crud操作枚举
public enum DataSyncOperateTypeEnum implements Serializable {
    ADD, UPD, DEL
}
  • 推送的事件类
/**
 * 数据同步通知事件,作为一般通用事件使用,如需要特殊处理建议新增事件
 */
public abstract class DataSyncEvent<T> extends RemoteApplicationEvent {

    /**
     * 事件数据
     */
    private DataSync<T> dataSync;

    public DataSync<T> getDataSync() {
        return dataSync;
    }

    public void setDataSync(DataSync<T> dataSync) {
        this.dataSync = dataSync;
    }

    /**
     * 基础构造器
     *
     * @param source             引发事件的原始数据
     * @param originService      引发事件的原始服务
     * @param destinationService 事件的目标服务
     */
    public DataSyncEvent(DataSync<T> source, String originService, String destinationService) {
        super(source, originService, destinationService);
        this.dataSync = source;
    }

    /**
     * 事件的日志打印,会在监听器监听到事件时输出打印
     * 结果尽可能不要有换行,保证日志输出在一行内
     * 该方法可以在子类中重写
     *
     * @return 日志
     */
    public String logPrint() {
        return String.format("{\"originService\":\"%s\",\"destinationService\":\"%s\",\"id\":\"%s\",\"dataSync\":%s,\"timestamp\":\"%s\"}", this.getId(), this.getOriginService(), this.getDestinationService(), Objects.nonNull(this.dataSync) ? this.dataSync.toString() : "null", this.getTimestamp());
    }

    /**
     * 数据同步的原始数据封装
     */
    public static class DataSync<T> implements Serializable {
        private DataSyncOperateTypeEnum operateType;
        private T data;

        public DataSync() {
        }

        public DataSync(DataSyncOperateTypeEnum operateType, T data) {
            this.operateType = operateType;
            this.data = data;
        }

        public DataSyncOperateTypeEnum getOperateType() {
            return operateType;
        }

        public T getData() {
            return data;
        }

        @Override
        public String toString() {
            return "{\"operateType\":" +
                    operateType
                    + ",\"data\":" +
                    data
                    + "}";
        }
    }
}
  • 应用枚举
/**
 * 服务枚举
 */
public enum ServiceEnum {
    SMS_BLACK_API("sms-black-api"),
    SMS_RULES("sms-rules");

    public final String serviceName;

    ServiceEnum(String serviceName) {
        this.serviceName = serviceName;
    }
}

接收的应用

  • 类似于消费者

监听器

  • 推送过来的操作枚举类crud的值,决定执行哪个crud的具体方法
  • 该类放在接收的应用中,其他顶部继承的类放在common包中即可
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.xyc.sms.common.bus.DataSyncListener;
import com.xyc.sms.common.bus.events.dataSync.RouteSyncEvent;
import com.xyc.sms.common.entity.sms.Route;
import com.xyc.sms.rules.dao.boss.RouteMapper;
import com.xyc.sms.rules.data.RuleSymbol;
import com.xyc.sms.rules.service.SynService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 路由同步通知监听器
 */
@Component
public class RouteSynNotifyListener extends DataSyncListener<RouteSyncEvent, List<Route>> {

    private static final Log log = LogFactory.get();

    @Autowired
    private RouteMapper routeMapper;

    @Autowired
    private SynService synService;

    @Override
    public void handleByADD(List<Route> data) {
        Optional.ofNullable(data).ifPresent(ls -> {
            if (ls.isEmpty()) {
                return;
            }

            long l = System.currentTimeMillis();

            String time = DateUtil.formatDateTime(ls.get(0).getCreateTime());
            List<Route> list = routeMapper.selectByCreatetime(time);
            if (CollectionUtil.isEmpty(list)) {
                return;
            }

            // 加载到内存中
            list.forEach(r -> RuleSymbol.RouteMap.put(r.getId(), r));
            synService.transformRoute(list, (s, r) -> RuleSymbol.RouteChannelMap.put(s, r));
            log.info("RouteSynNotifyListener - {} - add | createTime:{}", (System.currentTimeMillis() - l), time);
        });
    }

    @Override
    public void handleByUPD(List<Route> data) {
        // 流程还是先删除后新增的方式
        Optional.ofNullable(data).ifPresent(ls -> {
            List<Integer> collect = ls.stream()
                    .map(Route::getId)
                    .filter(Objects::nonNull)
                    .collect(Collectors.toList());
            if (collect.isEmpty()) {
                return;
            }

            long l = System.currentTimeMillis();

            // 如果有,先删除
            List<Route> c = collect.stream()
                    .map(RuleSymbol.RouteMap::get)
                    .filter(Objects::nonNull)
                    .collect(Collectors.toList());
            if (!c.isEmpty()) {
                synService.transformRoute(c, (s, r) -> RuleSymbol.RouteChannelMap.remove(s, r));
            }


            // 如果有,再加入
            List<Route> list = routeMapper.selectById(collect);
            if (!list.isEmpty()) {
                list.forEach(r -> RuleSymbol.RouteMap.put(r.getId(), r));
                synService.transformRoute(list, (s, r) -> RuleSymbol.RouteChannelMap.put(s, r));
            }
            log.info("RouteSynNotifyListener - {} - update | {}", (System.currentTimeMillis() - l), collect);
        });
    }

    @Override
    public void handleByDEL(List<Route> data) {
        Optional.ofNullable(data).ifPresent(ls -> {
            long l = System.currentTimeMillis();
            List<Route> collect = ls.stream()
                    .map(r -> RuleSymbol.RouteMap.remove(r.getId()))
                    .filter(Objects::nonNull)
                    .collect(Collectors.toList());

            if (collect.isEmpty()) {
                return;
            }
            synService.transformRoute(collect, (s, r) -> RuleSymbol.RouteChannelMap.remove(s));
            log.info("RouteSynNotifyListener - {} - remove", (System.currentTimeMillis() - l));
        });
    }
}
  • 继承的抽象监听类
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.xyc.sms.common.bus.events.DataSyncEvent;
import org.springframework.context.ApplicationListener;

/**
 * 数据同步事件监听器
 * 需要具体的子类实现,并注册到spring容器中
 *
 * @param <T> 数据同步件
 */
public abstract class DataSyncListener<T extends DataSyncEvent<D>, D> implements ApplicationListener<T> {

    private static final Log logger = LogFactory.get();

    @Override
    public void onApplicationEvent(T event) {
        logger.info("[DataSyncListener][onApplicationEvent] trigger event - {} - {}", event.getClass().getName(), event.logPrint());
        try {
            triggerEvent(event);
        } catch (Exception e) {
            logger.error(e);
        }
    }

    /**
     * 触发监听,处理事件
     *
     * @param event 事件
     */
    public void triggerEvent(T event) {
        DataSyncEvent.DataSync<D> source = event.getDataSync();
        switch (source.getOperateType()) {
            case ADD:
                handleByADD(source.getData());
                return;
            case UPD:
                handleByUPD(source.getData());
                return;
            case DEL:
                handleByDEL(source.getData());
                return;
            default:
        }
    }

    /**
     * 处理添加事件
     * 由子类实现
     *
     * @param data 需要处理的数据
     */
    public abstract void handleByADD(D data);

    /**
     * 处理修改事件
     * 由子类实现
     *
     * @param data 需要处理的数据
     */
    public abstract void handleByUPD(D data);

    /**
     * 处理删除事件
     * 由子类实现
     *
     * @param data 需要处理的数据
     */
    public abstract void handleByDEL(D data);
}

定义的事件类

  • 上面封装的事件枚举所记录的是该类的全类限定名称
package com.xyc.sms.common.bus.events.dataSync;

import com.xyc.sms.common.bus.events.DataSyncEvent;
import com.xyc.sms.common.bus.events.DataSyncOperateTypeEnum;
import com.xyc.sms.common.entity.sms.Route;

import java.util.List;

public class RouteSyncEvent extends DataSyncEvent<List<Route>> {

    private static final long serialVersionUID = -501657066268464154L;

    public RouteSyncEvent(DataSyncOperateTypeEnum operateType, List<Route> Routes, String originService, String destinationService) {
        super(new DataSync<>(operateType, Routes), originService, destinationService);
    }
}
  • 继承的抽象事件类
/**
 * 数据同步通知事件,作为一般通用事件使用,如需要特殊处理建议新增事件
 */
public abstract class DataSyncEvent<T> extends RemoteApplicationEvent {

    /**
     * 事件数据
     */
    private DataSync<T> dataSync;

    public DataSync<T> getDataSync() {
        return dataSync;
    }

    public void setDataSync(DataSync<T> dataSync) {
        this.dataSync = dataSync;
    }

    /**
     * 基础构造器
     *
     * @param source             引发事件的原始数据
     * @param originService      引发事件的原始服务
     * @param destinationService 事件的目标服务
     */
    public DataSyncEvent(DataSync<T> source, String originService, String destinationService) {
        super(source, originService, destinationService);
        this.dataSync = source;
    }

    /**
     * 事件的日志打印,会在监听器监听到事件时输出打印
     * 结果尽可能不要有换行,保证日志输出在一行内
     * 该方法可以在子类中重写
     *
     * @return 日志
     */
    public String logPrint() {
        return String.format("{\"originService\":\"%s\",\"destinationService\":\"%s\",\"id\":\"%s\",\"dataSync\":%s,\"timestamp\":\"%s\"}", this.getId(), this.getOriginService(), this.getDestinationService(), Objects.nonNull(this.dataSync) ? this.dataSync.toString() : "null", this.getTimestamp());
    }

    /**
     * 数据同步的原始数据封装
     */
    public static class DataSync<T> implements Serializable {
        private DataSyncOperateTypeEnum operateType;
        private T data;

        public DataSync() {
        }

        public DataSync(DataSyncOperateTypeEnum operateType, T data) {
            this.operateType = operateType;
            this.data = data;
        }

        public DataSyncOperateTypeEnum getOperateType() {
            return operateType;
        }

        public T getData() {
            return data;
        }

        @Override
        public String toString() {
            return "{\"operateType\":" +
                    operateType
                    + ",\"data\":" +
                    data
                    + "}";
        }
    }
}

使用bus

  • 引用注入bus应用的接口远程调用

定义bus远程调用

@FeignClient(value="sms-bus", fallbackFactory = DataSyncNotifyEventServiceFallbackFactory.class)
public interface DataSyncNotifyEventService {

    /**
     * 发布数据同步通知事件
     * destination 参数被删除,不需要指定服务
     *
     * @param eventEnum   事件枚举,可通过枚举找到对应的事件类
     * @param operateType 操作类型枚举
     * @param obj         需要处理的消息
     * @return 发布结果
     */
    @PostMapping("/default/publish/{eventEnum}/{operateType}")
    Result publishDataSyncNotifyEvent(@PathVariable("eventEnum") DataSyncEventEnum eventEnum,
                                      @PathVariable("operateType") DataSyncOperateTypeEnum operateType,
                                      @RequestBody Object obj,
                                      @RequestParam("destination") String destination);
}
  • 注入使用
    在这里插入图片描述

A应用数据更新后通过bus数据同步给B应用

  • 在A应用的业务层写以下代码
 try {
                result = dataSyncNotifyEventService.publishDataSyncNotifyEvent(DataSyncEventEnum.ROUTE_SYN,
                        DataSyncOperateTypeEnum.ADD,
                        new ArrayList<Route>() {{
                            Route r = new Route();
                            r.setCreateTime(date);
                            add(r);
                        }}, ServiceEnum.SMS_RULES.serviceName);
                log.info("新增路由调用通知同步所有服务 result:{}", result);
            } catch (Exception e) {
                log.error("同步异常 {}", result, e);
            }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1420115.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

51单片机通过级联74HC595实现倒计时秒表Protues仿真设计

一、设计背景 近年来随着科技的飞速发展&#xff0c;单片机的应用正在不断的走向深入。本文阐述了51单片机通过级联74HC595实现倒计时秒表设计&#xff0c;倒计时精度达0.05s&#xff0c;解决了传统的由于倒计时精度不够造成的误差和不公平性&#xff0c;是各种体育竞赛的必备设…

一家企业需要CRM,通常有以下这些迹象

CRM软件是一个集成的套件——通常是——云应用程序&#xff0c;例如营销云、销售云和服务云&#xff0c;用于收集和存储客户数据。它为销售团队提供了一个集中的平台来管理客户交互并确定活动的优先级&#xff0c;这样客户就不会感到被忽视&#xff0c;从而提升了他们的客户体验…

Flask使用Jinja2渲染模版使用变量实战

前言&#xff1a; Flask 使用 Jinja2 作为其默认模板引擎&#xff0c;这意味着您可以直接在 Flask 应用程序中使用 Jinja2 模板。您可以创建模板文件&#xff0c;然后在视图函数中渲染这些模板&#xff0c;将动态数据传递给模板进行渲染&#xff0c;并最终生成最终的 HTML 页面…

mcu专用看门狗复位芯片(如MAX706)

mcu专用看门狗复位芯片&#xff08;如MAX706&#xff09; 为什么要使用电压复位芯片RESET引脚WDO引脚MR引脚WDI引脚 国产替代型号应用电路1 推荐电路&#xff08;用一个跳线帽使能/关闭看门狗功能&#xff0c;调试MCU时防止看门狗芯片随便触发复位功能&#xff09;&#xff0c;…

ChatGPT PLUS升级步骤--支付宝、微信

AI伴随着我们已经有一年多了&#xff0c;这一年多里我使用ChatGPT做ppt、生成绘画、写文案、做旅游攻略&#xff0c;还有一些医学知识&#xff0c;医学知识我感觉没有回答的很好&#xff0c;对比于医生给的建议我个人觉得还是医生的比较好&#xff0c;Chat GPT回答的比较官方 …

【极数系列】Flink集成DataSource读取文件数据(08)

文章目录 01 引言02 简介概述03 基于文件读取数据3.1 readTextFile(path)3.2 readFile(fileInputFormat, path)3.3 readFile(fileInputFormat, path, watchType, interval, pathFilter, typeInfo)3.4 实现原理3.5 注意事项3.6 支持读取的文件形式 04 源码实战demo4.1 pom.xml依…

ROS学习笔记11——ROS中的重名问题

一、ros功能包重名——ros工作空间覆盖 功能包重名时&#xff0c;会按照 ROS_PACKAGE_PATH 查找&#xff0c;在前的会优先执行。ROS 会解析 .bashrc 文件&#xff0c;并生成 ROS_PACKAGE_PATH ROS包路径&#xff0c;即调用功能包的顺序&#xff0c;该变量中按照 .bashrc 中配置…

leetcode—跳跃游戏—贪心算法

1 跳跃游戏1 给你一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标&#xff0c;如果可以&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&a…

图像畸变校正(2)

畸变校正是一种用于矫正图像或视频中的失真或畸变的技术。这种失真通常是由摄像头镜头的特性或角度造成的&#xff0c;可能会导致图像中的对象形状、大小或位置不准确。以下是畸变校正的一般方法&#xff1a; 摄像头模型建立&#xff1a; 首先&#xff0c;需要建立摄像头的模型…

【React教程】(1) React简介、React核心概念、React初始化

目录 ReactReact 介绍React 特点React 的发展历史React 与 Vue 的对比技术层面开发团队社区Native APP 开发 相关资源链接 EcmaScript 6 补充React 核心概念组件化虚拟 DOM 起步初始化及安装依赖Hello World React React 介绍 React 是一个用于构建用户界面的渐进式 JavaScrip…

海外云手机为什么吸引用户?

近年来&#xff0c;随着全球化的飞速发展&#xff0c;海外云手机逐渐成为各行各业关注的焦点。那么&#xff0c;究竟是什么让海外云手机如此吸引用户呢&#xff1f;本文将深入探讨海外云手机的三大吸引力&#xff0c;揭示海外云手机的优势所在。 1. 高效的社交媒体运营 海外云…

Android 13以上版本读写SD卡权限适配

如题&#xff0c;最近工作上处理的问题&#xff0c;把解决方案简单逻列出来&#xff0c;供有需要的朋友参考之 解决方案&#xff1a; 1、配置权限 <uses-permission android:name"android.permission.READ_MEDIA_IMAGES" /><uses-permission android:name&q…

PyQt5零基础入门(八)——按钮控件(QPushButton、QToolButton)

前言 按钮控件是图形用户界面(GUI)中常用的交互元素&#xff0c;用于触发特定的事件或行为。在Qt框架中&#xff0c;QPushButton和QToolButton是两种常用的按钮控件。 后边我们将以test.png为按钮图标&#xff0c;对比使用两种按钮控件。 普通按钮控件(QPushButton) QPushB…

禁止 ios H5 中 bounces 滑动回弹效果

在开发面向 iOS 设备的 HTML5 应用时&#xff0c;控制页面的滚动行为至关重要&#xff0c;特别是禁用在 Safari 中默认的滑动回弹效果。本文旨在提供一个简洁明了的解决方案&#xff0c;帮助开发者在特定的 Web 应用中禁用这一效果。 1. 什么是滑动回弹效果&#xff1f; 在 iO…

编写交互式 Shell 脚本

在日常的系统管理和自动化任务中&#xff0c;使用 Shell 脚本可以为我们节省大量时间和精力。 文章将以输入 IP 为例&#xff0c;通过几个版本逐步完善一个案例。 原始需求 编写一个交互式的 Shell 脚本&#xff0c;运行时让用户可以输入IP地址&#xff0c;并且脚本会将输入…

【高效开发工具系列】Wolfram Alpha

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

【RT-DETR有效改进】2024.1最新MFDS-DETR的HS-FPN改进特征融合层(降低100W参数,全网独家首发)

👑欢迎大家订阅本专栏,一起学习RT-DETR👑 一、本文介绍 本文给大家带来的改进机制是最近这几天最新发布的改进机制MFDS-DETR提出的一种HS-FPN结构,其是一种为白细胞检测设计的网络结构,主要用于解决白细胞数据集中的多尺度挑战。它的基本原理包括两个关键部分:特征…

“全”实力认可 | 美创科技领跑CCSIP 2023全景图数据安全领域

近日&#xff0c;FreeBuf咨询正式发布《CCSIP&#xff08;China Cyber Security Industry Panorama&#xff09;2023中国网络安全行业全景册&#xff08;第六版&#xff09;》。本次全景册面向广大国内安全厂商&#xff0c;由厂商自主申报并填写信息征集表&#xff0c;经FreeBu…

【俄乌之战】乌克兰声称280台俄罗斯服务器被毁,损失数据超2 PB

乌克兰报告针对俄罗斯政府关键基础设施和私营公司的多次网络攻击&#xff0c;导致全国范围内的中断和大量数据丢失。 乌克兰 HUR&#xff08;乌克兰国防部主要情报局&#xff09;的网络安全专家声称对IPL Consulting进行了成功的网络攻击。据报道&#xff0c;他们摧毁了整个IT…

uniapp H5 实现上拉刷新 以及 下拉加载

uniapp H5 实现上拉刷新 以及 下拉加载 1. 先上图 下拉加载 2. 上代码 <script>import DragableList from "/components/dragable-list/dragable-list.vue";import {FridApi} from /api/warn.jsexport default {data() {return {tableList: [],loadingHi…