springboot+vue3+vue-simple-uploader輕松實現大文件分片上傳Minio

最近在寫視頻課程的上傳,需要上傳的視頻幾百MB到幾個G不等,普通的上傳都限制了文件的大小,況且上傳的文件太大的話會超時、異常等。所以這時候需要考慮分片上傳了,把需要上傳的視頻分成多個小塊上傳到,最后再合并成一個視頻進行存儲。我這里上傳到自有的Minio,其它存儲應該也是大同小異。

前端:vue3+vue-simple-uploader
后端:springboot+Minio

先看前端效果

vue-simple-uploader原生組件的樣式效果很不錯了,vue-simple-uploader文檔
在這里插入圖片描述
下面這個是我上傳成功后自定義的樣式
在這里插入圖片描述

再來看看流程圖思路

在這里插入圖片描述

有了流程我們就直接上代碼了

1、前端安裝vue-simple-uploader

npm install vue-simple-uploader@next --save

2、在main.ts引入

import uploader from 'vue-simple-uploader'
import 'vue-simple-uploader/dist/style.css';
// ...
const app = createApp(App)
// ...
// 引入上傳組件
app.use(uploader)

3、前端組件全部代碼

<template><uploaderref="uploaderRef":options="options":auto-start="false":fileStatusText="fileStatusText"class="uploader-container"@file-added="onFileAdded"@file-progress="onFileProgress"@file-success="onFileSuccess"@file-error="onFileError"@file-removed="onDelete"><uploader-unsupport>您的瀏覽器不支持上傳組件</uploader-unsupport><uploader-drop><uploader-btn :attrs="attrs">{{deProps.btnText}}</uploader-btn></uploader-drop><uploader-list><template #default="props"><!-- 已上傳的文件列表 --><div v-for="file in uploadFileList" :key="file.fileId" :file="file" class="raw-list"><div class="file-title">{{ file.name }}</div><div class="file-size">{{ parseFloat(file.size / 1024 / 1024).toFixed(2) }} MB</div><div class="file-status">已上傳</div><el-button size="mini" type="danger" @click="onDelete(uploadFileList, file)">刪除文件</el-button></div><!-- 正在上傳的文件列表 --><uploader-file v-for="file in props.fileList" :key="file.fileId" :file="file" :list="true" v-show="!file.completed" /></template></uploader-list></uploader>
</template><script setup>
import axios from 'axios';
import { getAccessToken,getTenantId } from '@/utils/auth';
import { propTypes } from '@/utils/propTypes'
const token = getAccessToken();
import {config} from '@/config/axios/config';
const emit = defineEmits(['success','delete'])const fileStatusText = {success: '上傳成功',error: '上傳失敗',uploading: '正在上傳',paused: '暫停上傳',waiting: '等待上傳'
};
// 原來已上傳過的文件列表
const uploadFileList = ref([]);
// const uploader = ref(null);
const currentFile = ref(null);
const isPaused = ref(false);const deProps = defineProps({btnText: propTypes.string.def('選擇文件上傳') ,fileList: propTypes.array.def([]), // 原來已上傳的文件列表singleFile: propTypes.bool.def(true), // 是否單文件上傳
})uploadFileList.value = deProps.fileList;/*** 上傳組件配置*/
const options = {target: config.base_url + '/infra/minio/upload', // 目標上傳 URLheaders: {'tenant-id': getTenantId(),'Authorization': `Bearer ${token}`}, // 接口的定義, 根據實際情況而定chunkSize: 5 * 1024 * 1024, // 分塊大小singleFile:  deProps.singleFile, // 是否單文件上傳simultaneousUploads: 3, // 同時上傳3個分片forceChunkSize: true, // 是否強制所有的塊都是小于等于 chunkSize 的值。默認是 false。// fileParameterName: 'file', // 上傳文件時文件的參數名,默認filemaxChunkRetries: 3, // 最大自動失敗重試上傳次數testChunks: false, // 是否開啟服務器分片校驗// 額外的請求參數query: (file) => {return {uploadId: file.uploadId,fileName: file.name,totalChunks: file.chunks.length};},// 處理請求參數, 將參數名字修改成接口需要的processParams: (params, file, chunk) => {params.chunkIndex = chunk.offset; // 分片索引return params;}
};
// 限制上傳的文件類型
const attrs = {accept: '.mp4,.png,.jpg,.txt,.pdf,.ppt,.pptx,.doc,docx,.xls,xlsx,.ofd,.zip,.rar',
};const uploaderRef = ref(null);/*** 模版中禁止了自動上傳(:auto-start="false")*/
const onFileAdded = async (file) => {currentFile.value = file;isPaused.value = false;try {// 1. 初始化上傳會話const initResponse = await axios.post(`${config.base_url}/infra/minio/init`,{ fileName: file.name, fileSize: file.size },{headers: {'tenant-id': getTenantId(),'Authorization': `Bearer ${token}`},});if (initResponse.data.code === 0) {file.uploadId = initResponse.data.data;} else {throw new Error(initResponse.data.msg);}// 2. 獲取已上傳分片列表const chunksResponse = await axios.get(`${config.base_url}/infra/minio/uploaded-parts/${file.uploadId}`,{params: { totalChunks: file.chunks.length },headers: {'tenant-id': getTenantId(),'Authorization': `Bearer ${token}`},},);if (chunksResponse.data.code === 0) {// 設置已上傳分片file.uploadedChunks = chunksResponse.data.data || [];}// 開始上傳file.resume();} catch (error) {file.cancel();console.error('初始化上傳出錯:', error);}
};// 上傳進度事件
const onFileProgress = (rootFile, file, chunk) => {// 使用 progress() 方法獲取上傳進度const progress = Math.round(file.progress() * 100);console.log(`上傳進度: ${progress}%`);
};// 文件上傳成功
const onFileSuccess = async (rootFile, file, response) => {try {// 調用合并接口const mergeResponse = await axios.post(config.base_url + '/infra/minio/merge', {uploadId: file.uploadId,fileName: file.name},{headers: {'tenant-id': getTenantId(),'Authorization': `Bearer ${token}`},});if (mergeResponse.data.code === 0) {// 添加到已上傳文件列表uploadFileList.value.push({fileId: file.uploadId,name: file.name,size: file.size,url: mergeResponse.data.data});} else {console.error('文件合并失敗:', mergeResponse.data.msg);}console.log(uploadFileList.value)emit('success', uploadFileList.value);} catch (error) {console.error('文件合并請求失敗:', error);} finally {currentFile.value = null;}
};// 文件上傳失敗
const onFileError = (rootFile, file, message) => {console.error('文件上傳失敗:', message);currentFile.value = null;
};// 暫停/繼續上傳
const togglePause = () => {if (!currentFile.value) return;if (isPaused.value) {currentFile.value.resume();} else {currentFile.value.pause();}isPaused.value = !isPaused.value;
};// 取消上傳
const onCancel = async (file) => {if (file.status === 'uploading') {try {// 調用后端取消接口await axios.post(`${config.base_url}/infra/minio/cancel/${file.uploadId}`,{headers: {'tenant-id': getTenantId(),'Authorization': `Bearer ${token}`},});file.cancel();} catch (error) {console.error('取消上傳失敗:', error);}} else {file.cancel();}currentFile.value = null;
};// 刪除文件
const onDelete = async (list,file) => {try {// 調用后端刪除接口await axios.delete(`http://localhost:48080/admin-api/infra/minio/delete?path=${file.url}`,{headers: {'tenant-id': getTenantId(),'Authorization': `Bearer ${token}`},});// 從列表中移除const index = list.findIndex(f => f.fileId === file.fileId);if (index !== -1) {list.splice(index, 1);}emit('delete', list);} catch (error) {console.error('刪除文件失敗:', error);}
};
</script>
<style lang="scss" scoped>
.uploader-container {border: 1px solid #eee;border-radius: 4px;padding: 15px;
}.raw-list{display: flex;align-items: center;justify-content: space-between;padding: 10px 20px;.file-title{width: 30%;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;}
}</style> 

4、使用組件

<upload-chunk 
ref="uploadChunkRef" 
btnText="上傳視頻" 
:fileList="fileList" 
@success="uploadChunkSuccess" 
@delete="uploadChunkDelete" />

前端的代碼就這么多,接下來看看后端。

1、添加minio依賴

<dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.5.7</version>
</dependency>

2、創建3個請求實體類

public class FileChunkInitReqVO {private String fileId;private String fileName;private Long fileSize;
}public class FileChunkMergeReqVO {private String uploadId;private String fileName;
}public class FileChunkUploadReqVO {private String uploadId;private String fileName;private Integer chunkIndex;private Integer totalChunks;private MultipartFile file;
}

3、Controller類

/*** 刪除指定文件** @param path 文件ID* @return 響應狀態*/
@DeleteMapping("/delete")
@PermitAll
public CommonResult<String> deleteFile(@RequestParam String path) {try {fileService.deleteFile(path);return CommonResult.success("File deleted successfully.");} catch (IOException | NoSuchAlgorithmException | InvalidKeyException e) {return CommonResult.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), "Error deleting file: " + e.getMessage());}
}///初始化分片上傳
@PostMapping("/init")
@PermitAll
public CommonResult<String> initUploadSession(@RequestBody FileChunkInitReqVO reqVO) {try {String uploadId = fileService.initUploadSession(reqVO.getFileName(), reqVO.getFileSize());return CommonResult.success(uploadId);} catch (Exception e) {log.error("初始化上傳會話失敗", e);return CommonResult.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), "初始化上傳會話失敗");}
}//上傳文件分片
@PostMapping("/upload")
@PermitAll
public CommonResult<Boolean> uploadFilePart(@Validated FileChunkUploadReqVO reqVO) {try {boolean result = fileService.uploadFilePart(reqVO.getUploadId(),reqVO.getChunkIndex(),reqVO.getTotalChunks(),reqVO.getFile());return CommonResult.success(result);} catch (Exception e) {log.error("上傳分片失敗", e);return CommonResult.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), "上傳分片失敗");}
}//獲取已上傳分片列表
@GetMapping("/uploaded-parts/{uploadId}")
@PermitAll
public CommonResult<List<Integer>> getUploadedParts(@PathVariable String uploadId,@RequestParam int totalChunks) {try {List<Integer> uploadedParts = fileService.getUploadedParts(uploadId, totalChunks);return CommonResult.success(uploadedParts);} catch (Exception e) {log.error("獲取已上傳分片失敗", e);return CommonResult.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), "獲取已上傳分片失敗");}
}//合并文件分片
@PostMapping("/merge")
@PermitAll
public CommonResult<String> mergeFileParts(@RequestBody FileChunkMergeReqVO reqVO) {try {String fileUrl = fileService.mergeFileParts(reqVO.getUploadId(),reqVO.getFileName());return CommonResult.success(fileUrl);} catch (Exception e) {log.error("合并文件失敗", e);return CommonResult.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), "合并文件失敗");}
}//取消上傳
@PostMapping("/cancel/{uploadId}")
@PermitAll
public CommonResult<Boolean> cancelUpload(@PathVariable String uploadId) {try {fileService.cancelUpload(uploadId);return CommonResult.success(true);} catch (Exception e) {log.error("取消上傳失敗", e);return CommonResult.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), "取消上傳失敗");}
}

