使用Apache Commons SCXML实现状态机管理

第1章:引言

大家好,我是小黑,咱们程序员在开发过程中,经常会遇到需要管理不同状态和状态之间转换的场景。比如,一个在线购物的订单,它可能有“新建订单”、“已支付”、“配送中”、“已完成”等状态。在这些不同的状态之间转换,其实就是一个状态机的过程。

状态机,简单来说,就是一种模型,用来描述一个系统在不同状态下的行为。它的魅力在于能够让复杂的状态转换变得简洁清晰。想象一下,如果没有状态机,我们可能需要写很多if-else来处理不同的状态和事件,那代码可就乱得像鸡窝了。

这就引出了小黑今天要聊的主角——Apache Commons SCXML。这货是一个用来管理状态机的Java库,能让咱们以一种更优雅的方式来处理状态转换。它不仅支持XML配置状态机,还提供了API来控制状态机的行为,简直是管理复杂状态的利器!

第2章:SCXML简介

Apache Commons SCXML,这个名字听起来可能有点小长,但它其实是个非常给力的工具。它提供了一个基于SCXML标准(State Chart XML)的状态机实现,让咱们可以用XML文件来定义状态机。

为什么要用SCXML呢?因为它基于XML,这让状态机的定义变得非常直观和灵活。你可以直接在XML文件里定义状态、事件和转换规则,而不需要在Java代码里写一大堆逻辑。这样一来,状态机的修改和维护就简单多了,不用每次都去翻Java代码。

使用Apache Commons SCXML的好处还不止这些。它支持嵌套状态、并行状态、历史状态等高级特性,这些都是在复杂应用场景中非常有用的功能。比如,你的应用可能需要同时管理多个独立的状态机,或者在用户返回时保持之前的状态,SCXML都能轻松搞定。

那怎么用这个库呢?先来看看如何添加它到你的项目里。如果你用的是Maven,只需要在pom.xml中添加如下依赖:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-scxml</artifactId>
    <version>0.9</version>
</dependency>

依赖配置好了之后,就可以开始愉快地定义状态机了。比如,小黑想定义一个简单的订单状态机,可能会这样写:

<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0"
       initial="新建订单">
    <state id="新建订单">
        <transition event="支付" target="已支付"/>
    </state>
    <state id="已支付">
        <transition event="发货" target="配送中"/>
    </state>
    <state id="配送中">
        <transition event="签收" target="已完成"/>
    </state>
    <state id="已完成"/>
</scxml>

这段XML就定义了一个简单的订单状态机。它从“新建订单”开始,然后可以按照支付、发货、签收的顺序转换到“已完成”。这样一来,咱们就用几行XML描述了整个订单流程。

第3章:状态机基础 - 让复杂的流程简单起来

聊到状态机,咱们得先搞明白它的三大基石:状态(State)、事件(Event)和转换(Transition)。这就像是学开车,得知道油门、刹车和方向盘怎么用一样。咱们先来一点点拆解这些概念。

状态(State):程序的各种场景

状态,就是程序在某一时刻的情形或者场景。比如,一个游戏角色可能有“静止”、“行走”、“跳跃”等状态。每个状态代表了角色在不同时刻的不同行为和特征。在状态机里,状态是静态的,就像是一张静止的照片,记录了某个瞬间的全部信息。

事件(Event):触发状态转换的信号

事件则是导致状态转换的外部输入。继续拿游戏角色来说,当玩家按下跳跃键时,就发生了一个“跳跃”事件,这个事件会触发角色从“静止”状态转换到“跳跃”状态。在状态机中,事件是动态的,就像是电影里的一幕幕,推动故事的发展。

转换(Transition):从一个状态到另一个状态的桥梁

最后,转换是连接两个状态的桥梁。它定义了在什么事件发生时,状态应该如何改变。例如,如果当前状态是“静止”,当“跳跃”事件发生时,状态就会转换到“跳跃”。

好了,理论知识讲完,小黑来给咱们看个具体的例子。假设小黑要管理一个电商的订单流程,订单有“新建”、“已支付”、“已发货”和“已完成”这几个状态。咱们用Java代码来实现一个简单的状态机:

