设计并用Java实现一个简易的规则引擎

news2024/11/15 6:46:20

文章目录

  • 前言
  • 正文
    • 一、代码结构
    • 二、核心代码
      • 2.1 上下文数据接口 ContextData.java
      • 2.2 规则接口 Rule.java
      • 2.3 规则引擎接口 RuleEngine.java
      • 2.4 规则引擎上下文类 RuleEngineContext.java
      • 2.5 规则引擎默认实现类 DefaultRuleEngine.java
      • 2.6 执行时出错监听器接口 ExecuteOnErrorListener.java
      • 2.7 规则引擎执行模版类 RuleEngineExecuteTemplate.java
    • 三、测试业务
      • 3.1 新增折扣价格上下文实现类DiscountPriceContextData.java
      • 3.2 新增固定金额折扣规则实现类 FixedAmountDiscountRule.java
      • 3.3 新增百分比折扣规则实现类 PercentageDiscountRule.java
      • 3.4 新增满减折扣规则实现类 FullReductionDiscountRule.java
      • 3.5 编写测试类 Test.java
      • 3.6 测试类运行结果

前言

使用规则引擎可以很方便的实现一些比较复杂的业务逻辑。
本文介绍的简易版,是一个小的通用代码结构。

通过组装业务数据,创建执行模版,最终执行,获取到最终结果。

大家在复杂场景下,也可以选用Drools来实现。

Drools 是一个开源的业务规则管理系统,它提供了基于Java的规则引擎,用于实现复杂的事件处理和业务逻辑。Drools 支持声明式编程,允许开发人员将业务逻辑从应用程序代码中分离出来,这使得业务逻辑的管理和变更更加灵活和便捷。

正文

一、代码结构

在这里插入图片描述

二、核心代码

maven依赖文件:

    <properties>
        <java.version>17</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
    </dependencies>

2.1 上下文数据接口 ContextData.java

package com.song.tools.ruleengine.core;

/**
 * 上下文数据
 *
 * @author song tools
 */
public interface ContextData {

    /**
     * 校验上下文数据
     */
    default void validProperty() {
    }
}

2.2 规则接口 Rule.java

package com.song.tools.ruleengine.core;

/**
 * 规则接口
 *
 * @author song tools
 */
public interface Rule<ContextData extends com.song.tools.ruleengine.core.ContextData> {

    /**
     * 执行前
     *
     * @param contextData 上下文数据
     */
    default void before(ContextData contextData) {
        contextData.validProperty();
    }

    /**
     * 执行
     *
     * @param context 上下文
     */
    void execute(RuleEngineContext<ContextData> context);

    /**
     * 执行后
     *
     * @param contextData 上下文数据
     */
    default void after(ContextData contextData) {
    }
}

2.3 规则引擎接口 RuleEngine.java

package com.song.tools.ruleengine.core;

/**
 * 规则引擎
 *
 * @author song tools
 */
public interface RuleEngine<ContextData extends com.song.tools.ruleengine.core.ContextData> {

    /**
     * 注册规则
     *
     * @param ruleKey 规则key
     * @param rule    规则
     */
    void registerRule(String ruleKey, Rule<ContextData> rule);

    /**
     * 执行规则
     *
     * @param context 上下文
     */
    void executeRule(RuleEngineContext<ContextData> context) throws Exception;

    /**
     * 规则数量
     *
     * @return 规则数量
     */
    int ruleSize();
}

2.4 规则引擎上下文类 RuleEngineContext.java

package com.song.tools.ruleengine.core;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 规则引擎上下文
 *
 * @author song tools
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class RuleEngineContext<ContextData extends com.song.tools.ruleengine.core.ContextData> {

    /**
     * 上下文数据
     */
    private ContextData contextData;
}

2.5 规则引擎默认实现类 DefaultRuleEngine.java

package com.song.tools.ruleengine.core;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 默认实现的规则引擎
 *
 * @author song tools
 */
public class DefaultRuleEngine<ContextData extends com.song.tools.ruleengine.core.ContextData> implements RuleEngine<ContextData> {

    private final Map<String, Rule<ContextData>> RULE_MAP;

    public DefaultRuleEngine() {
        RULE_MAP = new LinkedHashMap<>(16);
    }

