如何设计事件管理器

2023-05-16

目录

  • 需求描述:
  • 项目依赖:
  • 代码实现:
    • 定义通用的事件对象
    • 定义事件监听器接口
    • 定义事件监听器适配器对象
    • 定义事件管理器接口
    • 定义默认的事件管理器对象
    • 创建三个不同的监听器对象
  • 运行效果:

需求描述:

创建一个事件管理器,然后向其注册事件监听器,事件监听器上有各种处理不同事件的方法,当有事件被触发的时候,要求监听器能自动处理。

测试代码如下:

public class DefaultEventManagerTest {
    public static void main(String[] args) {
        //创建事件管理器
        EventManager eventManager = new DefaultEventManager();
        //创建三个监听器
        CustomAppListener1 customAppListener1 = new CustomAppListener1();
        CustomAppListener2 customAppListener2 = new CustomAppListener2();
        CustomAppListener3 customAppListener3 = new CustomAppListener3();
        //注册事件监听器
        eventManager.register(customAppListener1);
        eventManager.register(customAppListener2);
        eventManager.register(customAppListener3);
        //查看现有监听器
        System.out.println("==========查看现有监听器==========");
        for (EventListener registeredListener : eventManager.getRegisteredListeners()) {
            System.out.println(registeredListener.getClass().getSimpleName());
        }
        //处理指定的事件
        System.out.println("==========处理指定的事件==========");
        eventManager.handle(new MessageCreateEvent());
        eventManager.handle(new MessageDeleteEvent());
        eventManager.handle(new MessageReceivedEvent());
        eventManager.handle(new MessageUpdateEvent());
        eventManager.handle(new GenericEvent());
        //卸载事件监听器
        eventManager.unregister(customAppListener1);
        eventManager.unregister(customAppListener2);
        eventManager.unregister(customAppListener3);
        //查看现有监听器
        System.out.println("==========查看现有监听器==========");
        System.out.println(eventManager.getRegisteredListeners().size());
    }
}

运行效果如下:

==========查看现有监听器==========
CustomAppListener1
CustomAppListener2
CustomAppListener3
==========处理指定的事件==========
main	==>	CustomAppListener1 onMessageCreate handle
main	==>	CustomAppListener2 onMessageCreate handle
main	==>	CustomAppListener3 onMessageCreate handle
main	==>	CustomAppListener1 onMessageDelete handle
main	==>	CustomAppListener2 onMessageDelete handle
main	==>	CustomAppListener3 onMessageDelete handle
main	==>	CustomAppListener1 onMessageReceived handle
main	==>	CustomAppListener2 onMessageReceived handle
main	==>	CustomAppListener3 onMessageReceived handle
main	==>	CustomAppListener1 onMessageUpdate handle
main	==>	CustomAppListener2 onMessageUpdate handle
main	==>	CustomAppListener3 onMessageUpdate handle
==========查看现有监听器==========
0

项目依赖:

无需第三方依赖,完全由自己实现。

最终实现的结构:

image-20220717211436810

代码实现:

定义通用的事件对象

我们先要定义一个通用事件对象(GenericEvent),这是一个父类,然后我们根据不同的类型创建不同的子类,比如可以分为:user类型、message类型等等。

user类型我们可以定义如下子类:(举例说明,请根据实际情况自行拓展)

