SpringBoot框架如何实现上传与下载查看文件

news2025/1/10 10:39:35

基于SpringBoot框架,如何实现文件的上传与下载查看

提要

本项目借鉴于spring-guides/gs-uploading-files: Uploading Files :: Learn how to build a Spring application that accepts multi-part file uploads. (github.com)SpringBoot官网学习文档关于如何下载文件一章提供的演示代码;

GitHub

Download-File-Java: Demonstration How to implement file upload, client download, or view files under the springboot framework. (github.com),

本项目使用GitHub作为代码托管平台,友友们,点亮小星星是对博主莫大的支持哦!!!

演示环境

  • idea集成开发工具
  • JDK21
  • Apache Maven 3.9.4

接口设计

URL: http://localhost/files/{filename}

method: GET

query: filename-文件名

function: 查看文件

URL: http://localhost/files/download/{filename}

method: GET

query: filename-文件名

function: 下载文件

URL: http://localhost/upload

method: GET

param: file-多文件对象

function: 上传文件

单元测试

分别使用MockMvc与TestRestTemplate测试工具类,模拟客户端发送HTTP请求,对项目接口与存储服务层进行了测试;

项目文件

项目文件层次

具体实现

配置类

配置客户端上传到服务端的文件存储地址,博主是默认存放在存储静态文件的resources目录下;

@Value注解可以获取properties文件中存储的配置信息;

package test.springboot.demo.config;


import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

/**
 * 配置存储
 **/
@Configuration
public class StorageConfigure {
    @Value("${storage.path}")
    private String location;

    public String getLocation() {
        return location;
    }

    public void setLocation(String location) {
        this.location = location;
    }

}

properties文件

存放配置的信息

spring.servlet.multipart.max-file-size=4MB
spring.servlet.multipart.max-request-size=4MB
storage.path=src/main/resources/localStorage

API层

package test.springboot.demo.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import test.springboot.demo.exception.StorageFileNotFoundException;
import test.springboot.demo.service.StorageService;

@Controller
public class FileUploadController {


    private final StorageService storageService;

    /**
     * 采用构造函数来注入StorageService对象,方便进行单测
     * @param storageService StorageService对象
     **/
     @Autowired
    public FileUploadController(StorageService storageService) {
        this.storageService = storageService;
    }

    // 与上面的构造函数一样,用于注入StorageService对象
    // @Autowired
    // private StorageService storageService;

    /**
     * 做代理,客户端可下载资源或查看资源
     * @return 文件后缀
     **/
    @GetMapping(value = {"/files/{filename:.+}", "/files/{download:.+}/{filename:.+}"})
    @ResponseBody
    public ResponseEntity<Resource> serveFile(@PathVariable(required = false) String download, @PathVariable String filename) {
        // 获取文件数据
        Resource file = storageService.loadAsResource(filename);
        // 如果文件为空就返回响应404
        if (file == null) {
            return ResponseEntity.notFound().build();
        }
        // 创建响应实体,设置状态码为200
        ResponseEntity.BodyBuilder req = ResponseEntity.status(HttpStatus.OK);
        // 如果download不为空,则执行下载,添加消息头attachment
        if (download!=null) {
            req.header(HttpHeaders.CONTENT_DISPOSITION,
                    "attachment; filename=\"" + file.getFilename() + "\"");
        }
        // 设置默认文件类型为application/octet-stream,二进制流
        String contentType = "application/octet-stream";
        if (file.getFilename() != null) {
            // 获得文件名后缀
            String ext = getFileExtension(file.getFilename());
            switch (ext) {
                case "pdf":
                    contentType = "application/pdf";
                    break;
                case "png", "gif", "jpg":
                    contentType = "image/" + ext;
                    break;
                case "jpeg":
                    contentType = "image/jpeg";
                    break;
                case "ofd", "zip":
                    contentType = "application/" + ext;
                    break;
                case "xlsx":
                    contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
                    break;
            }
        }
        // 返回封装好的响应实体
        return req.contentType(MediaType.valueOf(contentType))
                .body(file);
    }

