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

springboot项目实现断点续传

  • java代码
package com.ruoyi.web.upload.controller;
import com.ruoyi.web.upload.dto.FileChunkDTO;
import com.ruoyi.web.upload.dto.FileChunkResultDTO;
import com.ruoyi.web.upload.result.Result;
import com.ruoyi.web.upload.service.IUploadService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/*** @ProjectName UploaderController* @author Administrator* @version 1.0.0* @Description 附件分片上传* @createTime 2022/4/13 0013 15:58*/
@RestController
@RequestMapping("upload")
public class UploaderController {@Resourceprivate IUploadService uploadService;/*** 检查分片是否存在** @return*/@GetMapping("chunk")public Result checkChunkExist(FileChunkDTO chunkDTO) {FileChunkResultDTO fileChunkCheckDTO;try {fileChunkCheckDTO = uploadService.checkChunkExist(chunkDTO);return Result.ok(fileChunkCheckDTO);} catch (Exception e) {return Result.fail(e.getMessage());}}/*** 上传文件分片** @param chunkDTO* @return*/@PostMapping("chunk")public Result uploadChunk(FileChunkDTO chunkDTO) {try {uploadService.uploadChunk(chunkDTO);return Result.ok(chunkDTO.getIdentifier());} catch (Exception e) {return Result.fail(e.getMessage());}}/*** 请求合并文件分片** @param chunkDTO* @return*/@PostMapping("merge")public Result mergeChunks(@RequestBody FileChunkDTO chunkDTO) {try {boolean success = uploadService.mergeChunk(chunkDTO.getIdentifier(), chunkDTO.getFilename(), chunkDTO.getTotalChunks());return Result.ok(success);} catch (Exception e) {return Result.fail(e.getMessage());}}
}
package com.ruoyi.web.upload.dto;
import org.springframework.web.multipart.MultipartFile;
/*** @ProjectName FileChunkDTO* @author Administrator* @version 1.0.0* @Description 附件分片上传* @createTime 2022/4/13 0013 15:59*/
public class FileChunkDTO {/*** 文件 md5*/private String identifier;/*** 分块文件*/MultipartFile file;/*** 当前分块序号*/private Integer chunkNumber;/*** 分块大小*/private Long chunkSize;/*** 当前分块大小*/private Long currentChunkSize;/*** 文件总大小*/private Long totalSize;/*** 分块总数*/private Integer totalChunks;/*** 文件名*/private String filename;public String getIdentifier() {return identifier;}public void setIdentifier(String identifier) {this.identifier = identifier;}public MultipartFile getFile() {return file;}public void setFile(MultipartFile file) {this.file = file;}public Integer getChunkNumber() {return chunkNumber;}public void setChunkNumber(Integer chunkNumber) {this.chunkNumber = chunkNumber;}public Long getChunkSize() {return chunkSize;}public void setChunkSize(Long chunkSize) {this.chunkSize = chunkSize;}public Long getCurrentChunkSize() {return currentChunkSize;}public void setCurrentChunkSize(Long currentChunkSize) {this.currentChunkSize = currentChunkSize;}public Long getTotalSize() {return totalSize;}public void setTotalSize(Long totalSize) {this.totalSize = totalSize;}public Integer getTotalChunks() {return totalChunks;}public void setTotalChunks(Integer totalChunks) {this.totalChunks = totalChunks;}public String getFilename() {return filename;}public void setFilename(String filename) {this.filename = filename;}@Overridepublic String toString() {return "FileChunkDTO{" +"identifier='" + identifier + '\'' +", file=" + file +", chunkNumber=" + chunkNumber +", chunkSize=" + chunkSize +", currentChunkSize=" + currentChunkSize +", totalSize=" + totalSize +", totalChunks=" + totalChunks +", filename='" + filename + '\'' +'}';}
}
package com.ruoyi.web.upload.dto;
import java.util.Set;
/*** @ProjectName FileChunkResultDTO* @author Administrator* @version 1.0.0* @Description 附件分片上传* @createTime 2022/4/13 0013 15:59*/
public class FileChunkResultDTO {/*** 是否跳过上传*/private Boolean skipUpload;/*** 已上传分片的集合*/private Set<Integer> uploaded;public Boolean getSkipUpload() {return skipUpload;}public void setSkipUpload(Boolean skipUpload) {this.skipUpload = skipUpload;}public Set<Integer> getUploaded() {return uploaded;}public void setUploaded(Set<Integer> uploaded) {this.uploaded = uploaded;}public FileChunkResultDTO(Boolean skipUpload, Set<Integer> uploaded) {this.skipUpload = skipUpload;this.uploaded = uploaded;}public FileChunkResultDTO(Boolean skipUpload) {this.skipUpload = skipUpload;}
}
package com.ruoyi.web.upload.dto;
import lombok.Getter;
/*** @Author* @Date Created in  2023/2/23 17:25* @DESCRIPTION:  统一返回结果状态信息类* @Version V1.0*/
@Getter
@SuppressWarnings("all")
public enum ResultCodeEnum {SUCCESS(200,"成功"),FAIL(201, "失败"),PARAM_ERROR( 202, "参数不正确"),SERVICE_ERROR(203, "服务异常"),DATA_ERROR(204, "数据异常"),DATA_UPDATE_ERROR(205, "数据版本异常"),LOGIN_AUTH(208, "未登陆"),PERMISSION(209, "没有权限"),CODE_ERROR(210, "验证码错误"),LOGIN_MOBLE_ERROR(211, "账号不正确"),LOGIN_DISABLED_ERROR(212, "改用户已被禁用"),REGISTER_MOBLE_ERROR(213, "手机号码格式不正确"),REGISTER_MOBLE_ERROR_NULL(214, "手机号码为空"),LOGIN_AURH(214, "需要登录"),LOGIN_ACL(215, "没有权限"),URL_ENCODE_ERROR( 216, "URL编码失败"),ILLEGAL_CALLBACK_REQUEST_ERROR( 217, "非法回调请求"),FETCH_ACCESSTOKEN_FAILD( 218, "获取accessToken失败"),FETCH_USERINFO_ERROR( 219, "获取用户信息失败");private Integer code;private String message;private ResultCodeEnum(Integer code, String message) {this.code = code;this.message = message;}
}
package com.ruoyi.web.upload.service;
import com.ruoyi.web.upload.dto.FileChunkDTO;
import com.ruoyi.web.upload.dto.FileChunkResultDTO;
import java.io.IOException;
/*** @ProjectName IUploadService* @author Administrator* @version 1.0.0* @Description 附件分片上传* @createTime 2022/4/13 0013 15:59*/
public interface IUploadService {/*** 检查文件是否存在,如果存在则跳过该文件的上传,如果不存在,返回需要上传的分片集合* @param chunkDTO* @return*/FileChunkResultDTO checkChunkExist(FileChunkDTO chunkDTO);/*** 上传文件分片* @param chunkDTO*/void uploadChunk(FileChunkDTO chunkDTO) throws IOException;/*** 合并文件分片* @param identifier* @param fileName* @param totalChunks* @return* @throws IOException*/boolean mergeChunk(String identifier,String fileName,Integer totalChunks)throws IOException;
}
package com.ruoyi.web.upload.service.impl;
import com.ruoyi.web.upload.dto.FileChunkDTO;
import com.ruoyi.web.upload.dto.FileChunkResultDTO;
import com.ruoyi.web.upload.service.IUploadService;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.io.*;
import java.util.*;
/*** @ProjectName UploadServiceImpl* @author Administrator* @version 1.0.0* @Description 附件分片上传* @createTime 2022/4/13 0013 15:59*/
@Service
@SuppressWarnings("all")
public class UploadServiceImpl implements IUploadService {private Logger logger = LoggerFactory.getLogger(UploadServiceImpl.class);@Autowiredprivate RedisTemplate redisTemplate;@Value("${ruoyi.profile}")private String uploadFolder;/*** 检查文件是否存在,如果存在则跳过该文件的上传,如果不存在,返回需要上传的分片集合*  检查分片是否存在○ 检查目录下的文件是否存在。○ 检查redis存储的分片是否存在。○ 判断分片数量和总分片数量是否一致。如果文件存在并且分片上传完毕,标识已经完成附件的上传,可以进行秒传操作。如果文件不存在或者分片为上传完毕,则返回false并返回已经上传的分片信息。* @param chunkDTO* @return*/@Overridepublic FileChunkResultDTO checkChunkExist(FileChunkDTO chunkDTO) {//1.检查文件是否已上传过//1.1)检查在磁盘中是否存在String fileFolderPath = getFileFolderPath(chunkDTO.getIdentifier());logger.info("fileFolderPath-->{}", fileFolderPath);String filePath = getFilePath(chunkDTO.getIdentifier(), chunkDTO.getFilename());File file = new File(filePath);boolean exists = file.exists();//1.2)检查Redis中是否存在,并且所有分片已经上传完成。Set<Integer> uploaded = (Set<Integer>) redisTemplate.opsForHash().get(chunkDTO.getIdentifier(), "uploaded");if (uploaded != null && uploaded.size() == chunkDTO.getTotalChunks() && exists) {return new FileChunkResultDTO(true);}File fileFolder = new File(fileFolderPath);if (!fileFolder.exists()) {boolean mkdirs = fileFolder.mkdirs();logger.info("准备工作,创建文件夹,fileFolderPath:{},mkdirs:{}", fileFolderPath, mkdirs);}// 断点续传,返回已上传的分片return new FileChunkResultDTO(false, uploaded);}/*** 上传分片*  上传附件分片○ 判断目录是否存在,如果不存在则创建目录。○ 进行切片的拷贝,将切片拷贝到指定的目录。○ 将该分片写入redis* @param chunkDTO*/@Overridepublic void uploadChunk(FileChunkDTO chunkDTO) {//分块的目录String chunkFileFolderPath = getChunkFileFolderPath(chunkDTO.getIdentifier());logger.info("分块的目录 -> {}", chunkFileFolderPath);File chunkFileFolder = new File(chunkFileFolderPath);if (!chunkFileFolder.exists()) {boolean mkdirs = chunkFileFolder.mkdirs();logger.info("创建分片文件夹:{}", mkdirs);}//写入分片try (InputStream inputStream = chunkDTO.getFile().getInputStream();FileOutputStream outputStream = new FileOutputStream(new File(chunkFileFolderPath + chunkDTO.getChunkNumber()))) {IOUtils.copy(inputStream, outputStream);logger.info("文件标识:{},chunkNumber:{}", chunkDTO.getIdentifier(), chunkDTO.getChunkNumber());//将该分片写入redislong size = saveToRedis(chunkDTO);} catch (Exception e) {e.printStackTrace();}}@Overridepublic boolean mergeChunk(String identifier, String fileName, Integer totalChunks) throws IOException {return mergeChunks(identifier, fileName, totalChunks);}/*** 合并分片** @param identifier* @param filename*/private boolean mergeChunks(String identifier, String filename, Integer totalChunks) {String chunkFileFolderPath = getChunkFileFolderPath(identifier);String filePath = getFilePath(identifier, filename);// 检查分片是否都存在if (checkChunks(chunkFileFolderPath, totalChunks)) {File chunkFileFolder = new File(chunkFileFolderPath);File mergeFile = new File(filePath);File[] chunks = chunkFileFolder.listFiles();// 切片排序1、2/3、---List fileList = Arrays.asList(chunks);Collections.sort(fileList, (Comparator<File>) (o1, o2) -> {return Integer.parseInt(o1.getName()) - (Integer.parseInt(o2.getName()));});try {RandomAccessFile randomAccessFileWriter = new RandomAccessFile(mergeFile, "rw");byte[] bytes = new byte[1024];for (File chunk : chunks) {RandomAccessFile randomAccessFileReader = new RandomAccessFile(chunk, "r");int len;while ((len = randomAccessFileReader.read(bytes)) != -1) {randomAccessFileWriter.write(bytes, 0, len);}randomAccessFileReader.close();}randomAccessFileWriter.close();} catch (Exception e) {return false;}return true;}return false;}/*** 检查分片是否都存在* @param chunkFileFolderPath* @param totalChunks* @return*/private boolean checkChunks(String chunkFileFolderPath, Integer totalChunks) {try {for (int i = 1; i <= totalChunks + 1; i++) {File file = new File(chunkFileFolderPath + File.separator + i);if (file.exists()) {continue;} else {return false;}}} catch (Exception e) {return false;}return true;}/*** 分片写入Redis* 判断切片是否已存在,如果未存在,则创建基础信息,并保存。* @param chunkDTO*/private synchronized long saveToRedis(FileChunkDTO chunkDTO) {Set<Integer> uploaded = (Set<Integer>) redisTemplate.opsForHash().get(chunkDTO.getIdentifier(), "uploaded");if (uploaded == null) {uploaded = new HashSet<>(Arrays.asList(chunkDTO.getChunkNumber()));HashMap<String, Object> objectObjectHashMap = new HashMap<>();objectObjectHashMap.put("uploaded", uploaded);objectObjectHashMap.put("totalChunks", chunkDTO.getTotalChunks());objectObjectHashMap.put("totalSize", chunkDTO.getTotalSize());
//            objectObjectHashMap.put("path", getFileRelativelyPath(chunkDTO.getIdentifier(), chunkDTO.getFilename()));objectObjectHashMap.put("path", chunkDTO.getFilename());redisTemplate.opsForHash().putAll(chunkDTO.getIdentifier(), objectObjectHashMap);} else {uploaded.add(chunkDTO.getChunkNumber());redisTemplate.opsForHash().put(chunkDTO.getIdentifier(), "uploaded", uploaded);}return uploaded.size();}/*** 得到文件的绝对路径** @param identifier* @param filename* @return*/private String getFilePath(String identifier, String filename) {String ext = filename.substring(filename.lastIndexOf("."));
//        return getFileFolderPath(identifier) + identifier + ext;return uploadFolder + filename;}/*** 得到文件的相对路径** @param identifier* @param filename* @return*/private String getFileRelativelyPath(String identifier, String filename) {String ext = filename.substring(filename.lastIndexOf("."));return "/" + identifier.substring(0, 1) + "/" +identifier.substring(1, 2) + "/" +identifier + "/" + identifier+ ext;}/*** 得到分块文件所属的目录** @param identifier* @return*/private String getChunkFileFolderPath(String identifier) {return getFileFolderPath(identifier) + "chunks" + File.separator;}/*** 得到文件所属的目录** @param identifier* @return*/private String getFileFolderPath(String identifier) {return uploadFolder + identifier.substring(0, 1) + File.separator +identifier.substring(1, 2) + File.separator +identifier + File.separator;
//        return uploadFolder;}
}
package com.ruoyi.web.upload.result;
import com.ruoyi.web.upload.dto.ResultCodeEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/*** @Author* @Date Created in  2023/2/23 17:25* @DESCRIPTION:  全局统一返回结果* @Version V1.0*/
@Data
@ApiModel(value = "全局统一返回结果")
@SuppressWarnings("all")
public class Result<T> {@ApiModelProperty(value = "返回码")private Integer code;@ApiModelProperty(value = "返回消息")private String message;@ApiModelProperty(value = "返回数据")private T data;private Long total;public Result(){}protected static <T> Result<T> build(T data) {Result<T> result = new Result<T>();if (data != null)result.setData(data);return result;}public static <T> Result<T> build(T body, ResultCodeEnum resultCodeEnum) {Result<T> result = build(body);result.setCode(resultCodeEnum.getCode());result.setMessage(resultCodeEnum.getMessage());return result;}public static <T> Result<T> build(Integer code, String message) {Result<T> result = build(null);result.setCode(code);result.setMessage(message);return result;}public static<T> Result<T> ok(){return Result.ok(null);}/*** 操作成功* @param data* @param <T>* @return*/public static<T> Result<T> ok(T data){Result<T> result = build(data);return build(data, ResultCodeEnum.SUCCESS);}public static<T> Result<T> fail(){return Result.fail(null);}/*** 操作失败* @param data* @param <T>* @return*/public static<T> Result<T> fail(T data){Result<T> result = build(data);return build(data, ResultCodeEnum.FAIL);}public Result<T> message(String msg){this.setMessage(msg);return this;}public Result<T> code(Integer code){this.setCode(code);return this;}public boolean isOk() {if(this.getCode().intValue() == ResultCodeEnum.SUCCESS.getCode().intValue()) {return true;}return false;}
}
  • 前端代码
  • mainjs导入uploader
import uploader from 'vue-simple-uploader'
Vue.use(uploader)
  • 安装uploader和spark-md5的依赖
npm install --save vue-simple-uploader
npm install --save spark-md5
  • 创建uploader组件
<template><div><uploader:autoStart="false":options="options":file-status-text="statusText"class="uploader-example"@file-complete="fileComplete"@complete="complete"@file-success="fileSuccess"@files-added="filesAdded"><uploader-unsupport></uploader-unsupport><uploader-drop><p>将文件拖放到此处以上传</p><uploader-btn>选择文件</uploader-btn><uploader-btn :attrs="attrs">选择图片</uploader-btn><uploader-btn :directory="true">选择文件夹</uploader-btn></uploader-drop><!-- <uploader-list></uploader-list> --><uploader-files> </uploader-files></uploader><br /><el-button @click="allStart()" :disabled="disabled">全部开始</el-button><el-button @click="allStop()" style="margin-left: 4px">全部暂停</el-button><el-button @click="allRemove()" style="margin-left: 4px">全部移除</el-button></div>
</template><script>
import axios from "axios";
import SparkMD5 from "spark-md5";
import {upload} from "@/api/user";
// import storage from "store";
// import { ACCESS_TOKEN } from '@/store/mutation-types'
export default {name: "Home",data() {return {skip: false,options: {target: "//localhost:9999/upload/chunk",// 开启服务端分片校验功能testChunks: true,parseTimeRemaining: function (timeRemaining, parsedTimeRemaining) {return parsedTimeRemaining.replace(/\syears?/, "年").replace(/\days?/, "天").replace(/\shours?/, "小时").replace(/\sminutes?/, "分钟").replace(/\sseconds?/, "秒");},// 服务器分片校验函数checkChunkUploadedByResponse: (chunk, message) => {const result = JSON.parse(message);if (result.data.skipUpload) {this.skip = true;return true;}return (result.data.uploaded || []).indexOf(chunk.offset + 1) >= 0;},// headers: {//   // 在header中添加的验证,请根据实际业务来//   "Access-Token": storage.get(ACCESS_TOKEN),// },},attrs: {accept: "image/*",},statusText: {success: "上传成功",error: "上传出错了",uploading: "上传中...",paused: "暂停中...",waiting: "等待中...",cmd5: "计算文件MD5中...",},fileList: [],disabled: true,};},watch: {fileList(o, n) {this.disabled = false;},},methods: {// fileSuccess(rootFile, file, response, chunk) {//   // console.log(rootFile);//   // console.log(file);//   // console.log(message);//   // console.log(chunk);//   const result = JSON.parse(response);//   console.log(result.success, this.skip);////   if (result.success && !this.skip) {//     axios//         .post(//             "http://127.0.0.1:9999/upload/merge",//             {//               identifier: file.uniqueIdentifier,//               filename: file.name,//               totalChunks: chunk.offset,//             },//             // {//             //   headers: { "Access-Token": storage.get(ACCESS_TOKEN) }//             // }//         )//         .then((res) => {//           if (res.data.success) {//             console.log("上传成功");//           } else {//             console.log(res);//           }//         })//         .catch(function (error) {//           console.log(error);//         });//   } else {//     console.log("上传成功,不需要合并");//   }//   if (this.skip) {//     this.skip = false;//   }// },fileSuccess(rootFile, file, response, chunk) {// console.log(rootFile);// console.log(file);// console.log(message);// console.log(chunk);const result = JSON.parse(response);console.log(result.success, this.skip);const user = {identifier: file.uniqueIdentifier,filename: file.name,totalChunks: chunk.offset,}if (result.success && !this.skip) {upload(user).then((res) => {if (res.code == 200) {console.log("上传成功");} else {console.log(res);}}).catch(function (error) {console.log(error);});} else {console.log("上传成功,不需要合并");}if (this.skip) {this.skip = false;}},fileComplete(rootFile) {// 一个根文件(文件夹)成功上传完成。// console.log("fileComplete", rootFile);// console.log("一个根文件(文件夹)成功上传完成。");},complete() {// 上传完毕。// console.log("complete");},filesAdded(file, fileList, event) {// console.log(file);file.forEach((e) => {this.fileList.push(e);this.computeMD5(e);});},computeMD5(file) {let fileReader = new FileReader();let time = new Date().getTime();let blobSlice =File.prototype.slice ||File.prototype.mozSlice ||File.prototype.webkitSlice;let currentChunk = 0;const chunkSize = 1024 * 1024;let chunks = Math.ceil(file.size / chunkSize);let spark = new SparkMD5.ArrayBuffer();// 文件状态设为"计算MD5"file.cmd5 = true; //文件状态为“计算md5...”file.pause();loadNext();fileReader.onload = (e) => {spark.append(e.target.result);if (currentChunk < chunks) {currentChunk++;loadNext();// 实时展示MD5的计算进度console.log(`${currentChunk}分片解析完成, 开始第${currentChunk + 1} / ${chunks}分片解析`);} else {let md5 = spark.end();console.log(`MD5计算完毕:${file.name} \nMD5:${md5} \n分片:${chunks} 大小:${file.size} 用时:${new Date().getTime() - time} ms`);spark.destroy(); //释放缓存file.uniqueIdentifier = md5; //将文件md5赋值给文件唯一标识file.cmd5 = false; //取消计算md5状态file.resume(); //开始上传}};fileReader.onerror = function () {this.error(`文件${file.name}读取出错,请检查该文件`);file.cancel();};function loadNext() {let start = currentChunk * chunkSize;let end =start + chunkSize >= file.size ? file.size : start + chunkSize;fileReader.readAsArrayBuffer(blobSlice.call(file.file, start, end));}},allStart() {console.log(this.fileList);this.fileList.map((e) => {if (e.paused) {e.resume();}});},allStop() {console.log(this.fileList);this.fileList.map((e) => {if (!e.paused) {e.pause();}});},allRemove() {this.fileList.map((e) => {e.cancel();});this.fileList = [];},},
};
</script><style>
.uploader-example {width: 100%;padding: 15px;margin: 0px auto 0;font-size: 12px;box-shadow: 0 0 10px rgba(0, 0, 0, 0.4);
}
.uploader-example .uploader-btn {margin-right: 4px;
}
.uploader-example .uploader-list {max-height: 440px;overflow: auto;overflow-x: hidden;overflow-y: auto;
}
</style>

相关文章:

springboot项目实现断点续传

java代码 package com.ruoyi.web.upload.controller; import com.ruoyi.web.upload.dto.FileChunkDTO; import com.ruoyi.web.upload.dto.FileChunkResultDTO; import com.ruoyi.web.upload.result.Result; import com.ruoyi.web.upload.service.IUploadService; import org.s…...

解析经典面试题:for 循环中的 let var

更多文章可以看看我的博客&#xff1a;https://icheng.github.io/ 题目 for循环中&#xff0c;使用 var 或 let 声明 i 变量&#xff0c;会得到不同的结果 var arr []; for (var i 0; i < 2; i) {arr[i] function () {console.log(i);} } arr[0](); arr[1]();输出&…...

CSS按钮-跑马灯边框

思路很简单&#xff0c;实现方法有很多很多。但是大体思路与实现方法都类似&#xff1a;渐变色 动画&#xff0c;主要区别在动画的具体实现 0、HTML 结构 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><titl…...

【PCIE系统学习】Gen1/2Gen3/4 symobl与OrderSet概念对比

这个专栏要干的事:学习PCIE理论知识,学会PCIE IP/VIP的使用。可以达到上手做项目,而不是空有理论 适合谁看:正在学习PCIE 设计验证,但学的过于零散。想有对比的系统的学习。 低价收费的目的:抵制胡乱传播转载现象。 版本控制:便于增加内容以及勘误 版本说明v20230829 …...

C++ Qt 中QMimeDatabase类详细介绍以及应用场景

C Qt 中QMimeDatabase类详细介绍以及应用场景 文章目录 C Qt 中QMimeDatabase类详细介绍以及应用场景一、QMimeDatabase类是什么&#xff1f;二、QMimeDatabase类中的关键功能和特点三、QMimeDatabase的用法四、QMimeDatabase的应用场景 一、QMimeDatabase类是什么&#xff1f;…...

深度学习7:生成对抗网络 – Generative Adversarial Networks | GAN

生成对抗网络 – GAN 是最近2年很热门的一种无监督算法&#xff0c;他能生成出非常逼真的照片&#xff0c;图像甚至视频。我们手机里的照片处理软件中就会使用到它。 目录 生成对抗网络 GAN 的基本原理 大白话版本 非大白话版本 第一阶段&#xff1a;固定「判别器D」&#x…...

R语言空气污染数据的地理空间可视化和分析:颗粒物2.5(PM2.5)和空气质量指数(AQI)...

原文链接&#xff1a;http://tecdat.cn/?p23800 由于空气污染对公众健康的不利影响&#xff0c;人们一直非常关注。世界各国的环境部门都通过各种方法&#xff08;例如地面观测网络&#xff09;来监测和评估空气污染问题&#xff08;点击文末“阅读原文”获取完整代码数据&…...

实现excel导出最简单方式

今天来记录一下导出excel的实现方式&#xff0c;导出的格式是xlsx的文件。 这里用到的是hutool的工具包&#xff0c;依赖如下&#xff1a; <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.3.5&…...

【每日一题Day310】LC1654到家的最少跳跃次数 | BFS

到家的最少跳跃次数【LC1654】 有一只跳蚤的家在数轴上的位置 x 处。请你帮助它从位置 0 出发&#xff0c;到达它的家。 跳蚤跳跃的规则如下&#xff1a; 它可以 往前 跳恰好 a 个位置&#xff08;即往右跳&#xff09;。它可以 往后 跳恰好 b 个位置&#xff08;即往左跳&…...

[Android AIDL] --- AIDL原理简析

上一篇文章已经讲述了如何在Android studio中搭建基于aidl的cs模型框架&#xff0c;只是用起来了&#xff0c;这次对aidl及cs端如何调用的原理进行简单分析 1 创建AIDL文件 AIDL 文件可以分为两类。 一类是用来定义接口方法&#xff0c;声明要暴露哪些接口给客户端调用&#…...

企业的固定资产管理怎么操作

一家拥有多台大型设备的工厂&#xff0c;这些设备需要定期进行保养和维护&#xff0c;以确保其正常运转。而企业内部员工由于专业知识和技能的不同&#xff0c;需要分工协作才能更好地完成各项工作任务。因此&#xff0c;在设备资产管理方面&#xff0c;如何实现高效、便捷、透…...

Rust 进阶学习

Rust 进阶学习 文章目录 Rust 进阶学习所有权作用域移动和克隆涉及函数的所有权机制涉及参数的所有权涉及返回值的所有权 引用和租借可变引用 枚举类枚举成员的属性枚举匹配 结构体结构体方法结构体关联函数 错误处理不可恢复错误可恢复错误 Rust代码组织管理Module默认的Modul…...

保护网站安全:学习蓝莲花的安装和使用,复现跨站脚本攻击漏洞及XSS接收平台

这篇文章旨在用于网络安全学习&#xff0c;请勿进行任何非法行为&#xff0c;否则后果自负。 环境准备 一、XSS基础 1、反射型XSS 攻击介绍 原理 攻击者通过向目标网站提交包含恶意脚本的请求&#xff0c;然后将该恶意脚本注入到响应页面中&#xff0c;使其他用户在查看…...

Redis——如何解决redis穿透、雪崩、击穿问题

目录 一、查询商品信息的常规代码示例二、缓存击穿2.1、缓存击穿的理解2.2、缓存击穿的解决方案2.3、解决缓存击穿的代码示例 三、缓存雪崩3.1、缓存雪崩的理解3.2、缓存雪崩的解决方案3.2.1、缓存集中过期的情况3.2.2、缓存服务器宕机的情况3.2.3、缓存服务器断电的情况 3.3、…...

MySQL一行记录是如何存储的?

目录 MySQL的数据存放在哪个文件&#xff1f; 表空间文件的结构是怎么样的&#xff1f; 1、行&#xff08;row&#xff09; 2、页&#xff08;page&#xff09; 3、区&#xff08;extent&#xff09; 4、段&#xff08;segment&#xff09; InnoDB 行格式有哪些&#xf…...

[element-ui] el-tree全部展开与收回

shrinkTreeNode () {// 改变一个全局变量this.treeStatus !this.treeStatus;// 改变每个节点的状态this.changeTreeNodeStatus(this.$refs.attrList.store.root); },// 改变节点的状态 changeTreeNodeStatus (node) {node.expanded this.treeStatus;for (let i 0; i < no…...

git 统计(命令)

查询某人某个时刻提交了多少代码 added 添加代码 removed 删除代码 total 总代码 git log --author刘俊秦 --since2023-08-01 00:00:00 --until2023-08-23 23:00:00 --prettytformat: --numstat | awk { add $1; subs $2; loc $1 - $2 } END { printf "added lines: %s…...

斐波那契1(矩阵快速幂加速递推,斐波那契前n项平方和)

链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 Keven 特别喜欢斐波那契数列&#xff0c;已知 fib11fib_11fib1​1&#xff0c;fib21fib_21fib2​1&#xff0c;对于 n>3n>3n>3&#xff0c;fibnfibn−2fibn−1fib_{n}fib_{n-2}fib_{n…...

minikube mac 启动

系统信息如下 最开始使用的minikube是1.22.0版本&#xff0c;按照如下命令启动&#xff1a; minikube start --memory7851 --cpus4 --image-mirror-countrycn遇到了下面一些问题&#xff1a; 1、拉取coredns:v1.8.0镜像失败 Error response from daemon: manifest for regis…...

从零开始学习 Java:简单易懂的入门指南之查找算法及排序算法(二十)

查找算法及排序算法 常见的七种查找算法&#xff1a;1. 基本查找2. 二分查找3. 插值查找4. 斐波那契查找5. 分块查找6. 哈希查找7. 树表查找 四种排序算法&#xff1a;1. 冒泡排序1.1 算法步骤1.2 动图演示1.3 代码示例 2. 选择排序2.1 算法步骤2.2 动图演示 3. 插入排序3.1 算…...

非煤矿山风险监测预警算法 yolov8

非煤矿山风险监测预警算法通过yolov8网络模型深度学习算法框架&#xff0c;非煤矿山风险监测预警算法在煤矿关键地点安装摄像机等设备利用智能化视频识别技术&#xff0c;能够实时分析人员出入井口的情况&#xff0c;人数变化并检测作业状态。YOLO的结构非常简单&#xff0c;就…...

Ansible学习笔记(一)

1.什么是Ansible 官方网站&#xff1a;https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html Ansible是一个配置管理和配置工具&#xff0c;类似于Chef&#xff0c;Puppet或Salt。这是一款很简单也很容易入门的部署工具&#xff0c;它使用SS…...

2024毕业设计选题指南【附选题大全】

title: 毕业设计选题指南 - 如何选择合适的毕业设计题目 date: 2023-08-29 categories: 毕业设计 tags: 选题指南, 毕业设计, 毕业论文, 毕业项目 - 如何选择合适的毕业设计题目 当我们站在大学生活的十字路口&#xff0c;毕业设计便成了我们面临的一项重要使命。这不仅是对我们…...

Error: PostCSS plugin autoprefixer requires PostCSS 8 问题解决办法

报错&#xff1a;Error: PostCSS plugin autoprefixer requires PostCSS 8 原因&#xff1a;autoprefixer版本过高 解决方案&#xff1a; 降低autoprefixer版本 执行&#xff1a;npm i postcss-loader autoprefixer8.0.0...

pymongo通过oplog获取数据(mongodb)

使用 MongoDB 的 oplog&#xff08;操作日志&#xff09;进行数据同步是高级的用法&#xff0c;主要用于复制和故障恢复。需要确保源 MongoDB 实例是副本集的一部分&#xff0c;因为只有副本集才会维护 oplog。 以下是简化的步骤&#xff0c;描述如何使用 oplog 进行数据同步&…...

MySQL数据备份与恢复

备份的主要目的&#xff1a; 备份的主要目的是&#xff1a;灾难恢复&#xff0c;备份还可以测试应用、回滚数据修改、查询历史数据、审计等。 日志&#xff1a; MySQL 的日志默认保存位置为&#xff1a; /usr/local/mysql/data##配置文件 vim /etc/my.cnf [mysqld] ##错误日志…...

基于ssm+vue汽车售票网站源码和论文

基于ssmvue汽车售票网站源码和论文088 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm 摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让…...

【List】List集合有序测试案例:ArrayList,LinkedList,Vector(123)

List是有序、可重复的容器。 有序&#xff1a; List中每个元素都有索引标记。可以根据元素的索引标记(在List中的位置)访问 元素&#xff0c;从而精确控制这些元素。 可重复&#xff1a; List允许加入重复的元素。更确切地讲&#xff0c;List通常允许满足 e1.equals(e2) 的元素…...

【javaweb】学习日记Day6 - Mysql 数据库 DDL DML

之前学习过的SQL语句笔记总结戳这里→【数据库原理与应用 - 第六章】T-SQL 在SQL Server的使用_Roye_ack的博客-CSDN博客 目录 一、概述 1、如何安装及配置路径Mysql&#xff1f; 2、SQL分类 二、DDL 数据定义 1、数据库操作 2、IDEA内置数据库使用 &#xff08;1&…...

使用 PyTorch C ++前端

使用 PyTorch C 前端 PyTorch C 前端是 PyTorch 机器学习框架的纯 C 接口。 虽然 PyTorch 的主要接口自然是 Python&#xff0c;但此 Python API 建立于大量的 C 代码库之上&#xff0c;提供基本的数据结构和功能&#xff0c;例如张量和自动微分。 C 前端公开了纯 C 11 API&a…...

6、NoSQL的四大分类

6、NoSQL的四大分类 kv键值对 不同公司不同的实现 新浪&#xff1a;Redis美团&#xff1a;RedisTair阿里、百度&#xff1a;Redismemcache 文档型数据库&#xff08;bson格式和json一样&#xff09; MongoDB MongoDB是一个基于分布式文件存储的数据库&#xff0c;一般用于存储…...

(动态规划) 剑指 Offer 60. n个骰子的点数 ——【Leetcode每日一题】

❓ 剑指 Offer 60. n个骰子的点数 难度&#xff1a;中等 把 n 个骰子扔在地上&#xff0c;所有骰子朝上一面的点数之和为 s 。输入 n&#xff0c;打印出s的所有可能的值出现的概率。 你需要用一个浮点数数组返回答案&#xff0c;其中第 i 个元素代表这 n 个骰子所能掷出的点…...

ArrayList与顺序表

文章目录 一. 顺序表是什么二. ArrayList是什么三. ArrayList的构造方法四. ArrayList的常见方法4.1 add()4.2 size()4.3 remove()4.4 get()4.5 set()4.6 contains()4.7 lastIndexOf()和 indexOf(&#xff09;4.8 subList()4.9 clear() 以上就是ArrayList的常见方法&#xff01…...

【【萌新的STM32-22中断概念的简单补充】】

萌新的STM32学习22-中断概念的简单补充 我们需要注意的是这句话 从上面可以看出&#xff0c;STM32F1 供给 IO 口使用的中断线只有 16 个&#xff0c;但是 STM32F1 的 IO 口却远远不止 16 个&#xff0c;所以 STM32 把 GPIO 管脚 GPIOx.0~GPIOx.15(xA,B,C,D,E,F,G)分别对应中断…...

Java 中数据结构HashMap的用法

Java HashMap HashMap 是一个散列表&#xff0c;它存储的内容是键值对(key-value)映射。 HashMap 实现了 Map 接口&#xff0c;根据键的 HashCode 值存储数据&#xff0c;具有很快的访问速度&#xff0c;最多允许一条记录的键为 null&#xff0c;不支持线程同步。 HashMap 是…...

Request对象和response对象

一、概念 request对象和response对象是通过Servlet容器&#xff08;如Tomcat&#xff09;自动创建并传递给Servlet的。 Servlet容器负责接收客户端的请求&#xff0c;并将请求信息封装到request对象中&#xff0c;然后将request对象传 递给相应的Servlet进行处理。类似地&…...

设计模式之桥接模式

文章目录 一、介绍二、案例1. 组件抽象化2. 桥梁抽象化 一、介绍 桥接模式&#xff0c;属于结构型设计模式。通过提供抽象与实现之间的桥接结构&#xff0c;把抽象化与实现化解耦&#xff0c;使得二者可以独立变化。 《Head First 设计模式》&#xff1a; 将抽象和实现放在两…...

pom.xml配置文件失效,显示已忽略的pom.xml --- 解决方案

现象&#xff1a; 在 Maven 创建模块Moudle时,由于开始没有正确创建好&#xff0c;所以把它删掉了&#xff0c;然后接着又创建了与一个与之前被删除的Moudle同名的Moudle时&#xff0c;出现了 Ignore pom.xml&#xff0c;并且新创建的 Module 的 pom.xml配置文件失效&#xf…...

文本编辑器Vim常用操作和技巧

文章目录 1. Vim常用操作1.1 Vim简介1.2 Vim工作模式1.3 插入命令1.4 定位命令1.5 删除命令1.6 复制和剪切命令1.7 替换和取消命令1.8 搜索和搜索替换命令1.9 保存和退出命令 2. Vim使用技巧 1. Vim常用操作 1.1 Vim简介 Vim是一个功能强大的全屏幕文本编辑器&#xff0c;是L…...

【算法系列篇】位运算

文章目录 前言什么是位运算算法1.判断字符是否唯一1.1 题目要求1.2 做题思路1.3 Java代码实现 2. 丢失的数字2.1 题目要求2.2 做题思路2.3 Java代码实现 3. 两数之和3.1 题目要求3.2 做题思路3.3 Java代码实现 4. 只出现一次的数字4.1 题目要求4.2 做题思路4.3 Java代码实现 5.…...

机器学习的测试和验证(Machine Learning 研习之五)

关于 Machine Learning 研习之三、四&#xff0c;可到秋码记录上浏览。 测试和验证 了解模型对新案例的推广效果的唯一方法是在新案例上进行实际尝试。 一种方法是将模型投入生产并监控其性能。 这很有效&#xff0c;但如果你的模型非常糟糕&#xff0c;你的用户会抱怨——这…...

RNN循环神经网络

目录 一、卷积核与循环核 二、循环核 1.循环核引入 2.循环核&#xff1a;循环核按时间步展开。 3.循环计算层&#xff1a;向输出方向生长。 4.TF描述循环计算层 三、TF描述循环计算 四、RNN使用案例 1.数据集准备 2.Sequential中RNN 3.存储模型&#xff0c;acc和lose…...

安防视频监控/视频集中存储/云存储平台EasyCVR无法播放HLS协议该如何解决?

视频云存储/安防监控EasyCVR视频汇聚平台基于云边端智能协同&#xff0c;支持海量视频的轻量化接入与汇聚、转码与处理、全网智能分发、视频集中存储等。音视频流媒体视频平台EasyCVR拓展性强&#xff0c;视频能力丰富&#xff0c;具体可实现视频监控直播、视频轮播、视频录像、…...

Docker技术--Docker的安装

1..Docker的安装方式介绍 Docker官方提供了三种方式可以实现Docker环境的安装。分别为:Script、yum、rpm。在实际的环境中建议使用yum或者是rpm。 2..Docker的yum安装 # 1.下载docker wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.re…...

客户案例|MemFire Cloud助推应急管理业务,打造百万级数据可视化大屏

「导语」 硬石科技&#xff0c;成立于2018年&#xff0c;总部位于武汉&#xff0c;是一家专注于应急管理行业和物联感知预警算法模型的技术核心的物联网产品和解决方案提供商。硬石科技作为一家高新技术企业&#xff0c;持有6项发明专利&#xff0c;拥有100余项各类平台认证和资…...

蒲公英路由器如何设置远程打印?

现如今&#xff0c;打印机已经是企业日常办公中必不可少的设备&#xff0c;无论何时何地&#xff0c;总有需要用到打印的地方&#xff0c;包括资料文件、统计报表等等。 但若人在外地或分公司&#xff0c;有文件急需通过总部的打印机进行打印时&#xff0c;由于不在同一物理网络…...

国产自主可控C++工业软件可视化图形架构源码

关于国产自主代替的问题是当前热点&#xff0c;尤其是工业软件领域。 “一个功能强大的全自主C跨平台图形可视化架构对开发自主可控工业基础软件至关重要&#xff01;” 作为全球领先的C工业基础图形可视化软件提供商&#xff0c;UCanCode软件有自己的思考&#xff0c;我们认…...

【linux命令讲解大全】022.网络管理工具和命令概述

文章目录 lsattr命令语法选项参数实例 nmcli补充说明语法选项OPTIONSOBJECT 实例 systemctl补充说明任务 旧指令 新指令 实例 开启防火墙22端口 从零学 python lsattr命令 用于查看文件的第二扩展文件系统属性。 语法 lsattr(选项)(参数) 选项 -E&#xff1a;可显示设备属…...

应急响应流程及思路

应急响应流程及思路 一&#xff1a;前言 对于还没有在项目中真正接触、参与过应急响应的同学来说&#xff0c;“应急响应”这四个字见的最多的就是建筑工地上的横幅 —— 人人懂应急&#xff0c;人人会响应。这里的应急响应和我们网络安全中的应急响应有着某种本质的相似&…...

网页自适应

自适应 那就要最好提前商量好 是全局自适应 或者是 局部自适应 一般网站页面纵向滚动条都是无法避免的 都是做横向适配也就是宽度 那就不能写死宽度像素 局部自适应 一般对父元素设置百分比就行 里面的子元素就设置固定像素、 比如一些登录 全局自适应 也就是要对每个元素…...