根据json构建uml类图代码工具实现

news2024/9/17 9:27:12

文章目录

  • 1.UML简介
    • 1.1 什么是UML建模
    • 1.2 使用UML建模的好处
  • 2.当前UML在研发场景下痛点
  • 3.UML工具的优化实现
    • 3.1 json结构设计
    • 3.2 json类图解析器实现
    • 3.3 在线uml类图渲染实现
      • 3.3.1 前端渲染页面
      • 3.3.2 后端数据接口
    • 3.4 在线渲染效果
  • 4. 总结

【摘要】本文介绍UML基本概念及相关类型作用,分析UML在研发场景下存在痛点, 分析改进思路,并阐述实现结构化json绘制uml类图的技术方案。最后总结下根据新技术方案,可进行的衍生拓展设计。

【关键词】: UML;JSON;建模

1.UML简介

1.1 什么是UML建模

UML(Unified Modeling Language,统一建模语言)是一种标准化的建模语言,用于在软件工程中可视化、描述、构建和记录软件系统的各种构件。UML图是用UML语言绘制的图表,用于表示系统的静态结构和动态行为。

下面主要列举一些常用的uml图如下

类图 (Class Diagram)

作用:表示系统中的类及其相互关系,描述系统的静态结构。
元素:类、接口、属性、方法、关联关系、继承关系、实现关系等。

用例图 (Use Case Diagram)

作用:展示系统的功能及其用户(称为参与者),描述系统的功能需求。
元素:用例、参与者、系统边界、关联关系等。

序列图 (Sequence Diagram)

作用:显示对象之间的交互及其调用顺序,描述系统的动态行为。
元素:对象、生命线、消息、激活等。

活动图 (Activity Diagram)

作用:表示系统中活动的流程,类似于流程图,用于描述业务流程或方法的逻辑。
元素:活动、决策节点、并行节点、开始和结束节点等。

状态图 (State Diagram)

作用:表示对象在生命周期中的状态变化及其触发事件。
元素:状态、转换、事件、起始状态、终止状态等。

组件图 (Component Diagram)

作用:展示系统的物理结构,表示系统中的软件组件及其关系。
元素:组件、接口、依赖关系等。

部署图 (Deployment Diagram)

作用:表示系统的硬件配置及其部署的组件。
元素:节点、组件、关联等。

对象图 (Object Diagram)

作用:显示系统在某个时刻的对象实例及其关系,是类图的实例化。
元素:对象、链接等。

1.2 使用UML建模的好处

系统设计和分析

  • 帮助系统设计人员和开发人员理解和设计系统的结构和行为。
  • 在系统开发的早期阶段,用于捕捉和分析需求。

文档记录

  • 提供系统的图形化文档,有助于维护和升级系统。
  • 作为开发过程中的参考资料。

沟通和交流

  • 帮助团队成员之间更好地沟通和交流系统的设计和需求。
  • 为项目利益相关者提供直观的系统视图。

代码生成和逆向工程

  • 有助于从模型生成代码或从代码生成模型,支持自动化开发工具。

质量保证和测试

  • 通过图形化的模型,可以更容易地发现系统设计中的问题和缺陷。
  • 有助于测试用例的设计和验证。

2.当前UML在研发场景下痛点

uml工具虽然好,但是在我们实际工作工作中,会发现大部分软件开发都没有使用起来。
原因笔者分析如下:

  1. 研发觉得开发前规范设计是额外的工作量,没有直接写代码来的快, 特别在项目周期短,甚至产品生命都不长的研发工作中,显得特别没有性价比。
  2. UML设计侧重点更多是设计沟通工具,UML建模和实际的代码之间关系,是比较弱的逻辑关系,而且需要人为手动维护。可能设计之初,UML建模和代码是一致的。但是随着产品迭代,UML忘记及时维护,就会UML版本落后于真实的代码。一个不准确的设计,对于理解系统可能会误导。这样反过来就导致更不愿意使用UML。