5、service類


@Service
public class MinioChunkUploadService {@Resourceprivate FileMapper fileMapper;// 改成自己的private static final String endpoint = "http://xxxx";private static final String accessKey = "BDnZ1SS3Kq0pxxxxxx";private static final String accessSecret = "MAdjW4rd0hXoZNrxxxxxxxx";private static final String bucketName = "xxtigrixxx";private static final String CHUNK_PREFIX = "chunks/";private static final String MERGED_PREFIX = "merged/";/*** 創建 Minio 客戶端* @return*/private MinioClient createMinioClient() {return MinioClient.builder().endpoint(endpoint).credentials(accessKey, accessSecret).build();}/*** 刪除指定文件** @param path 文件路徑*/public void deleteFile(String path) throws IOException, NoSuchAlgorithmException, InvalidKeyException {MinioClient minioClient = createMinioClient();try {String fileNames = MERGED_PREFIX + path;// 刪除文件minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(fileNames).build());} catch (MinioException e) {throw new IOException("Error deleting file: " + e.getMessage(), e);}}// 新增方法:檢查分片是否已存在public boolean checkChunkExists(String fileId, int chunkIndex)throws IOException, NoSuchAlgorithmException, InvalidKeyException {MinioClient minioClient = createMinioClient();try {String objectName = fileId + "/chunk-" + chunkIndex;minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());return true;} catch (Exception e) {throw new IOException("Error checking chunk existence: " + e.getMessage(), e);}}// 新增方法:獲取已上傳分片列表public List<Integer> getUploadedChunks(String fileId)throws IOException, NoSuchAlgorithmException, InvalidKeyException {MinioClient minioClient = createMinioClient();List<Integer> uploadedChunks = new ArrayList<>();// 列出所有分片Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(fileId + "/chunk-").build());for (Result<Item> result : results) {Item item = null;try {item = result.get();} catch (Exception e) {throw new RuntimeException(e);}String objectName = item.objectName();// 提取分片索引: fileId/chunk-123String chunkStr = objectName.substring(objectName.lastIndexOf("-") + 1);try {int chunkIndex = Integer.parseInt(chunkStr);uploadedChunks.add(chunkIndex);} catch (NumberFormatException ignored) {// 忽略無效分片名}}return uploadedChunks;}/*** 初始化上傳會話*/public String initUploadSession(String fileName, long fileSize) {// 生成唯一上傳IDreturn UUID.randomUUID().toString();}/*** 上傳文件分片*/public boolean uploadFilePart(String uploadId, int chunkIndex, int totalChunks, MultipartFile filePart)throws IOException, NoSuchAlgorithmException, InvalidKeyException, MinioException {// 構建分片對象名稱String objectName = CHUNK_PREFIX + uploadId + "/" + chunkIndex;MinioClient minioClient = createMinioClient();// 上傳文件分片minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(filePart.getInputStream(), filePart.getSize(), -1).contentType(filePart.getContentType()).build());return true;}/*** 獲取已上傳分片列表*/public List<Integer> getUploadedParts(String uploadId, int totalChunks)throws IOException, NoSuchAlgorithmException, InvalidKeyException, MinioException {List<Integer> uploadedParts = new ArrayList<>();MinioClient minioClient = createMinioClient();// 列出所有分片Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(CHUNK_PREFIX + uploadId + "/").build());for (Result<Item> result : results) {try {Item item = result.get();String objectName = item.objectName();// 提取分片索引: chunks/uploadId/123String chunkIndexStr = objectName.substring(objectName.lastIndexOf("/") + 1);uploadedParts.add(Integer.parseInt(chunkIndexStr));} catch (Exception e) {System.out.println(e.getMessage());}}return uploadedParts;}/*** 合并文件分片*/public String mergeFileParts(String uploadId, String fileName)throws IOException, NoSuchAlgorithmException, InvalidKeyException, MinioException {// 獲取所有分片List<String> partNames = new ArrayList<>();List<ComposeSource> sources = new ArrayList<>();MinioClient minioClient = createMinioClient();Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(CHUNK_PREFIX + uploadId + "/").build());for (Result<Item> result : results) {Item item = result.get();partNames.add(item.objectName());sources.add(ComposeSource.builder().bucket(bucketName).object(item.objectName()).build());}// 按分片索引排序sources.sort((a, b) -> {int indexA = Integer.parseInt(a.object().substring(a.object().lastIndexOf("/") + 1));int indexB = Integer.parseInt(b.object().substring(b.object().lastIndexOf("/") + 1));return Integer.compare(indexA, indexB);});// 構建最終文件對象名稱String finalObjectName = MERGED_PREFIX + DateUtil.format(LocalDateTime.now(), "yyyyMMdd") + "/" + uploadId + "/" + fileName;// 合并文件minioClient.composeObject(ComposeObjectArgs.builder().bucket(bucketName).object(finalObjectName).sources(sources).build());// 刪除分片文件for (String partName : partNames) {minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(partName).build());}// 返回文件訪問URLreturn finalObjectName;}/*** 取消上傳*/public void cancelUpload(String uploadId)throws IOException, NoSuchAlgorithmException, InvalidKeyException, MinioException {MinioClient minioClient = createMinioClient();// 刪除所有分片Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(CHUNK_PREFIX + uploadId + "/").build());for (Result<Item> result : results) {Item item = result.get();minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(item.objectName()).build());}}
}

