通过postgresql的Ltree字段类型实现目录结构的基本操作

news2024/9/25 15:24:07

通过postgresql的Ltree字段类型实现目录结构的基本操作

将这种具有目录结构的excel表存储到数据库中,可以采用树型结构存储[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZLXAzpxj-1691660171264)(C:\Users\20745\AppData\Roaming\Typora\typora-user-images\image-20230810172124733.png)]

DROP TABLE IF EXISTS "public"."directory_tree";
CREATE TABLE "public"."directory_tree" (
  "id" varchar(100) COLLATE "pg_catalog"."default",
  "path" "public"."ltree",
  "name" varchar(100) COLLATE "pg_catalog"."default" NOT NULL,
  "description" text COLLATE "pg_catalog"."default",
  "updated_at" timestamp(6) DEFAULT now(),
  "created_at" timestamp(6) DEFAULT now()
)
;

-- ----------------------------
-- Records of directory_tree
-- ----------------------------
INSERT INTO "public"."directory_tree" VALUES ('04e19944aa1d3d8bc13971b4488a4e0d', '04e19944aa1d3d8bc13971b4488a4e0d', 'root', 'root', '2023-08-09 02:11:35.145821', '2023-08-09 02:11:35.145821');

上面是建一张表,并且插入一条根节点。这里我们的id是mybatisPuls提供的UUID,并且我们的path字段采用祖id+爷id+父id+子id的结构。这是处理excel表格的工具类

package com.cdcas.utils;

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.*;

/**
 * @author jiao xn
 * @date 2023/4/20 22:44
 * @description
 */
@Component
public class ExcelUtil {
    /**
     * 根据文件地址,读取指定 Excel 文件的内容,并以对象数组的方式返回
     *
     * @param excelFilePath Excel 文件地址
     * @param sheetIndex 指定 Sheet 的索引值,从 0 开始
     * @param startLine 开始读取的行:从0开始
     * @param tailLine 去除最后读取的行
     * @return Excel 文件内容,对象数组
     */
    public List<Map<String, String>> readExcelFile(String excelFilePath, Integer sheetIndex, Integer startLine
            , Integer tailLine) {
        Workbook workbook = this.generateWorkbook(excelFilePath);
        return this.readExcelSheetToObject(workbook, sheetIndex, startLine, tailLine);
    }

    /**
     * 从 MultipartFile 中读取 Excel 文件的内容,并以对象数组的方式返回
     *
     * @param multipartFile MultipartFile 对象,一般是从前端接收
     * @param sheetIndex 指定 Sheet 的索引值,从 0 开始
     * @param startLine 开始读取的行:从0开始
     * @param tailLine 去除最后读取的行
     * @return Excel 文件内容,对象数组
     */
    public List<Map<String, String>> readExcelFile(MultipartFile multipartFile, Integer sheetIndex, Integer startLine
            , Integer tailLine) {
        Workbook workbook = this.generateWorkbook(multipartFile);
        return this.readExcelSheetToObject(workbook, sheetIndex, startLine, tailLine);
    }

    /**
     * 生成 Workbook 对象
     *
     * @param excelFilePath Excel 文件路径
     * @return Workbook 对象,允许为空
     */
    private Workbook generateWorkbook(String excelFilePath) {
        Workbook workbook;

        try {
            File excelFile = new File(excelFilePath);
            workbook = WorkbookFactory.create(excelFile);
        } catch (IOException | InvalidFormatException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }

        return workbook;
    }
    /**
     * 生成 Workbook 对象
     *
     * @param multipartFile MultipartFile 对象
     * @return Workbook 对象
     */
    private Workbook generateWorkbook(MultipartFile multipartFile) {
        Workbook workbook;

        try {
            workbook = WorkbookFactory.create(multipartFile.getInputStream());
        } catch (IOException | InvalidFormatException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }

        return workbook;
    }

