vue3+threejs+koa可视化项目——模型文件上传(第四步)

news2024/12/23 8:46:33

文章目录

    • ⭐前言
      • 💖往期node系列文章
      • 💖threejs系列相关文章
      • 💖vue3+threejs系列
    • ⭐koa后端文件上传(koa-body)
      • 💖自动创建目录
      • 💖自定义目录上传
      • 💖apifox自测上传接口
    • ⭐vue3前端上传模型文件
      • 💖 axios 接口上传
      • 💖 使用 ant design vue 上传
    • ⭐总结
      • 💖 后端koa
      • 💖 前端vue3
    • ⭐结束

yma16-logo

⭐前言

大家好,我是yma16,本文分享关于 vue3+threejs+koa可视化项目——模型文件上传(第四步)。

multipart切片上传
multipart content type 是指一种HTTP报文中的Content-Type的类型,它可以将一个HTTP请求或响应分为多个部分,每个部分可以有自己的Content-Type和内容。这种类型的报文通常用于传输多个文件或者消息体,每个部分可以有不同的编码方式和内容类型,比如图片、文本等不同的数据类型。

💖往期node系列文章

node_windows环境变量配置
node_npm发布包
linux_配置node
node_nvm安装配置
node笔记_http服务搭建(渲染html、json)
node笔记_读文件
node笔记_写文件
node笔记_连接mysql实现crud
node笔记_formidable实现前后端联调的文件上传
node笔记_koa框架介绍
node_koa路由
node_生成目录
node_读写excel
node笔记_读取目录的文件
node笔记——调用免费qq的smtp发送html格式邮箱
node实战——搭建带swagger接口文档的后端koa项目(node后端就业储备知识)
node实战——后端koa结合jwt连接mysql实现权限登录(node后端就业储备知识)
node实战——koa给邮件发送验证码并缓存到redis服务(node后端储备知识)
node实战——koa实现文件下载和图片/pdf/视频预览(node后端储备知识)

💖threejs系列相关文章

THREE实战1_代码重构点、线、面
THREE实战2_正交投影相机与透视相机
THREE实战3_理解光源
THREE实战4_3D纹理
THREE实战5_canvans纹理
THREE实战6_加载fbx模型

💖vue3+threejs系列

vue3+threejs可视化项目——搭建vue3+ts+antd路由布局(第一步)
vue3+threejs可视化项目——引入threejs加载钢铁侠模型(第二步)
vue3+threejs+koa可视化项目——实现登录注册(第三步)

⭐koa后端文件上传(koa-body)

node 安装 koa-body

npm install koa-body

由于之前的博客是实现使用koa-bodyparser
需要卸载npm uninstall koa-bodyparser
引入koa-body

// 文件上传
app.use(koaBody({
    multipart: true
}))

💖自动创建目录

封装创建目录dirExists(不存在则创建)

const fs = require('fs');
const path = require('path');


/**
 * 读取路径信息
 * @param {string} path 路径
 */
function getStat(path) {
    return new Promise((resolve, reject) => {
        fs.stat(path, (err, stats) => {
            if (err) {
                resolve(false);
            } else {
                resolve(stats);
            }
        })
    })
}

/**
 * 创建路径
 * @param {string} dir 路径
 */
function mkdir(dir) {
    return new Promise((resolve, reject) => {
        fs.mkdir(dir, err => {
            if (err) {
                resolve(false);
            } else {
                resolve(true);
            }
        })
    })
}

/**
 * 路径是否存在,不存在则创建
 * @param {string} dir 路径
 */
async function dirExists(dir) {
    let isExists = await getStat(dir);
    //路径存在是目录
    if (isExists && isExists.isDirectory()) {
        return true;
    } else if (isExists) {
        // 文件
        return false;
    }
    //拿到上级路径
    let tempDir = path.parse(dir).dir;
    //递归判断,如果上级目录也不存在,则会代码会在此处继续循环执行,直到目录存在
    let status = await dirExists(tempDir);
    let mkdirStatus;
    if (status) {
        mkdirStatus = await mkdir(dir);
    }
    return mkdirStatus;
}


module.exports={
    dirExists
}

💖自定义目录上传

实现文件上传

const {dirExists} =require("../../utils/createDir");

const Router = require('koa-router');
const router = new Router();
const fs=require('fs')


// 当前时间
const  getCurrentTime=() =>{
    const now = new Date()
    return `${now.valueOf()}`
};