OK,全部代碼完成,有問題或哪里不對的地方歡迎指正

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/84134.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/84134.shtml
英文地址,請注明出處:http://en.pswp.cn/web/84134.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

AI 重構代碼實戰:如何用飛算 JavaAI 快速升級遺留系統?

在企業數字化進程中&#xff0c;遺留系統如同陳舊的基礎設施&#xff0c;雖承載著重要業務邏輯&#xff0c;但因技術落后、架構復雜&#xff0c;升級維護困難重重。飛算 JavaAI 的出現&#xff0c;為遺留系統的二次開發帶來了新的轉機&#xff0c;其基于智能分析與關聯項目的技…

鴻蒙運動開發實戰:打造專屬運動視頻播放器

##鴻蒙核心技術##運動開發##Media Kit&#xff08;媒體服務&#xff09;# 在當今數字化時代&#xff0c;運動健身已經成為許多人生活的一部分。今天我將在應用中添加視頻播放器&#xff0c;幫助用戶在運動前、運動后更好地進行熱身和拉伸。這篇文章將從代碼核心點入手&#xf…

一個包含15個界面高質量的電商APP客戶端UI解決方案

一個包含15個界面高質量的電商APP客戶端UI解決方案 您可以將其用于電商APP應用項目。包含一系列完整的界面設計元素&#xff0c;包括歡迎頁、登錄、注冊、首頁、產品分類、產品詳情、尺碼選擇、購物車、訂單、支付&#xff0c;覆蓋電商APP的大部分界面。每個部分都精心設計&…