    /**
     * 读取指定 Sheet 中的数据
     *
     * @param workbook Workbook 对象
     * @param sheetIndex 指定 Sheet 的索引值,从 0 开始
     * @param startLine 开始读取的行:从0开始
     * @param tailLine 去除最后读取的行
     * @return 指定 Sheet 的内容
     */
    private List<Map<String, String>> readExcelSheetToObject(Workbook workbook,
                                                             Integer sheetIndex, Integer startLine, Integer tailLine) {
        List<Map<String, String>> result = new ArrayList<>();

        Sheet sheet = workbook.getSheetAt(sheetIndex);

        // 获取第一行内容,作为标题内容
        Row titileRow = sheet.getRow(0);
        Map<String, String> titleContent = new LinkedHashMap<>();
        for (int i = 0; i < titileRow.getLastCellNum(); i++) {
            Cell cell = titileRow.getCell(i);
            titleContent.put(cell.getStringCellValue(), cell.getStringCellValue());
        }
        result.add(titleContent);

        // 获取正文内容
        Row row;
        for (Integer i = startLine; i < sheet.getLastRowNum() - tailLine + 1; i++) {
            row = sheet.getRow(i);
            Map<String, String> rowContent = new HashMap<>();

            for (Cell cell : row) {
                String returnStr;
                boolean isMergedCell  = this.isMergedCell(sheet, i, cell.getColumnIndex());

                if (isMergedCell) {
                    returnStr = this.getMergedRegionValue(sheet, row.getRowNum(), cell.getColumnIndex());
                } else {
                    returnStr = cell.getRichStringCellValue().getString();
                }

                rowContent.put(titileRow.getCell(cell.getColumnIndex()).getStringCellValue(), returnStr);
            }
            result.add(rowContent);
        }

        return result;
    }

    /**
     * 判断指定的单元格是否是合并单元格
     *
     * @param sheet Excel 指定的 Sheet 表
     * @param row 行下标
     * @param column 列下标
     * @return 是否为合并的单元格
     */
    private boolean isMergedCell(Sheet sheet, int row, int column) {
        int sheetMergeCount = sheet.getNumMergedRegions();
        for (int i = 0; i < sheetMergeCount; i++) {
            CellRangeAddress range = sheet.getMergedRegion(i);
            int firstColumn = range.getFirstColumn();
            int lastColumn = range.getLastColumn();
            int firstRow = range.getFirstRow();
            int lastRow = range.getLastRow();
            if(row >= firstRow && row <= lastRow && (column >= firstColumn && column <= lastColumn)){
                return true;
            }
        }
        return false;
    }

    /**
     * 获取合并单元格的值
     *
     * @param sheet 指定的值
     * @param row 行号
     * @param column 列好
     * @return 合并单元格的值
     */
    private String getMergedRegionValue(Sheet sheet, int row, int column){
        int sheetMergeCount = sheet.getNumMergedRegions();
        for(int i = 0 ; i < sheetMergeCount ; i++){
            CellRangeAddress ca = sheet.getMergedRegion(i);
            int firstColumn = ca.getFirstColumn();
            int lastColumn = ca.getLastColumn();
            int firstRow = ca.getFirstRow();
            int lastRow = ca.getLastRow();
            if(row >= firstRow && row <= lastRow && (column >= firstColumn && column <= lastColumn)) {
                Row fRow = sheet.getRow(firstRow);
                Cell fCell = fRow.getCell(firstColumn);
                return this.getCellValue(fCell) ;
            }
        }
        return null ;
    }

    /**
     * 获取单元格的值
     *
     * @param cell Cell 对象
     * @return 单元格的值
     */
    private String getCellValue(Cell cell){
        if(cell == null) {
            return "";
        }

        if(cell.getCellTypeEnum() == CellType.STRING){
            return cell.getStringCellValue();
        } else if(cell.getCellTypeEnum() == CellType.BOOLEAN){
            return String.valueOf(cell.getBooleanCellValue());
        } else if(cell.getCellTypeEnum() == CellType.FORMULA){
            return cell.getCellFormula() ;
        } else if(cell.getCellTypeEnum() == CellType.NUMERIC){
            return String.valueOf(cell.getNumericCellValue());
        }

        return "";
    }
}

下面是将生成的List<Map<String, String>> excel数据插入到excel表中的工具类

package com.cdcas;

import com.cdcas.mapper.DirectoryTreeMapper;
import com.cdcas.pojo.DirectoryTree;
import com.cdcas.utils.ExcelDataUtil;
import com.cdcas.utils.ExcelUtil;
import org.junit.jupiter.api.Test;
import org.junit.platform.commons.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.util.CollectionUtils;

import java.io.FileInputStream;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

