基于策略模式和简单工厂模式实现zip、tar、rar、7z四种压缩文件格式的解压

news2024/11/25 22:37:19

推荐语

这篇技术文章深入探讨了基于策略模式和简单工厂模式实现四种常见压缩文件格式的解压方法。通过阅读该文章,你将了解到如何利用这两种设计模式来实现灵活、可扩展的解压功能,同时适应不同的压缩文件格式。如果你对设计模式和文件处理感兴趣或刚好碰到类似的情况,那么这篇文章绝对值得一读。它会为你打开一个新的思路,并帮助你提升在软件开发中的技能和效率。

需求描述与分析

最近我遇到了一个需求,需要上传一个压缩包文件,其中包含目录和文件。上传成功后,后台会自动解压该文件,并保持压缩包内目录和文件的结构不变,然后将该结构渲染到页面上。

这个需求其实相对来说非常简单,实现起来并不困难。为了满足需求,我们需要解决以下三个问题:

  • 压缩包文件有多种格式,例如ZIP、RAR、TAR等等,我们需要支持哪些格式?
  • 如何选择合适的技术或工具来自动化地解压这些不同格式的文件?
  • 在解压压缩包的同时,如何解析出里面的目录、文件之间的关系和结构,以便被正确地渲染到前端页面上?

实现原理

先解决第一个问题:压缩包文件的格式有很多,要支持多少种?

下面这四种相对比较常见,支持解析的格式暂时定为这四种:

  • ZIP (.zip):ZIP 是最常见的压缩文件格式之一,多数操作系统都默认支持它。ZIP 文件通常用于在网络或电子邮件中传输文件,以及在本地计算机上备份和存档文件。
  • TAR (.tar):TAR 是一种用于将多个文件和文件夹打包成一个单独的文件的文件格式。与其他压缩格式不同,TAR 不会对文件进行压缩,仅用于打包和归档文件。
  • RAR (.rar):RAR 是另一种常见的压缩文件格式,它可以压缩许多文件,并提供比 ZIP 更好的压缩率。RAR 格式通常用于将大型文件分成多个部分,以便在互联网上分发和下载。
  • 7Z (.7z):7Z 是一种开源的压缩文件格式,可提供比其他压缩文件格式更高的压缩率。7Z 文件通常用于压缩大型文件和文件夹,以便在网络上传输和存储。

第二个问题:如何解压这些不同格式的文件?

支付的压缩文件的格式暂定为上面四种格式的压缩包文件那如何对这些不同格式的压缩包文件进行解压操作呢?如文章标题,基于策略模式和 简单工厂模式先实现上面四种格式的压缩文件解压,具体怎么实现呢?

  • 定义一个解压策略的抽象接口,内部定义一个抽象方法,作用是执行解压操作,但是这里不提供具体实现,具体实现由不同格式的具体解压策略来实现,这个方法的输入参数采用java标准的输入流,方便与其他业务对象,输出参数则是一个List集合类型,集合内存储的是解压文件的FileObj对象;
  • 分别根据四种压缩文件格式,定义四个不同的解压策略实现类,这四个解压策略实现类来实现上面的解压策略抽象接口,重写接口的抽象方法,方法的业务逻辑是来执行具体格式的压缩文件的解压操作;
  • 再定义一个解压策略的简单工厂类,用于根据不同的后缀,生成不同的解压策略,这个工工厂类最大的意义莫过于实现了解压客户端业务与具体解压操作的解耦;如果后续业务变更,需要新增其他格式的压缩文件解压,可以实现一个具体的解压策略类,然后再扩展一下这里的工厂类;解压客户端业务不需要做任何变更,这也符合设计模式中的单一职责;

第三个问题:压缩包文件解压的同时,怎么解析出压缩包里面的目录、文件的关系和结构?

  • 从压缩包文件中解析出文件后,解压结果是一个包含FileObj对象的集合,FileObj对象包含了三个属性:1、文件在压缩包内的全路径(包含有文件名称、后缀);2、文件后缀;3、文件的全部字节(这里封装为字节的目的是方便,后面的处理,如写入本地、写入远程文件服务器等);
  • 从解析结果中提取出文件在压缩包内的全路径;然后再进一步处理,转换为一个包含FileDir类型对象的集合,FileDir对象中有两个重要属性当前文件或目录的唯一标识和其父级的唯一标识,据此可以构建出一个树形结构,也就还原了压缩包里面的目录、文件的关第和结构;

