当前位置: 首页 > news >正文

java实现文件分片上传并且断点续传

文章目录

    • 什么是断点续传
    • 后端实现
    • JAVA实现大文件分片上传断点续传

什么是断点续传

用户上传大文件,网络差点的需要历时数小时,万一线路中断,不具备断点续传的服务器就只能从头重传,而断点续传就是,允许用户从上传断线的地方继续传送,这样大大减少了用户的烦恼。
解决上传大文件服务器内存不够的问题
解决如果因为其他因素导致上传终止的问题,并且刷新浏览器后仍然能够续传,重启浏览器(关闭浏览器后再打开)仍然能够继续上传,重启电脑后仍然能够上传
检测上传过程中因网络波动导致文件出现了内容丢失那么需要自动检测并且从新上传
解决方案
前端
需要进行分割上传的文件
需要对上传的分片文件进行指定文件序号
需要监控上传进度,控制进度条
上传完毕后需要发送合并请求
Blob 对象,操作文件
后端
上传分片的接口
合并分片的接口
获取分片的接口
其他工具方法,用于辅助
前端端需要注意的就是: 文件的切割,和进度条
后端需要注意的就是: 分片存储的地方和如何进行合并分片

后端实现

package com.controller.commontools.fIleupload;import com.alibaba.fastjson.JSON;
import com.application.Result;
import com.container.ArrayByteUtil;
import com.encryption.hash.HashUtil;
import com.file.FileUtils;
import com.file.FileWebUpload;
import com.file.ReadWriteFileUtils;
import com.function.impl.ExecutorUtils;
import com.path.ResourceFileUtil;
import com.string.PatternCommon;
import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;@RestController
@RequestMapping("/fileslice")
public class FIleSliceUploadController {private  final  String identification="-slice-";private  final  String uploadslicedir="uploads"+File.separator+"slice"+File.separator;//分片目录private  final  String uploaddir="uploads"+File.separator+"real"+File.separator;//实际文件目录//获取分片@GetMapping("/testing/{fileName}/{fileSlicSize}/{fileSize}")public Result testing(@PathVariable String fileName,@PathVariable long fileSlicSize,@PathVariable long fileSize  ) throws Exception {String dir = fileNameMd5Dir(fileName,fileSize);String absoluteFilePathAndCreate = ResourceFileUtil.getAbsoluteFilePathAndCreate(uploadslicedir)+File.separator+dir;File file = new File(absoluteFilePathAndCreate);if (file.exists()) {List<String> filesAll = FileUtils.getFilesAll(file.getAbsolutePath());if (filesAll.size()<2){//分片缺少 删除全部分片文件 ,从新上传FileUtils.delFilesAllReview(absoluteFilePathAndCreate,true);return Result.Error();}//从小到大文件进行按照序号排序,和判断分片是否损坏List<String> collect = fileSliceIsbadAndSort(file, fileSlicSize);//获取最后一个分片String fileSliceName = collect.get(collect.size() - 1);fileSliceName = new File(fileSliceName).getName();int code = fileId(fileSliceName);//服务器的分片总大小必须小于或者等于文件的总大小if ((code*fileSlicSize)<=fileSize) {Result result = new Result();String finalFileSliceName = fileSliceName;String str = PatternCommon.renderString("{\"code\":\"$[code]\",\"fileSliceName\":\"${fileSliceName}\"}", new HashMap<String, String>() {{put("code", String.valueOf(code));put("fileSliceName", finalFileSliceName);}});result.setData(JSON.parse(str));return result;}else {//分片异常 ,删除全部分片文件,从新上传FileUtils.delFilesAllReview(absoluteFilePathAndCreate,true);return Result.Error();}}//不存在return Result.Error();}@PostMapping(value = "/uploads")public Result uploads(HttpServletRequest request)  {String fileSliceName = request.getParameter("fileSliceName");long fileSize = Long.parseLong(request.getParameter("fileSize")); //文件大小String dir = fileSliceMd5Dir(fileSliceName,fileSize);String absoluteFilePathAndCreate = ResourceFileUtil.getAbsoluteFilePathAndCreate(uploadslicedir+dir);FileWebUpload.fileUpload(absoluteFilePathAndCreate,fileSliceName,request);int i = fileId(fileSliceName); //返回上传成功的文件id,用于前端计算进度Result result=new Result();result.setData(i);return result;}// 合并分片@GetMapping(value = "/merge-file-slice/{fileSlicNamee}/{fileSlicSize}/{fileSize}")public Result mergeFileSlice(@PathVariable String fileSlicNamee,@PathVariable long fileSlicSize,@PathVariable long fileSize ) throws Exception {int l =(int) Math.ceil((double) fileSize / fileSlicSize); //有多少个分片String dir = fileSliceMd5Dir(fileSlicNamee,fileSize); //分片所在的目录String absoluteFilePathAndCreate = ResourceFileUtil.getAbsoluteFilePathAndCreate(uploadslicedir+dir);File file=new File(absoluteFilePathAndCreate);if (file.exists()){List<String> filesAll = FileUtils.getFilesAll(file.getAbsolutePath());//阻塞循环判断是否还在上传  ,解决前端进行ajax异步上传的问题int beforeSize=filesAll.size();while (true){Thread.sleep(1000);//之前分片数量和现在分片数据只差,如果大于1那么就在上传,那么继续filesAll = FileUtils.getFilesAll(file.getAbsolutePath());if (filesAll.size()-beforeSize>=1){beforeSize=filesAll.size();//继续检测continue;}//如果是之前分片和现在的分片相等的,那么在阻塞2秒后检测是否发生变化,如果还没变化那么上传全部完成,可以进行合并了//当然这不是绝对的,只能解决网络短暂的波动,因为有可能发生断网很长时间,网络恢复后文件恢复上传, 这个问题是避免不了的,所以我们在下面的代码进行数量的效验// 因为我们不可能一直等着他网好,所以如果1~3秒内没有上传新的内容,那么我们默认判定上传完毕if (beforeSize==filesAll.size()){Thread.sleep(2000);filesAll = FileUtils.getFilesAll(file.getAbsolutePath());if (beforeSize==filesAll.size()){break;}}}//分片数量效验if (filesAll.size()!=l){//分片缺少 ,删除全部分片文件,从新上传FileUtils.delFilesAllReview(absoluteFilePathAndCreate,true);return Result.Error();}//获取实际的文件名称,组装路径String realFileName = realFileName(fileSlicNamee);String realFileNamePath = ResourceFileUtil.getAbsoluteFilePathAndCreate(uploaddir+ realFileName);//从小到大文件进行按照序号排序 ,和检查分片文件是否有问题List<String> collect = fileSliceIsbadAndSort(file, fileSlicSize);int fileSliceSize = collect.size();List<Future<?>> futures = new ArrayList<>();// 将文件按照序号进行合并 ,算出Runtime.getRuntime().availableProcessors()个线程 ,每个线程需要读取多少分片, 和每个线程需要读取多少字节大小//有人会说一个分片一个线程不行吗,你想想如果上千或者上万分片的话,你创建这么多的线程需要多少时间,以及线程切换上下文切换和销毁需要多少时间? // 就算使用线程池,也顶不住啊,你内存又有多大,能存下多少队列?,并发高的话直接怼爆int availableProcessors = Runtime.getRuntime().availableProcessors();//每个线程读取多少文件int readFileSize = (int)Math.ceil((double)fileSliceSize / availableProcessors);//每个线程需要读取的文件大小long readSliceSize = readFileSize * fileSlicSize;for (int i = 0; i < availableProcessors; i++) {int finalI = i;Future<?> future =   ExecutorUtils.createFuture("FIleSliceUploadController",()->{//每个线程需要读取多少字节byte[] bytes=new byte[(int) readSliceSize];int index=0;for (int i1 = finalI *readFileSize,i2 = readFileSize*(finalI+1)>fileSliceSize?fileSliceSize:readFileSize*(finalI+1); i1 < i2; i1++) {try ( RandomAccessFile r = new RandomAccessFile(collect.get(i1), "r");){r.read(bytes, (int)(index*fileSlicSize),(int)fileSlicSize);} catch (IOException e) {e.printStackTrace();}index++;}if(finalI==availableProcessors-1){//需要调整数组bytes = ArrayByteUtil.getActualBytes(bytes);}try ( RandomAccessFile w = new RandomAccessFile(realFileNamePath, "rw");){//当前文件写入的位置w.seek(finalI*readSliceSize);w.write(bytes);} catch (IOException e) {e.printStackTrace();}});futures.add(future);}//阻塞到全部线程执行完毕后ExecutorUtils.waitComplete(futures);//删除全部分片文件FileUtils.delFilesAllReview(absoluteFilePathAndCreate,true);}else {//没有这个分片相关的的目录return Result.Error();}return Result.Ok();}//获取分片文件的目录private String fileSliceMd5Dir(String fileSliceName,long fileSize){int i = fileSliceName.indexOf(identification) ;String substring = fileSliceName.substring(0, i);String dir = HashUtil.md5(substring+fileSize);return dir;}//通过文件名称获取文件目录private String fileNameMd5Dir(String fileName,long fileSize){return HashUtil.md5(fileName+fileSize);}//获取分片的实际文件名private String realFileName(String fileSliceName){int i = fileSliceName.indexOf(identification) ;String substring = fileSliceName.substring(0, i);return substring;}//获取文件序号private  int fileId(String fileSliceName){int i = fileSliceName.indexOf(identification)+identification.length() ;String fileId = fileSliceName.substring(i);return Integer.parseInt(fileId);}//判断是否损坏private List<String>  fileSliceIsbadAndSort(File file,long fileSlicSize) throws Exception {String absolutePath = file.getAbsolutePath();List<String> filesAll = FileUtils.getFilesAll(absolutePath);if (filesAll.size()<1){//分片缺少,删除全部分片文件 ,从新上传FileUtils.delFilesAllReview(absolutePath,true);throw  new Exception("分片损坏");}//从小到大文件进行按照序号排序List<String> collect = filesAll.stream().sorted((a, b) -> fileId(a) - fileId(b)).collect(Collectors.toList());//判断文件是否损坏,将文件排序后,进行前后序号相差大于1那么就代表少分片了for (int i = 0; i < collect.size()-1; i++) {//检测分片的连续度if (fileId(collect.get(i)) - fileId(collect.get(i+1))!=-1) {//分片损坏 删除全部分片文件 ,从新上传FileUtils.delFilesAllReview(absolutePath,true);throw  new Exception("分片损坏");}//检测分片的完整度if (new File(collect.get(i)).length()!=fileSlicSize) {//分片损坏 删除全部分片文件 ,从新上传FileUtils.delFilesAllReview(absolutePath,true);throw  new Exception("分片损坏");}}return  collect;}
}