    /**
     * 获得文件名后缀
     * @param fileName 文件名
     * @return 文件后缀
     **/
    public String getFileExtension(String fileName) {
        if (fileName.lastIndexOf(".") != -1 && fileName.lastIndexOf(".") != 0)
            return fileName.substring(fileName.lastIndexOf(".") + 1);
        else
            return "";
    }

    /**
     * 上传文件
     * @return 上传是否成功
     */
    @PostMapping("/upload")
    @ResponseBody
    public boolean handleFileUpload(@RequestParam("file") MultipartFile file) {
        return storageService.store(file);
    }

    // 用于处理StorageFileNotFoundException异常。
    // 当抛出该异常时,函数会返回一个ResponseEntity对象,其状态码为404 Not Found,
    // 表示找不到指定的文件或资源。
    // 该函数通过@ExceptionHandler注解指定用于处理特定类型的异常
    @ExceptionHandler(StorageFileNotFoundException.class)
    public ResponseEntity<?> handleStorageFileNotFound(StorageFileNotFoundException exc) {
        return ResponseEntity.notFound().build();
    }

}

报错处理

针对存储数据失败,文件查询失败封装的异常信息;

package test.springboot.demo.exception;

/**
 * 封装'存储失败'异常信息
 **/
public class StorageException extends RuntimeException {

    /**
     * 构造函数
     * @param message 异常原因
     **/
    public StorageException(String message) {
        super(message);
    }
    
    /**
     * 构造函数
     * @param message 异常原因
     * @param cause 异常报错
     **/
    public StorageException(String message, Throwable cause) {
        super(message, cause);
    }
}
package test.springboot.demo.exception;

/**
 * 封装'文件未找到'异常信息
 **/
public class StorageFileNotFoundException extends StorageException {

    /**
     * 构造函数
     * @param message 异常原因
     **/
    public StorageFileNotFoundException(String message) {
        super(message);
    }

    /**
     * 构造函数
     * @param message 异常原因
     * @param cause 异常报错
     **/
    public StorageFileNotFoundException(String message, Throwable cause) {
        super(message, cause);
    }
}

服务层接口

package test.springboot.demo.service;


import org.springframework.core.io.Resource;
import org.springframework.web.multipart.MultipartFile;
import test.springboot.demo.exception.StorageException;
import test.springboot.demo.exception.StorageFileNotFoundException;

import java.nio.file.Path;
import java.util.stream.Stream;

public interface StorageService {
    /**
     * 初始化下载路径
     * @exception StorageException 存储异常
     **/
    void init();
    /**
     * 存储多文件对象到下载路径下
     * @param file MultipartFile类型的多文件对象
     * @return 是否存储成功
     * @exception StorageException 存储异常
     **/
    boolean store(MultipartFile file);
    /**
     * 获得下载路径下的所有文件Path流
     * @return Path文件流
     * @exception StorageException 存储异常
     **/
    Stream<Path> loadAll();
    /**
     * 获得Path文件路径
     * @param filename 文件名
     * @return Path文件路径
     **/
    Path load(String filename);
    /**
     * 获得文件资源
     * @param filename 文件名
     * @return 文件资源
     * @exception StorageFileNotFoundException 文件不存在异常
     **/
    Resource loadAsResource(String filename);
    /**
     * 删除下载路径文件夹及其路径下所有文件
     **/
    void deleteAll();

}

服务层实现

package test.springboot.demo.service.impl;


import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.stream.Stream;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Service;
import org.springframework.util.FileSystemUtils;
import org.springframework.web.multipart.MultipartFile;
import test.springboot.demo.exception.StorageException;
import test.springboot.demo.exception.StorageFileNotFoundException;
import test.springboot.demo.config.StorageConfigure;
import test.springboot.demo.service.StorageService;