实现方案

mavne依赖

  <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-compress</artifactId>
      <version>1.24.0</version>
    </dependency>
    <dependency>
      <groupId>net.sf.sevenzipjbinding</groupId>
      <artifactId>sevenzipjbinding</artifactId>
      <version>16.02-2.01</version>
    </dependency>
    <dependency>
      <groupId>org.tukaani</groupId>
      <artifactId>xz</artifactId>
      <version>1.9</version>
    </dependency>
    <dependency>
      <groupId>com.github.junrar</groupId>
      <artifactId>junrar</artifactId>
      <version>7.5.5</version>
    </dependency>
    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>1.2</version>
    </dependency>
    <dependency>
      <groupId>net.sf.sevenzipjbinding</groupId>
      <artifactId>sevenzipjbinding-all-platforms</artifactId>
      <version>16.02-2.01</version>
    </dependency>
    <dependency>
      <groupId>org.apache.ant</groupId>
      <artifactId>ant</artifactId>
      <version>1.10.12</version>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.30</version>
    </dependency>
    <dependency>
      <groupId>cn.hutool</groupId>
      <artifactId>hutool-all</artifactId>
      <version>5.8.23</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>1.7.32</version>
    </dependency>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.2.6</version>
    </dependency>

FileObj和FileDir

FileObj:从压缩包中解压出的每一个文件,封装到一个FileObj对象中,FileObj对象有三个属性:1、文件在压缩包内的全路径(包含有文件名称、后缀);2、文件后缀;3、文件的全部字节(这里封装为字节的目的是方便,后面的处理,如写入本地、写入远程文件服务器等)

@Data
public class FileObj {
    /**
     * 压缩包内文件全路径
     */
    private String filePath;
    /**
     * 压缩包内文件后缀
     */
    private String suffix;
    /**
     * 压缩包内文件的字节
     */
    private byte[] bytes;
}

FileDir:把压缩包文件里的每一个目录封装成一个FileDir对象,FileDir对象包有六个属性:1、目录名称;2、目录级别,根目录为1,其子目录依次递增;3、父级目录的名称,如果是根目录,则父级目录为空;4、目录的唯一标识;5、父级目录的唯一标识;6、当前节点的孩子节点;这里注意一下要重写一个hashCode和equals方法,因为在解析压缩文件内的目录、文件的关系和结构时,使用了Set集合的去重功能;

@Data
public class FileDir{
    /**
     * 类型,1:目录;2:文件;
     */
    private Integer docType=1;
    /**
     * 目录名称
     */
    private String docName;
    /**
     * 目录级别,根目录为1,其子目录依次递增
     */
    private Integer level;
    /**
     * 父级目录名称
     */
    private String parentDocName;
    /**
     * 目录唯一标识
     */
    private Long id;
    /**
     * 父级目录唯一标识
     */
    private Long parentId;
    /**
     * 当前节点的孩子节点
     */
    private List<FileDir> children;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        FileDir fileDir = (FileDir) o;
        if (!Objects.equals(docType, fileDir.docType)) return false;
        if (!Objects.equals(docName, fileDir.docName)) return false;
        if (!Objects.equals(level, fileDir.level)) return false;
        if (!Objects.equals(parentDocName, fileDir.parentDocName))
            return false;
        if (!Objects.equals(id, fileDir.id)) return false;
        if (!Objects.equals(parentId, fileDir.parentId)) return false;
        return Objects.equals(children, fileDir.children);
    }
    @Override
    public int hashCode() {
        int result = docType != null ? docType.hashCode() : 0;
        result = 31 * result + (docName != null ? docName.hashCode() : 0);
        result = 31 * result + (level != null ? level.hashCode() : 0);
        result = 31 * result + (parentDocName != null ? parentDocName.hashCode() : 0);
        result = 31 * result + (id != null ? id.hashCode() : 0);
        result = 31 * result + (parentId != null ? parentId.hashCode() : 0);
        result = 31 * result + (children != null ? children.hashCode() : 0);
        return result;
    }
}

UnZipStrategy

UnZipStrategy:是解压策略的抽象接口,内部定义一个抽象方法,作用是执行解压操作,具体实现由不同格式的具体解压策略来实现,这个方法的输入参数采用java标准的输入流,方便与其他业务对象,输出参数则是一个List集合类型,集合内存储的是解压文件的FileObj对象;