// upload file
router.post('/upload/file', async (ctx) => {
    try{
        // 获取上传的文件
        const file = ctx.request.files.files;
        console.log('file',file)
        const dir='./db/file/'+getCurrentTime()
        await dirExists(dir);
        const file_path=`${dir}/${file.originalFilename}`;
        console.log('file_path',file_path)
        // 创建可读流
        const reader = fs.createReadStream(file._writeStream.path);
        // 创建可写流
        const upStream = fs.createWriteStream(file_path);
        // 可读流通过管道写入可写流
        reader.pipe(upStream);
        ctx.body={
            'code':200,
            msg:'上传成功!'
        }
    }
    catch(e){
        ctx.body = {
            code: 0,
            data:e,
            msg: 'upload media fail'
        };
    }
});

module.exports=router;

💖apifox自测上传接口

上传一张图片
upload-apifox

上传成功!
upload-success

⭐vue3前端上传模型文件

💖 axios 接口上传

http封装 上传配置content-type和token

// 实例
const createUploadInstance = (baseURL:string)=>{
    //token
    const token = localStorage.getItem("userInfoPermissionToken")
    const Authorization = `bearer ${token}`
    return axios.create({
        baseURL:baseURL,
        timeout: 1000000,
        headers: {"Content-Type": "multipart/form-data",Authorization}
    })
};

// @ts-ignore
const uploadHttp:any=createUploadInstance('');

上传接口

// @ts-ignore
import {uploadHttp} from "@/http/index";
export const uploadFile: any = (params: any) => {
    return uploadHttp.post("/api/upload/file", params);
};

💖 使用 ant design vue 上传

上传页面

<template>
<div>
    <div>
        选择模型
    </div>
    <a-upload-dragger
            name="file"
            :multiple="false"
            :file-list="state.fileList"
            :before-upload="beforeUpload"
            @remove="handleRemove"
    >
        <p class="ant-upload-drag-icon">
            <inbox-outlined></inbox-outlined>
        </p>
        <p class="ant-upload-text">点击获取拖拽选择文件上传</p>
    </a-upload-dragger>
    <div style="margin-top: 20px;">
        <a-button type="primary" @click="handleUpload">
            上传
        </a-button>
    </div>
</div>
</template>
<script lang="ts" setup>
    import { reactive } from 'vue';
    import { InboxOutlined } from '@ant-design/icons-vue';
    import { message } from 'ant-design-vue';
    import {uploadFile} from '@/service/upload/index'
    const state:any=reactive({
        loading:false,
        fileList:[]
    })
    const beforeUpload=(file:File)=>{
        state.fileList=[file]
        return false;
    }

    const handleRemove = (file) => {
        state.fileList=[]
    };

    const handleUpload = async () => {
        if(!state.fileList.length){
            return message.warn('请选择文件')
        }
        const formData = new FormData();
        state.fileList.forEach((file: any) => {
            formData.append('file', file as any);
        });
        state.loading = true;
        try{
            const res=await uploadFile(formData)
            console.log('res',res)
        }
        catch (e) {
            message.error(JSON.stringify(e))
        }
    };

</script>

上传成功!
upload-vue3
上传iron_man模型文件成功!
upload-success

⭐总结

💖 后端koa

koa-body使用
koa-body是一个koa中间件,用于解析HTTP请求的body内容。它支持多种类型的body内容,包括json、form、text、multipart等。

使用koa-body的步骤如下:

  1. 安装koa-body模块:可以使用npm或者yarn进行安装。

    npm install koa-body
    
  2. 引入koa-body模块:在koa的代码文件中,使用require语句引入koa-body。

    const koaBody = require('koa-body');
    
  3. 注册koa-body中间件:在koa的代码文件中,使用app.use方法来注册koa-body中间件。

    app.use(koaBody());
    

    可以在传递koa-body的参数中指定解析body的类型和其他配置。例如,可以指定multipart的配置项如下:

    app.use(koaBody({
      multipart: true,
      formidable: {
        uploadDir: './uploads',
        keepExtensions: true,
        maxFileSize: 200 * 1024 * 1024
      }
    }));
    

    上述代码指定了将multipart类型的body解析为文件上传,并保存在"./uploads"目录下,同时限制了上传文件的大小为200MB。

  4. 在koa的路由处理函数中使用解析后的body内容:koa-body中间件会将解析后的body内容保存在ctx.request.body属性中,可以在koa的路由处理函数中通过ctx.request.body来使用解析后的body内容。

    router.post('/', async (ctx) => {
      const requestBody = ctx.request.body;
      // ...
    });
    

可以根据具体的需求配置koa-body中间件,具体的配置项可以参考koa-body的文档。

💖 前端vue3