/**
 * @version 1.0
 * @Author zhaozhixin
 * @Date 2023/8/7 15:01
 * @注释
 */   //983
@SpringBootTest
public class Test2 {

    /**
     * 替换和插入
     *
     * @param parentPath
     * @param directoryTree
     */
    private String Insert(String parentPath, DirectoryTree directoryTree, String name) {
        directoryTree.setName(name);
        directoryTree.setDescription(parentPath);
        directoryTreeMapper.insert(directoryTree);
        directoryTree.setPath(parentPath + "." + directoryTree.getId());
        directoryTreeMapper.updateDirectoryTree(directoryTree);
        return directoryTree.getId();
    }

    /**
     * 通过名称查询父路径
     *
     * @param name
     * @return
     */
    private String getParentPathByName(String name) {
        DirectoryTree parent = directoryTreeMapper.getOneByName(name);
        return parent.getPath();
    }

    @Test
    public void get() {
        String path = directoryTreeMapper.getPath(1);
        System.out.println(path);
    }

    @Autowired
    private ExcelUtil excelUtil;

    @Autowired
    private ExcelDataUtil excelDataUtil;
    @Autowired
    private DirectoryTreeMapper directoryTreeMapper;

    @Test
    public void insert() throws Exception {
        //读取一个excel
        List<Map<String, String>> maps = excelUtil.readExcelFile("C:\\Users\\20745\\Desktop\\git库\\gitee\\pg-demo-itree\\src\\main\\resources\\国土规划目录树.xlsx", 0, 1, 0);
        maps.remove(0);
        System.out.println(maps);
        for (Map<String, String> map : maps) {
            String A1 = map.get("A1");
            String A2 = map.get("A2");
            String A3 = map.get("A3");
            String A4 = map.get("A4");
            String A5 = map.get("A5");
            String A6 = map.get("A6");
            String A7 = map.get("A7");
            String A8 = map.get("A8");
            String A9 = map.get("A9");
            StringBuilder parentPath = new StringBuilder();//用来拼接父节点id
            parentPath.append("04e19944aa1d3d8bc13971b4488a4e0d");//这是根节点id
            if (A1 != null && !"".equals(A1)) {
                    //二级节点  根节点为root
                    DirectoryTree directoryTree = new DirectoryTree();
                    String name = A1;
                    String id = isExtis(name, directoryTree, parentPath.toString());
                    if (id==null){

                    }else {
                        parentPath.append(".").append(id);
                    }
            }
            if (A2 != null && !"".equals(A2)) {
                    //拿到所有同名的行
                    DirectoryTree directoryTree = new DirectoryTree();
                    String name = A2;
                    String id = isExtis(name, directoryTree, parentPath.toString());
                    if (id==null){
                    }else {
                        parentPath.append(".").append(id);
                    }
            }
            if (A3 != null && !"".equals(A3)) {
                    DirectoryTree directoryTree = new DirectoryTree();
                    String name = A3;
                    String id = isExtis(name, directoryTree, parentPath.toString());
                    if (id==null){
                    }else {
                        parentPath.append(".").append(id);
                    }
            }
            if (A4 != null && !"".equals(A4)) {
                    DirectoryTree directoryTree = new DirectoryTree();
                    String name = A4;
                    String id = isExtis(name, directoryTree, parentPath.toString());
                    if (id==null){
                    }else {
                        parentPath.append(".").append(id);
                    }
            }
            if (A5 != null && !"".equals(A5)) {
                    DirectoryTree directoryTree = new DirectoryTree();
                    String name = A5;
                    String id = isExtis(name, directoryTree, parentPath.toString());
                    if (id==null){
                    }else {
                        parentPath.append(".").append(id);
                    }
            }
            if (A6 != null && !"".equals(A6)) {
                    DirectoryTree directoryTree = new DirectoryTree();
                    String name = A6;
                    String id = isExtis(name, directoryTree, parentPath.toString());
                    if (id==null){
                    }else {
                        parentPath.append(".").append(id);
                    }
            }
            if (A7 != null && !"".equals(A7)) {
                    DirectoryTree directoryTree = new DirectoryTree();
                    String name = A7;
                    String id = isExtis(name, directoryTree, parentPath.toString());
                    if (id==null){
                    }else {
                        parentPath.append(".").append(id);
                    }
            }
            if (A8 != null && !"".equals(A8)) {
                    DirectoryTree directoryTree = new DirectoryTree();
                    String name = A8;
                    String id = isExtis(name, directoryTree, parentPath.toString());
                    if (id==null){
                    }else {
                        parentPath.append(".").append(id);
                    }
                }
            if (A9 != null && !"".equals(A9)) {
                    DirectoryTree directoryTree = new DirectoryTree();
                    String name = A9;
                    String id = isExtis(name, directoryTree, parentPath.toString());
                    if (id==null){
                    }else {
                        parentPath.append(".").append(id);
                    }
            }
        }
    }