public interface UnZipStrategy {
    List<FileObj> analysis(InputStream inputStream);
}

ZipAnalysisStrategy

ZipAnalysisStrategy:是zip格式的压缩文件的解压策略,实现UnZipStrategy抽象接口,具体来执行zip格式的压缩文件的解压操作;

@Slf4j
public class ZipAnalysisStrategy implements UnZipStrategy {
    @Override
    public List<FileObj> analysis(InputStream inputStream) {
        List<FileObj> list = new ArrayList<>();
        ArchiveInputStream ais = new ZipArchiveInputStream(inputStream);
        ArchiveEntry entry;
        try {
            while ((entry = ais.getNextEntry()) != null) {
                if (!entry.isDirectory()) {
                    FileObj fileObj = extractFile(ais, entry);
                    list.add(fileObj);
                }
            }
            ais.close();
            inputStream.close();
        } catch (IOException e) {
            log.error("zip格式压缩文件在解压时发生错误:",e);
            throw new RuntimeException(e);
        }
        return list;
    }
    private FileObj extractFile(ArchiveInputStream ais, ArchiveEntry entry) throws IOException {
        String name = entry.getName();
        log.info("解析文件:{}",name);
        int index = name.lastIndexOf(".");
        String suffix = name.substring(index + 1);
        FileObj fileObj = new FileObj();
        fileObj.setFilePath(entry.getName());
        fileObj.setSuffix(suffix);
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int length;
        while ((length = ais.read(buffer)) > 0) {
            byteArrayOutputStream.write(buffer, 0, length);
        }
        byte[] bytes = byteArrayOutputStream.toByteArray();
        fileObj.setBytes(bytes);
        byteArrayOutputStream.close();
        return fileObj;
    }
}

TarAnalysisStrategy

TarAnalysisStrategy:是tar格式的压缩文件的解压策略,实现UnZipStrategy抽象接口,具体来执行tar格式的压缩文件的解压操作;

@Slf4j
public class TarAnalysisStrategy implements UnZipStrategy {
    @Override
    public List<FileObj> analysis(InputStream inputStream) {
        List<FileObj> list=new ArrayList<>();
        FileObj fileObj;
        TarInputStream tarInputStream = new TarInputStream(inputStream, 1024 * 2);
        TarEntry entry;
        try {
            while ((entry = tarInputStream.getNextEntry()) != null) {
                if (!entry.isDirectory()) {
                    fileObj=new FileObj();
                    String name = entry.getName();
                    int index = name.lastIndexOf(".");
                    String suffix = name.substring(index + 1);
                    fileObj.setFilePath(name);
                    fileObj.setSuffix(suffix);
                    int count;
                    byte data[] = new byte[2048];
                    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                    while ((count = tarInputStream.read(data)) != -1) {
                        outputStream.write(data, 0, count);
                    }
                    byte[] byteArray = outputStream.toByteArray();
                    outputStream.close();
                    fileObj.setBytes(byteArray);
                    list.add(fileObj);
                }
            }
            inputStream.close();
            tarInputStream.close();
        } catch (IOException e) {
            log.error("tar格式压缩文件在解压时发生错误:",e);
            throw new RuntimeException(e);
        }
        return list;
    }
}

SevenZAnalysisStrategy

SevenZAnalysisStrategy:是7z格式的压缩文件的解压策略,实现UnZipStrategy抽象接口,具体来执行7z格式的压缩文件的解压操作;