那么该如何解决呢?思路如下

  1. 互联网下班场更多的存量系统之间的竞争,系统运行时间长,业务复杂,拥有良好设计文档工具的系统更够降低维护成本,快速应对新需求。
  2. 从上面UML建模优点可以分析,UML实际上是可以作为代码生成的模板,也就是不仅仅是设计工具,也是代码的生产工具。笔者人为只有把uml和生产结合起来,才能保证保留UML建模优点,同时准确反映最新代码的设计。

有了解决思路下面围绕“代码即设计”和“设计及代码”的思路,来改变UML使用方式。

3.UML工具的优化实现

研发过程中绘制UML,主要有两种方式使用,在线UML建模网站的图形界面快速绘制和基于文本的图表绘制工具(mermaid/plantUML)

方式一: 以UML中的类图为例,在语雀的在线uml绘制类图
在这里插入图片描述
这种方式优点是方便快捷,可以最快方式绘图。确定依赖第三方,纯设计工具无法解析内容,实现拓展功能。

方式二:mermaid示例

classDiagram
    Animal <|-- Duck
    Animal <|-- Fish
    Animal <|-- Zebra
    Animal : +int age
    Animal : +String gender
    Animal: +isMammal()
    Animal: +mate()
    class Duck{
        +String beakColor
        +swim()
        +quack()
    }
    class Fish{
        -int sizeInFeet
        -canEat()
    }
    class Zebra{
        +bool is_wild
        +run()
    }

并通过解析器将这些文本渲染成图形效果:

Animal
+int age
+String gender
+isMammal()
+mate()
Duck
+String beakColor
+swim()
+quack()
Fish
-int sizeInFeet
-canEat()
Zebra
+bool is_wild
+run()

这种方式优点是可控性强,使用纯文本记录,和git管理工具结合可以版本化。缺点是需要手写,非技术人员上手难度大,而且符号很容易写错,导致图片渲染失败。

因此需要以下改进

  1. 非结构化的写法使用结构化,如使用json替代。
  2. json数据通过解析器自动翻译成mermaid的代码
  3. 支持在线实时预览

3.1 json结构设计

uml 分解为节点与边,分别代表类与类之间的关系。节点内部包含属性和方法,对应java的字段及成员方法

- 节点(数组)
	- 属性
	- 方法 
- 关系(数组)

json 示例

{
  "classDiagram": {
    "nodes": [
      {
        "id": "Order",
        "type": "AggregateRoot",
        "properties": [
          { "name": "orderId", "type": "String", "description": "订单 ID", "pk": true },
          { "name": "orderItems", "type": "List[OrderItem]", "description": "订单项列表" },
          { "name": "accountId", "type": "String", "description": "账户 ID" },
          { "name": "address", "type": "Address", "description": "地址对象" },
          { "name": "status", "type": "Integer", "description": "订单状态" },
          { "name": "createTime", "type": "Date", "description": "创建时间" },
          { "name": "updateTime", "type": "Date", "description": "更新时间" },
          { "name": "paymentTime", "type": "Date", "description": "支付时间" },
          { "name": "amount", "type": "BigDecimal", "description": "订单总金额" },
          { "name": "currency", "type": "String", "description": "货币类型", "defaultValue": "CNY" }
        ],
        "methods": [
          { "name": "addItem", "parameters": [{ "name": "product", "type": "Product" }, { "name": "quantity", "type": "int" }], "description": "添加商品到订单" },
          { "name": "removeItem", "parameters": [{ "name": "productId", "type": "String" }], "description": "移除商品" },
          { "name": "clearItems", "description": "清空订单项" },
          { "name": "calculateTotalPrice", "returnType": "BigDecimal", "description": "计算订单总金额" },
          { "name": "calculateGifts", "description": "计算赠品" },
          { "name": "verifyCloseStatus", "returnType": "Order", "description": "验证关闭状态" },
          { "name": "verifyOwner", "parameters": [{ "name": "accountId", "type": "String" }], "returnType": "Order", "description": "验证所有者" }
        ]
      },
      {
        "id": "OrderItem",
        "type": "Entity",
        "properties": [
          { "name": "itemId", "type": "String", "description": "订单项ID" , "pk": true},
          { "name": "product", "type": "ProductSnapShot", "description": "商品对象" },
          { "name": "quantity", "type": "int", "description": "数量" },
          { "name": "price", "type": "Price", "description": "价格对象" },
          { "name": "remarks", "type": "String", "description": "备注" }
        ]
      },
    
    ],
    "relationships": [
      { "source": "Order", "target": "OrderItem", "type": "contains", "description": "包含" }
    ]
  }
}