    @Override
    public void registerRule(String ruleKey, Rule<ContextData> rule) {
        RULE_MAP.put(ruleKey, rule);
    }

    @Override
    public void executeRule(RuleEngineContext<ContextData> context) {
        for (Rule<ContextData> rule : RULE_MAP.values()) {
            rule.before(context.getContextData());
            rule.execute(context);
            rule.after(context.getContextData());
        }
    }

    @Override
    public int ruleSize() {
        return RULE_MAP.size();
    }
}

2.6 执行时出错监听器接口 ExecuteOnErrorListener.java

package com.song.tools.ruleengine.core;

/**
 * 执行时出错监听器
 *
 * @author song tools
 */
public interface ExecuteOnErrorListener<ContextData extends com.song.tools.ruleengine.core.ContextData> {

    void onError(ContextData contextData, Exception e);
}

2.7 规则引擎执行模版类 RuleEngineExecuteTemplate.java

package com.song.tools.ruleengine.core;

import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 规则执行模版
 *
 * @author song tools
 */
@Getter
@Slf4j
public class RuleEngineExecuteTemplate<ContextData extends com.song.tools.ruleengine.core.ContextData> {

    /**
     * 规则引擎
     */
    private final RuleEngine<ContextData> ruleEngine;

    /**
     * 规则索引
     */
    private final AtomicInteger ruleIndex;

    /**
     * 执行失败监听器
     */
    private ExecuteOnErrorListener<ContextData> executeOnErrorListener;

    public RuleEngineExecuteTemplate() {
        this(new DefaultRuleEngine<>());
    }

    public RuleEngineExecuteTemplate(RuleEngine<ContextData> ruleEngine) {
        Objects.requireNonNull(ruleEngine, "ruleEngine is null");
        this.ruleIndex = new AtomicInteger(1);
        this.ruleEngine = ruleEngine;
    }


    /**
     * 注册规则
     *
     * @param rule 规则
     * @return this 当前模版对象
     */
    public RuleEngineExecuteTemplate<ContextData> registerRule(Rule<ContextData> rule) {
        String ruleKey = rule.getClass().getSimpleName();
        return this.registerRule(ruleKey, rule);
    }

    /**
     * 注册规则
     *
     * @param rules 规则列表
     * @return this 当前模版对象
     */
    public RuleEngineExecuteTemplate<ContextData> registerRule(List<Rule<ContextData>> rules) {
        for (Rule<ContextData> rule : rules) {
            this.registerRule(rule);
        }
        return this;
    }

    /**
     * 注册规则
     *
     * @param ruleKey 规则key
     * @param rule    规则
     * @return this 当前模版对象
     */
    public RuleEngineExecuteTemplate<ContextData> registerRule(String ruleKey, Rule<ContextData> rule) {
        ruleEngine.registerRule(ruleKey + ruleIndex.getAndIncrement(), rule);
        return this;
    }

    public RuleEngineExecuteTemplate<ContextData> registerExecuteOnErrorListener(ExecuteOnErrorListener<ContextData> executeOnErrorListener) {
        this.executeOnErrorListener = executeOnErrorListener;
        return this;
    }


    /**
     * 执行规则
     */
    public void execute(ContextData contextData) throws Exception {
        Objects.requireNonNull(contextData, "contextData is null");
        if (ruleEngine.ruleSize() == 0) {
            throw new IllegalArgumentException("ruleEngine not found register rule");
        }

        // 组装上下文
        RuleEngineContext<ContextData> context = new RuleEngineContext<>();
        context.setContextData(contextData);

        try {
            // 执行规则
            ruleEngine.executeRule(context);
        } catch (Exception e) {
            log.error("execute rule error", e);
            if (Objects.nonNull(executeOnErrorListener)) {
                executeOnErrorListener.onError(context.getContextData(), e);
            }
            throw e;
        }
    }
}


三、测试业务

假设现在需要灵活的计算单个商品的价格折扣相关的内容。

3.1 新增折扣价格上下文实现类DiscountPriceContextData.java

package com.song.tools.ruleengine;

import com.song.tools.ruleengine.core.ContextData;
import lombok.Data;

import java.math.BigDecimal;
import java.util.Objects;

/**
 * 折扣价格上下文(对于单件商品,简单场景的计算)
 *
 * @author song tools
 */