@Slf4j
public class SevenZAnalysisStrategy implements UnZipStrategy {
    @Override
    public List<FileObj> analysis(InputStream inputStream) {
        List<FileObj> list = new ArrayList<>();
        FastByteArrayOutputStream read = IoUtil.read(inputStream);
        byte[] byteArray = read.toByteArray();
        SeekableInMemoryByteChannel seekableInMemoryByteChannel = new SeekableInMemoryByteChannel(byteArray);
        try {
            SevenZFile sevenZFile = new SevenZFile(seekableInMemoryByteChannel);
            // 创建输出目录
            SevenZArchiveEntry entry;
            while ((entry = sevenZFile.getNextEntry()) != null) {
                if (!entry.isDirectory()) {
                    FileObj fileObj = new FileObj();
                    String name = entry.getName();
                    log.info("解析文件:{}",name);
                    int index = name.lastIndexOf(".");
                    String suffix = name.substring(index + 1);
                    fileObj.setFilePath(name);
                    fileObj.setSuffix(suffix);
                    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                    int len = 0;
                    byte[] b = new byte[2048];
                    while ((len = sevenZFile.read(b)) != -1) {
                        outputStream.write(b, 0, len);
                    }
                    byte[] bytes = outputStream.toByteArray();
                    outputStream.close();
                    fileObj.setBytes(bytes);
                    list.add(fileObj);
                }
            }
            inputStream.close();
            read.close();
            seekableInMemoryByteChannel.close();
        } catch (IOException e) {
            log.error("7z格式的压缩文件在解压时发生错误:",e);
            throw new RuntimeException(e);
        }
        return list;
    }
}

RarAnalysisStrategy

RarAnalysisStrategy:是rar格式的压缩文件的解压策略,实现UnZipStrategy抽象接口,具体来执行rar格式的压缩文件的解压操作;这个格式的压缩文件解压起来稍微有点费力,用到了一个回调RarExtractCallback类,这个RarExtractCallback类实现IArchiveExtractCallback接口,重写getStream()和setOperationResult(),来实现压缩文件的解压;

@Slf4j
public class RarAnalysisStrategy implements UnZipStrategy {
    @Override
    public List<FileObj> analysis(InputStream inputStream) {

        try {
            byte[] bytes = IoUtil.readBytes(inputStream);
            ByteArrayStream byteArrayStream = new ByteArrayStream(bytes, false);
            IInArchive inArchive = SevenZip.openInArchive(null, byteArrayStream);
            int[] in = new int[inArchive.getNumberOfItems()];
            for (int i = 0; i < in.length; i++) {
                in[i] = i;
            }
            //使用回调函数
            RarExtractCallback rarExtractCallback = new RarExtractCallback(inArchive);
            inArchive.extract(in, false, rarExtractCallback);
            byteArrayStream.close();
            inputStream.close();
            return rarExtractCallback.getFileObjs();
        } catch (IOException e) {
            log.error("rar格式的压缩文件在解压时发生错误:", e);
            throw new RuntimeException(e);
        }
    }
}
@Slf4j
public class RarExtractCallback implements IArchiveExtractCallback {
    private Integer index;
    private IInArchive inArchive;
    private ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

    @Getter
    private List<FileObj> fileObjs=new ArrayList<>();

    public RarExtractCallback(IInArchive inArchive) {
        this.inArchive = inArchive;
    }
    @Override
    public void setCompleted(long arg0) throws SevenZipException {
    }
    @Override
    public void setTotal(long arg0) throws SevenZipException {
    }
    @Override
    public ISequentialOutStream getStream(int index, ExtractAskMode extractAskMode) throws SevenZipException {
        this.index=index;
        boolean isFolder = (boolean) inArchive.getProperty(index, PropID.IS_FOLDER);
        return data -> {
                if (!isFolder) {
                    try {
                        outputStream.write(data);
                    } catch (IOException e) {
                        log.error("rar格式的压缩文件在解压时发生错误:",e);
                        throw new RuntimeException(e);
                    }
                }
            return data.length;
        };
    }
    @Override
    public void prepareOperation(ExtractAskMode arg0) throws SevenZipException {
    }
    @Override
    public void setOperationResult(ExtractOperationResult extractOperationResult) throws SevenZipException {
        String path = (String) inArchive.getProperty(index, PropID.PATH);
        boolean isFolder = (boolean) inArchive.getProperty(index, PropID.IS_FOLDER);
        if (!isFolder) {
            FileObj fileObj=new FileObj();
            fileObj.setFilePath(path);
            log.info("解析文件:{}",path);
            int index1 = path.lastIndexOf(".");
            String suffix = path.substring(index1 + 1);
            fileObj.setSuffix(suffix);
            byte[] byteArray = outputStream.toByteArray();
            outputStream.reset();
            fileObj.setBytes(byteArray);
            fileObjs.add(fileObj);
        }
    }
}

UnZipStrategyFactory

UnZipStrategyFactory:解压策略的简单工厂类,用于根据不同的后缀,生成不同的解压策略,最大的意义莫过于实现了解压主业务与具体解压操作的解耦;