http封装
Axios是一个基于Promise的HTTP客户端库,可以用于浏览器和Node.js。它提供了一种简单、直观的方式来发送HTTP请求和处理响应。

为了更好地使用和管理Axios,可以对其进行封装。封装Axios可以使代码更加简洁、易于维护,并提供一些常用的功能,如错误处理、拦截请求和响应等。

以下是一个简单的Axios封装示例:

import axios from 'axios';

// 创建一个Axios实例
const instance = axios.create({
  baseURL: 'http://api.example.com', // 设置请求的基础URL
  timeout: 5000 // 设置请求超时时间
});

// 请求拦截器
instance.interceptors.request.use(
  config => {
    // 在发送请求之前做些什么
    return config;
  },
  error => {
    // 对请求错误做些什么
    return Promise.reject(error);
  }
);

// 响应拦截器
instance.interceptors.response.use(
  response => {
    // 对响应数据做些什么
    return response.data;
  },
  error => {
    // 对响应错误做些什么
    return Promise.reject(error);
  }
);

export default instance;

在封装的Axios实例中,可以设置一些通用的配置,如基础URL和超时时间。还可以通过请求拦截器在发送请求之前做一些操作,如添加请求头,对请求参数进行处理等。类似地,通过响应拦截器可以对响应数据进行处理,如统一处理错误,转换响应数据等。

封装后的Axios实例可以通过导入的方式在其他地方使用,简化了代码的编写和维护。可以根据实际需求,进一步封装一些通用的API请求方法,以便在项目中重复使用。

总之,封装Axios可以提高开发效率,增强代码的可读性和可维护性,并提供一些常用的功能。

⭐结束

本文分享到这结束,如有错误或者不足之处欢迎指出!

robot

👍 点赞,是我创作的动力!
⭐️ 收藏,是我努力的方向!
✏️ 评论,是我进步的财富!
💖 最后,感谢你的阅读!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1432050.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

echarts使用之饼图(四)

1 基本使用 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><meta http-equiv"X-UA-Compatible" cont…

latex multirow学习

今天搞了一晚上的这个multirow&#xff0c;总算弄出来了几个比较好的例子&#xff0c;主要是这个multirow的语法我没看懂&#xff0c;这个逻辑我是没理解&#xff0c;就很尴尬&#xff0c;一改就报错&#xff0c;只能先弄几个例子&#xff0c;自己慢慢试 \documentclass{artic…

k8s学习-Kubernetes的网络

Kubernetes作为编排引擎管理着分布在不同节点上的容器和Pod。Pod、Service、外部组件之间需要⼀种可靠的方找到彼此并进行通信&#xff0c;Kubernetes网络则负责提供这个保障。1.1 Kubernetes网络模型 Container-to-Container的网络 当Pod被调度到某个节点&#xff0c;Pod中的…

【Python】【完整代码】解析Excel 文件中的内容并检查是否包含某字符串,并返回判断结果

示例&#xff1a; 开发需求&#xff1a;解析Excel 文件中的内容并检查是否包含 "Fail" 字符&#xff0c;若没有则返回True&#xff0c;若有则返回False 实现代码&#xff1a; #!/usr/bin/env python3 # -*- encoding: utf-8 -*-File : check_excel_for_fail.py Ti…

后端程序员入门react笔记——react的生命周期(二)

React常用的钩子函数 constructor 这个函数我们太常见了&#xff0c;在初始化类的state的时候&#xff0c;或者初始化类的props的时候都会用到&#xff0c;就是一个类的构造函数。对后端人员来说很熟悉 constructor() {super();this.state {age: 18}}getDerivedStateFromPro…

【C++入门学习指南】:函数重载提升代码清晰度与灵活性

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; C入门到进阶 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一、函数重载1.1 函数重载的概念1.2 函数重载的作用1.3 C支持函数重载的原理1.4 扩展 &…

如何写好论文——(15)如何写研究目标之实例讲解

写好研究目标一要有方向、二要有边界。 定边界的时候要有方法和结论。 下面的例子为目标的两种写法&#xff0c;第二种提供了更明确可以测量的目标。 下面的第二个例子更有方向性。第一个例子的本质是去验证一种假说&#xff0c;这种假说如果成立完全可以支撑第二种写法中的目…

【C/C++ 08】简单计算器

一、题目 输入算术表达式&#xff0c;可包含空格&#xff0c;检查算术表达式的合法性&#xff0c;若算术表达式不合法&#xff0c;打印错误类型&#xff0c;若合法&#xff0c;则进行运算&#xff0c;打印计算结果。 二、算法 1. 将输入的算术表达式字符串去除空格。 2. 检查…