JAVA实现大文件分片上传断点续传

import org.springframework.web.multipart.MultipartFile;
import java.util.concurrent.CompletableFuture;
import org.apache.commons.lang3.StringUtils;
import lombok.extern.slf4j.Slf4j;
import java.text.DecimalFormat;
import java.io.*;@Slf4j 
public class FileSliceUpload {// 文件上传地址 private final String uploadPath = "/data/upload/";/** * @description: 文件分片上传 * @date: 2024/3/12 15:25 * @param fileSliceDTO * @return boolean */public boolean fileUpload(FileSliceDTO fileSliceDTO) {// 当前分片序号Integer chunkNumber = fileSliceDTO.getChunkNumber();// 当前分片大小 Long currentChunkSize = fileSliceDTO.getCurrentChunkSize();// 总分片数 Integer totalChunks = fileSliceDTO.getTotalChunks();// 原文件md5 String fileMd5 = fileSliceDTO.getFileMd5();// 文件名称 String fileName = fileSliceDTO.getFileName();// 用户账号 String userAccount = fileSliceDTO.getUserAccount();// 文件总大小 Long totalSize = fileSliceDTO.getTotalSize();// 当前分片文件流 MultipartFile mFile = fileSliceDTO.getFile();log.info("接收到文件:{},总大小:{} 总分片:{} 当前分片:{}", fileName, this.readableFileSize(totalSize), totalChunks, chunkNumber);String path = uploadPath + fileMd5 + "_" + userAccount + File.separator;File dirfile = new File(path);if (!dirfile.exists()) {dirfile.mkdirs();}String currentChunkFileName = path + fileMd5 + "_" + chunkNumber + ".tmp";File file = new File(currentChunkFileName);boolean uploadFlag = this.fileUpload(mFile, file);if (uploadFlag) {if (chunkNumber < totalChunks) {return true;} else {// 如果是最后一个分片,上传成功后就进行文件合并String mergeFileName = null;try {mergeFileName = this.fileMerge(fileMd5, totalChunks, fileName, totalSize, userAccount);} catch (IOException e) {log.info("文件合并发生异常:{}, {}", fileName, e.toString());}if (StringUtils.isBlank(mergeFileName)) {// 合并失败后异步删除文件夹CompletableFuture.runAsync(() - > { delFile(new File(path)); });return false;}log.info("文件合并成功:{}, 总大小: {}", fileName, this.readableFileSize(totalSize)); // 合并成功后异步删除文件夹CompletableFuture.runAsync(() - > {delFile(new File(path)); });return true;}}return false;}/** * @description: 文件上传私有方法* @date: 2024/3/12 15:25 * @param multipartFile  分片文件* @param file  目标文件* @return boolean */private boolean fileUpload(MultipartFile multipartFile, File file) {boolean flag = false;try {if (!file.exists()) {file.createNewFile();multipartFile.transferTo(file);} else {log.info("当前分片文件已存在:{}", file.getName());}flag = true;} catch (Exception e) {log.info("文件上传失败:{}, {}", multipartFile.getOriginalFilename(), e.toString());}return flag;} /** * @description: 合并文件 * @date: 2024/3/12 15:21 * @param fileMd5 * @param chunks * @param fileName * @param totalSize * @param userAccount * @return java.lang.String */private String fileMerge(String fileMd5, Integer chunks, String fileName, long totalSize, String userAccount) throws IOException {String fileType = this.getFileSuffix(fileName);String mergePath = uploadPath + UUIDUtil.uuid32() + "." + fileType;FileOutputStream fileOutputStream = new FileOutputStream(mergePath);String mergeFileName = null;long fileSize = 0 L;try {byte[] buf = new byte[1024 * 4];for (int i = 1; i <= chunks; i++) {String chunkFile = i + ".tmp";File file = new File(uploadPath + fileMd5 + "_" + userAccount + File.separator + fileMd5 + "_" + chunkFile);fileSize = fileSize + file.length();InputStream inputStream = new FileInputStream(file);int len;while ((len = inputStream.read(buf)) != -1) {fileOutputStream.write(buf, 0, len);}inputStream.close();}mergeFileName = mergePath;} catch (Exception e) {log.info("合并文件失败:{},{}", fileName, e.toString());} finally {fileOutputStream.close();}if (fileSize != totalSize) {log.info("文件总大小不一致:{}", fileName);return null;}return mergeFileName;} /*** @description: 删除文件/文件夹 * @date: 2024/3/12 15:19* @param file * @return boolean*/private boolean delFile(File file) {if (file == null || !file.exists()) {return true;}if (!file.isDirectory()) {file.delete();return true;} else {File[] files = file.listFiles();for (File f: files) {if (f.isDirectory()) {delFile(f);} else {f.delete();}}file.delete();return true;}} /** * @description: 文件大小可读化转换* @date: 2024/3/12 15:18 * @param size* @return java.lang.String */private String readableFileSize(long size) {if (size <= 0) {return "0";}final String[] units = new String[] {"B", "KB", "MB", "GB", "TB"};int digitGroups = (int)(Math.log10(size) / Math.log10(1024));return new DecimalFormat("#,###.##").format(size / Math.pow(1024, digitGroups)) + " " + units[digitGroups];} /** * @description: 获取文件的拓展名 支持形式 abc.jpg or D:/data/abc.txt; * @date: 2024/3/12 15:16 * @param fileName * @return java.lang.String */private String getFileSuffix(String fileName) {String newFileName = fileName;      if(fileName.contains("/") || fileName.contains("\\")){            String replaceFileName = fileName.replaceAll("\\\\", "/");            int lastIndexOf = replaceFileName.lastIndexOf("/");            if(lastIndexOf > 0) {                  newFileName = replaceFileName.substring(lastIndexOf);            }      }     int lastIndexOf = newFileName.lastIndexOf(".");String fileSuffix = lastIndexOf >= 0 ? newFileName.substring(lastIndexOf + 1).toLowerCase() : "";fileSuffix = newFileName.toLowerCase().endsWith(".tar.gz") ? "tar.gz" : fileSuffix;return fileSuffix;}
}