@Service
public class FileStorageServiceImpl implements StorageService {

    private final Path rootLocation;
    /**
     * 构造方法
     * @param properties StorageProperties对象
     **/
    @Autowired
    public FileStorageServiceImpl(StorageConfigure properties) {
        // 若下载路径为空,抛出异常
        if(properties.getLocation().trim().length() == 0){
            throw new StorageException("File upload location can not be Empty.");
        }
        // 设置下载路径
        this.rootLocation = Paths.get(properties.getLocation());
    }

    /**
     * 存储多文件对象到下载路径下
     * @param file MultipartFile类型的多文件对象
     * @return 是否存储成功
     * @exception StorageException 存储异常
     **/
    @Override
    public boolean store(MultipartFile file) {
        try {
            // 判断是否为空
            if (file.isEmpty()) {
                throw new StorageException("Failed to store empty file.");
            }

            Path destinationFile = this.rootLocation.resolve(
                            // Paths.get获取文件名并转为Path对象
                            Paths.get(file.getOriginalFilename()))
                    // 转为绝对路径
                    .normalize().toAbsolutePath();
            // 判断是否与期望的下载路径一致
            if (!destinationFile.getParent().equals(this.rootLocation.toAbsolutePath())) {
                // This is a security check
                throw new StorageException(
                        "Cannot store file outside current directory.");
            }
            // 拷贝文件,到下载路径
            try (InputStream inputStream = file.getInputStream()) {
                long size = Files.copy(inputStream, destinationFile,
                        StandardCopyOption.REPLACE_EXISTING);
                if (size > 0) {
                    return true;
                }
            }
        }
        catch (IOException e) {
            throw new StorageException("Failed to store file.", e);
        }
        return false;
    }

    /**
     * 获得下载路径下的所有文件Path流
     * @return Path文件流
     * @exception StorageException 存储异常
     **/
    @Override
    public Stream<Path> loadAll() {
        try {
            //获得下载路径下的深度为一的所有文件夹与文件
            return Files.walk(this.rootLocation, 1)
                    // 去掉下载路径的文件夹
                    .filter(path -> !path.equals(this.rootLocation))
                    // 返回处理成相对路径的Path流
                    .map(this.rootLocation::relativize);
        }
        catch (IOException e) {
            throw new StorageException("Failed to read stored files", e);
        }

    }

    /**
     * 获得Path文件路径
     * @param filename 文件名
     * @return Path文件路径
     **/
    @Override
    public Path load(String filename) {
        // 获得Path文件路径
        return rootLocation.resolve(filename);
    }

    /**
     * 获得文件资源
     * @param filename 文件名
     * @return 文件资源
     * @exception StorageFileNotFoundException 文件不存在异常
     **/
    @Override
    public Resource loadAsResource(String filename) {
        try {
            // Path 是 Java 7 引入的一个接口,它是 java.nio.file 包的一部分,用于表示文件系统中的路径。
            // Path 接口定义了一些基本的操作,而具体的实现类如 java.nio.file.Paths 提供了创建 Path 对象的方法。

            // 获得本地存储的此文件名的Path
            Path file = load(filename);
            // 获得文件URL,Resource是Spring Framework中的类,用于封装对资源的访问
            // toUri() 方法返回一个 URI 对象,表示文件可访问的网络位置
            Resource resource = new UrlResource(file.toUri());
            // 检测文件是否存在或可读
            if (resource.exists() || resource.isReadable()) {
                return resource;
            }
            else {
                throw new StorageFileNotFoundException(
                        "Could not read file: " + filename);

            }
        }
        catch (MalformedURLException e) {
            throw new StorageFileNotFoundException("Could not read file: " + filename, e);
        }
    }

    /**
     * 删除下载路径文件夹及其路径下所有文件
     **/
    @Override
    public void deleteAll() {
        // toFile()将下载路径转为File对象,并遍历删除所有文件
        FileSystemUtils.deleteRecursively(rootLocation.toFile());
    }

