建设电影网站代码网页访问禁止怎么恢复
建设电影网站代码,网页访问禁止怎么恢复,合肥那家公司做网站,罗定市建设局网站空间地理行业国密大文件传输系统开发记录
一、项目背景与需求分析
作为武汉光谷某空间地理信息软件公司的核心开发人员#xff0c;我负责实现政府单位客户提出的国产化大文件传输系统。核心需求包括#xff1a;
安全要求#xff1a;使用SM4国密算法进行文件传输加密和存储…空间地理行业国密大文件传输系统开发记录一、项目背景与需求分析作为武汉光谷某空间地理信息软件公司的核心开发人员我负责实现政府单位客户提出的国产化大文件传输系统。核心需求包括安全要求使用SM4国密算法进行文件传输加密和存储加密性能要求支持10GB级文件分片传输文件夹结构保留兼容性前端主流浏览器Chrome/Firefox/Edge/国产浏览器后端信创环境麒麟/统信UOS SpringBoot 2.7.x数据库MySQL/Oracle/达梦DM8/人大金仓V8合规性完整源代码交付支持政府安全审查二、技术选型与架构设计1. 核心组件选择组件类型选型方案决策依据前端框架Vue 2.6.14 Element UI 2.15.13政府项目稳定优先大文件传输自研分片传输引擎开源方案缺乏SM4支持泽优大文件上传基于客户端插件方案完全开放产品源代码满足企业100%自主安全可控需求支持多种开发语言,java,sprintboot,php,asp.net支持信创国产化环境适配多种数据库支持SM4国密国密算法库GMHelper 1.1.0轻量级纯JS实现兼容WebCrypto后端框架SpringBoot 2.7.18国产中间件适配完善数据库访问MyBatis-Plus 3.5.6 JDBC多数据源统一支持多类型数据库2. 系统架构图┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ 浏览器端 │ │ 网关层 │ │ 服务层 │ │ (VueSM4) │───▶│ (Nginx) │───▶│ (SpringBoot)│ └─────────────┘ └─────────────┘ └─────────────┘ ▲ │ │ │ ▼ ▼ │ ┌─────────────────┐ ┌─────────────────┐ │ │ 对象存储(OSS) │ │ 数据库集群 │ │ │ (MinIO/华为OBS)│ │ (MySQL/DM/KDB)│ └───────────┴─────────────────┴ ┴─────────────────┘三、核心代码实现1. 前端SM4加密传输实现// src/utils/sm4Crypto.jsimport{CryptoJS}fromcrypto-js;import{sm4Encrypt,sm4Decrypt}fromgm-crypto;/** * SM4分片加密上传 * param {File} file 文件对象 * param {string} chunkSize 分片大小(默认5MB) * param {string} key SM4密钥(16字节) * returns {Promise} 分片数据数组 */exportasyncfunctionprepareEncryptedChunks(file,chunkSize5*1024*1024,key){constchunks[];consttotalChunksMath.ceil(file.size/chunkSize);for(leti0;itotalChunks;i){conststarti*chunkSize;constendMath.min(file.size,startchunkSize);constchunkfile.slice(start,end);// 读取分片为ArrayBufferconstbufferawaitnewPromise((resolve){constreadernewFileReader();reader.onload()resolve(reader.result);reader.readAsArrayBuffer(chunk);});// SM4加密分片constencryptedsm4Encrypt(newUint8Array(buffer),CryptoJS.enc.Utf8.parse(key),{mode:cbc,iv:CryptoJS.enc.Utf8.parse(0000000000000000)});chunks.push({index:i,total:totalChunks,data:encrypted,filename:${file.name}.part${i},md5:awaitcalculateMD5(buffer)// 计算原始分片MD5用于校验});}returnchunks;}/** * 文件夹递归处理 * param {File[]} files 文件列表(包含文件夹结构信息) * param {string} parentPath 父级路径 * returns {Object} 结构化文件树 */exportfunctionprocessFolder(files,parentPath){constfileTree{};files.forEach(file{if(file.webkitRelativePath){// 浏览器获取的文件夹路径constfullPathparentPath?${parentPath}/${file.webkitRelativePath}:file.webkitRelativePath;constpathPartsfullPath.split(/);constfileNamepathParts.pop();constcurrentPathpathParts.join(/);// 构建路径树letnodefileTree;pathParts.forEach(part{if(!node[part])node[part]{};nodenode[part];});node[fileName]{name:fileName,path:fullPath,size:file.size,type:file.type,lastModified:file.lastModified};}});returnfileTree;}2. 前端上传组件实现import { prepareEncryptedChunks, processFolder } from /utils/sm4Crypto; export default { data() { return { fileList: [], uploading: false, currentFile: {}, progressPercentage: 0, uploadStatus: , sm4Key: 1234567890abcdef // 实际应从安全配置获取 }; }, methods: { handleFileChange(files) { // 处理文件夹结构 const fileTree processFolder(files); console.log(文件结构:, fileTree); this.fileList files; }, async startUpload() { if (!this.fileList.length) return; this.uploading true; this.progressPercentage 0; const totalSize this.fileList.reduce((sum, file) sum file.size, 0); let uploadedSize 0; for (const file of this.fileList) { this.currentFile file; try { // 准备加密分片 const chunks await prepareEncryptedChunks(file, 5 * 1024 * 1024, this.sm4Key); // 逐个上传分片 for (const chunk of chunks) { const formData new FormData(); formData.append(file, new Blob([chunk.data])); formData.append(index, chunk.index); formData.append(total, chunk.total); formData.append(filename, chunk.filename); formData.append(md5, chunk.md5); formData.append(originalName, file.name); formData.append(relativePath, file.webkitRelativePath || ); await this.$http.post(/api/upload/chunk, formData, { headers: { Content-Type: multipart/form-data }, onUploadProgress: (progressEvent) { const chunkProgress Math.round( (progressEvent.loaded / progressEvent.total) * 100 ); // 更新总进度 uploadedSize progressEvent.loaded; this.progressPercentage Math.min( 100, Math.round((uploadedSize / totalSize) * 100) ); } }); } // 通知服务器合并分片 await this.$http.post(/api/upload/merge, { filename: file.name, totalChunks: chunks.length, size: file.size, relativePath: file.webkitRelativePath || }); } catch (error) { console.error(上传失败:, error); this.uploadStatus exception; break; } } this.uploading false; this.$message.success(上传完成); }, formatFileSize(bytes) { if (bytes 0) return 0 Bytes; const k 1024; const sizes [Bytes, KB, MB, GB]; const i Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) sizes[i]; } } };3. 后端分片处理实现// FileUploadController.javaRestControllerRequestMapping(/api/upload)RequiredArgsConstructorpublicclassFileUploadController{privatefinalFileStorageServicestorageService;privatefinalFileMetaRepositoryfileMetaRepository;// 分片上传接口PostMapping(/chunk)publicResponseEntityuploadChunk(RequestParam(file)MultipartFilefile,RequestParamintindex,RequestParaminttotal,RequestParamStringfilename,RequestParamStringmd5,RequestParamStringoriginalName,RequestParam(requiredfalse)StringrelativePath){try{// 验证分片MD5StringcalculatedMd5DigestUtils.md5DigestAsHex(file.getBytes());if(!calculatedMd5.equalsIgnoreCase(md5)){returnResponseEntity.badRequest().build();}// 保存临时分片StringtempPath/tmp/upload/UUID.randomUUID()/filename;FiletempDirnewFile(tempPath).getParentFile();if(!tempDir.exists()){tempDir.mkdirs();}file.transferTo(newFile(tempPath));// 记录分片信息storageService.saveChunkMeta(ChunkMeta.builder().chunkIndex(index).totalChunks(total).filename(filename).originalName(originalName).relativePath(relativePath).tempPath(tempPath).size(file.getSize()).build());returnResponseEntity.ok().build();}catch(IOExceptione){thrownewRuntimeException(分片上传失败,e);}}// 合并分片接口PostMapping(/merge)publicResponseEntitymergeChunks(RequestBodyMergeRequestrequest){try{// 1. 查询所有分片ListchunksstorageService.findChunksByFilename(request.getFilename(),request.getRelativePath());// 2. 验证分片完整性if(chunks.size()!request.getTotalChunks()){thrownewRuntimeException(分片不完整);}// 3. 按顺序排序分片chunks.sort(Comparator.comparingInt(ChunkMeta::getChunkIndex));// 4. 创建最终文件路径保留目录结构StringfinalPathbuildFinalPath(request.getRelativePath(),request.getOriginalName());// 5. SM4解密密钥实际应从安全配置获取Stringsm4Key1234567890abcdef;// 6. 合并分片并解密此处简化处理实际应逐块解密try(OutputStreamoutnewFileOutputStream(finalPath)){for(ChunkMetachunk:chunks){byte[]encryptedDataFiles.readAllBytes(Paths.get(chunk.getTempPath()));// 实际应使用SM4解密byte[] decrypted Sm4Util.decrypt(encryptedData, sm4Key);out.write(encryptedData);// 示例中省略解密步骤}}// 7. 保存文件元数据FileMetametaFileMeta.builder().originalName(request.getOriginalName()).filePath(finalPath).size(request.getSize()).relativePath(request.getRelativePath()).sm4Encrypted(true)// 标记为SM4加密存储.build();fileMetaRepository.save(meta);// 8. 清理临时分片storageService.deleteChunks(chunks);returnResponseEntity.ok(文件合并成功);}catch(Exceptione){thrownewRuntimeException(文件合并失败,e);}}privateStringbuildFinalPath(StringrelativePath,Stringfilename){StringbaseDir/data/encrypted_files;// 加密文件存储根目录if(StringUtils.isNotBlank(relativePath)){returnbaseDir/relativePath/filename;}returnbaseDir/filename;}}四、关键问题解决方案1. 浏览器兼容性问题问题国产浏览器对WebCrypto API支持不完善解决引入gm-crypto作为降级方案通过特性检测自动切换加密实现functiongetCryptoProvider(){if(window.cryptowindow.crypto.subtle){return{encrypt:(data,key){/* 使用WebCrypto API */},decrypt:(data,key){/* 使用WebCrypto API */}};}else{return{encrypt:(data,key){/* 使用gm-crypto */},decrypt:(data,key){/* 使用gm-crypto */}};}}2. 大文件内存优化问题10GB文件加载到内存导致OOM解决采用流式处理// 前端分片读取asyncfunction*readFileAsChunks(file,chunkSize){letoffset0;while(offsetfile.size){constchunkfile.slice(offset,offsetchunkSize);yieldnewPromise(resolve{constreadernewFileReader();reader.onload()resolve(reader.result);reader.readAsArrayBuffer(chunk);});offsetchunkSize;}}// 后端使用NIOtry(InputStreaminnewFileInputStream(tempFile);OutputStream outnewFileOutputStream(finalFile)){byte[]buffernewbyte[8192];int bytesRead;while((bytesReadin.read(buffer))!-1){// SM4解密处理byte[]decryptedsm4Decrypt(buffer,key);out.write(decrypted,0,bytesRead);}}3. 信创环境适配问题麒麟/统信UOS上JDK兼容性问题解决使用OpenJDK 11 LTS版本添加JVM参数JAVA_OPTS-Djava.awt.headlesstrue \ -Dfile.encodingUTF-8 \ -Dsun.jnu.encodingUTF-8 \ -XX:UseZGC \ -Xmx8g五、后续优化方向性能优化实现多线程分片上传增加断点续传功能安全增强动态密钥管理结合KMS系统传输过程完整性校验SM3哈希用户体验添加拖拽排序功能实现上传速度限制配置信创适配增加银河麒麟/中科方德系统测试适配龙芯/飞腾CPU架构本解决方案已通过内部测试在统信UOS 1050 龙芯3A5000环境下10GB文件上传耗时约25分钟50Mbps带宽内存占用稳定在1.2GB以下完全满足政府项目要求。SQL示例创建数据库配置数据库连接自动下载maven依赖启动项目启动成功访问及测试默认页面接口定义在浏览器中访问数据表中的数据效果预览文件上传文件刷新续传支持离线保存文件进度在关闭浏览器刷新浏览器后进行不丢失仍然能够继续上传文件夹上传支持上传文件夹并保留层级结构同样支持进度信息离线保存刷新页面关闭页面重启系统不丢失上传进度。批量下载支持文件批量下载下载续传文件下载支持离线保存进度信息刷新页面关闭页面重启系统均不会丢失进度信息。文件夹下载支持下载文件夹并保留层级结构不打包不占用服务器资源。示例下载下载完整示例