相关文章:

java实现文件分片上传并且断点续传

文章目录 什么是断点续传后端实现JAVA实现大文件分片上传断点续传 什么是断点续传 用户上传大文件,网络差点的需要历时数小时&#xff0c;万一线路中断&#xff0c;不具备断点续传的服务器就只能从头重传&#xff0c;而断点续传就是&#xff0c;允许用户从上传断线的地方继续传…...

leetcode hot100 之【LeetCode 15. 三数之和】 java实现

LeetCode 15. 三数之和 题目描述 给你一个包含 n 个整数的数组 nums&#xff0c;判断 nums 中是否存在三个元素 a&#xff0c;b&#xff0c;c 使得 a b c 0&#xff1f;请你找出所有和为 0 且不重复的三元组。 注意&#xff1a; 答案中的三元组可以按任意顺序组织。在 n…...

mysql学习教程,从入门到精通,sql序列使用(45)

sql序列使用 在SQL中&#xff0c;序列&#xff08;Sequence&#xff09;是一种数据库对象&#xff0c;用于生成唯一的数值&#xff0c;通常用于自动递增的主键。不同的数据库管理系统&#xff08;DBMS&#xff09;对序列的支持和语法可能有所不同。以下是一些常见的DBMS&#…...

Java 中的异常处理、常见异常、如何自定义异常类、Checked 和 Unchecked 异常的区别、如何处理数据库事务中的异常