import org.apache.commons.scxml2.model.*;

public class OrderStateMachine {
    // 创建状态机
    private SCXMLExecutor executor;

    public OrderStateMachine() throws ModelException {
        // 定义状态机
        State newState = new State("新建");
        State paidState = new State("已支付");
        State shippedState = new State("已发货");
        State completedState = new State("已完成");

        // 定义状态转换
        Transition payTransition = new Transition("支付", paidState);
        Transition shipTransition = new Transition("发货", shippedState);
        Transition completeTransition = new Transition("签收", completedState);

        // 添加转换到各个状态
        newState.addTransition(payTransition);
        paidState.addTransition(shipTransition);
        shippedState.addTransition(completeTransition);

        // 设置初始状态
        SCXML scxml = new SCXML();
        scxml.setInitialstate(newState);
        scxml.addState(newState);
        scxml.addState(paidState);
        scxml.addState(shippedState);
        scxml.addState(completedState);

        // 初始化状态机执行器
        this.executor = new SCXMLExecutor();
        this.executor.setStateMachine(scxml);
        this.executor.go();
    }

    // 触发事件的方法
    public void fireEvent(String event) throws ModelException {
        this.executor.triggerEvent(new TriggerEvent(event, TriggerEvent.SIGNAL_EVENT));
    }

    // 获取当前状态
    public String getCurrentState() {
        return this.executor.getStatus().getStates().iterator().next().getId();
    }
}

这段代码中,小黑创建了一个订单状态机。它包含四个状态,通过定义转换来控制状态的变化。这样一来,咱们就可以根据不同的事件(比如支付、发货等)来改变订单的状态了。

通过这个例子,咱们可以看到,状态机其实就是一种把复杂流程图变成代码的工具。它可以帮助咱们清晰地管理程序的各种状态,让代码既简洁又易于理解。

第4章:初始化状态机

假设咱们要创建一个简单的流程控制,比如一个简单的任务流程,它有“开始”、“进行中”和“完成”这几个状态。

首先,小黑要定义状态机的SCXML文件。创建一个名为task-state-machine.scxml的文件,内容如下:

<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0"
       initial="开始">
    <state id="开始">
        <transition event="开始任务" target="进行中"/>
    </state>
    <state id="进行中">
        <transition event="完成任务" target="完成"/>
    </state>
    <state id="完成"/>
</scxml>

这个文件定义了三个状态:开始、进行中和完成,并且定义了从“开始”到“进行中”以及从“进行中”到“完成”的转换。

然后,在Java代码中加载这个SCXML文件。小黑这里用一个简单的方法来演示:

import org.apache.commons.scxml2.SCXMLExecutor;
import org.apache.commons.scxml2.model.*;
import org.apache.commons.scxml2.io.SCXMLReader;

import java.io.File;

public class TaskStateMachine {
    private SCXMLExecutor executor;

    public TaskStateMachine() throws Exception {
        // 读取SCXML文件
        SCXML stateMachine = SCXMLReader.read(new File("path/to/task-state-machine.scxml"));

        // 初始化状态机
        this.executor = new SCXMLExecutor();
        this.executor.setStateMachine(stateMachine);
        this.executor.go();
    }

    // 触发事件
    public void fireEvent(String event) throws ModelException {
        this.executor.triggerEvent(new TriggerEvent(event, TriggerEvent.SIGNAL_EVENT));
    }

    // 获取当前状态
    public String getCurrentState() {
        return this.executor.getStatus().getStates().iterator().next().getId();
    }

    // 主函数,用于测试
    public static void main(String[] args) throws Exception {
        TaskStateMachine taskStateMachine = new TaskStateMachine();

        System.out.println("当前状态: " + taskStateMachine.getCurrentState());
        taskStateMachine.fireEvent("开始任务");
        System.out.println("当前状态: " + taskStateMachine.getCurrentState());
        taskStateMachine.fireEvent("完成任务");
        System.out.println("当前状态: " + taskStateMachine.getCurrentState());
    }
}

在这段代码中,咱们创建了一个TaskStateMachine类,它可以加载SCXML文件来初始化状态机。然后,通过fireEvent方法来触发不同的事件,实现状态的转换。