用户创建事件(UserCreateEvent)
用户销毁事件(UserDestroyEvent

message类型我们可以定义如下子类:(举例说明,请根据实际情况自行拓展)

消息创建事件(MessageCreateEvent)
消息删除事件(MessageDeleteEvent)
消息接收事件(MessageReceivedEvent)
消息更新事件(MessageUpdateEvent

父类代码:

cn.caochenlei.event.GenericEvent

public class GenericEvent {
    // 请在这里编写通用事件对象结构
}

子类代码:

cn.caochenlei.event.message.MessageCreateEvent(消息创建事件对象)

package cn.caochenlei.event.message;

import cn.caochenlei.event.GenericEvent;

public class MessageCreateEvent extends GenericEvent {
}

cn.caochenlei.event.message.MessageDeleteEvent(消息删除事件对象)

package cn.caochenlei.event.message;

import cn.caochenlei.event.GenericEvent;

public class MessageDeleteEvent extends GenericEvent {
}

cn.caochenlei.event.message.MessageReceivedEvent(消息接收事件对象)

package cn.caochenlei.event.message;

import cn.caochenlei.event.GenericEvent;

public class MessageReceivedEvent extends GenericEvent {
}

cn.caochenlei.event.message.MessageUpdateEvent(消息更新事件对象)

package cn.caochenlei.event.message;

import cn.caochenlei.event.GenericEvent;

public class MessageUpdateEvent extends GenericEvent {
}

定义事件监听器接口

cn.caochenlei.event.EventListener

package cn.caochenlei.event;

@FunctionalInterface
public interface EventListener {
    /**
     * 处理事件
     *
     * @param event
     */
    void onEvent(GenericEvent event);
}

定义事件监听器适配器对象

监听器适配器对象的核心思想:通过onEvent中的事件对象实际类型在EventListenerAdapter中找到对应的方法,然后执行即可。

cn.caochenlei.event.EventListenerAdapter

package cn.caochenlei.event;

import cn.caochenlei.event.message.MessageCreateEvent;
import cn.caochenlei.event.message.MessageDeleteEvent;
import cn.caochenlei.event.message.MessageReceivedEvent;
import cn.caochenlei.event.message.MessageUpdateEvent;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public abstract class EventListenerAdapter implements EventListener {
    public void onGenericEvent(GenericEvent event) {}

    // 在这里加自定义事件子类
    public void onMessageCreate(MessageCreateEvent event) {}
    public void onMessageDelete(MessageDeleteEvent event) {}
    public void onMessageReceived(MessageReceivedEvent event) {}
    public void onMessageUpdate(MessageUpdateEvent event) {}

    // 监听器适配器的基本属性
    private static final MethodHandles.Lookup lookup = MethodHandles.lookup();
    private static final ConcurrentMap<Class<?>, MethodHandle> methods = new ConcurrentHashMap<>();
    private static final Set<Class<?>> unresolved;

    static {
        unresolved = ConcurrentHashMap.newKeySet();
        Collections.addAll(unresolved,
                Object.class, // Objects aren't events
                GenericEvent.class // onGenericEvent has already been called
        );
    }

    @Override
    public final void onEvent(GenericEvent event) {
        onGenericEvent(event);

        for (Class<?> clazz : ClassWalker.range(event.getClass(), GenericEvent.class)) {
            if (unresolved.contains(clazz))
                continue;
            MethodHandle mh = methods.computeIfAbsent(clazz, EventListenerAdapter::findMethod);
            if (mh == null) {
                unresolved.add(clazz);
                continue;
            }

            try {
                mh.invoke(this, event);
            } catch (Throwable throwable) {
                if (throwable instanceof RuntimeException)
                    throw (RuntimeException) throwable;
                if (throwable instanceof Error)
                    throw (Error) throwable;
                throw new IllegalStateException(throwable);
            }
        }
    }

    private static MethodHandle findMethod(Class<?> clazz) {
        String name = clazz.getSimpleName();
        MethodType type = MethodType.methodType(Void.TYPE, clazz);
        try {
            name = "on" + name.substring(0, name.length() - "Event".length());
            return lookup.findVirtual(EventListenerAdapter.class, name, type);
        } catch (NoSuchMethodException | IllegalAccessException ignored) {
        } // this means this is probably a custom event!
        return null;
    }
}

cn.caochenlei.event.ClassWalker

package cn.caochenlei.event;

import java.util.*;

public class ClassWalker implements Iterable<Class<?>> {
    private final Class<?> clazz;
    private final Class<?> end;

    private ClassWalker(Class<?> clazz) {
        this(clazz, Object.class);
    }

    private ClassWalker(Class<?> clazz, Class<?> end) {
        this.clazz = clazz;
        this.end = end;
    }

    public static ClassWalker range(Class<?> start, Class<?> end) {
        return new ClassWalker(start, end);
    }

    public static ClassWalker walk(Class<?> start) {
        return new ClassWalker(start);
    }

    @Override
    public Iterator<Class<?>> iterator() {
        return new Iterator<Class<?>>() {
            private final Set<Class<?>> done = new HashSet<>();
            private final Deque<Class<?>> work = new LinkedList<>();

            {
                work.addLast(clazz);
                done.add(end);
            }

            @Override
            public boolean hasNext() {
                return !work.isEmpty();
            }

            @Override
            public Class<?> next() {
                Class<?> current = work.removeFirst();
                done.add(current);
                for (Class<?> parent : current.getInterfaces()) {
                    if (!done.contains(parent))
                        work.addLast(parent);
                }

                Class<?> parent = current.getSuperclass();
                if (parent != null && !done.contains(parent))
                    work.addLast(parent);
                return current;
            }
        };
    }
}

定义事件管理器接口

cn.caochenlei.event.EventManager

package cn.caochenlei.event;

import java.util.List;

public interface EventManager {
    /**
     * 注册监听器
     *
     * @param listener
     */
    void register(EventListener listener);

    /**
     * 卸载监听器
     *
     * @param listener
     */
    void unregister(EventListener listener);

    /**
     * 执行所有监听器
     *
     * @param event
     */
    void handle(GenericEvent event);

    /**
     * 获取所有监听器
     *
     * @return
     */
    List<EventListener> getRegisteredListeners();
}

定义默认的事件管理器对象

默认事件管理器实现的核心思想:通过调用handle方法,然后将listeners中所有的监听器都执行一次onEvent方法,在上边我们介绍了,onEvent方法实际上去找EventListenerAdapter中定义的方法,然后执行,这里的EventListenerAdapter定义的方法,一般是我们自己重写之后的方法,马上就会介绍到。

cn.caochenlei.event.DefaultEventManager

package cn.caochenlei.event;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public class DefaultEventManager implements EventManager {
    private final List<EventListener> listeners = new CopyOnWriteArrayList<>();

    public DefaultEventManager() {}

    @Override
    public void register(EventListener listener) {
        if (!(listener instanceof EventListener)) {
            throw new IllegalArgumentException("Listener must implement EventListener");
        }
        listeners.add(listener);
    }

    @Override
    public void unregister(EventListener listener) {
        if (!(listener instanceof EventListener)) {
            throw new IllegalArgumentException("Listener must implement EventListener");
        }
        listeners.remove(listener);
    }

    @Override
    public List<EventListener> getRegisteredListeners() {
        return Collections.unmodifiableList(new ArrayList<>(listeners));
    }

    @Override
    public void handle(GenericEvent event) {
        for (EventListener listener : listeners) {
            try {
                listener.onEvent(event);
            } catch (Throwable throwable) {
                System.err.println("One of the EventListeners had an uncaught exception");
                if (throwable instanceof Error)
                    throw (Error) throwable;
            }
        }
    }
}

创建三个不同的监听器对象

cn.caochenlei.event.listener.CustomAppListener1

package cn.caochenlei.event.listener;

import cn.caochenlei.event.EventListenerAdapter;
import cn.caochenlei.event.message.MessageCreateEvent;
import cn.caochenlei.event.message.MessageDeleteEvent;
import cn.caochenlei.event.message.MessageReceivedEvent;
import cn.caochenlei.event.message.MessageUpdateEvent;

public class CustomAppListener1 extends EventListenerAdapter {
    @Override
    public void onMessageCreate(MessageCreateEvent event) {
        System.out.println(Thread.currentThread().getName() + "\t==>\tCustomAppListener1 onMessageCreate handle");
    }

    @Override
    public void onMessageDelete(MessageDeleteEvent event) {
        System.out.println(Thread.currentThread().getName() + "\t==>\tCustomAppListener1 onMessageDelete handle");
    }

    @Override
    public void onMessageReceived(MessageReceivedEvent event) {
        System.out.println(Thread.currentThread().getName() + "\t==>\tCustomAppListener1 onMessageReceived handle");
    }

    @Override
    public void onMessageUpdate(MessageUpdateEvent event) {
        System.out.println(Thread.currentThread().getName() + "\t==>\tCustomAppListener1 onMessageUpdate handle");
    }
}

cn.caochenlei.event.listener.CustomAppListener2

package cn.caochenlei.event.listener;

import cn.caochenlei.event.EventListenerAdapter;
import cn.caochenlei.event.message.MessageCreateEvent;
import cn.caochenlei.event.message.MessageDeleteEvent;
import cn.caochenlei.event.message.MessageReceivedEvent;
import cn.caochenlei.event.message.MessageUpdateEvent;

public class CustomAppListener2 extends EventListenerAdapter {
    @Override
    public void onMessageCreate(MessageCreateEvent event) {
        System.out.println(Thread.currentThread().getName() + "\t==>\tCustomAppListener2 onMessageCreate handle");
    }

    @Override
    public void onMessageDelete(MessageDeleteEvent event) {
        System.out.println(Thread.currentThread().getName() + "\t==>\tCustomAppListener2 onMessageDelete handle");
    }

    @Override
    public void onMessageReceived(MessageReceivedEvent event) {
        System.out.println(Thread.currentThread().getName() + "\t==>\tCustomAppListener2 onMessageReceived handle");
    }

    @Override
    public void onMessageUpdate(MessageUpdateEvent event) {
        System.out.println(Thread.currentThread().getName() + "\t==>\tCustomAppListener2 onMessageUpdate handle");
    }
}

cn.caochenlei.event.listener.CustomAppListener3

package cn.caochenlei.event.listener;

import cn.caochenlei.event.EventListenerAdapter;
import cn.caochenlei.event.message.MessageCreateEvent;
import cn.caochenlei.event.message.MessageDeleteEvent;
import cn.caochenlei.event.message.MessageReceivedEvent;
import cn.caochenlei.event.message.MessageUpdateEvent;

public class CustomAppListener3 extends EventListenerAdapter {
    @Override
    public void onMessageCreate(MessageCreateEvent event) {
        System.out.println(Thread.currentThread().getName() + "\t==>\tCustomAppListener3 onMessageCreate handle");
    }

    @Override
    public void onMessageDelete(MessageDeleteEvent event) {
        System.out.println(Thread.currentThread().getName() + "\t==>\tCustomAppListener3 onMessageDelete handle");
    }

    @Override
    public void onMessageReceived(MessageReceivedEvent event) {
        System.out.println(Thread.currentThread().getName() + "\t==>\tCustomAppListener3 onMessageReceived handle");
    }

    @Override
    public void onMessageUpdate(MessageUpdateEvent event) {
        System.out.println(Thread.currentThread().getName() + "\t==>\tCustomAppListener3 onMessageUpdate handle");
    }
}

运行效果:

cn.caochenlei.event.DefaultEventManagerTest

package cn.caochenlei.event;

import cn.caochenlei.event.listener.CustomAppListener1;
import cn.caochenlei.event.listener.CustomAppListener2;
import cn.caochenlei.event.listener.CustomAppListener3;
import cn.caochenlei.event.message.MessageCreateEvent;
import cn.caochenlei.event.message.MessageDeleteEvent;
import cn.caochenlei.event.message.MessageReceivedEvent;
import cn.caochenlei.event.message.MessageUpdateEvent;

public class DefaultEventManagerTest {
    public static void main(String[] args) {
        //创建事件管理器
        EventManager eventManager = new DefaultEventManager();
        //创建三个监听器
        CustomAppListener1 customAppListener1 = new CustomAppListener1();
        CustomAppListener2 customAppListener2 = new CustomAppListener2();
        CustomAppListener3 customAppListener3 = new CustomAppListener3();
        //注册事件监听器
        eventManager.register(customAppListener1);
        eventManager.register(customAppListener2);
        eventManager.register(customAppListener3);
        //查看现有监听器
        System.out.println("==========查看现有监听器==========");
        for (EventListener registeredListener : eventManager.getRegisteredListeners()) {
            System.out.println(registeredListener.getClass().getSimpleName());
        }
        //处理指定的事件
        System.out.println("==========处理指定的事件==========");
        eventManager.handle(new MessageCreateEvent());
        eventManager.handle(new MessageDeleteEvent());
        eventManager.handle(new MessageReceivedEvent());
        eventManager.handle(new MessageUpdateEvent());
        eventManager.handle(new GenericEvent());
        //卸载事件监听器
        eventManager.unregister(customAppListener1);
        eventManager.unregister(customAppListener2);
        eventManager.unregister(customAppListener3);
        //查看现有监听器
        System.out.println("==========查看现有监听器==========");
        System.out.println(eventManager.getRegisteredListeners().size());
    }
}
==========查看现有监听器==========
CustomAppListener1
CustomAppListener2
CustomAppListener3
==========处理指定的事件==========
main	==>	CustomAppListener1 onMessageCreate handle
main	==>	CustomAppListener2 onMessageCreate handle
main	==>	CustomAppListener3 onMessageCreate handle
main	==>	CustomAppListener1 onMessageDelete handle
main	==>	CustomAppListener2 onMessageDelete handle
main	==>	CustomAppListener3 onMessageDelete handle
main	==>	CustomAppListener1 onMessageReceived handle
main	==>	CustomAppListener2 onMessageReceived handle
main	==>	CustomAppListener3 onMessageReceived handle
main	==>	CustomAppListener1 onMessageUpdate handle
main	==>	CustomAppListener2 onMessageUpdate handle
main	==>	CustomAppListener3 onMessageUpdate handle
==========查看现有监听器==========
0
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何设计事件管理器 的相关文章

  • 【C++】shared_ptr共享型智能指针详解

    指针是C C 43 43 区别于其他语言的最强大的语法特性 xff0c 借助指针 xff0c C C 43 43 可以直接操纵内存内容 但是 xff0c 指针的引入也带来了一些使用上的困难 xff0c 这要求程序员自己必须手动地对分配申请的
  • 【C++】weak_ptr弱引用智能指针详解

    weak ptr这个指针天生一副小弟的模样 xff0c 也是在C 43 43 11的时候引入的标准库 xff0c 它的出现完全是为了弥补它老大shared ptr天生有缺陷的问题 相比于上一代的智能指针auto ptr来说 xff0c 新进
  • 【C++】模板声明与定义不分离

    一般在写C 43 43 相关代码的时候 xff0c 我们总习惯于将类声明和类实现进行分离 也就是说 xff0c 类的声明一般写在 h文件中 xff0c 而它的实现一般写在 cpp文件中 但是 xff0c 在模板类中 xff0c 这个习惯却要
  • 【C++】空指针调用成员函数及访问成员变量

    最近在review代码的时候发现 xff0c 使用了空指针调用成员函数 xff0c 并且成员函数内部有使用到成员变量 xff0c 居然没有出错 很是奇怪 xff0c 就用一篇博客把关于空指针调用成员函数相关的内容总结起来 空指针调用成员函数
  • 【C++】两个类的相互引用

    有时候在设计数据结构的时候 xff0c 可能会遇到两个类需要相互引用的情形 比如类A有类型为B的成员 xff0c 而类B又有类型为A的成员 那么这种情形下 xff0c 两个类的设计上需要注意什么呢 xff1f 同一文件 尝试方案 将A和B的
  • 【滤波】离散贝叶斯滤波器

    本文参考自rlabbe Kalman and Bayesian Filters in Python的第2章节02 Discrete Bayes xff08 离散贝叶斯 xff09 span class token operator span
  • 用iPad编写C/C++代码(计算机考研党也能用iPad写算法题)

    下载iSH软件 1 在AppStore商店中下载名叫iSH Shell的软件 PS xff1a iSH是一个使用用户模式x86模拟器在iOS设备上获得本地运行的Linux Shell环境的项目 2 安装后点开iSH xff0c 初步了解iS
  • FreeRTOS数据结构——列表与列表项

    在FreeRTOS中存在着大量的基础数据结构列表和列表项的操作 xff0c 要想读懂FreeRTOS的源代码 xff0c 就必须弄懂列表和列表项的操作 一 C语言链表简介 链表就好比一个圆形的晾衣架 xff0c 晾衣架上有很多钩子 xff0
  • ROS1常见问题及解决办法——ROS依赖包安装问题

    ROS依赖包安装问题 问题描述解决方案 问题描述 在ROS编译过程中经常会遇到找不到ROS包的情况 xff0c 如下所示 CMake Error at span class token operator span opt span clas
  • Attention Model(mechanism) 的 套路

    最近刷了一些attention相关的paper 照着here的列表 43 自己搜的paper xff0c 网上相关的资料也有很多 xff0c 在此只讲一讲自己对于attention的理解 xff0c 力求做到简洁明了 一 attention
  • 程序=数据结构+算法

    数据 由 数据元素 组成 xff0c 数据元素 由 数据项 组成 数据元素 xff1a 组成数据的基本单位 xff0c 是集合的个体 数据对象 xff1a 性质相同的数据元素的集合 xff0c 是数据的一个子集 数据结构 xff1a 数据元
  • ROS为上位机与STM32为下位机串口通讯(一)

    STM32通过串口向ROS上位机发送信息 主要实现了STM32 通过串口向ROS上位机发送数据 xff0c 发布者将接收到的数据发布出去并打印出来 xff0c 订阅者订阅发布者发布的消息并打印出来 xff0c 最后通过roslaunch启动
  • 程序员面试真的全都答对就有offer?

    程序员面试 xff0c 技术水平重要吗 xff1f 只要面对面试官 xff0c 估计大家都认为技术水平最重要 xff0c 其他都是幌子 xff01 当然 xff0c 技术是基础 xff0c 但技术并不是全部 xff0c 而且一个面试者的技术
  • 解决vncserver打开远程桌面后没有图标,只有一个鼠标问题

    前言 介绍一个VNC客户端 IIS7服务器管理工具 作为VNC客户端 xff0c 它最优秀的功能就是支持一键导出或导入 xff0c 一键批量打开VNC xff0c 一键批量关闭VNC xff0c 多台VNC 自定义备注 xff0c 自定义分
  • openmv的串口传输

    import sensor image time from pid import PID from pyb import Servo from pyb import UART uartCP 61 UART 1 115200 用于电脑与OPe
  • 三层交换机的“三层”是什么意思?

    关注我们的朋友应该知道 xff0c 之前我们简单分析过二层工业交换机和三层工业交换机的区别 但是近期有客户向我们咨询 xff0c 工业交换机中的三层是指什么意思 xff1f 是指工业交换机中有三层 东西 吗 xff1f 就这个问题我们一起来
  • 外贸人SOHO怎么收汇?2020最新外贸B2B收款结汇方法详解!

    很多做外贸朋友都知道 xff0c 外贸收款 结汇是外贸交易中非常重要的一个环节 一个好的外贸收款渠道 xff0c 可以快速地帮助企业资金回笼 xff0c 支付货款 退税等等 xff0c 能省去很多不必要的麻烦 所以 xff0c 对于外贸从业
  • 在回收站删除的文件怎么恢复

    问题描述 xff1a 回收站清空是很常见的数据恢复故障 在回收站删除的文件怎么恢复接下来我们还需要了解下具体如何恢复回收站清空的资料 xff0c 具体请看正文了解 工具 软件 xff1a 极限数据恢复软件 步骤1 xff1a 先百度搜索并下
  • Jenkins修改显示语言为中文

    最近在Centos7 4里安装了jenkins 2 235 1版本 xff0c 使用的推荐安装插件 xff0c 安装后发现部分中文简体不翻译的情况 一 解决方法 xff1a 默认初始安装的时候已经安排了插件Localization Chin
  • 第三章 九析带你轻松完爆 MinIO - MinIO 客户端使用(mc)

    目录 1 前言 2 邀约 3 介绍 4 mc 安装 5 操作 5 1 查看 minio server 5 2 添加 minio server 5 3 删除 minio server 5 4 查看 minio server 中 bucket

随机推荐

  • 分享一款巨微MS1586低功耗蓝牙芯片

    MS1586包含8位单片机和低功耗 低成本的BLE收发器 xff0c 内部集成了发射机 接收机 GFSK调制解调器和BLE基带处理 遵循BLE广播通道通信 xff0c 具有成本低 体积小 控制方便等优点 特点 4KWOTPROM 256by
  • 推荐系统经典论文文献及业界应用

    Survey方面的文章及资料 Adomavicius G Tuzhilin A Toward the next generation of recommender systems A survey of the state of the a
  • 群辉web station开启http访问文件功能

  • centos7.6 快速架设kiftd私有网盘 文件管理系统

    一 基础环境 安装源ISO CentOS 7 x86 64 DVD 1810 最小化安装系统后先更新 root 64 Server yum update y root 64 Server cat etc redhat release Cen
  • 微信公众号开发

    文章目录 第一章 环境准备1 1 开发工具1 2 创建工程1 3 添加依赖1 4 添加模板1 5 测试接口1 6 内网穿透1 7 接入指南 第二章 基础支持2 1 获取 AccessToken 令牌2 2 获取微信API接口IP地址2 3
  • 果然新鲜电商系统

    项目简介 果然新鲜电商系统是一个类似小米商城的B2C电商平台 xff0c 可做毕业设计参考 访问地址 xff1a https gitee com caochenlei fresh parent 项目截图 网站首页 本地访问 xff1a ht
  • 通用代码生成工具

    项目简介 CodeBuilder可以帮助你快速生成模板文件 xff0c 目前支持mysql oracle sql server数据库 您可以自己制作代码模板并添加到模板目录 xff0c 帮助您可以应付各种开发场景 访问地址 xff1a ht
  • 后台权限管理系统

    项目简介 CommonAdmin是一个按钮级权限管理系统 xff0c 包含企业后台最常用的系统模块 xff0c 代码简洁 xff0c 开箱即用 访问地址 xff1a https gitee com caochenlei common adm
  • 个人博客管理系统

    项目简介 Blog是一款个人博客管理系统 xff0c 是我和同学上学期的期末大作业 xff0c 完成的比较仓促 xff0c 大部分功能已经完成 访问地址 xff1a https gitee com caochenlei blog 主要页面
  • Docker的学习与使用

    目录 第一章 Docker介绍第二章 Docker架构第三章 Docker安装第四章 Docker进程相关命令第五章 Docker镜像相关命令第六章 Docker容器相关命令第七章 Docker容器的数据卷第八章 Docker常见应用部署8
  • Java工程师的进阶之路

    目录 知识点01 xff1a 九大排序算法知识点02 xff1a 二分查找算法知识点03 xff1a 二叉树的遍历知识点04 xff1a Spring IOC知识点05 xff1a Spring AOP知识点06 xff1a Spring
  • 在线代码执行系统

    目录 第一章 安装ubuntu第二章 安装SSH第三章 安装docker第四章 安装docker compose第五章 安装judge0 第一章 安装ubuntu 虚拟机 xff1a VirtualBox 6 1 30 148432 Win
  • TF-IDF

    1 TF IDF是什么 xff1f TF IDF xff1a term frequency inverse document frequency 1 tf idf 作为一种权重经常被用作信息检索和文本挖掘领域 2 这样一种权重时通过统计计算
  • 时间区间拆分算法

    目录 需求描述 xff1a 项目依赖 xff1a 代码实现 xff1a 运行效果 xff1a 需求描述 xff1a 时间范围 xff1a 2022 04 10 09 00 00 2022 04 12 18 00 00 具体描述 xff1a
  • 时间区间合并算法

    目录 需求描述 xff1a 项目依赖 xff1a 代码实现 xff1a 运行效果 xff1a 需求描述 xff1a 时间范围 xff1a 2022 04 10 09 00 00 2022 04 10 10 00 00 2022 04 10
  • 如何排查线上OOM

    目录 操作步骤 xff1a 其他知识 xff1a 操作步骤 xff1a 换目录进行以下操作 xff08 不要在 操作 xff09 span class token builtin class name cd span 安装WGET下载工具
  • 计算饼状图百分比

    目录 需求描述 xff1a 项目依赖 xff1a 代码实现 xff1a 运行效果 xff1a 需求描述 xff1a 给定一个整数数组 xff0c 例如 xff1a 2 3 4 xff0c 计算各个元素的百分比 xff0c 要求百分比累加为1
  • 我是如何解决码云图床失效问题?

    目录 第一章 购买资源包第二章 配置存储桶第三章 上传图片集第四章 替访问域名第五章 配置Typora 第一章 购买资源包 第一步 xff1a 登录阿里云账号第二步 xff1a 访问资源包管理 第三步 xff1a 购买资源包套餐 第四步 x
  • Discord机器人开发

    目录 第一章 Discord账号注册第二章 Discord创建服务器第三章 Discord创建机器人3 1 创建应用3 2 创建机器人3 3 配置机器人3 4 添加机器人 第四章 Discord机器人开发准备4 1 推荐资料4 2 创建工程
  • 如何设计事件管理器

    目录 需求描述 xff1a 项目依赖 xff1a 代码实现 xff1a 定义通用的事件对象定义事件监听器接口定义事件监听器适配器对象定义事件管理器接口定义默认的事件管理器对象创建三个不同的监听器对象 运行效果 xff1a 需求描述 xff1