3.2 json类图解析器实现

public class MermaidClassDiagramGenerator {

    private static final Logger LOGGER = LoggerFactory.getLogger(MermaidClassDiagramGenerator.class);

    public static void main(String[] args) throws IOException {

        
        // 或者直接提交 JSON 内容进行解析
        String jsonContent = "{\n" +
                "  \"classDiagram\": {\n" +
                "    \"nodes\": [\n" +
                "      {\n" +
                "        \"id\": \"Order\",\n" +
                "        \"type\": \"AggregateRoot\",\n" +
                "        \"properties\": [\n" +
                "          {\n" +
                "            \"name\": \"orderId\",\n" +
                "            \"type\": \"String\",\n" +
                "            \"description\": \"订单 ID\",\n" +
                "            \"pk\": true\n" +
                "          }\n" +
                "        ],\n" +
                "        \"methods\": [],\n" +
                "        \"relationships\": []\n" +
                "      }\n" +
                "    ]\n" +
                "  }\n" +
                "}";
        String markdownFromContent = generateMermaidMarkdownFromContent(jsonContent);
        System.out.println(markdownFromContent);
    }

    public static String generateMermaidMarkdownFromFile(String jsonFilePath) throws IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode rootNode = objectMapper.readTree(new File(jsonFilePath));
        return generateMermaidMarkdown(rootNode);
    }

    public static String generateMermaidMarkdownFromContent(String jsonContent) throws IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode rootNode = objectMapper.readTree(jsonContent);
        return generateMermaidMarkdown(rootNode);
    }

    private static String generateMermaidMarkdown(JsonNode rootNode) {
        StringBuilder markdownBuilder = new StringBuilder();
//        markdownBuilder.append("<script class='mermaid'>\n");
        markdownBuilder.append("classDiagram\n\n");

        // Process nodes
        Iterator<JsonNode> nodesIterator = rootNode.path("classDiagram").path("nodes").elements();
        while (nodesIterator.hasNext()) {
            JsonNode node = nodesIterator.next();
            String id = node.path("id").asText();
            String type = node.path("type").asText();
            LOGGER.info("解析ID[{}] 类型[{}]", id, type);
            String classText = "class " + id + " {\n";
            if (!type.isEmpty()) {
                classText += "\t<< " + type + " >>\n";
            }
            markdownBuilder.append(classText);

            // Process properties
            Iterator<JsonNode> propertiesIterator = node.path("properties").elements();
            while (propertiesIterator.hasNext()) {
                JsonNode property = propertiesIterator.next();
                String propertyName = property.path("name").asText();
                String propertyType = property.path("type").asText();
                String propertyDescription = property.path("description").asText();
                String propertyExtra = property.path("pk").asBoolean() ? "[pk]" : "";
                String propertyText = "\t- " + propertyName + ": " + propertyType + " [" + propertyDescription + "]" + propertyExtra + "\n";

                markdownBuilder.append(propertyText);
                // 引用关系推断
                buildEntityRelationShip(propertyType, node, rootNode);

            }

            // Process methods
            Iterator<JsonNode> methodsIterator = node.path("methods").elements();
            while (methodsIterator.hasNext()) {
                JsonNode method = methodsIterator.next();
                String methodName = method.path("name").asText();
                String methodReturnType = method.path("returnType").asText();
                String methodDescription = method.path("description").asText();
                StringBuilder parametersBuilder = new StringBuilder();
                Iterator<JsonNode> parametersIterator = method.path("parameters").elements();
                while (parametersIterator.hasNext()) {
                    JsonNode parameter = parametersIterator.next();
                    String parameterName = parameter.path("name").asText();
                    String parameterType = parameter.path("type").asText();
                    parametersBuilder.append(parameterName).append(": ").append(parameterType).append(", ");
                }
                if (parametersBuilder.length() > 0) {
                    parametersBuilder.setLength(parametersBuilder.length() - 2); // Remove the trailing comma and space
                }
                String methodText = "\t+ ";
                if (!methodReturnType.isEmpty()) {
                    methodText += methodReturnType + " ";
                } else {
                    methodText += "void ";
                }
                methodText += methodName + "(" + parametersBuilder.toString() + ") : " + methodDescription + "\n";
                markdownBuilder.append(methodText);
            }

            markdownBuilder.append("}\n\n");
        }

        // Process relationships
        Iterator<JsonNode> relationshipsIterator = rootNode.path("classDiagram").path("relationships").elements();
        while (relationshipsIterator.hasNext()) {
            JsonNode relationship = relationshipsIterator.next();
            String source = relationship.path("source").asText();
            String target = relationship.path("target").asText();
            String type = relationship.path("type").asText();
            String description = relationship.path("description").asText();
            String relationshipText = "";
            if ("contains".equals(type) || "has".equals(type)) {
                relationshipText = source + " *-- " + target + " : " + type + "\n";
            } else if ("use".equals(type)) {
                relationshipText = source + " ..> " + target + " : " + type + "\n";
            }
            markdownBuilder.append(relationshipText);
        }

//        markdownBuilder.append("</script>\n");
        System.out.println(markdownBuilder);
        return markdownBuilder.toString();
    }

    private static void buildEntityRelationShip(String propertyType, JsonNode currentNode, JsonNode rootNode) {
        ObjectMapper objectMapper = new ObjectMapper();
        ObjectNode classDiagramNode = (ObjectNode) rootNode.path("classDiagram");
        ArrayNode relationshipsNode;

        if (classDiagramNode.has("relationships")) {
            relationshipsNode = (ArrayNode) classDiagramNode.path("relationships");
        } else {
            relationshipsNode = objectMapper.createArrayNode();
            classDiagramNode.set("relationships", relationshipsNode);
        }

        Iterator<JsonNode> nodesIterator = rootNode.path("classDiagram").path("nodes").elements();
        String realType = propertyType;
        if (propertyType.endsWith("[]")) { // 解析数组类型如 Date[]
            realType = propertyType.substring(0, propertyType.length() - 2);
        } else if (propertyType.startsWith("List[")) {
            realType = propertyType.substring(5, propertyType.length() - 1);
        }

        while (nodesIterator.hasNext()) {
            JsonNode node = nodesIterator.next();
            String id = node.path("id").asText();
            if (realType.equals(id)) {
                String source = currentNode.path("id").asText();
                String target = node.path("id").asText();


                // Check if the relationship already exists
                boolean relationshipExists = false;
                Iterator<JsonNode> existingRelationships = relationshipsNode.elements();
                while (existingRelationships.hasNext()) {
                    JsonNode existingRelationship = existingRelationships.next();
                    if (existingRelationship.path("source").asText().equals(source) &&
                            existingRelationship.path("target").asText().equals(target)) {
                        relationshipExists = true;
                        break;
                    }
                }

                // If relationship does not exist, add it
                if (!relationshipExists) {
                    ObjectNode relationshipNode = objectMapper.createObjectNode();
                    relationshipNode.put("source", source);
                    relationshipNode.put("target", target);
                    relationshipNode.put("type", "has");
                    relationshipsNode.add(relationshipNode);
                }
            }
        }
    }
}