    /**
     * 判断一个同名的是否存在在其它数 返回当前节点id
     * @param name
     * @param directoryTree
     * @param parentPath
     */
    private String isExtis(String name,DirectoryTree directoryTree,String parentPath){
        //最终标识  开始表明不存在
        boolean isExtis = false;
        //获取到所有的和name同名的行
        List<DirectoryTree> oneByNames = directoryTreeMapper.getListByName(name);
        //如果没有同名的直接插入
        if (CollectionUtils.isEmpty(oneByNames)){
            directoryTree.setName(name);
            directoryTree.setDescription(parentPath);
            directoryTreeMapper.insert(directoryTree);
            directoryTree.setPath(parentPath+"."+directoryTree.getId());
            directoryTreeMapper.updateDirectoryTree(directoryTree);
            return directoryTree.getId();
        }
        //如果有同名的,需要判断父路径是否相同
        String path = "";
        int lastIndexOf = 0;
        for (DirectoryTree oneByName : oneByNames) {
            if (oneByName!=null) {
                path = oneByName.getPath();
                lastIndexOf = path.lastIndexOf(".");
            }
            //重复的数据应该也要被插入进去  查出的父路径传入的父路径进行对比
            if (path.substring(0,lastIndexOf).equals(parentPath)){
                isExtis = true;
            }
        }
        //最后如果同名的数据但是父路径不相同,就需要插入进去
        if (!isExtis){
                directoryTree.setName(name);
                directoryTree.setDescription(parentPath);
                directoryTreeMapper.insert(directoryTree);
                directoryTree.setPath(parentPath+"."+directoryTree.getId());
                directoryTreeMapper.updateDirectoryTree(directoryTree);
            return directoryTree.getId();
        }
        return oneByNames.get(oneByNames.size()-1).getId();
    }
    //查看重复条数和 总条数
    @Test
    public void look() throws Exception {
        FileInputStream fileInputStream = new FileInputStream("C:\\Users\\20745\\Desktop\\git库\\gitee\\pg-demo-itree\\src\\main\\resources\\国土规划目录树.xlsx");
        List<Map<String, String>> maps = excelDataUtil.readExcel(fileInputStream);

        int count = 0;
        HashSet<String> set = new HashSet();
        for (Map<String, String> map : maps) {
            if (StringUtils.isNotBlank(map.get("A1"))) {
                set.add(map.get("A1"));
                count++;
            }
            if (StringUtils.isNotBlank(map.get("A2"))) {
                set.add(map.get("A2"));
                count++;
            }
            if (StringUtils.isNotBlank(map.get("A3"))) {
                set.add(map.get("A3"));
                count++;
            }
            if (StringUtils.isNotBlank(map.get("A4"))) {
                set.add(map.get("A4"));
                count++;
            }
            if (StringUtils.isNotBlank(map.get("A5"))) {
                set.add(map.get("A5"));
                count++;
            }
            if (StringUtils.isNotBlank(map.get("A6"))) {
                set.add(map.get("A6"));
                count++;
            }
            if (StringUtils.isNotBlank(map.get("A7"))) {
                set.add(map.get("A7"));
                count++;
            }
            if (StringUtils.isNotBlank(map.get("A8"))) {
                set.add(map.get("A8"));
                count++;
            }
            if (StringUtils.isNotBlank(map.get("A9"))) {
                set.add(map.get("A9"));
                count++;
            }
        }
        System.out.println(count);
        System.out.println(set.size());
    }
}

最后插入的数据大概是这样[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-449koFvW-1691660171266)(C:\Users\20745\AppData\Roaming\Typora\typora-user-images\image-20230810172712617.png)]