public class UnZipStrategyFactory {
    public static UnZipStrategy generate(String suffix){
        UnZipStrategy strategy;
        switch (suffix){
            case "zip":
                strategy=new ZipAnalysisStrategy();
                break;
            case "tar":
                strategy=new TarAnalysisStrategy();
                break;
            case "rar":
                strategy=new RarAnalysisStrategy();
                break;
            case "7z":
                strategy=new SevenZAnalysisStrategy();
                break;
            default:
                strategy=null;
                break;
        }
        return strategy;
    }
}

FileDirProcessor

FileDirProcessor:用于从压缩包里解压出的文件列表里,解析出目录与文件的结构,即包含FileDir对象的集合;

public class FileDirProcessor {
    public static List<FileDir> process(List<String> list) {
        //解析和去重
        Set<FileDir> sets = new HashSet<>();
        if (CollUtil.isNotEmpty(list)) {
            for (String dirStr : list) {
                String[] split = dirStr.split("/");
                if (split.length > 0) {
                    if (split.length == 1) {
                        FileDir fileDir = new FileDir();
                        fileDir.setDocName(split[0]);
                        fileDir.setDocType(2);
                        fileDir.setLevel(1);
                        fileDir.setParentDocName("");
                        sets.add(fileDir);
                    } else {
                        for (int i = 0; i < split.length; i++) {
                            FileDir fileDir = new FileDir();
                            fileDir.setDocName(split[i]);
                            fileDir.setLevel(i + 1);
                            fileDir.setDocType(1);
                            if (i == 0) {
                                fileDir.setParentDocName("");
                            }
                            if (i == (split.length - 1)) {
                                fileDir.setDocType(2);
                                fileDir.setParentDocName(split[i - 1]);
                            }
                            if (i != 0 && i != split.length - 1) {
                                fileDir.setParentDocName(split[i - 1]);
                            }
                            sets.add(fileDir);
                        }
                    }
                }
            }
        }
        if (CollUtil.isNotEmpty(sets)) {
            //设置id
            Map<String, Long> map = new HashMap<>();
            Snowflake snowflake = IdUtil.getSnowflake();
            for (FileDir fileDir : sets) {
                long id = snowflake.nextId();
                fileDir.setId(id);
                map.put(fileDir.getLevel() + fileDir.getDocName(), id);
            }
            //设置父id
            for (FileDir fileDir : sets) {
                if (fileDir.getLevel() == 1) {
                    fileDir.setParentId(0L);
                } else {
                    Long parentId = map.get((fileDir.getLevel() - 1) + fileDir.getParentDocName());
                    fileDir.setParentId(parentId);
                }
            }
        }
        return new ArrayList<>(sets);
    }
}

FileDirTree

FileDirTree:在FileDirProcessor类的解析结果中定义了两个关键东西,当前文件或目录的唯一标识id和父id,FileDirTree的作用用在于把FileDirProcessor类的解析结果转换成一种树形结构,以便在页面上渲染展示;

public class FileDirTree {
    public List<FileDir> nodeList;

    public FileDirTree(List<FileDir> nodeList) {
        this.nodeList = nodeList;
    }

    private List<FileDir> getRootNode() {
        List<FileDir> rootNodeList = new ArrayList<>();
        for (FileDir treeNode : nodeList) {
            if (0 == treeNode.getParentId()) {
                rootNodeList.add(treeNode);
            }
        }
        return rootNodeList;
    }

    public List<FileDir> buildTree() {
        List<FileDir> treeNodes = new ArrayList<FileDir>();
        for (FileDir treeRootNode : getRootNode()) {
            treeRootNode = buildChildTree(treeRootNode);
            treeNodes.add(treeRootNode);
        }
        return treeNodes;
    }

    private FileDir buildChildTree(FileDir pNode) {
        List<FileDir> childTree = new ArrayList<FileDir>();
        for (FileDir treeNode : nodeList) {
            if (treeNode.getParentId().equals(pNode.getId())) {
                childTree.add(buildChildTree(treeNode));
            }
        }
        pNode.setChildren(childTree);
        return pNode;
    }

}