@Data
public class DiscountPriceContextData implements ContextData {

    /**
     * 临时价格(存在多个计算规则时,使用它进行传递计算的中间值)
     */
    private BigDecimal calculatedTempPrice;

    /**
     * 原价
     */
    private BigDecimal originalPrice;

    /**
     * 折扣后价格
     */
    private BigDecimal discountedPrice;

    @Override
    public void validProperty() {
        Objects.requireNonNull(originalPrice, "原价不能为空");
    }
}

3.2 新增固定金额折扣规则实现类 FixedAmountDiscountRule.java

package com.song.tools.ruleengine;

import com.song.tools.ruleengine.core.Rule;
import com.song.tools.ruleengine.core.RuleEngineContext;

import java.math.BigDecimal;
import java.math.RoundingMode;

public class FixedAmountDiscountRule implements Rule<DiscountPriceContextData> {
    private final BigDecimal discountAmount;

    public FixedAmountDiscountRule(BigDecimal discountAmount) {
        this.discountAmount = discountAmount;
    }

    @Override
    public void execute(RuleEngineContext<DiscountPriceContextData> context) {
        DiscountPriceContextData contextData = context.getContextData();
        // 临时价格
        BigDecimal calculatedTempPrice = contextData.getCalculatedTempPrice();
        // 原始价格
        BigDecimal originalPrice = contextData.getOriginalPrice();
        if (calculatedTempPrice != null) {
            originalPrice = calculatedTempPrice;
        }

        // 进行精确减法运算,并确保结果不会小于0
        BigDecimal discountedPrice = (originalPrice.subtract(discountAmount).max(BigDecimal.ZERO)).setScale(2, RoundingMode.HALF_UP);

        // 设置折扣后的价格
        contextData.setDiscountedPrice(discountedPrice);
        contextData.setCalculatedTempPrice(discountedPrice);
    }

    @Override
    public void before(DiscountPriceContextData contextData) {
        Rule.super.before(contextData);
    }

    @Override
    public void after(DiscountPriceContextData contextData) {
        Rule.super.after(contextData);
    }
}

3.3 新增百分比折扣规则实现类 PercentageDiscountRule.java

package com.song.tools.ruleengine;

import com.song.tools.ruleengine.core.Rule;
import com.song.tools.ruleengine.core.RuleEngineContext;

import java.math.BigDecimal;
import java.math.RoundingMode;

public class PercentageDiscountRule implements Rule<DiscountPriceContextData> {

    private static final BigDecimal ONE_HUNDRED = new BigDecimal("100");
    private final BigDecimal discountPercentage;

    public PercentageDiscountRule(BigDecimal discountPercentage) {
        this.discountPercentage = discountPercentage;
    }

    @Override
    public void execute(RuleEngineContext<DiscountPriceContextData> context) {
        DiscountPriceContextData contextData = context.getContextData();
        // 临时价格
        BigDecimal calculatedTempPrice = contextData.getCalculatedTempPrice();
        // 原始价格
        BigDecimal originalPrice = contextData.getOriginalPrice();
        if (calculatedTempPrice != null) {
            originalPrice = calculatedTempPrice;
        }

        // 计算折扣率
        BigDecimal discountRate = discountPercentage.divide(ONE_HUNDRED, 2, RoundingMode.HALF_UP);

        // 计算折扣后的价格(四舍五入,保留2位小数)
        BigDecimal discountedPrice = originalPrice.multiply(discountRate).setScale(2, RoundingMode.HALF_UP);

        contextData.setDiscountedPrice(discountedPrice);
        contextData.setCalculatedTempPrice(discountedPrice);
    }

    @Override
    public void before(DiscountPriceContextData contextData) {
        Rule.super.before(contextData);
    }

    @Override
    public void after(DiscountPriceContextData contextData) {
        Rule.super.after(contextData);
    }
}

3.4 新增满减折扣规则实现类 FullReductionDiscountRule.java

package com.song.tools.ruleengine;

import com.song.tools.ruleengine.core.Rule;
import com.song.tools.ruleengine.core.RuleEngineContext;

import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * 满减折扣规则
 *
 * @author song tools
 */
public class FullReductionDiscountRule implements Rule<DiscountPriceContextData> {