3.3 在线uml类图渲染实现

3.3.1 前端渲染页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/mermaid@10.7.0/dist/mermaid.min.js"></script>
</head>
<body>

<div>
    <label for="diagram-input">Diagram Type:</label>
    <input type="text" id="diagram-input" value="class_diagram">
    <button id="button_1" type="button" onclick="fetchAndRender()">实时渲染</button>
</div>
<div id="mermaid-container">


</div>
</body>

<script  type="text/javascript">

    function fetchAndRender() {
        var rootValue = $('#diagram-input').val();
        $.ajax({
            url: 'mermaid/classDiagram', // Replace 'your_backend_url' with your actual backend URL
            data: {root: rootValue},
            method: 'GET',
            success: function(response) {
                renderMermaid(response.data);
            },
            error: function(xhr, status, error) {
                console.error('Error fetching data:', error);
            }
        });
    }

    function renderMermaid(graphDefinition) {
        console.log(graphDefinition)
        $('#mermaid-container').html(graphDefinition).removeAttr('data-processed');
        mermaid.init(undefined, $("#mermaid-container"));
    }

    // Call fetchAndRender() once when the page loads to initially render the graph
    $(document).ready(function() {
        // fetchAndRender();
    });
</script>
</html>

3.3.2 后端数据接口