文章目录 1. 异常的基本概念与处理方法定义常见异常类补充说明&#xff1a; 异常处理方法示例 2.如何自定义异常类步骤示例 3. Java 中的 Checked 和 Unchecked 异常的区别Checked 异常Unchecked 异常示例 4. 如何处理数据库事务中的异常常见场景处理方式示例讨论 总结 异常是指…...

6.1 特征值介绍

一、特征值和特征向量介绍 本章会开启线性代数的新内容。前面的第一部分是关于 A x b A\boldsymbol x\boldsymbol b Axb&#xff1a;平衡、均衡和稳定状态&#xff1b;现在的第二部分是关于变化的。时间会加入进来 —— 连续时间的微分方程 d u / d t A u \pmb{\textrm{d}…...

Vue01

前端最新Vue2Vue3基础入门到实战项目全套教程&#xff0c;自学前端vue就选黑马程序员&#xff0c;一套全通关&#xff01;_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1HV4y1a7n4?spm_id_from333.788.videopod.episodes&vd_source016213ecd945408976ff307a6bda30…...

MySQL - Navicat自动备份MySQL数据

对于从事IT开发的工程师&#xff0c;数据备份我想大家并不陌生&#xff0c;这件工程太重要了&#xff01;对于比较重要的数据&#xff0c;我们希望能定期备份&#xff0c;每天备份1次或多次&#xff0c;或者是每周备份1次或多次。 如果大家在平时使用Navicat操作数据库&#x…...

