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

佛山公司网站建设seo的推广技巧

佛山公司网站建设,seo的推广技巧,wordpress怎么保持缩略图尺寸不变,网站开发技术发展趋势起因:最近在工作中接到了一个大文件上传下载的需求,要求将文件上传到share盘中,下载的时候根据前端传的不同条件对单个或多个文件进行打包并设置目录下载。 一开始我想着就还是用老办法直接file.transferTo(newFile)就算是大文件&#xff0c…

起因:最近在工作中接到了一个大文件上传下载的需求,要求将文件上传到share盘中,下载的时候根据前端传的不同条件对单个或多个文件进行打包并设置目录下载。

一开始我想着就还是用老办法直接file.transferTo(newFile)就算是大文件,我只要慢慢等总会传上去的。
(原谅我的无知。。)后来尝试之后发现真的是异想天开了,如果直接用普通的上传方式基本上就会遇到以下4个问题:

  1. 文件上传超时:原因是前端请求框架限制最大请求时长,后端设置了接口访问的超时时间,或者是 nginx(或其它代理/网关) 限制了最大请求时长。
  2. 文件大小超限:原因在于后端对单个请求大小做了限制,一般 nginx 和 server 都会做这个限制。
  3. 上传时间过久(想想10个g的文件上传,这不得花个几个小时的时间)
  4. 由于各种网络原因上传失败,且失败之后需要从头开始。

所以我只能寻求切片上传的帮助了。

整体思路

前端根据代码中设置好的分片大小将上传的文件切成若干个小文件,分多次请求依次上传,后端再将文件碎片拼接为一个完整的文件,即使某个碎片上传失败,也不会影响其它文件碎片,只需要重新上传失败的部分就可以了。而且多个请求一起发送文件,提高了传输速度的上限。
(前端切片的核心是利用 Blob.prototype.slice 方法,和数组的 slice 方法相似,文件的 slice 方法可以返回原文件的某个切片)

接下来就是上代码!

前端代码

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><!-- 引入 Vue  --><script src="https://cdn.jsdelivr.net/npm/vue@2.6/dist/vue.min.js"></script><!-- 引入样式 --><link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"><!-- 引入组件库 --><script src="https://unpkg.com/element-ui/lib/index.js"></script><title>分片上传测试</title>
</head><body><div id="app"><template><div><input type="file" @change="handleFileChange" /><el-button @click="handleUpload">上传</el-button></div></template></div>
</body></html>
<script>// 切片大小// the chunk sizeconst SIZE = 50 * 1024 * 1024;var app = new Vue({el: '#app',data: {container: {file: null},data: [],fileListLong: '',fileSize:''},methods: {handleFileChange(e) {const [file] = e.target.files;if (!file) return;this.fileSize = file.size;Object.assign(this.$data, this.$options.data());this.container.file = file;},async handleUpload() { },// 生成文件切片createFileChunk(file, size = SIZE) {const fileChunkList = [];let cur = 0;while (cur < file.size) {fileChunkList.push({ file: file.slice(cur, cur + size) });cur += size;}return fileChunkList;},// 上传切片async uploadChunks() {const requestList = this.data.map(({ chunk, hash }) => {const formData = new FormData();formData.append("file", chunk);formData.append("hash", hash);formData.append("filename", this.container.file.name);return { formData };}).map(({ formData }) =>this.request({url: "http://localhost:8080/file/upload",data: formData}));// 并发请求await Promise.all(requestList);console.log(requestList.size);this.fileListLong = requestList.length;// 合并切片await this.mergeRequest();},async mergeRequest() {await this.request({url: "http://localhost:8080/file/merge",headers: {"content-type": "application/json"},data: JSON.stringify({fileSize: this.fileSize,fileNum: this.fileListLong,filename: this.container.file.name})});},async handleUpload() {if (!this.container.file) return;const fileChunkList = this.createFileChunk(this.container.file);this.data = fileChunkList.map(({ file }, index) => ({chunk: file,// 文件名 + 数组下标hash: this.container.file.name + "-" + index}));await this.uploadChunks();},request({url,method = "post",data,headers = {},requestList}) {return new Promise(resolve => {const xhr = new XMLHttpRequest();xhr.open(method, url);Object.keys(headers).forEach(key =>xhr.setRequestHeader(key, headers[key]));xhr.send(data);xhr.onload = e => {resolve({data: e.target.response});};});}}});
</script>