    /**
     * 满减金额,满xx金额数
     */
    private final BigDecimal fullReductionBoundAmount;

    /**
     * 满减折扣金额,减去xx金额数
     */
    private final BigDecimal fullReductionDiscountAmount;

    public FullReductionDiscountRule(BigDecimal fullReductionBoundAmount, BigDecimal fullReductionDiscountAmount) {
        this.fullReductionBoundAmount = fullReductionBoundAmount;
        this.fullReductionDiscountAmount = fullReductionDiscountAmount;
    }

    public void execute(RuleEngineContext<DiscountPriceContextData> context) {
        DiscountPriceContextData contextData = context.getContextData();
        // 临时价格
        BigDecimal calculatedTempPrice = contextData.getCalculatedTempPrice();
        // 原始价格
        BigDecimal originalPrice = contextData.getOriginalPrice();
        if (calculatedTempPrice != null) {
            originalPrice = calculatedTempPrice;
        }

        // 比较金额是否满足满减条件
        if (originalPrice.compareTo(fullReductionBoundAmount) >= 0) {
            BigDecimal discountedPrice = originalPrice.subtract(fullReductionDiscountAmount).setScale(2, RoundingMode.HALF_UP);
            contextData.setDiscountedPrice(discountedPrice);
            contextData.setCalculatedTempPrice(discountedPrice);
        }
    }
}

3.5 编写测试类 Test.java

编排不同的规则,不通的顺序,验证最终的执行结果。

package com.song.tools.ruleengine;

import com.song.tools.ruleengine.core.DefaultRuleEngine;
import com.song.tools.ruleengine.core.RuleEngineContext;
import com.song.tools.ruleengine.core.RuleEngineExecuteTemplate;

import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * 测试规则执行
 *
 * @author song tools
 */
public class Test {

    public static void main(String[] args) throws Exception {
        System.out.println("----------------test1----------------");
        test1();
        System.out.println("----------------test1----------------");

        System.out.println("----------------test2----------------");
        test2();
        System.out.println("----------------test2----------------");
    }


    private static void test1() {
        // 创建规则引擎
        DefaultRuleEngine<DiscountPriceContextData> ruleEngine = new DefaultRuleEngine<>();
        // 创建规则+注册规则
        ruleEngine.registerRule("percentageDiscountRule1", new PercentageDiscountRule(BigDecimal.valueOf(95)));
        ruleEngine.registerRule("fixedAmountDiscountRule1", new FixedAmountDiscountRule(BigDecimal.valueOf(12.34)));
        ruleEngine.registerRule("percentageDiscountRule2", new PercentageDiscountRule(BigDecimal.valueOf(80)));
        ruleEngine.registerRule("fixedAmountDiscountRule2", new FixedAmountDiscountRule(BigDecimal.valueOf(12.4)));

        // 创建上下文数据
        RuleEngineContext<DiscountPriceContextData> context = new RuleEngineContext<>();
        DiscountPriceContextData discountPriceContextData = new DiscountPriceContextData();
        discountPriceContextData.setOriginalPrice(BigDecimal.valueOf(100));
        context.setContextData(discountPriceContextData);

        // 执行规则引擎
        ruleEngine.executeRule(context);

        // 打印执行结果
        System.out.println(discountPriceContextData.getDiscountedPrice());

        System.out.println(BigDecimal.valueOf(100).multiply(BigDecimal.valueOf(0.95)).subtract(BigDecimal.valueOf(12.34)));
        System.out.println(BigDecimal.valueOf(82.66).multiply(BigDecimal.valueOf(0.8).setScale(2, RoundingMode.HALF_UP)).subtract(BigDecimal.valueOf(12.4)).setScale(2, RoundingMode.HALF_UP));
    }