package com.sample.controller;

import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.io.InputStream;
import java.text.MessageFormat;
import java.util.Map;

@RestController
public class MermaidController {

    @GetMapping("/mermaid/classDiagram")
    public Map<String, Object> getClassDiagram(String root) throws IOException {
        Resource data = new ClassPathResource(MessageFormat.format("data/{0}.json", root));
        if (!data.exists()) {
            data = new ClassPathResource("data/class_diagram_v1.json");
        }

        try (InputStream inputStream = data.getInputStream()) {
            String json = new String(FileCopyUtils.copyToByteArray(inputStream));
            // 根据json生成mermaid的语法构建uml类图
            String classDiagram = MermaidClassDiagramGenerator.generateMermaidMarkdownFromContent(json);
            return Map.of("data",  classDiagram);
        }
    }

}

3.4 在线渲染效果

在这里插入图片描述
完整json示例

{
  "classDiagram": {
    "nodes": [
      {
        "id": "Order",
        "type": "AggregateRoot",
        "properties": [
          { "name": "orderId", "type": "String", "description": "订单 ID", "pk": true },
          { "name": "orderItems", "type": "List[OrderItem]", "description": "订单项列表" },
          { "name": "accountId", "type": "String", "description": "账户 ID" },
          { "name": "address", "type": "Address", "description": "地址对象" },
          { "name": "status", "type": "Integer", "description": "订单状态" },
          { "name": "createTime", "type": "Date", "description": "创建时间" },
          { "name": "updateTime", "type": "Date", "description": "更新时间" },
          { "name": "paymentTime", "type": "Date", "description": "支付时间" },
          { "name": "amount", "type": "BigDecimal", "description": "订单总金额" },
          { "name": "currency", "type": "String", "description": "货币类型", "defaultValue": "CNY" }
        ],
        "methods": [
          { "name": "addItem", "parameters": [{ "name": "product", "type": "Product" }, { "name": "quantity", "type": "int" }], "description": "添加商品到订单" },
          { "name": "removeItem", "parameters": [{ "name": "productId", "type": "String" }], "description": "移除商品" },
          { "name": "clearItems", "description": "清空订单项" },
          { "name": "calculateTotalPrice", "returnType": "BigDecimal", "description": "计算订单总金额" },
          { "name": "calculateGifts", "description": "计算赠品" },
          { "name": "verifyCloseStatus", "returnType": "Order", "description": "验证关闭状态" },
          { "name": "verifyOwner", "parameters": [{ "name": "accountId", "type": "String" }], "returnType": "Order", "description": "验证所有者" }
        ]
      },
      {
        "id": "OrderItem",
        "type": "Entity",
        "properties": [
          { "name": "itemId", "type": "String", "description": "订单项ID" , "pk": true},
          { "name": "product", "type": "ProductSnapShot", "description": "商品对象" },
          { "name": "quantity", "type": "int", "description": "数量" },
          { "name": "price", "type": "Price", "description": "价格对象" },
          { "name": "remarks", "type": "String", "description": "备注" }
        ]
      },
      {
        "id": "Address",
        "type": "ValueObject",
        "properties": [
          { "name": "street", "type": "String", "description": "街道" },
          { "name": "city", "type": "String", "description": "城市" },
          { "name": "state", "type": "String", "description": "省份" },
          { "name": "zipCode", "type": "String", "description": "邮政编码" }
        ]
      },
      {
        "id": "Price",
        "type": "ValueObject",
        "properties": [
          { "name": "amount", "type": "BigDecimal", "description": "金额" },
          { "name": "currency", "type": "String", "description": "货币类型" }
        ]
      },
      {
        "id": "ProductSnapShot",
        "type": "ValueObject",
        "properties": [
          { "name": "id", "type": "Long", "description": "商品 ID" },
          { "name": "code", "type": "String", "description": "商品编码" },
          { "name": "name", "type": "String", "description": "商品名称" },
          { "name": "price", "type": "Price", "description": "商品价格" }
        ]
      },
      {
        "id": "Product",
        "type": "Entity",
        "properties": [
          { "name": "id", "type": "Long", "description": "商品 ID" },
          { "name": "code", "type": "String", "description": "商品编码" },
          { "name": "productName", "type": "String", "description": "商品名称" },
          { "name": "price", "type": "Price", "description": "商品价格" }
        ]
      },
      {
        "id": "OrderDomainService",
        "type": "DomainService",
        "methods": [
          { "name": "addItem", "parameters": [{ "name": "product", "type": "Product" }, { "name": "quantity", "type": "int" }], "description": "添加商品到订单" },
          { "name": "removeItem", "parameters": [{ "name": "productId", "type": "String" }], "description": "移除商品" },
          { "name": "clearItems", "description": "清空订单项" },
          { "name": "verifyCloseStatus", "returnType": "Order", "description": "验证关闭状态" },
          { "name": "verifyOwner", "parameters": [{ "name": "accountId", "type": "String" }], "returnType": "Order", "description": "验证所有者" }
        ]
      },
      {
        "id": "OrderAppService",
        "type": "AppService",
        "methods": [
          { "name": "bpmnInvoke", "description": "流程编排" }
        ]
      },
      {
        "id": "OrderInterfaceService",
        "type": "Service"
      },
      {
        "id": "OrderPageQuery",
        "type": "Query",
        "properties": [
          { "name": "productName", "type": "String", "description": "商品名称"},
          { "name": "createTime", "type": "Date", "description": "订单创建时间" }
        ],
        "methods": [
          { "name": "invoke", "description": "执行查询", "returnType": "List[OrderPageQueryDTO]"}
        ]
      },
      {
        "id": "OrderDetailQuery",
        "type": "Query",
        "properties": [
          { "name": "orderId", "type": "String", "description": "订单 ID"}
        ]
      },
      {
        "id": "OrderPageQueryDTO",
        "type": "DTO",
        "properties": [
          { "name": "orderId", "type": "String", "description": "订单 ID" },
          { "name": "accountId", "type": "String", "description": "账户 ID" },
          { "name": "address", "type": "Address", "description": "地址对象" },
          { "name": "status", "type": "Integer", "description": "订单状态" },
          { "name": "createTime", "type": "Date", "description": "创建时间" },
          { "name": "updateTime", "type": "Date", "description": "更新时间" },
          { "name": "paymentTime", "type": "Date", "description": "支付时间" },
          { "name": "amount", "type": "BigDecimal", "description": "订单总金额" },
          { "name": "currency", "type": "String", "description": "货币类型", "defaultValue": "CNY" }
        ]
      }

    ]
  }
}