執行 PGPT_PROFILES=ollama make run下面報錯,

執行 PGPT_PROFILESollama make run 下面報錯&#xff0c; File "/home/powersys/.cache/pypoetry/virtualenvs/private-gpt-ZIwX6JeM-py3.11/lib/python3.11/site-packages/qdrant_client/http/api_client.py", line 108, in send_inner raise ResponseHandling…

【Docker基礎】Docker核心概念:命名空間(Namespace)之User詳解

目錄 引言 1 基礎概念回顧 1.1 命名空間概述 1.2 命名空間的類型 2 User命名空間詳解 2.1 基本概念 2.2 工作原理 User命名空間的工作流程 User命名空間架構 3 應用場景 4 配置與使用 5 總結 引言 隨著容器化技術的廣泛應用&#xff0c;Docker已成為現代軟件開發、…

DIDCTF-應急響應

前言 最近在學長分享應急響應與電子取證的知識&#xff0c;又恰逢期末周沒有課&#xff0c;記錄自己在取證道路的成長。 linux-basic-command 下載附件&#xff0c;得到Apache 服務器訪問日志文件&#xff0c;根據題目要求找出排名前五的ip&#xff0c;題目提示寫腳本&#…

MybatisPlus深入學習

今天深入的學習了一下mp&#xff0c;從頭開始學習&#xff01;哈哈哈哈哈 本節只講干的&#xff01; 我們上來先看一段代碼&#xff0c;不知道你能不能看明白&#xff01; package com.itheima.mp.mapper;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapp…