注意这里的path!!!!!是id拼起来的具有目录层次的!![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UHQCBxy4-1691660171267)(C:\Users\20745\AppData\Roaming\Typora\typora-user-images\image-20230810173241809.png)]

这些关于目录树的基本操作,楼主写了一个小demo放在gitee上面了。本人不会算法,里面写的很菜见谅哈哈。喜欢的点个赞谢谢<.>! gitee地址:pg-demo-itree: 基于postgresql的Itree功能实现目录树的操作 (gitee.com)

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

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

相关文章

使用 PyTorch 进行高效图像分割:第 1 部分

一、说明 在这个由 4 部分组成的系列中&#xff0c;我们将使用 PyTorch 中的深度学习技术从头开始逐步实现图像分割。我们将在本文中从图像分割所需的基本概念和想法开始本系列。 图1&#xff1a;宠物图像及其分割掩码&#xff08;来源&#xff1a;牛津-IIIT宠物数据集) 图像分…

OpenLayers入门,OpenLayers加载船讯网航海地图

专栏目录: OpenLayers入门教程汇总目录 前言 本章实现OpenLayers加载船讯网航海地图。 二、依赖和使用 "ol": "^6.15.1"使用npm安装依赖npm install ol@6.15.1使用Yarn安装依赖yarn add olvue中如何使用: vue项目使用请参考这篇文章:

Maven之JDK编译问题

IDEA Maven 默认使用 JDK 1.5 编译问题 IDEA 在「调用」maven 时&#xff0c;IDEA 默认都会采用 JDK 1.5 编译&#xff0c;不管你安装的 JDK 版本是 JDK 7 还是 JDK 8 或者更高。这样一来非常不方便&#xff0c;尤其是时不时使用 JDK 7/8 的新特性时。如果使用新特性&#xff…

[10min速通]STM32CubemMX配置W25Q128

[10min速通]&#x1f98f;STM32CubemMX配置W25Q128 文章目录 [10min速通]&#x1f98f;STM32CubemMX配置W25Q1281、下载源码2、配置Cube2.1 基础配置2.2 SPI配置 3、配置MDK3.1 添加源文件3.2 管理源文件3.3 完成接口配置 4、接口介绍4.1 初始化4.2 擦除4.3 写入4.4 读取 5、代…

AntDB数据库受邀参加【ACDU 中国行】,共促行业发展和创新

作为数据的集中存储和管理系统&#xff0c;数据库在现代信息化时代扮演着至关重要的角色&#xff0c;随着人工智能&#xff0c;物联网和大数据时代的到来&#xff0c;数据库的发展需要进一步拓展其广度和深度&#xff0c;持续创新&#xff0c;实现技术进步&#xff0c;以更好地…

香港服务器备案会通过吗?

​  对于企业或个人来说&#xff0c;合规备案是网络运营的基本要求&#xff0c;也是保护自身权益的重要举措。以下内容围绕备案展开话题&#xff0c;希望为您解开疑惑。 香港服务器备案会通过吗? 目前&#xff0c;香港服务器无法备案&#xff0c;这是由于国内管理规定的限制…

Salient主题 - 创意多用途和WooCommerce商城主题

Salient主题是下一代WordPress主题&#xff0c;给任何人带来专业的设计结果&#xff0c;而不需要任何编码。Salient 提供永久更新的专业剖面模板库&#xff0c;目前有超过425个可供选择 – 所有这些都充满热情并坚持高标准的审美质量。 网址: Salient主题 - 创意多用途和WooCo…

Linux下安装nodejs

1、下载nodejs 点击前往&#xff1a;Download | Node.js 2、解压 tar -xvf node-v18.16.0-linux-x64.tar.xz mv node-v18.16.0-linux-x64/ /usr/local/nodejs 3、 建立软链接 此时的bin文件夹中已经存在node以及npm&#xff0c;如果你进入到对应文件的中执行命令行一点问题…

vue3 路由缓存问题

目录 解决问题的思路&#xff1a; 解决问题的方案&#xff1a; 1、给roter-view添加key&#xff08;破坏复用机制&#xff0c;强制销毁重建&#xff09; 2、使用beforeRouteUpdate导航钩子 3、使用watch监听路由 vue3路由缓存&#xff1a;当用户从/users/johnny导航到/use…

估算森林蓄积量哨兵2号变量计算详情