第5章:设计状态机 - 把复杂的逻辑变简单

状态机设计的基本原则

设计状态机时,有几个原则要记住:

  1. 明确状态: 确定所有可能的状态,每个状态应该有明确的定义和边界。
  2. 定义转换: 明确状态之间如何转换,每个转换应该对应一个明确的事件。
  3. 避免过度复杂: 不要让状态机太复杂,否则会难以维护和理解。
实战演练:设计一个简单的工作流状态机

来吧,咱们用SCXML来设计一个简单的工作流状态机。这个状态机将有三个状态:待办进行中已完成。用户可以从待办状态开始任务,进入进行中,然后完成任务,到达已完成状态。

定义SCXML文件

首先,小黑得写一个SCXML文件来定义这个状态机。创建一个名为workflow-state-machine.scxml的文件,内容如下:

<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0"
       initial="待办">
    <state id="待办">
        <transition event="开始任务" target="进行中"/>
    </state>
    <state id="进行中">
        <transition event="完成任务" target="已完成"/>
    </state>
    <state id="已完成"/>
</scxml>

这个文件定义了状态机的各个状态和转换规则。从待办状态,当接收到开始任务事件时,转换到进行中状态;在进行中状态,当接收到完成任务事件时,转换到已完成状态。

在Java中加载和使用SCXML

接下来,小黑要在Java代码中加载这个SCXML文件,并使用它来管理状态。来看看具体怎么操作:

import org.apache.commons.scxml2.SCXMLExecutor;
import org.apache.commons.scxml2.model.*;
import org.apache.commons.scxml2.io.SCXMLReader;

import java.io.File;

public class WorkflowStateMachine {
    private SCXMLExecutor executor;

    public WorkflowStateMachine() throws Exception {
        // 读取SCXML文件
        SCXML stateMachine = SCXMLReader.read(new File("path/to/workflow-state-machine.scxml"));

        // 初始化状态机
        this.executor = new SCXMLExecutor();
        this.executor.setStateMachine(stateMachine);
        this.executor.go();
    }

    // 触发事件
    public void fireEvent(String event) throws ModelException {
        this.executor.triggerEvent(new TriggerEvent(event, TriggerEvent.SIGNAL_EVENT));
    }

    // 获取当前状态
    public String getCurrentState() {
        return this.executor.getStatus().getStates().iterator().next().getId();
    }

    // 测试状态机
    public static void main(String[] args) throws Exception {
        WorkflowStateMachine workflowStateMachine = new WorkflowStateMachine();

        System.out.println("当前状态: " + workflowStateMachine.getCurrentState());
        workflowStateMachine.fireEvent("开始任务");
        System.out.println("当前状态: " + workflowStateMachine.getCurrentState());
        workflowStateMachine.fireEvent("完成任务");
        System.out.println("当前状态: " + workflowStateMachine.getCurrentState());
    }
}

在这个例子中,小黑创建了一个WorkflowStateMachine类来表示工作流状态机。它可以加载SCXML文件并根据事件来转换状态。

第6章:实现状态机逻辑 - 让代码动起来

状态转换与事件触发

状态机的核心就是状态的转换和事件的触发。咱们之前已经在SCXML文件里定义了状态和转换规则,现在就要在Java中实现这些转换的触发。

在小黑之前的例子中,已经展示了如何触发事件。现在咱们来看一个更实际的例子。假设有一个简单的用户认证流程,它包含未登录登录中登录成功登录失败这几个状态。咱们会根据用户的行为(比如输入用户名和密码)来触发状态转换。

编写SCXML文件

首先,定义SCXML文件authentication-state-machine.scxml

<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0"
       initial="未登录">
    <state id="未登录">
        <transition event="尝试登录" target="登录中"/>
    </state>
    <state id="登录中">
        <transition event="登录成功" target="登录成功"/>
        <transition event="登录失败" target="登录失败"/>
    </state>
    <state id="登录成功"/>
    <state id="登录失败"/>
</scxml>

这个文件定义了用户认证的状态机模型。

Java中的状态机逻辑实现

接下来,咱们在Java中加载这个状态机,并根据用户行为触发事件:

import org.apache.commons.scxml2.SCXMLExecutor;
import org.apache.commons.scxml2.model.*;
import org.apache.commons.scxml2.io.SCXMLReader;

import java.io.File;

public class AuthenticationStateMachine {
    private SCXMLExecutor executor;

    public AuthenticationStateMachine() throws Exception {
        // 读取SCXML文件
        SCXML stateMachine = SCXMLReader.read(new File("path/to/authentication-state-machine.scxml"));

        // 初始化状态机
        this.executor = new SCXMLExecutor();
        this.executor.setStateMachine(stateMachine);
        this.executor.go();
    }

    // 触发事件
    public void fireEvent(String event) throws ModelException {
        this.executor.triggerEvent(new TriggerEvent(event, TriggerEvent.SIGNAL_EVENT));
    }

    // 获取当前状态
    public String getCurrentState() {
        return this.executor.getStatus().getStates().iterator().next().getId();
    }

    // 模拟用户登录过程
    public void simulateUserLogin(String username, String password) {
        System.out.println("用户正在尝试登录...");
        fireEvent("尝试登录");

        // 这里只是一个简单的示例,实际应用中应该有更复杂的逻辑
        if ("admin".equals(username) && "123456".equals(password)) {
            System.out.println("登录成功!");
            fireEvent("登录成功");
        } else {
            System.out.println("登录失败!");
            fireEvent("登录失败");
        }
    }

    // 测试状态机
    public static void main(String[] args) throws Exception {
        AuthenticationStateMachine authStateMachine = new AuthenticationStateMachine();

        System.out.println("当前状态: " + authStateMachine.getCurrentState());
        authStateMachine.simulateUserLogin("admin", "123456");
        System.out.println("当前状态: " + authStateMachine.getCurrentState());
    }
}

在这个例子中,咱们创建了一个AuthenticationStateMachine类,用来处理用户认证的状态机。这个类可以根据用户的登录尝试来触发不同的事件,从而改变状态机的状态。

第7章:高级功能与技巧

并行状态的使用

在某些情况下,咱们可能需要状态机同时处于多个状态,这就是并行状态。比如,在一个复杂的业务流程中,可能同时需要跟踪订单的状态和客户的满意度,这两个状态是独立的,可以同时存在。

SCXML中定义并行状态

在SCXML中,咱们可以使用<parallel>元素来定义并行状态。来看一个例子:

<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0"
       initial="订单处理">
    <state id="订单处理">
        <parallel>
            <state id="订单状态">
                <state id="新建"/>
                <state id="处理中"/>
                <state id="完成"/>
            </state>
            <state id="客户满意度">
                <state id="未评价"/>
                <state id="满意"/>
                <state id="不满意"/>
            </state>
        </parallel>
    </state>
</scxml>

这个SCXML文件定义了一个“订单处理”的并行状态机,它同时跟踪“订单状态”和“客户满意度”两个独立的状态。

历史状态的运用

历史状态是另一个有用的功能,它可以让状态机记住之前的状态。这在需要返回到之前状态的场景中非常有用,比如用户在一个复杂表单的多个步骤之间来回切换。

SCXML中定义历史状态

在SCXML中,可以使用<history>元素来定义历史状态。来看一个例子:

<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0"
       initial="步骤一">
    <state id="步骤一">
        <transition event="下一步" target="步骤二"/>
    </state>
    <state id="步骤二">
        <history id="历史状态"/>
        <transition event="返回" target="历史状态"/>
        <transition event="下一步" target="步骤三"/>
    </state>
    <state id="步骤三">
        <transition event="返回" target="步骤二"/>
    </state>
</scxml>

这个例子定义了一个包含历史状态的简单流程。当用户从“步骤二”返回时,状态机会记住之前的状态(“步骤一”或“步骤三”),并据此恢复。

Java中实现高级功能

有了SCXML的定义后,咱们还需要在Java代码中实现相应的逻辑。由于篇幅限制,这里就不详细展开了,但小黑可以给出个大概的指导:

  • 并行状态: 你需要在Java中分别管理每个并行状态的转换和事件。
  • 历史状态: 你可以利用SCXMLExecutor的状态管理功能来记录和恢复历史状态。