    private static void test2() throws Exception {
        // 创建上下文数据
        DiscountPriceContextData discountPriceContextData = new DiscountPriceContextData();
        discountPriceContextData.setOriginalPrice(BigDecimal.valueOf(100));

        // 创建规则引擎执行模板
        RuleEngineExecuteTemplate<DiscountPriceContextData> ruleEngineExecuteTemplate = new RuleEngineExecuteTemplate<>();

        // 注册规则&执行规则
        ruleEngineExecuteTemplate.registerRule(new PercentageDiscountRule(BigDecimal.valueOf(95))) // 95折
                .registerRule(new FixedAmountDiscountRule(BigDecimal.valueOf(12.34))) // 减12.34元
                .registerRule(new PercentageDiscountRule(BigDecimal.valueOf(80))) // 80折
                .registerRule(new FullReductionDiscountRule(BigDecimal.valueOf(50), BigDecimal.valueOf(10))) // 满50减10
                .registerRule(new FixedAmountDiscountRule(BigDecimal.valueOf(12.4))) // 减12.4元
                .registerRule(new FullReductionDiscountRule(BigDecimal.valueOf(40), BigDecimal.valueOf(19.9))) // 满40减19.9元
                .execute(discountPriceContextData);

        // 打印最终结果
        System.out.println(discountPriceContextData.getDiscountedPrice());
    }
}

3.6 测试类运行结果

----------------test1----------------
53.73
82.66
53.73
----------------test1----------------
----------------test2----------------
23.83
----------------test2----------------

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

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

相关文章

[mysql]SQL语言的规则和规范

规则 是什么呢&#xff0c;规则就是我们最基本&#xff0c;每时每刻都要遵守的比如人行道靠右&#xff0c;不能逆行&#xff0c; 规范 呢就是锦上添花&#xff0c;如果你不这么做&#xff0c;是不那么道德&#xff0c;不那么好的&#xff0c;就像小学生见到老师要问好&#…

【秋招笔试题】浇水

题解&#xff1a;离散化之后差分数组&#xff0c;注意左闭右闭区间的处理&#xff0c;将点和线段都抽象成点 #include <iostream> #include <vector> #include <set> #include <algorithm>using namespace std;const int MAXN 3000000 5; const int…

基于Spring Boot的火车订票管理系统

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;JAVA语言 Spring Boot框架 工具&#xff1a;IDEA/Eclipse、Navicat、Tomcat 系统展示 首页 管理…

方正畅享新闻采编系统 binary.do SQL注入漏洞分析复现

漏洞简介 binary.do接口的TableName参数对传入的数据没有充足的校验&#xff0c;导致该接口存在SQL注入漏洞&#xff0c;未授权的攻击者可获取数据库敏感信息。资产测绘搜索语句 hunter&#xff1a;web.body"/newsedit/newsedit/" 路由与鉴权分析 通过分析web.xml配置…

ubuntu 安装python3 教程

本篇教程,主要介绍如何在Ubuntu上安装python3教程。 1、查看是否有python 在安装前,首先看看自己系统上,是否存在python环境,可能有些系统,默认就安装过python,如果已经有python了,可以直接跳过安装教程。 2、安装步骤 apt update && apt install -y python3 p…

【知识分享】MQTT实战-使用mosquitto客户端连接emqx服务器

一、简介 MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;是一种轻量级的、基于发布/订阅模式的通信协议&#xff0c;旨在实现物联网设备之间的低带宽、高延迟的通信。MQTT协议设计简洁&#xff0c;使用TCP/IP协议进行通信&#xff0c;适用于各种网络环境&am…

OpenGL——着色器画一个点

一、 绘制 在窗口中间画一个像素点&#xff1a; #include <GL/glew.h> #include <GLFW/glfw3.h> #include <iostream>using namespace std;#define numVAOs 1GLuint renderingProgram; GLuint vao[numVAOs];GLuint createShaderProgram () {const char *v…

基于canal的Redis缓存双写

canal地址&#xff1a;alibaba/canal: 阿里巴巴 MySQL binlog 增量订阅&消费组件 (github.com)https://github.com/alibaba/canal 1. 准备 1.1 MySQL 查看主机二进制日志 show master status 查看binlog是否开启 show variables like log_bin 授权canal连接MySQL账号 …

有限自动机例题

答案&#xff1a;A 解析&#xff1a; 从图中可以看出从1出发&#xff0c;有一个a的闭环&#xff0c;可以多次重复a&#xff0c;因此选项A不正确 选项B&#xff0c;如果有b&#xff0c;必然经过a回去&#xff0c;不可能出现连续的b 选项C&#xff0c;可以从图中看出&#xf…

前端学习-day14