系统分析师20:【案例特训专题3】系统设计与运维

1 Web开发 1.1 Web开发涉及技术的综合应用 高性能高可用可维护应变安全 1.2 Web系统架构演化过程 1.2.1 单台机器到数据库与Web服务器分离 早期的web系统往往以单台机器形态出现&#xff0c;web网站无论是前端还是后台数据库都部署在一台服务器上&#xff0c;部署起来比较…...

Linux 局域网中使用NTP配置时间服务

一&#xff1a;NTP 时间服务器配置 前提&#xff1a; 局域网环境中一般不能直接使用互联网上提供的时间服务器&#xff0c;例如ntp.aliyun.com。所以可以使用局域网中的一个服务器时间为基准&#xff0c;其他服务器的时间都和他保持一致。 1、将服务器的系统时间配置为时间源…...

Shiro会话管理和加密

一、会话相关API及会话使用 Shiro提供了完整的企业级会话管理功能&#xff0c;不依赖于底层容器&#xff08;如Web容器Tomcat&#xff09;&#xff0c;可以在JavaSE和JavaEE环境中使用。会话相关API主要包括&#xff1a; Subject.getSession(): 获取当前用户的会话&#xff0…...

GPON、XG-PON和XGS-PON的区别

类别GPON10G PON 细分 GPON XG-PON XGS-PON 下行速率 2.488 Gbps 9.953 Gbps 9.953Gbps 上行速率 1.244 Gbps 2.488 Gbps 9.953Gbps 可用带宽 2200Mbps 8500Mbps 8500Mbps 1000Mbps2000Mbps8500Mbps ITU-T标准 G.984&#xff08;2003年&#xff09; G.987 &a…...

Spring 项目返回值枚举类编写技巧