    /**
     * 初始化下载路径
     * @exception StorageException 存储异常
     **/
    @Override
    public void init() {
        try {
            // 创建下载路径文件夹,若该文件夹已经存在则不做任何操作
            Files.createDirectories(rootLocation);
        }
        catch (IOException e) {
            throw new StorageException("Could not initialize storage", e);
        }
    }
}

项目启动类

package test.springboot.demo;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import test.springboot.demo.service.StorageService;

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
       SpringApplication.run(DemoApplication.class, args);
    }

    /**
     * 初始化存储,CommandLineRunner是Spring Boot提供的接口,允许在应用启动完成后执行一些操作
     * 实现该接口的方法会在应用启动后自动运行,通常用于执行启动时的任务,如数据初始化等
     * @param storageService-存储服务
     * @return
     **/
    @Bean
    CommandLineRunner init(StorageService storageService) {
       return (args) -> {
          storageService.deleteAll();
          storageService.init();
       };
    }
}

单元测试

测试本地存储服务
package test.springboot.demo.storage;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import test.springboot.demo.service.impl.FileStorageServiceImpl;
import test.springboot.demo.exception.StorageException;
import test.springboot.demo.config.StorageConfigure;

import java.util.Random;

import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

/**
 * 用于测试本地文件存储的服务层
 **/
public class FileStorageServiceImplTests {

    private StorageConfigure properties = new StorageConfigure();
    private FileStorageServiceImpl service;

    @BeforeEach
    public void init() {
       properties.setLocation("src/main/resources/localStorage/files/" + Math.abs(new Random().nextLong()));
       service = new FileStorageServiceImpl(properties);
       service.init();
    }
    @AfterEach
    public void terminate() {
       properties.setLocation("src/main/resources/localStorage/files/");
       service = new FileStorageServiceImpl(properties);
       service.deleteAll();
    }

    @Test
    public void emptyUploadLocation() {
        service = null;
        properties.setLocation("");
        assertThrows(StorageException.class, () -> {
            service = new FileStorageServiceImpl(properties);
       });
    }

    @Test
    public void loadNonExistent() {
       assertThat(service.load("foo.txt")).doesNotExist();
    }

    @Test
    public void saveAndLoad() {
       service.store(new MockMultipartFile("admin", "admin.txt", MediaType.TEXT_PLAIN_VALUE,
             "I am cool boy!".getBytes()));
       assertThat(service.load("admin.txt")).exists();
    }

    @Test
    public void saveRelativePathNotPermitted() {
       assertThrows(StorageException.class, () -> {
          service.store(new MockMultipartFile("admin", "../admin.txt",
                MediaType.TEXT_PLAIN_VALUE, "I am cool boy!".getBytes()));
       });
    }

    @Test
    public void savePermitted() {
       service.store(new MockMultipartFile("amdin", "localStorage/../admin.txt",
             MediaType.TEXT_PLAIN_VALUE, "I am cool boy!".getBytes()));
    }

}
MockMvc测试文件上传下载
package test.springboot.demo;

import org.junit.jupiter.api.Test;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.web.servlet.MockMvc;
import test.springboot.demo.exception.StorageFileNotFoundException;
import test.springboot.demo.service.StorageService;

import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

/**
 * 使用MockMvc测试
 **/
@AutoConfigureMockMvc
@SpringBootTest
public class FileMockMvcTests {

    @Autowired
    private MockMvc mvc;

    @MockBean
    private StorageService storageService;

    /**
     * 测试上传文件
     **/
    @Test
    public void shouldSaveUploadedFile() throws Exception {
       MockMultipartFile multipartFile = new MockMultipartFile("file", "test.txt",
             "text/plain", "hello world".getBytes());
       this.mvc.perform(multipart("/upload").file(multipartFile))
             .andExpect(status().isOk());

       then(this.storageService).should().store(multipartFile);
    }