哨兵2号估算森林蓄积量变量计算详细步骤 变量概括哨兵2号变量计算详情1. 生物物理变量计算2. 植被指数3. 纹理特征 变量概括 需要计算的变量参数有&#xff1a; 生物物理变量 采用SNAP软件的工具生成5个生物物理变量。植被指数 采用gdal库计算&#xff0c;共17个植被指数变量…

「爱校对」——如何让每一篇公文都完美无瑕

在繁忙的办公环境中&#xff0c;公文是企业沟通的桥梁和载体&#xff0c;每一篇公文都关乎公司的形象和效率。但是&#xff0c;即使是最细心的员工&#xff0c;也难免会在公文中出现笔误或格式错误。这时&#xff0c;「爱校对」就显得尤为重要。 1.什么是「爱校对」&#xff1f…

Hyper-v导致Vmware window无法启动崩溃记录

最近有几次vmware启动window10直接崩溃情况&#xff0c;显示蓝屏报错。一开始没在意&#xff0c;以为是因为固态硬盘错了几个字节导致的&#xff1f; 但后来想想不对啊。vmware用了也有10来年了&#xff0c;稳得一笔&#xff0c;在仔细思考了一下后发现打不开的win10这三个虚拟…

springboot自定义banner的输出与源码解析

文章目录 一、介绍二、演示环境三、自定义banner1. 文本2. 图片3. placeholder占位符4. 关闭banner 四、源码分析1. 关闭banner2. banner模式3. banner打印器4. 打印banner① 获取banner② 打印banner 5. 版本号占位符的解析器6. 文本格式占位符的解析器7. 应用标题占位符的解析…

windows下, artemis学习

1. download artemis from apache ActiveMQhttps://activemq.apache.org/components/artemis/download/2. 解压缩到 C:/software/apache-artemis-2.30.0/ 2. 进入到cmd&#xff0c; 执行 C:\software\apache-artemis-2.30.0\bin>artemis create C:/software/apache-artem…

C语言实现将字典dict.txt上传到数据库中

代码 #include <stdio.h> #include <string.h> #include <unistd.h> #include <sqlite3.h>int do_insert(sqlite3 *db,char *word,char *mean);int main(int argc, const char *argv[]) {//以读的方式打开文件FILE* fpfopen("./dict.txt",&…

Android Studio run app 设置 release 模式

背景 为验证我们的 SDK 集成在客户应用上的质量&#xff0c;需要我们的测试环境尽量的与客户应用保持一致。客户普遍都会打 release 包并混淆&#xff0c;然后进行上线应用&#xff0c;因此我们在测试过程中也需要使用 release 包进行验证。对于 Android Studio 运行项目&…

基于web的旅游管理系统/旅游网站的设计与实现

摘要 随着计算机技术&#xff0c;网络技术的迅猛发展&#xff0c;Internet 的不断普及&#xff0c;网络在各个领域里发挥了越来越重要的作用。特别是随着近年人民生活水平不断提高&#xff0c;在线旅游给景区商家的业务带来了更大的发展机遇。 在经济快速发展的带动下&#xff…

这6个免费设计素材网站,设计师都在用,马住

新手设计师不知道去哪里找素材&#xff0c;那就看看这几个设计师都在用的网站吧&#xff0c;免费、付费、商用素材都有&#xff0c;可根据需求选择&#xff0c;赶紧收藏~ 菜鸟图库 https://www.sucai999.com/?vNTYxMjky 菜鸟图库是一个非常大的素材库&#xff0c;站内包含设…

如何做好意大利语翻译,北京翻译哪里比较专业?

意大利语被誉为世界上最美的语言之一&#xff0c;在国内应用广泛&#xff0c;市场对意大利语翻译的需求量也很大。那么&#xff0c;如何做好意大利语翻译&#xff0c;北京翻译哪里比较专业&#xff1f; 业内人士指出&#xff0c;要想做好意大利语翻译&#xff0c;首先要充分理解…

【C语言】动态通讯录 -- 详解

⚪前言 前面详细介绍了静态版通讯录【C语言】静态通讯录 -- 详解_炫酷的伊莉娜的博客-CSDN博客&#xff0c;但是静态版通讯录的空间是无法被改变的&#xff0c;而且空间利用率也不高。为了解决静态通讯录这一缺点&#xff0c;这时就要有一个能够随着存入联系人数量的增加而增大…