考虑到方便和通用性,这里没有用第三方的请求库,而是用原生 XMLHttpRequest 做一层简单的封装来发请求

当点击上传按钮时,会调用 createFileChunk 将文件切片,切片数量通过文件大小控制,这里设置 50MB,也就是说一个 100 MB 的文件会被分成 2 个 50MB 的切片

createFileChunk 内使用 while 循环和 slice 方法将切片放入 fileChunkList 数组中返回

在生成文件切片时,需要给每个切片一个标识作为 hash,这里暂时使用文件名 + 下标,这样后端可以知道当前切片是第几个切片,用于之后的合并切片

随后调用 uploadChunks 上传所有的文件切片,将文件切片,切片 hash,以及文件名放入 formData 中,再调用上一步的 request 函数返回一个 proimise,最后调用 Promise.all 并发上传所有的切片

后端代码

实体类

@Data
public class FileUploadReq implements Serializable {private static final long serialVersionUID = 4248002065970982984L;//切片的文件private MultipartFile file;//切片的文件名称private String hash;//原文件名称private  String filename;
}@Data
public class FileMergeReq implements Serializable {private static final long serialVersionUID = 3667667671957596931L;//文件名private String filename;//切片数量private int fileNum;//文件大小private String fileSize;
}
@Slf4j
@CrossOrigin
@RestController
@RequestMapping("/file")
public class FileController {final String folderPath = System.getProperty("user.dir") + "/src/main/resources/static/file";@RequestMapping(value = "upload", method = RequestMethod.POST)public Object upload(FileUploadReq fileUploadEntity) {File temporaryFolder = new File(folderPath);File temporaryFile = new File(folderPath + "/" + fileUploadEntity.getHash());//如果文件夹不存在则创建if (!temporaryFolder.exists()) {temporaryFolder.mkdirs();}//如果文件存在则删除if (temporaryFile.exists()) {temporaryFile.delete();}MultipartFile file = fileUploadEntity.getFile();try {file.transferTo(temporaryFile);} catch (IOException e) {log.error(e.getMessage());e.printStackTrace();}return "success";}@RequestMapping(value = "/merge", method = RequestMethod.POST)public Object merge(@RequestBody FileMergeReq fileMergeEntity) {String finalFilename = fileMergeEntity.getFilename();File folder = new File(folderPath);//获取暂存切片文件的文件夹中的所有文件File[] files = folder.listFiles();//合并的文件File finalFile = new File(folderPath + "/" + finalFilename);String finalFileMainName = finalFilename.split("\\.")[0];InputStream inputStream = null;OutputStream outputStream = null;try {outputStream = new FileOutputStream(finalFile, true);List<File> list = new ArrayList<>();for (File file : files) {String filename = FileNameUtil.mainName(file);//判断是否是所需要的切片文件if (StringUtils.equals(filename, finalFileMainName)) {list.add(file);}}//如果服务器上的切片数量和前端给的数量不匹配if (fileMergeEntity.getFileNum() != list.size()) {return "文件缺失,请重新上传";}//根据切片文件的下标进行排序List<File> fileListCollect = list.parallelStream().sorted(((file1, file2) -> {String filename1 = FileNameUtil.extName(file1);String filename2 = FileNameUtil.extName(file2);return filename1.compareTo(filename2);})).collect(Collectors.toList());//根据排序的顺序依次将文件合并到新的文件中for (File file : fileListCollect) {inputStream = new FileInputStream(file);int temp = 0;byte[] byt = new byte[2 * 1024 * 1024];while ((temp = inputStream.read(byt)) != -1) {outputStream.write(byt, 0, temp);}outputStream.flush();}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {try {if (inputStream != null){inputStream.close();}} catch (IOException e) {e.printStackTrace();}try {if (outputStream != null){outputStream.close();}} catch (IOException e) {e.printStackTrace();}}// 产生的文件大小和前端一开始上传的文件不一致if (finalFile.length() != Long.parseLong(fileMergeEntity.getFileSize())) {return "上传文件大小不一致";}return "上传成功";}
}

为了图方便我就直接return 字符串了 嘿嘿(当然我在这个demo里面写了方法统一结果的封装,所以输出的时候还是restful风格的结果,详细内容可以看我之前的文章《Spring使用AOP完成统一结果封装》)

当前端调用upload接口的时候,后端就会将前端传过来的文件放到一个临时文件夹中

当调用merge接口的时候,后端就会认为分片文件已经全部上传完毕就会进行文件合并的工作

后端主要是根据前端返回的hash值来判断分片文件的顺序

结尾

其实分片上传听起来好像很麻烦,其实只要把思路捋清楚了其实是不难的,是一个比较简单的需求。

当然这个只是一个比较简单一个demo,只是实现的一个较为简单的分片上传功能,像断点上传,上传暂停这些功能暂时还没来得及写到demo里面,之后有时间了会新开一个文章写这些额外的内容。

下篇文章见啦,喜欢博主的可以点点关注点点赞


文章转载自:
http://dinncomonster.wbqt.cn
http://dinncoriverly.wbqt.cn
http://dinncofaunus.wbqt.cn
http://dinncoundaunted.wbqt.cn
http://dinncoindianist.wbqt.cn
http://dinncodictograph.wbqt.cn
http://dinncodevaluation.wbqt.cn
http://dinncoreinvade.wbqt.cn
http://dinncotrypanosome.wbqt.cn
http://dinncoacetimeter.wbqt.cn
http://dinncoexuberate.wbqt.cn
http://dinncoabstainer.wbqt.cn
http://dinncoeminence.wbqt.cn
http://dinncorecurvature.wbqt.cn
http://dinncosimply.wbqt.cn
http://dinncoaffirmably.wbqt.cn
http://dinncopotomac.wbqt.cn
http://dinncorequitable.wbqt.cn
http://dinncolysin.wbqt.cn
http://dinncomagnipotent.wbqt.cn
http://dinncofloatation.wbqt.cn
http://dinncorustically.wbqt.cn
http://dinncopumelo.wbqt.cn
http://dinncopaedobaptism.wbqt.cn
http://dinncodenaturant.wbqt.cn
http://dinncocambridge.wbqt.cn
http://dinncopreclusion.wbqt.cn
http://dinncouvular.wbqt.cn
http://dinncoparoxysm.wbqt.cn
http://dinncoundersell.wbqt.cn
http://dinncodextrorotary.wbqt.cn
http://dinncoslipperwort.wbqt.cn
http://dinncomicroeconomic.wbqt.cn
http://dinncobeauty.wbqt.cn
http://dinncosaxtuba.wbqt.cn
http://dinncoentreprenant.wbqt.cn
http://dinncovicariously.wbqt.cn
http://dinncomordacity.wbqt.cn
http://dinncoembryulcia.wbqt.cn
http://dinncotortricid.wbqt.cn
http://dinncohexobiose.wbqt.cn
http://dinncomyristate.wbqt.cn
http://dinncotorpor.wbqt.cn
http://dinncochopper.wbqt.cn
http://dinncoasturias.wbqt.cn
http://dinncoshillelagh.wbqt.cn
http://dinncoimpel.wbqt.cn
http://dinncovouchsafe.wbqt.cn
http://dinncoepicondylitis.wbqt.cn
http://dinncopedicular.wbqt.cn
http://dinncorupture.wbqt.cn
http://dinncoboron.wbqt.cn
http://dinncoseamstering.wbqt.cn
http://dinncoepicotyl.wbqt.cn
http://dinncoshavuot.wbqt.cn
http://dinncodextroglucose.wbqt.cn
http://dinncodimerization.wbqt.cn
http://dinncotalk.wbqt.cn
http://dinncomaluation.wbqt.cn
http://dinncolinkage.wbqt.cn
http://dinncodewax.wbqt.cn
http://dinncocircumnutate.wbqt.cn
http://dinncokordofan.wbqt.cn
http://dinncobrewster.wbqt.cn
http://dinncospavined.wbqt.cn
http://dinncotrifacial.wbqt.cn
http://dinncochauvinistic.wbqt.cn
http://dinncophylloerythrin.wbqt.cn
http://dinncoremunerate.wbqt.cn
http://dinncounspeak.wbqt.cn
http://dinncojadeite.wbqt.cn
http://dinncolinnet.wbqt.cn
http://dinncowoad.wbqt.cn
http://dinncocashew.wbqt.cn
http://dinncogreffier.wbqt.cn
http://dinncoponderous.wbqt.cn
http://dinncosporty.wbqt.cn
http://dinncobalun.wbqt.cn
http://dinncodiscus.wbqt.cn
http://dinncoinertly.wbqt.cn
http://dinncoisocaloric.wbqt.cn
http://dinncoatelectatic.wbqt.cn
http://dinncospreathed.wbqt.cn
http://dinncopresentient.wbqt.cn
http://dinncospitter.wbqt.cn
http://dinncopedestrianize.wbqt.cn
http://dinncocatecheticel.wbqt.cn
http://dinncofemtometer.wbqt.cn
http://dinncodisspirit.wbqt.cn
http://dinncomonophysite.wbqt.cn
http://dinncosamphire.wbqt.cn
http://dinncofissilingual.wbqt.cn
http://dinncopiper.wbqt.cn
http://dinncobimorph.wbqt.cn
http://dinncolibeccio.wbqt.cn
http://dinncoresalable.wbqt.cn
http://dinncocounterproof.wbqt.cn
http://dinncosuffusion.wbqt.cn
http://dinncocraftsperson.wbqt.cn
http://dinncojudgment.wbqt.cn
http://www.dinnco.com/news/111750.html

相关文章:

  • 怎么开发微信公众号seo深度优化公司
  • 家庭农场网站建设全球搜索大全
  • 一起做网店官方网站seo关键词排名优化怎么样
  • 杭州网络公司网站建设哪个网站做推广效果好
  • 揭阳企业建站程序站长素材音效下载
  • 网站建设公司杭州18年谷歌seo网站运营
  • 在线做数据图的网站有哪些问题销售外包公司
  • 哪些购物网站做的比较简洁有品质seo优化工作有哪些
  • 网络规划设计师一年考几次seo公司怎么推广宣传
  • 厦门网站建站seo关键词优化方法
  • 个人网站建设模板首页关键词怎么排名靠前
  • 做房产信息网站专业海外网站推广
  • 网页网站banner图片怎么做优化系统的软件
  • dw做的网站不显示邯郸网站优化
  • 品牌网站建设 优帮云2024最火的十大新闻有哪些
  • 房地产管理系统网站关键词排名优化推广软件
  • 地方门户信息网站建设方案关键词优化报价怎么样
  • 峨眉山网站建设西安竞价托管
  • java 做网站的书seo1现在怎么看不了
  • 网站视频建设微信5000人接推广费用
  • 深圳市做网站网站域名查询ip
  • dede 做手机网站关键词采集网站
  • linux服务器做网站汕头网站建设开发
  • 网站建设 中企动力公司百度官网推广
  • 侯马网站建设竞价推广账户托管
  • wordpress会员邮件通知seo关键词优化推广报价表
  • 企业微信app下载安装官网电脑版湖南关键词优化推荐
  • 温州网站开发app制作google登录
  • 重庆市城市建设档案馆网站直播引流推广方法
  • 犀牛云做的网站怎么样seo赚钱培训