    /**
     * 测试文件不存在时抛出404错误
     * @throws Exception
     */
    @SuppressWarnings("unchecked") // 抑制编译器对方法体内可能出现的未经检查的警告
    @Test
    public void should404WhenMissingFile() throws Exception {
       given(this.storageService.loadAsResource("test.txt"))
             .willThrow(StorageFileNotFoundException.class);

       this.mvc.perform(get("/files/test.txt")).andExpect(status().isNotFound());
    }

}
TestRestTemplate测试文件上传下载
package test.springboot.demo;


import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import test.springboot.demo.service.StorageService;


import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.mockito.BDDMockito.given;

/**
 * 使用TestRestTemplate测试,模拟Spring Boot应用程序的运行环境,任意端口
 **/
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class FileRestTemplateTests {

    // TestRestTemplate是Spring提供的一个简化HTTP请求的工具类,
    // 常用于集成测试中模拟客户端向服务端发送HTTP请求。
    // 在这个上下文中,它将被用来执行文件上传和下载的HTTP请求操作。
    @Autowired
    private TestRestTemplate restTemplate;

    // StorageService的mock对象,用于模拟存储服务,避免对实际服务层进行调用
    @MockBean
    private StorageService storageService;

    // 获得应用的端口,用于测试
    @LocalServerPort
    private int port;


    /**
     * 测试文件上传功能
     **/
    @Test
    public void shouldUploadFile() throws Exception {
       // 获得本地存储的的test.txt文件
       ClassPathResource resource = new ClassPathResource("test.txt");
       // 放入多文件集合请求中
       MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
       map.add("file", resource);
       // 执行上传操作
       ResponseEntity<String> response = this.restTemplate.postForEntity("/upload", map,
             String.class);
       // 判断是否存储文件成功
       assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
    }

    /**
     * 测试文件下载功能
     **/
    @Test
    public void shouldDownloadFile() throws Exception {
       // 获得本地存储的的test.txt文件
       ClassPathResource resource = new ClassPathResource("test.txt");
       // mock设定调用loadAsResource("test.txt")时返回本地存储的此文件
       given(this.storageService.loadAsResource("test.txt")).willReturn(resource);
       // 使用RestTemplate对象发起GET请求,下载文件,返回数据类型指定为string
       ResponseEntity<String> response = this.restTemplate
             .getForEntity("/files/{filename}", String.class, "test.txt");

       assertThat(response.getStatusCodeValue()).isEqualTo(200);
       assertThat(response.getBody()).isEqualTo("hello world!");
    }

}
pom.xml依赖管理
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-parent</artifactId>
       <version>3.3.2</version>
       <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>test.springboot</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>
    <url/>
    <licenses>
       <license/>
    </licenses>
    <developers>
       <developer/>
    </developers>
    <scm>
       <connection/>
       <developerConnection/>
       <tag/>
       <url/>
    </scm>
    <properties>
       <java.version>21</java.version>
    </properties>
    <dependencies>
       <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-thymeleaf</artifactId>
       </dependency>
       <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
       </dependency>

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

    <build>
       <plugins>
          <plugin>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-maven-plugin</artifactId>
          </plugin>
       </plugins>
    </build>

</project>

提醒

  • 客户端上传的文件均存放在resourceslocalStorage目录下,可以在application.properties文件内修改storage.path来更改下载路径;
  • 客户端上传的文件设置了最大文件大小4MB,可以在application.properties文件内修改最大文件大小;
  • resources下的learningRecord目录下存放了author的部分学习知识点,仅供参考;
  • 本项目为自行编写的代码,撰写了大量注释帮助理解代码。

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

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

相关文章

Git基础学习(一)

文章目录 一. Git1. 定义2. SVN与Git的的区别 一. Git 1. 定义 Git 是一种分布式版本控制系统&#xff0c;用于管理软件项目的源代码。它是由 Linux 之父 Linus Torvalds 开发的&#xff0c;并已经成为了现代软件开发领域中最流行的版本控制系统之一。 使用 Git 可以追踪代码…