Spring 项目返回值枚举类编写技巧 在 Spring 项目中&#xff0c;使用枚举类来统一管理返回值和状态码是一种非常优雅的实现方式。这不仅能提升代码的可读性和维护性&#xff0c;还能避免在代码中硬编码字符串或数字来表示状态码。本文将以 ReturnCodeEnum 为例&#xff0c;介绍…...

【操作系统】06.进程控制

一、进程创建 1.1 认识fork函数 在linux中fork函数是非常重要的函数&#xff0c;它从已存在进程中创建一个新进程。新进程为子进程&#xff0c;而原进程为父进程。 进程调用fork&#xff0c;当控制转移到内核中的fork代码后&#xff0c;内核将 分配新的内存块和内核数据结构…...

16天自制CppServer-day02

day02-设置错误与异常处理机制 上一天我们写了一个客户端与服务器通过socket进行连接&#xff0c;对socket,bind,listen,accept,connect等函数&#xff0c;我们都设想程序完美地、没有任何异常地运行&#xff0c;但显然这不现实&#xff0c;应该设置出现异常的处理机制&#x…...

时空智友企业流程化管控系统uploadStudioFile接口存在任意文件上传漏洞

免责声明&#xff1a;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该文章仅供学习用途使用。 1. 时空智友…...

Linux 中文件的权限说明

目录 一&#xff1a;文件权限类型二&#xff1a;默认权限管理1. 查看当前用户的umask值2. 修改当前用户的umask值3. 根据umask计算默认权限 三&#xff1a;普通权限管理1. 三种普通权限说明1.1 对于非目录文件来说1.2 对于目录文件来说 2. 查看某个文件的权限信息2.1 使用 ls -…...

MySql数据库中数据类型

本篇将介绍在 MySql 中的所有数据类型&#xff0c;其中主要分为四类&#xff1a;数值类型、文本和二进制类型、时间日期、String 类型。如下&#xff08;图片来源&#xff1a;MySQL数据库&#xff09;&#xff1a; 目录如下&#xff1a; 目录 数值类型 1. 整数类型 2. …...

Godot中的信号

目录 概念 signal connect方法连接Callable 信号要求参数 查看信号 连接信号 监听信号 Button - text属性 pressed 连接源 「按钮」的信号连接 使用代码&#xff0c;将方法与信号相连接 节点的connect方法 节点直接使用emit_signal方法通过字符串的方式触发信号…...

vba学习系列(8)--指定列单元格时间按时间段计数

系列文章目录 文章目录 系列文章目录前言一、背景二、VBA总结 前言 一、背景 时间格式&#xff1a;00:00:00 时间段格式&#xff1a;00:00:00 - 01:00:00 计数N列单元格时间位于时间段内的行数 二、VBA 代码如下&#xff08;示例&#xff09;&#xff1a; Sub AssignTimeSeg…...

大型企业软件开发是什么样子的? - Web Dev Cody

引用自大型企业软件开发是什么样子的&#xff1f; - Web Dev Cody_哔哩哔哩_bilibili 一般来说 学技术的时候 我们会关注 开发语言特性 &#xff0c;各种高级语法糖&#xff0c;底层技术 但是很少有关注到企业里面的开发流程&#xff0c;本着以终为始&#xff08;以就业为导向…...

uniapp 对接腾讯云IM群组成员管理(增删改查)

UniApp 实战&#xff1a;腾讯云IM群组成员管理&#xff08;增删改查&#xff09; 一、前言 在社交类App开发中&#xff0c;群组成员管理是核心功能之一。本文将基于UniApp框架&#xff0c;结合腾讯云IM SDK&#xff0c;详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

Chapter03-Authentication vulnerabilities

文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

【Linux】shell脚本忽略错误继续执行

在 shell 脚本中&#xff0c;可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行&#xff0c;可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令&#xff0c;并忽略错误 rm somefile…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

Debian系统简介

目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版&#xff…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

代理篇12|深入理解 Vite中的Proxy接口代理配置

在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

docker 部署发现spring.profiles.active 问题

报错&#xff1a; org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...

深度学习水论文:mamba+图像增强

&#x1f9c0;当前视觉领域对高效长序列建模需求激增&#xff0c;对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模&#xff0c;以及动态计算优势&#xff0c;在图像质量提升和细节恢复方面有难以替代的作用。 &#x1f9c0;因此短时间内&#xff0c;就有不…...