4. 总结

本文分析UML作用及使用现状,并且通过json结构方式实现的UML模型中类图构建,降低了文本解析的绘图成本。同时后续可以根据json结构化信息,已经包含了类描述信息,可以从两个方向进行进一步伸延设计。

  • 根据类图定义注册接口
  • 根据类定义自动生成数据库定义

通过这样思路可以将UML建模和后续工作结合起来,设计工具变成代码生产的工具,或者设计出低代码工具。

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

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

相关文章

Linux中安装C#的.net,创建运行后端或控制台项目

安装脚本命令&#xff1a; 创建一个sh文件并将该文件更改权限运行 sudo apt update wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb sudo dpkg -i packages-microsoft-prod.deb sudo apt-get upd…

科普文:Spring Cloud Alibaba在GraalVM上的性能测试

GraalVM 介绍 GraalVM概述 - Spring Cloud Alibaba官网 科普文&#xff1a;GraalVM简介-CSDN博客 科普文&#xff1a;OpenJDK vs. GraalVM vs. Amazon Corretto性能测试-CSDN博客 科普文&#xff1a;【方向盘】OpenJDK生态圈-CSDN博客 科普文&#xff1a;Oracle JDK收费后…

【32单片机篇】项目:实时时钟

一、项目需求 1. OLED屏幕显示当前时间、日期、闹钟等信息&#xff1b; 2. 正常模式下&#xff0c;按下 KEY1 &#xff0c;进入时间设置模式&#xff0c;此时按下 KEY2 则可以循环跳转修改秒、分、时、日、月、年&#xff1b; 3. 时间设置模式下&#xff0c;KEY3 增加数值&…