第8章:总结

状态机的优势
  • 清晰的逻辑: 状态机让复杂的状态转换和条件判断变得清晰可视。
  • 易于维护: 随着项目的扩展,状态机更易于维护和修改。
  • 减少错误: 明确的状态和转换规则有助于减少逻辑错误。

通过这个案例,咱们可以看到,状态机不仅仅是理论上的概念,在实际的开发工作中它能大显身手,特别是在处理复杂逻辑和流程时。从一个简单的状态转换到整个系统的状态管理,状态机都能提供清晰、高效的解决方案。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

openmediavault(OMV) (26)网络(1)ddns-go

简介 "ddns-go" 是一个动态域名解析(Dynamic DNS)工具,用于更新域名的IP地址。它可以自动检测你的公共IP地址,并将其更新到指定的域名解析服务商,以确保你的域名始终与最新的IP地址相匹配。 安装 hub.docker.com上下载ddns-go镜像 配置compose文件 --- versio…

面向对象综合训练综合练习(文字版格斗游戏,对象数组,复杂的对象数组操作)

文章目录 练习一&#xff1a;文字版格斗游戏练习二&#xff1a;文字版格斗游戏进阶练习三&#xff1a;对象数组&#xff08;商品&#xff09;练习四&#xff1a;对象数组&#xff08;汽车&#xff09;练习五&#xff1a;对象数组&#xff08;手机&#xff09;练习六&#xff1a…

【教学类-43-13】 20240103 (4宫格数独:错误版:768套) 不重复的基础模板数量:768套

作品展示&#xff1a;——4宫格 768套不重复模板&#xff08;64页*12套题&#xff09; 有错误&#xff0c;实际数量小于768套 背景需求&#xff1a; 测试4宫格数独基础模板有几种。 写个程序&#xff0c;验算是不是真的是乘阶法的288种。 代码展示&#xff1a; 768套4宫格题…

Python for与while循环的介绍和对应练习题的巩固