安卓9.0系統修改定制化____安卓9.0系統精簡 了解系統app組件構成 系統app釋義 常識篇 一

在安卓 9.0 系統的使用過程中,許多用戶都希望能夠對系統進行深度定制,讓手機系統更加貼合個人需求。而系統精簡作為定制化的重要一環,不僅能夠釋放手機存儲空間,還能提升系統運行速度,優化資源分配。想要安全有效地對安卓 9.0 系統進行精簡,深入了解系統 app 組件的構成是…

2.4 Windows Conan編譯FFmpeg 4.4.1

Conan的安裝與使用參考之前的文章&#xff1a;Conan簡單使用 一、Conan編譯ffmpeg 1.1 Conan的配置文件 創建配置文件&#xff1a;C:\Users\wujh\.conan2\profiles\vs2019 [settings] archx86_64 build_typeRelease compilermsvc compiler.cppstd14 compiler.runtimedynami…

社群經濟視域下開源鏈動2+1模式與AI智能名片賦能S2B2C商城小程序的創新發展研究

摘要&#xff1a;在數字經濟蓬勃發展的背景下&#xff0c;社群經濟作為連接用戶情感與價值反哺的新型經濟形態&#xff0c;正通過技術創新與模式重構實現深度演化。本文基于社群經濟“創造有價值連接”的本質特征&#xff0c;系統探討“開源鏈動21模式”“AI智能名片”與“S2B2…