【Redis】如何利用 Redis 实现一个分布式锁?

&#x1f44f;大家好&#xff01;我是和风coding&#xff0c;希望我的文章能给你带来帮助&#xff01; &#x1f525;如果感觉博主的文章还不错的话&#xff0c;请&#x1f44d;三连支持&#x1f44d;一下博主哦 &#x1f4dd;点击 我的主页 还可以看到和风的其他内容噢&#x…

【优秀python算法设计】基于Python网络爬虫的今日头条新闻数据分析与热度预测模型构建的设计与实现

1 绪论 1.1 背景与意义 随着互联网的快速发展和移动互联技术的普及&#xff0c;作为新兴的资讯平台&#xff0c;今日头条成为了用户获取新闻资讯、时事热点和个性化推荐的重要渠道。大量用户在今日头条上浏览、阅读并产生热度&#xff0c;使得今日头条成为了观察舆论热点和分…

Csrf复习(pikachu靶场和防御手段)

CSRF漏洞简介 CSRF又称跨站请求伪造&#xff0c;是指攻击者在用户登录的状态下&#xff08;浏览器保存了用户的cookie&#xff09;通过伪造恶意url诱导用户点击&#xff0c;借助用户的cookie网站权限&#xff08;冒充用户身份来进行非法操作&#xff0c;对于服务器来说是合法的…

达梦数据库系列—36.分区表

目录 1、分区表的分类 1.1 范围分区表 1.2 List分区表 1.3 哈希分区表 1.4 多级分区表 二级分区 三级分区 2、分区表的维护 2.1 增加分区 2.2 删除分区 2.3 交换分区 2.4 融合分区 3、全局索引和局部索引 1、分区表的分类 范围(range)水平分区&#xff1a;对表中…

【LLM大模型】AI大模型大厂面试真题:「2024大厂大模型技术岗内部面试题+答案」

AI大模型岗的大厂门槛又降低了&#xff01;实在太缺人了&#xff0c;大模型岗位真的强烈建议各位多投提前批&#xff0c;▶️众所周知&#xff0c;2025届秋招提前批已经打响&#xff0c;&#x1f64b;在这里真心建议大家6月7月一定要多投提前批&#xff01; &#x1f4bb;我们…

【深度学习|目标跟踪】SSD+Sort实现MOT!

SSDSort实现目标跟踪 源码地址1、&#x1f64c;&#x1f3fb;匈牙利匹配算法1.1 什么是匈牙利匹配1.2 什么是二分图&#xff1a;1.3 最大匹配1.4 最优匹配1.5 最小点覆盖1.6 交替路1.7 增广路1.8 匈牙利匹配具体流程以及实例1.9 广度优先匹配1.10 深度优先匹配1.11 给匹配加权来…

SQL—数据库与表操作

目录 SQL语句分类 DDL 数据库操作 1. 查询所有数据库 2. 查询当前数据库 3. 创建数据库 案例&#xff1a;创建一个itcast数据库&#xff0c;使用数据库默认的字符集 案例&#xff1a;创建一个itheima数据库&#xff0c;并且指定字符集 4. 删除数据库 5. 切换数据库…

Java从入门到精通 (十) ~ 计算机是如何工作的呢 ?