旅游管理系统

TOC springboot0748旅游管理系统 第1章 绪论 1.1课题背景 计算机的普及和互联网时代的到来使信息的发布和传播更加方便快捷。用户可以通过计算机上的浏览器访问多个应用系统&#xff0c;从中获取一些可以满足用户需求的管理系统。网站系统有时更像是一个大型“展示平台”&a…

基于SpringBoot的家电销售展示平台--论文pf

TOC springboot514基于SpringBoot的家电销售展示平台--论文pf 第1章 绪论 1.1选题动因 当前的网络技术&#xff0c;软件技术等都具备成熟的理论基础&#xff0c;市场上也出现各种技术开发的软件&#xff0c;这些软件都被用于各个领域&#xff0c;包括生活和工作的领域。随着…

HTML+JS谁是卧底游戏

先说一句&#xff1a;一段时间没发文章&#xff0c;好多僵尸粉关注我&#xff0c;这CSDN&#x1f620; 主要功能 玩家设置&#xff1a;在游戏开始前&#xff0c;输入总人数、卧底人数和白板人数。系统会自动计算出剩下的平民人数&#xff0c;并随机分配身份。 身份查看&#…

html+css+js实现登录界面设计

在现代网页设计中&#xff0c;创建一个功能齐全且用户友好的登录页面是至关重要的。本文将介绍如何使用 HTML 和 CSS 创建一个简单而有效的登录页面&#xff0c;包括验证码、记住密码选项及忘记密码链接。 1. HTML 结构 我们将从 HTML 代码开始&#xff0c;构建一个包含登录表…

【Google SEO】搜索引擎索引综合SEO指南

有没有想过网站是如何在搜索引擎上列出的&#xff0c;以及 Google、Bing 和其他公司如何在几秒钟内为我们提供大量信息&#xff1f; 这种闪电般快速性能的秘诀在于搜索索引。它可以与所有页面的庞大且完美有序的目录档案进行比较。进入索引意味着搜索引擎已经看到了你的页面&a…

机器学习——lightGBM(学习整理)

目录 一、认识lightGBM 1. 简单介绍 2. 主要特点 LightGBM 的缺点 3. 模型训练方式 &#xff08;1&#xff09;Training API &#xff08;2&#xff09;Scikit-learn API 二、相关函数参数 1. Training API 2. Scikit-learn API&#xff08;重复只做补充&#xff09;…

python requests 被屏蔽(已设置header和代理IP,解决浏览器指纹问题)

情况说明&#xff1a; 已设置 User-Agent已使用代理IP之前请求没问题&#xff0c;突然无法请求了。我用浏览器打开网站可以正常访问。 我遇到的原因&#xff1a; 目标网站/接口&#xff0c;能够通过JA3或者其他浏览器指纹信息&#xff0c;识别到你不是通过浏览器进行访问的。…

【解决】JS Uncaught RangeError: Invalid array length

【解决】JS Uncaught RangeError: Invalid array length 在JavaScript编程中&#xff0c;Uncaught RangeError: Invalid array length 是一个相对常见的错误&#xff0c;通常发生在处理数组时提供了无效的长度值。这个错误可能由多种原因引起&#xff0c;本文将深入探讨此错误的…

LCP167 两数之和II--输入有序数组[leetcode-5]

LCP167 两数之和II–输入有序数组 给你一个下标从 1 开始的整数数组 numbers &#xff0c;该数组已按 非递减顺序排列 &#xff0c;请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1] 和 numbers[index2] &#xff0c;则 1 <…

Redis(day 2)

一、常用指令 哈希Hash kv模式不变&#xff0c;但v是一个键值对 &#xff08;1&#xff09;hset、hget命令用于为哈希表中的字段赋值 。 &#xff08;2&#xff09;hmset、hmget 同时将多个field-value对设置到哈希表中。会覆盖哈希表中已存在的字段。 &#xff08;3&…