Java并发(二十三)----同步模式之保护性暂停

1、定义 即 Guarded Suspension&#xff0c;用在一个线程等待另一个线程的执行结果 要点 有一个结果需要从一个线程传递到另一个线程&#xff0c;让他们关联同一个 GuardedObject 如果有结果不断从一个线程到另一个线程那么可以使用消息队列 JDK 中&#xff0c;join 的实现…

【MySQL】学习并使用DQL实现排序查询和分页查询

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-SP91zTA41FlGU0Ce {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

【Linux进程间通信】匿名管道

【Linux进程间通信】匿名管道 目录 【Linux进程间通信】匿名管道进程间通信介绍进程间通信目的进程间通信发展进程间通信分类 管道用fork来共享管道原理站在文件描述符角度——深度理解管道站在内核角度——管道本质 匿名管道在myshell中添加管道的实现&#xff1a;管道读写规则…

Linux 多线程 | 线程的概念

线程的概念 线程是一个执行分支&#xff0c;执行粒度比进程更细&#xff0c;调度成本更低&#xff1b; 线程是进程内部的一个执行流&#xff1b; 线程是CPU调度的基本单位&#xff0c;进程是承担分配系统资源的基本实体。 之前我们学习过虚拟地址空间的知识&#xff0c;知道…

大礼包 - 华为机试真题题解

考试平台&#xff1a; 时习知 分值&#xff1a; 200分&#xff08;第二题&#xff09; 考试时间&#xff1a; 2024-01-31 &#xff08;两小时&#xff09; 题目描述 某公司针对新用户推出大礼包&#xff0c;从任意一天注册开始&#xff0c;连续登陆 x 天&#xff0c;每天可以领…

C# 信号量(Semaphore)详细使用案例

文章目录 简介信号量的工作原理使用场景使用示例其他使用实例1. 数据库连接池管理2. 文件读写同步3. 生产者消费者问题4. 打印任务队列同步5. Web服务器并发请求限制 简介 在C#中&#xff0c;信号量&#xff08;Semaphore&#xff09;是.NET框架提供的一个同步类&#xff0c;位…

vue3:23—自定义hooks

正是因为有了hooks&#xff0c;组合式才发挥出了威力 其实 hooks 和 vue2 中的 mixin 有点类似&#xff0c;但是相对 mixins 而言&#xff0c; hooks 更清楚复用功能代码的来源, 更清晰易懂。 如何定义hooks 具备可复用功能&#xff0c;才需要抽离为 hooks 独立文件函数名/文…

【Linux】Ext2 文件系统

文件系统 前言一、磁盘硬件1. 磁盘的物理存储结构2. 磁盘存储的逻辑抽象结构 二、理解 Ext2 文件系统1. 初步理解文件系统2. 深入理解文件系统&#xff08;1&#xff09;inode Table&#xff08;2&#xff09;Data blocks&#xff08;3&#xff09;inode Bitmap&#xff08;4&a…

Lambda表达式(匿名函数)

C11中引入了lambda表达式&#xff0c;定义匿名的内联函数。 我们可以直接原地定义函数而不用再跑到外面去定义函数跳来跳去。 同时在stl的排序上也有作用。 [capture] (parameters) mutable ->return-type {statement}下面逐一介绍各个参数的含义. [capture] : 捕获&#…

【Spring】自定义注解 + AOP 记录用户的使用日志

目录 ​编辑 自定义注解 AOP 记录用户的使用日志 使用背景 落地实践 一&#xff1a;自定义注解 二&#xff1a;切面配置 三&#xff1a;Api层使用 使用效果 自定义注解 AOP 记录用户的使用日志 使用背景 &#xff08;1&#xff09;在学校项目中&#xff0c;安防平台…

阿里计算巢:开启数据集市场的宝库,助力AI研究和应用

阿里计算巢 阿里数据巢提供了一个丰富的数据集市场&#xff0c;官方地址&#xff1a; https://computenest.console.aliyun.com/dataset/service/cn-hangzhou 可以看到数据集内容涵盖了多个领域&#xff0c;且还在不断增加中。关键是免费&#xff01;且支持下载到本地。 以下…

oracle 根据身份证号码与指定日期计算年龄

自定义函数&#xff1a; CREATE OR REPLACE FUNCTION 获取年龄(身份证号 varchar2, 指定时间 date) RETURN varchar2 AS 年龄 varchar2(16); BEGINif length(身份证号) >18 thenSELECT TRUNC( MONTHS_BETWEEN(指定时间, TO_DATE(SUBSTR(身份证号, 7, 8), YYYYMMDD) …