for循环 重复执行同一段代码就是循环 循环列表 for val in list_name: list_num [1,2,3,4,5,6,7,8,9] for i in list_num:print(i)代码执行顺序 从上往下依次执行 遍历 通过某种顺序把某种集合所有元素都访问一遍 list_food{"火锅","烧烤","张…

Python贪吃蛇小游戏(PyGame)

文章目录 写在前面PyGame入门贪吃蛇注意事项写在后面 写在前面 本期内容&#xff1a;基于pygame的贪吃蛇小游戏 实验环境 python3.11及以上pycharmpygame 安装pygame的命令&#xff1a; pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pygamePyGame入门 pygam…

【人工智能】为什么说大模型会有「幻觉」问题,又如何去解决呢

大家好&#xff0c;我是全栈小5&#xff0c;欢迎阅读文章&#xff01; 此篇是【话题达人】序列文章&#xff0c;这一次的话题是《如何解决大模型的幻觉问题》 目录 大模型模型幻觉模型预训练庞大文本数据集语义关系 模型微调特定任务少量标签数据 如何解决普遍方法 大模型 先来…

java仓库管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java Web仓库管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0&…

双侧电源系统距离保护MATLAB仿真模型

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 系统原始数据 双侧电源系统模型如图所示&#xff1a; 仿真模型搭建 将线路AB分成Line1和Line2&#xff0c;将线路BC分成Line3和Line4&#xff0c;用三相电压电流测量模块作为系统母线&#xff0c;根据系统已…

我的NPI项目之设备系统启动(一) -- 客制化/给设备身份的CDT

做为设备设计和制造的公司&#xff0c;我们除了不能制造/生产PCB/PCBA/外壳&#xff0c;其它设备上的所有模块几乎都是自己设计的。那么&#xff0c;作为软件&#xff0c;会涉及到哪些设计内容呢&#xff1f; 选定主chipset/soc&#xff0c;例如qcmxxx/sdmxxx。根据chipset&am…

基于python+selenium的二次封装的实现

这是个人对selenium.webdriver写的一些常用操作的二次封装&#xff0c;也就相当于重写了&#xff0c;不再使用自带的框架&#xff0c;用自己写的框架完成。这样的话使代码更简洁&#xff0c;用自己的思想完成代码的编写。 首先在根目录下创建子目录名为Common作为公用数据&…

前缀和算法 -- [模版]一维前缀和

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 目录 本题链接 输入描述 输出描述 算法分析 算法一&#xff1a;暴力求解 算法二&#xff1a;前缀和 预处理前缀和dp表 使用前缀和dp表 解题源码 我们以一道题目为例详解一维前缀和原理。 本题链接 【模板】前缀和…

解决Redis序列化乱码问题

如果我们使用原生的JDK序列化&#xff0c;那么当我们将数据存储到Redis中就会出现乱码的情况 为了解决这个问题我们需要重写RedisTemplate从而解决序列化乱码问题 首先在Maven中引入相应的依赖 <dependency> <groupId>com.fasterxml.jackson.core</group…

ChatGPT 4.0真的值得花钱买入吗?

性能提升&#xff1a; ChatGPT 4.0的推出不仅意味着更先进的技术&#xff0c;还代表着更强大的性能。相较于3.5&#xff0c;4.0在处理任务时更为高效&#xff0c;响应更迅速。 更智能的理解&#xff1a; 随着版本的升级&#xff0c;ChatGPT 4.0对语境的理解能力得到了进一步的…

鸿蒙HarmonyOS- 弹框组件库

简介 今天介绍一个基于ArkUI框架开发的弹框组件库&#xff0c;该库基于ArkUI的弹框基础功能和自定义能力。针对通用的弹框业务场景&#xff0c;该库提供了丰富的组件弹窗功能。 包括确认输入弹窗、列表展示选择弹窗、自定义底部/顶部弹窗、自定义动画弹窗、自定义全屏弹窗、消息…

第十四章 :案例课:部暑KVM虚拟化平台

[rootLinux01 ~]# mount /dev/cdrom /mnt //挂载安装KVM需要的软件 [rootLinux01 ~]# yum -y install qemu-kvm-tools [rootLinux01 ~]# yum -y install qemu-kvm [rootLinux01 ~]# yum -y install virt-install [rootLinux01 ~]# yum -y install qemu-img [rootLinux01 ~]#…

自定义View之理解测量onMeasure和布局onLayout过程

Android应用的用户界面中&#xff0c;我们经常需要自定义View以满足特定的设计需求。在自定义视图的过程中&#xff0c;理解视图的测量&#xff08;onMeasure&#xff09;和布局&#xff08;onLayout&#xff09;过程至关重要。本篇博客将用通俗的语言&#xff0c;为你解析这两…

看似 bug 又非 bug 的一个 bug

最近的一个项目中&#xff0c;对于 CSS 的一些属性一些选择符可以大胆使用&#xff0c;然后很意外得撞上一个 iOS 中 Safari 的一个解析问题。 <Component style{{height: "calc(100vh - 46px)"}}>一个组件</Component> 这样的一段代码很简单&#xff…

浅谈接口自动化测试

昨晚在某个测试交流群&#xff0c;听了一个测试老司机分享接口自动化测试的内容&#xff0c;对接口自动化有了更深的一些认识&#xff0c;也为接下来公司的接口自动化实施&#xff0c;提供了更多的思路。 这篇博客&#xff0c;就说说功能测试到接口自动化的进阶&#xff0c;以及…

OS 7--DNS配置+Apache发布网站

环境准备 centOS 7 1.配置DNS 1.1 域名为lianxi.com 1.2 为WWW服务器、FTP服务器、NEWS服务器做域名解析 1)安装DNS yum -y install bind bind-utils (如果安装不上&#xff0c;就把磁盘在重洗挂载一下&#xff09; 2&#xff09;修改DNS配置文件 vim /etc/resolv.conf…

leetcode12 整数转罗马数字

题目描述&#xff1a;给定一个整数&#xff0c;将其转换为罗马数字。罗马数字由七个字符表示&#xff1a;I&#xff08;1&#xff09;、V&#xff08;5&#xff09;、X&#xff08;10&#xff09;、L&#xff08;50&#xff09;、C&#xff08;100&#xff09;、D&#xff08;5…