单元测试

    @Test
    public void test4() throws IOException {
        String fileName = "e:/zip/test.zip";
        int index = fileName.lastIndexOf(".");
        String suffix = fileName.substring(index + 1);
        //构建解压策略
        UnZipStrategy unZipStrategy = UnZipStrategyFactory.generate(suffix);
        //开始解压
        List<FileObj> analysis = unZipStrategy.analysis(Files.newInputStream(Paths.get(fileName)));
        //从解压结果中获取解压文件的全路径
        List<String> list = analysis.stream().map(FileObj::getFilePath).collect(Collectors.toList());
//        log.info(JSONUtil.toJsonStr(list));
//        this.saveFile(analysis, suffix);
        //根据解压文件的全路径解析出压缩包内文件和目录的树形结构
        List<FileDir> process = FileDirProcessor.process(list);
        FileDirTree fileDirTree = new FileDirTree(process);
        List<FileDir> tree = fileDirTree.buildTree();
        log.info(JSONUtil.toJsonStr(tree));
    }

源码下载

如果想获取完整的示例代码,可以从下面这个地址clone:

凡夫贩夫 / unzip-demo · GitCode

写在最后

感谢您阅读我的文章,如果您觉得我的内容对您有所启发或帮助,欢迎关注我并给我点赞。

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

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

相关文章

【ES】es介绍,使用spring-boot-starter-data-elasticsearch整合的ES来进行操作Es

文章目录 倒排索引&#xff08;Inverted Index&#xff09;和正排索引&#xff08;Forward Index&#xff09;es和MySQL对比IK分词器的总结mapping映射使用springboot整合的ES来进行操作Es1. 实体类中添加注解2. 编写Repository层3. 通过Repository进行增删改查 倒排索引&#…

学习Vue的key作用和原理

今天主要学习了列表渲染和key的作用和原理&#xff0c;先来说说列表渲染&#xff0c;顾名思义想要渲染列表最快的方式就是使用for循环&#xff0c;我们要学习的就是Vue中对标签实现for循环的语法&#xff0c;它和我们传统的js语法有些不同&#xff0c;它是先要有Vue实例中data的…

力扣热题100道-双指针篇

文章目录 双指针283.移动零11.盛最多水的容器15.三数之和42.接雨水 双指针 283.移动零 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 …

C语言 volatile关键字

volatile关键字介绍 volatile 是一个关键字&#xff0c;用于修饰变量&#xff0c;表示该变量是易变的&#xff0c;即可能在任何时候被意外地改变。在多线程编程中&#xff0c;当多个线程同时访问同一个变量时&#xff0c;由于线程之间的交互和优化&#xff0c;可能会导致变量的…

亚信安慧AntDB数据库——通信运营商核心系统的全面演进

AntDB数据库源自通信运营商核心系统&#xff0c;经过15年的平稳运行和不断演进&#xff0c;成功跟随通信技术的升级步伐&#xff0c;逐步迈向5G时代&#xff0c;并且在这期间完成了8次大版本的迭代&#xff0c;为行业树立了技术领先的典范。其独特之处在于具备超融合架构&#…

vue本地缓存搜索记录(最多4条)

核心代码 //保存到搜索历史&#xff0c;最多存四个 item.name和item.code格式为&#xff1a;塞力斯000001var history uni.getStorageSync(history) || [];console.log("history", history)var index history.findIndex((items) > {return item.name items.nam…

通过nginx配置防御web漏洞

一、常见web漏洞 二、nginx防御策略&#xff1a; 要使用Nginx配置防御Web漏洞&#xff0c;可以采取以下措施&#xff1a; 禁用不必要的HTTP方法&#xff1a;Nginx默认启用了许多HTTP方法&#xff0c;如PUT、DELETE等。可以通过在Nginx配置中禁用不必要的HTTP方法来减少潜在的安…

Vue - 使用Element UI Upload / importExcelJs进行文件导入

1 情景一 需求背景&#xff1a;后端配合&#xff0c;点击"导入"按钮&#xff0c;弹出“导入”弹窗&#xff0c;将电脑本地Excel表格数据导入到页面中表格位置&#xff08;需要调用后端接口&#xff09;&#xff0c;而页面中表格通过后端接口获取最新数据。 实现思路…

学python一定要下载python吗,学python都需要什么软件

大家好&#xff0c;本文将围绕想学python都要下载什么软件展开说明&#xff0c;初学python需要安装什么软件是一个很多人都想弄明白的事情&#xff0c;想搞清楚学python一定要下载python吗需要先了解以下几个事情。 工欲善其事必先利其器。初学者在学Python的时候&#xff0c;往…