每天进步一点点&#xff0c;每天创造一点点&#xff0c;每天做事多一点&#xff0c;愿你事事都领先&#xff0c;卓越成绩现眼前&#xff0c;美好生活一天又一天。 文章目录 目录 前言 前置知识 认识一下计算机的真实相貌 都说计算机使用二进制传输&#xff0c;为什么要使…

哇!0.8秒启动!Linux快速启动方案分享,全志T113-i国产平台!

本文主要介绍基于创龙科技TLT113-EVM评估板(基于全志T113-i)的系统快速启动方案,适用开发环境如下。 Windows开发环境:Windows 7 64bit、Windows 10 64bit 虚拟机:VMware15.5.5 Linux开发环境:Ubuntu18.04.4 64bit U-Boot:U-Boot-2018.07 Kernel:Linux-5.4.61、Li…

政策收紧下,给EI人的一个小建议!

自中央大力推动文化体制改革、促进文化产业加快发展以来&#xff0c;我国出版业的数字化转型升级工作拉开序幕。其后&#xff0c;得益于新技术的发展、市场趋势的变化&#xff0c;数字出版开始出现“井喷”&#xff0c;出版融合成绩巨大&#xff0c;但也面临诸多挑战&#xff0…

手持气象站:便携与精准的完美结合

在气象监测领域&#xff0c;手持气象站以其独特的优势特点&#xff0c;正逐渐成为专业人士和爱好者的首选工具。这款小巧而强大的设备&#xff0c;将便携性与精准性完美融合&#xff0c;为各种户外活动和科学研究提供了极大的便利。 首先&#xff0c;手持气象站的最大亮点在于其…

虚拟主播实时直播技术方案:以年轻人互动方式探索直播新玩法2

随着互联网将内容传播的渠道变得逐渐丰富&#xff0c;观众对直播内容形式、互动玩法的多元化要求越来越高&#xff0c;文旅、电商、企业品牌、广电、泛娱乐MCN、游戏动漫等等领域纷纷主动迎合Z世代喜好&#xff0c;利用虚拟人直播内容抢夺观众的注意力&#xff0c;以独特的虚拟…

2024 杭电多校 第四场

分组 给定 n 个正整数 a1,a2,…,an (1≤ai<2m) 以及 0 到 2m−1 的权重 w0,w1,…,w2m−1&#xff1b;你需要把这 n 个正整数分成四组 A,B,C,D&#xff0c;令 f(A),f(B),f(C),f(D) 分别表示每组中所有数字的异或和&#xff0c;你的分组方案需要最小化 wf(A),wf(B),wf(C),wf(…

智慧社区的秘密武器:数据可视化的力量

在现代城市的发展中&#xff0c;智慧社区已成为提升居民生活品质和管理效率的重要方式。而数据可视化作为信息技术的关键工具&#xff0c;正是实现智慧社区目标的强大助推器。通过将复杂的数据转化为直观的图表和可视化图像&#xff0c;数据可视化不仅能够帮助社区管理者快速理…

前端工具专有名词记录

目录 前言 正文 1.包管理器 2.构建工具和开发环境&#xff08;项目管理器&#xff09; 3.自动化测试工具 4.JavaScript 框架和模版 5.代码质量工具 尾声 &#x1f52d; Hi,I’m Pleasure1234&#x1f331; I’m currently learning Vue.js,SpringBoot,Computer Security and so…

全新小体积RK3562核心板,解锁神秘技能!

RK3562小体积金手指系列核心板基于瑞芯微四核Cortex-A53Cortex-M0处理器设计&#xff0c;工作主频高达2GHz&#xff0c;最高搭载4GB高速LPDDR4、32GB eMMC。该核心板拥有204 Pin脚&#xff0c;尺寸仅为67.6mm *45mm&#xff0c;支持千兆网、USB3.0、串口、PCIE、HDMI等丰富外设…

vite tsx项目的element plus集成 - 按需引入踩坑

前面我们进行了开源组件的自研&#xff0c;很多组件可直接用现成的开源组件库&#xff0c;并不需要自己重复造轮子&#xff0c;为此我们讲如何在当前vite vitepress tsx技术整合的项目中实现element plus组件的按需引入&#xff0c;同时解决遇到的一些坑。 安装Element Plus…