AI在医学领域:通过声纹特征来预测血糖水平

糖尿病代谢紊乱&#xff08;DM&#xff09;是一种以血糖水平异常为特征的代谢性疾病&#xff0c;其表现为高血糖&#xff08;≥230 mg/dL&#xff09;或低血糖&#xff08;<65 mg/dL&#xff09;。该病导致胰岛素产生或作用受损&#xff0c;胰岛素作为调节葡萄糖稳态的关键激…

20 动态内存管理

目录 一、为什么要有动态内存管理 二、malloc 和 free &#xff08;一&#xff09;malloc &#xff08;二&#xff09;free 三、calloc 和 realloc &#xff08;一&#xff09;calloc &#xff08;二&#xff09;realloc 四、常见的动态内存错误 &#xff08;一&#…

【初阶数据结构】顺序表与链表的比较(附题)

目录 一、顺序表和链表的区别&#xff08;其他链表存在缺陷&#xff0c;比较意义不大&#xff0c;这里用带头双向循环链表与顺序表进行比较&#xff09; 1.1插入、扩容与随机访问 二、缓存利用率的比较 2.1前置知识 详解及补充知识&#xff08;本文仅为比较顺序表及链表&am…

照片怎么转jpg格式?这些照片格式转换方法简单又高效

图片已成为我们日常生活与工作中不可或缺的一部分。然而&#xff0c;面对多种多样的图片格式&#xff0c;如何高效地将它们转换为最常用的JPG格式&#xff0c;成为了许多人面临的难题。下面给大家分享常用的几种照片格式转换方法&#xff0c;一起来了解下吧。 方法一&#xff1…

数据结构之树体系:二叉树、平衡二叉树、红黑树、AVL树、B树、B+树、最小生成树、哈夫曼树、决策树、LSM树、后缀树、R树

概述 数据结构与算法 二叉树 其中每个结点都不能有多于两个子结点&#xff1a; 满二叉树&#xff1a;若设二叉树的高度为 h h h&#xff0c;除第 h h h层外&#xff0c;其它各层(1&#xff5e;h-1) 的结点数都达到最大个数&#xff0c;最后一层都是叶子结点&#xff0c;且叶…

CICD持续集成持续交付部署

一、CICD概念 1、什么是CI/CD&#xff1f; 通俗来说就是启动一个服务&#xff0c;能够监听代码变化&#xff0c;然后自动执行构建、测试、打包、发布等流程&#xff1b; 2、CI 持续集成 指在开发人员频繁地提交新代码&#xff0c;都会自动执行构建、测试。根据测试结果&…

WPS回应“崩了”:提供15天会员补偿,另有新羊毛,你还不来薅?

近期&#xff0c;“WPS崩了”这一话题在时隔两个月后&#xff0c;再次因多名用户反馈软件使用问题而登上微博热搜。 WPS官方微博随后发布消息称&#xff0c;经过工程师的紧急修复&#xff0c;WPS服务已经恢复正常。 为了补偿用户&#xff0c;在8月22日0点至24点期间&#xff…

视频插帧—— RIFE 和 IFNet 的机制和应用

介绍 最近&#xff0c;数字和模拟技术开始加速融合。我们生活在一个人工智能技术能够显著提高质量的时代&#xff0c;只要模拟材料能够数字化。 例如&#xff0c;讨论中涉及到的纸艺软件&#xff0c;纸龙的移动模型被时间锁定&#xff0c;以大约 3 fps&#xff08;每秒帧数&a…

vm 虚拟机无法调用摄像头(亲测有效)

-- 前言1 报错说明1.1 opencv调用摄像头失败&#xff0c;画面窗口无法显示1.2 选择连接摄像头出现失败&#xff1a;桌面右下角出现【USB 设备“Acer Integrated RGB Camera"的连接失败】连接摄像头方法 2 解决方法步骤一步骤二步骤三 补充 前言 网上找的很多方法都是无效…