【計算機網絡】——reactor模式高并發網絡服務器設計

&#x1f525;個人主頁&#x1f525;&#xff1a;孤寂大仙V &#x1f308;收錄專欄&#x1f308;&#xff1a;計算機網絡 &#x1f339;往期回顧&#x1f339;&#xff1a;【計算機網絡】非阻塞IO——epoll 編程與ET模式詳解——(easy)高并發網絡服務器設計 &#x1f516;流水不…

Uniapp跨端兼容性全方位解決方案

在當今多端融合的移動互聯網時代&#xff0c;Uniapp作為一款優秀的跨平臺開發框架&#xff0c;已成為許多開發者的首選。然而&#xff0c;真正的挑戰在于如何優雅地處理不同平臺之間的差異。本文將全面剖析Uniapp跨端開發的兼容性處理方案&#xff0c;提供從基礎到高級的完整解…

迅為RK3576開發板NPUrknn-toolkit2環境搭建和使用docker環境安裝

開發板采用核心板底板結構&#xff0c;在我們的資料里提供了底板的原理圖工程以及PCB工程&#xff0c;可以實現真正意義上的裁剪、定制屬于自己的產品&#xff0c;滿足更多應用場合。 迅為針對RK3576開發板整理出了相應的開發流程以及開發中需要用到的資料&#xff0c;并進行詳…

什么是 OpenFeigin ?微服務中的具體使用方式

什么是Feign&#xff1f; Feign 是一種聲明式的 HTTP 客戶端框架&#xff0c;主要用于簡化微服務架構中服務之間的遠程調用&#xff0c;也可以通過定義接口和注解的方式調用遠程服務&#xff0c;無需手動構建 HTTP 請求或解析響應數據。Spring Cloud 對 Feign 進行了增強&…

對抗性提示:進階守護大語言模型

人工智能模型正快速進化 —— 變得更具幫助性、更流暢&#xff0c;并且更深入地融入我們的日常生活和商業運營中。但隨著其能力的提升&#xff0c;風險也在增加。在維護安全可信的人工智能方面&#xff0c;最緊迫的挑戰之一是對抗性提示&#xff1a;這是一種微妙且通常富有創意…

運營商頻段

以下是三大運營商&#xff08;中國移動、中國電信、中國聯通&#xff09;及中國廣電的 5G 主要頻段 及其所屬運營商的整理表格&#xff1a; 運營商頻段上行頻率 (MHz)下行頻率 (MHz)帶寬備注廣電n28703-733758-788230MHz移動共享n794900-4960-60MHz-移動n412515-2675-160MHz-n7…

項目拓展-Apache對象池,對象池思想結合ThreadLocal復用日志對象

優化日志對象創建以及日志對象復用 日志對象上下文實體類 traceId 請求到達時間戳 請求完成時間戳 請求總共耗費時長 get/post/put/delete請求方式 Http狀態碼 原始請求頭中的所有鍵值對 請求體內容 響應體內容 失敗Exception信息詳細記錄 是否命中緩存 package c…

Javaweb - Vue入門

Vue是一款用于構建用戶界面的漸進式的JavaScript框架。 使用步驟 引入Vue模塊&#xff0c;創建Vue的應用實例&#xff0c;定義元素&#xff0c;交給Vue控制。 一、引入Vue模塊 因為使用的是模塊化的JavaScript&#xff0c;因此在script標簽內要聲明一個屬性&#xff1a;typ…

C++ 標準模板庫各個容器的應用場景分析

C 標準模板庫&#xff08;STL&#xff09;中的容器分為序列式容器、關聯式容器和無序容器&#xff0c;各自適用于不同場景。以下是主要容器的應用場景及案例&#xff1a; 一、序列式容器 元素按插入順序存儲&#xff0c;支持線性訪問。 1. vector 場景&#xff1a;動態數組…

安裝前端vite框架,后端安裝fastapi框架

前期準備 首先新建一個文件夾&#xff0c;文件夾里面新建一個文件夾&#xff0c;用于安裝依賴 安裝vite框架 npm init -y 目的是安裝package.json配置文件 npm install vite --save-dev 安裝vite框架 安裝完是這個樣子 新建了一個文件夾和js文件 后端內容 main.js document.…