文章目录 01-媒体查询02-媒体查询-书写顺序03-媒体查询04-媒体查询-link引入06-Bootstrap-使用07-Bootstrap-栅格系统08-Bootstrap-按钮样式09-Bootstrap-表格样式10-bootstrap组件11-bootstrap字体图标alloyTeam项目index.htmlindex.less 01-媒体查询 <!DOCTYPE html> …

数学建模算法汇总(全网最全,含matlab案例代码)

数学建模常用的算法分类 全国大学生数学建模竞赛中&#xff0c;常见的算法模型有以下30种&#xff1a; 最小二乘法数值分析方法图论算法线性规划整数规划动态规划贪心算法分支定界法蒙特卡洛方法随机游走算法遗传算法粒子群算法神经网络算法人工智能算法模糊数学时间序列分析马…

一文梳理RAG(检索增强生成)的现状与挑战

一 RAG简介 大模型相较于过去的语言模型具备更加强大的能力&#xff0c;但在实际应用中&#xff0c;例如在准确性、知识更新速度和答案透明度方面&#xff0c;仍存在不少问题&#xff0c;比如典型的幻觉现象。因此&#xff0c;检索增强生成 (Retrieval-Augmented Generation, …

Learn ComputeShader 09 Night version lenses

这次将要制作一个类似夜视仪的效果 第一步就是要降低图像的分辨率&#xff0c; 这只需要将id.xy除上一个数字然后再乘上这个数字 可以根据下图理解&#xff0c;很明显通过这个操作在多个像素显示了相同的颜色&#xff0c;并且很多像素颜色被丢失了&#xff0c;自然就会有降低分…

Open-Sora代码详细解读(1):解读DiT结构

Diffusion Models专栏文章汇总&#xff1a;入门与实战 前言&#xff1a;目前开源的DiT视频生成模型不是很多&#xff0c;Open-Sora是开发者生态最好的一个&#xff0c;涵盖了DiT、时空DiT、3D VAE、Rectified Flow、因果卷积等Diffusion视频生成的经典知识点。本篇博客从Open-S…

攻防世界 Web_php_unserialize

Web_php_unserialize PHP反序列化 看看代码 <?php class Demo { private $file index.php;public function __construct($file) { $this->file $file; }function __destruct() { echo highlight_file($this->file, true); }function __wakeup() { if ($this->…

软件测试 | 性能测试

性能测试的概念 为了 发现系统性能问题 或 获取系统性能相关指标 而进行的测试。 常见性能测试指标 并发数 即并发用户数。 从业务层面看&#xff0c;并发用户数指的是 实际使用系统的用户总数。从后端服务器层面看&#xff0c;指的是 web服务器在一段时间内处理浏览器请求而建…

服务器环境搭建-5 Nexus搭建与使用介绍

背景 本文介绍nexus的安装、配置和使用&#xff0c;之后通过案例的方式演示使用过程。 1.下载和安装 本文使用Nexus 3.x版本进行演示 下载地址&#xff1a;Download Nexus Repository OSS | Sonatype 国外网站下载速度较慢&#xff0c;也可以通过百度网盘下载(提取码:9999): …

爆改YOLOv8|利用图像分割网络UNetV2改进yolov8主干-即插即用

1&#xff0c;本文介绍 U-Net v2 通过引入创新的跳跃连接设计来提升医学图像分割的精度。这一版本专注于更有效地融合不同层级的特征&#xff0c;包括高级特征中的语义信息和低级特征中的细节信息。通过这种优化&#xff0c;U-Net v2 能够在低级特征中注入丰富的语义&#xff…

wireshark安装及抓包新手使用教程

Wireshark是非常流行的网络封包分析软件&#xff0c;可以截取各种网络数据包&#xff0c;并显示数据包详细信息。常用于开发测试过程各种问题定位。本文主要内容包括&#xff1a; 1、Wireshark软件下载和安装以及Wireshark主界面介绍。 2、WireShark简单抓包示例。通过该例子学…

JetBrains Aqua安装步骤和基本配置

一、安装步骤 下载链接&#xff1a;https://www.jetbrains.com.cn/aqua/ 1、点击下载按钮。 2、点击下载IDE&#xff0c;浏览器下载.exe。&#xff08;如果是mac或linux可选择对应的下载安装包&#xff09; 3、双击.exe文件&#xff0c;点击下一步。 4、可点击【浏览】选择安装…