雷军称小米汽车不可能卖 9 万 9;杭州破获重大勒索病毒案丨 RTE 开发者日报 Vol.116

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE &#xff08;Real Time Engagement&#xff09; 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文…

thinkphp+vue_mysql汽车租赁管理系统1ma2x

运行环境:phpstudy/wamp/xammp等 开发语言&#xff1a;php 后端框架&#xff1a;Thinkphp5 前端框架&#xff1a;vue.js 服务器&#xff1a;apache 数据库&#xff1a;mysql 数据库工具&#xff1a;Navicat/phpmyadmin 课题主要分为三大模块&#xff1a;即管理员模块、用户模块…

优维携手深职大共建“中国高校‘双碳’技能仿真操作系统”!

优维“双碳”战略合作高校 优维科技与深圳职业技术大学碳中和技术研究院&#xff08;深职碳研院&#xff09;签署战略合作协议&#xff0c;深化产学研&#xff0c;聚力创新“双碳”发展。在“双碳”目标大背景下&#xff0c;优维科技和深职碳研院将携手共同开发中国高校“双碳…

Django(四)

1.数据库操作 MySQL数据库 pymysql import pymysql# 1.连接MySQL conn pymysql.connect(host"127.0.0.1", port3306, userroot, passwd"root123", charsetutf8, dbunicom) cursor conn.cursor(cursorpymysql.cursors.DictCursor)# 2.发送指令 cursor.…

{MySQL} 数据库约束 表的关系 新增删除 修改 查询

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、数据库约束1.1约束类型&#xff1a;1.2 NULL约束1.3unique 唯一约束1.4 DEFAULT&#xff1a;默认值约束1.5 PRIMARY KEY&#xff1a;主键约束1.6 FOREIGN K…

Flowable中6种部署方式

1. addClasspathResource src/main/resources/processes/LeaveProcess.bpmn20.xml Deployment deploy repositoryService.createDeployment().name("请假审批").addClasspathResource("processes/LeaveProcess.bpmn20.xml").deploy();2. addInputStream…

QCheckBoxQRadioBoxQComboBoxQSlider

QCheckBox QCheckBox 是 Qt 框架中一个常用的控件&#xff0c;用于创建一个可以勾选或取消勾选的复选框。它通常用于表示选项的开/关状态 autoExclusive 是一个与单选按钮&#xff08;QRadioButton&#xff09;相关的属性。这个属性决定了同一个父窗口下的单选按钮是否自动形成…

利用NPS跟踪客户忠诚度:问卷调查实用指南与技巧分享

许多营销人员表示&#xff0c;净推荐值&#xff08;NPS&#xff09;是任何行业成功的主要衡量标准。同时&#xff0c;它也是衡量客户忠诚度的绝佳工具。我们可以将NPS问题引入问卷调查中&#xff0c;从而获取出真实的数据。NPS是怎么衡量顾客的&#xff1f;NPS将顾客分为推荐者…

力扣刷题记录(21)LeetCode:121、123、188、309

目录 121. 买卖股票的最佳时机 123. 买卖股票的最佳时机 III 188. 买卖股票的最佳时机 IV 309. 买卖股票的最佳时机含冷冻期 如果某一天出售股票可以得到最大利润&#xff0c;那么股票买入的价格一定是这天之前股票的最低价格。 所以我们可以在遍历股票价格的时候不断更新股…

OCP NVME SSD规范解读-4.NVMe IO命令-2

NVMe-IO-3&#xff1a; 由于设备具有掉电保护功能&#xff08;如Power Loss Protection&#xff0c;PLP&#xff09;&#xff0c;因此在以下情况下&#xff0c;性能不应降低&#xff1a; FUA&#xff08;Force Unit Access&#xff09;&#xff1a;是计算机存储设备中的一种命…

《别让猴子跳回背上》——管理者的时间管理

讲时间管理的书很多&#xff0c;但这本是专门讲给管理者的时间管理。 在职场中&#xff0c;许多管理者都会碰到工作计划执行不下去、组织目标难于实现的问题&#xff0c;搭进了自己所有可以支配的时间&#xff0c;仍旧是焦头烂额&#xff0c;顾此失彼&#xff1b;而下属则因为…