前端毕业设计:Nodejs+Vue菜鸟驿站仓库管理系统的设计与实现

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 本系统使用 Node.JS 语言开发,该编程语言简单易学,能够与多个框架完美结合,又具备面向对象、与平台无关、多线程等特点,因此比较容易进行开发工作。开发工具使用Visual Studio Code,它强大的整合能力能更好的对项目进行管理,丰富的提示功能可以使开发人员更加高效的进行开发工作。数据库使用MySQL,其简单易用、开源免费、社区庞大而完善的特点,对于初次尝试人员非常友好。系统的架构是B/S,也就是浏览器/服务器模型,客户端完成主要的业务,一些交互或发起请求在前端完成。对于用户非常简单,通过一个浏览

项目编号:BS-QD-004        

前言:

当前时代,全球的经济已经从工业经济到知识经济的改变,过去专家说知识经济的两个首要属性是信息化和全球化,要完成化和全球化,这时就需要稳定的网络和完备的数据库。但时至今日中国的服务价值意识提高,人力成本开始骤增,对于很多快递企业来说一个10元成本的单子,有5元是在最后一公里被消耗了。研究快递驿站的智能物流货架的应用方案,随着社会和科学技术的演变,仓储管理的方法也不断优化。从全部人工管理的方法,这样不仅效率低,工作量大,并且准确率差。尤其是当今快递行业飞速发展,货流量大,人工管理更显不足。为了提高仓库管理效率,减少仓库管理成本,特开发菜鸟驿站库存管理系统。

一,项目简介

本系统使用 Node.JS 语言开发,该编程语言简单易学,能够与多个框架完美结合,又具备面向对象、与平台无关、多线程等特点,因此比较容易进行开发工作。开发工具使用Visual Studio Code,它强大的整合能力能更好的对项目进行管理,丰富的提示功能可以使开发人员更加高效的进行开发工作。数据库使用MySQL,其简单易用、开源免费、社区庞大而完善的特点,对于初次尝试人员非常友好。系统的架构是B/S,也就是浏览器/服务器模型,客户端完成主要的业务,一些交互或发起请求在前端完成。对于用户非常简单,通过一个浏览器就可以与系统进行访问和交互。为了实现高效的开发和后期维护,系统采用了MVC架构,即数据模型层、视图表现层、路由控制层,客户通过视图交互实现数据功能的使用效果,路由控制层主要处理前端传过来的各种请求,通过路由和参数以及身份认证来处理逻辑,并把最终的结果给到前端,数据模型层主要是对数据的增删改查等操作,当然主要依赖于路由控制层。如上的开发工具和技术都能够满足开发需求,故在技术上是可行的。随着科学技术的不断提高,计算机科学应用也越来越普及,相比手工管理,使用计算机软件对仓储信息进行管理,无论从效率、科学性还是规范性方面都有着巨大的优势,该软件的开发不会侵犯国家、集体和他人的利益,所以其具备社会公认的可行性。系统开发不需要高端设备,大部分技术开源免费,哪怕开发过程中发生重大失误,改正即可,不会损耗材料,系统开发出来,可以无限备份投入使用,非常完全符合经济上的可行性。

业务流程图

image.gif编辑

系统数据流程图

image.gif编辑

二,环境介绍

2.2相关技术和开发环境

2.2.1 相关技术

(1)B/S结构(Browser/Server结构)简介

B/S(Brower/Server,浏览器/服务器)模式又称B/S结构,是Web兴起后的一种网络结构模式。Web浏览器是客户端最主要的应用软件。这种模式统一了客户端,将系统功能实现的核心部分集中到服务器上,简化了系统的开发、维护和使用;客户机上只需要安装一个浏览器,服务器上安装SQL Server, Oracle, MySql等数据库;浏览器通过Web Server同数据库进行数据交互。Browser指的是Web浏览器,极少数事务逻辑在前端实现,但主要事务逻辑在服务器端实现。B/S架构的系统无须特别安装,只有Web浏览器即可。

其实就是我们前端现在做的一些事情,大部分的逻辑交给后台来实现,我们前端大部分是做一些数据渲染,请求等比较少的逻辑。通过三层结构模型,大大减轻了客户端的压力,降低了开发和维护的成本,也降低了客户的总成本。

(2)Mysql简介

MySQL是Web世界中使用最广泛的数据库服务器。SQLite的特点是轻量级、可嵌入,但不能承受高并发访问,适合桌面和移动应用。而MySQL是为服务器端设计的数据库,能承受高并发访问,同时占用的内存也远远大于SQLite。

此外,MySQL内部有多种数据库引擎,最常用的引擎是支持数据库事务的InnoDB。存储引擎就是存储数据,建立索引,更新、查询数据等技术的实现方式。存储引擎是基于表的。mysql支持多种存储引擎,而oracle、sqlserver等只有一种存储引擎

即市场占有率最大的关系型数据库,类似于excel表格

DML:select、insert、update、delete

DDL:drop、create等

    1. MySQL数据库的优点

    MySQL的主要优势如下:

    1、速度: 系统运行速度非常快。

    2、价格:MySQL对多数个人来说是免费使用的。

    3、容易使用:相比于其他数据库的设置和管理相比,相对于比较简单,容易学习。

    4、可移植性: 跨平台能力,可以适用于不同的系统平台之下,例如:Windows 、Linux、Unix、MacOS等。

    5、丰富的接口: 提供了用于C 、C++、Eiffel、Java、Perl、PHP、Python、Rudy和TCL 等语言的API。

    6、支持查询语言:MySQL可以利用标准SQL语法和支持ODBC(开放式数据库连接)的应用程序。

    7、安全性和连接性; 非常灵活的安全和校验机制,允许主机验证。连接到服务器时,所有的密码

    都采用加密形式,从而保证了密码安全。并且由于MySQL时网络化的,因此可以在因特网网上的任何地方访问,提高数据共享效率。

    (4)HTML简介

    HTML 是用来描述网页的一种语言。

    HTML 指的是超文本标记语言 (Hyper Text Markup Language)

    HTML 不是一种编程语言,而是一种标记语言 (markup language)

    标记语言是一套标记标签 (markup tag)

    HTML 使用标记标签来描述网页

    HTML 标签

    HTML 标记标签通常被称为 HTML 标签 (HTML tag)。

    HTML 标签是由尖括号包围的关键词,比如 <html>

    HTML 标签通常是成对出现的,比如 <b> 和 </b>

    标签对中的第一个标签是开始标签,第二个标签是结束标签

    开始和结束标签也被称为开放标签和闭合标签

    HTML 文档 = 网页

    HTML 文档描述网页

    HTML 文档包含 HTML 标签和纯文本

    HTML 文档也被称为网页

    (5)Node.js简介

    Node.js是基于google公司旗下的产品Chrome浏览器,其中使用的V8引擎就来自于此。由于浏览器的特殊性,引擎最显著的特点就是事件驱动、异步的I/O模式,在不断的优化下,非常的高效和轻量

    (6)Visual Studio Code简介

    相比于Visual Studio的重量级产品不同,Visual Studio Code可谓非常的轻量级,它诞生于2015年4月30日的开发者大会上,并且跨平台的特性,以及针对现代web应用和云平台的源代码编辑器。软件只有几十兆,因为不绑定任何的插件,但是因为拥有强大的插件系统和插件商城,所以开发者可以有选择的使用各种插件,提高效率,对于内置支持的Javascript和TypeScript,并且可以通过扩展来支持其他语言,比如C++、C、JAVA、Python等语言。

    (7)Nginx简介

    Nginx是支持多线程的方式的,只是我们主流的方式还是多进程的方式,也是nginx的默认方式。

      master进程主要用来管理worker进程,包含:接收来自外界的信号,向各worker进程发送信号,监控worker进程的运行状态,当worker进程退出后(异常情况下),会自动重新启动新的worker进程。

      worker进程则是处理基本的网络事件。多个worker进程之间是对等的,他们同等竞争来自客户端的请求,各进程互相之间是独立的。一个请求,只可能在一个worker进程中处理,一个worker进程,不可能处理其它进程的请求。

    2.2.2 系统的开发环境

    系统设计平台:Microsoft Windows 10

    数据库设计工具:MySQL

    程序设计工具:Visual studio code

    三,系统展示

    4.2.1 注册界面

    注册界面是管理系统最重要的环节,只有注册才能有能力访问管理后台系统,以及进一步的操作,这样也就规避了不同人员在没有权限下,操作管理后台。

    没有权限操作数据,会对整个数据造成破坏,产生不可挽回的影响。

    具体代码如下:

    let { name, password, password2, phone, username } = ctx.request.body;

    let adminUserList = await query('select * from admin_user');

    let time = dayjs().format('YYYY-MM-DD HH:mm:ss')

    if (adminUserList.some(item => item.username === username)) {

      ctx.body = {

    code: -1,

    data: null,

    message:  '该用户已经注册'

    };

    } else {

     try {

       let str = `INSERT INTO admin_user(username, password, name, phone, time) VALUES('${username}', '${password}', '${name}', '${phone}', '${time}')`;

       console.log(str);

       await query(str);

       ctx.response.redirect('/login');

    } catch(err) {

       console.log(err);

      ctx.response.redirect('/register');

    }

    }

    注册操作需要的信息有:用户名(登录名)、用户密码、确认密码、真实姓名、用户手机号。具体操作页面如4-1所示:

    image.gif编辑

    4.2.2 登录界面

    管理员登录是验证用户身份最主要的手段,后台系统通过token保存用户身份,前端把token放到浏览器storage中存储,每次请求带上token数据。整体的实现也非常简单,通过输入用户名和密码,前端发起http请求,给到后端,后端拿到用户名和密码,进一步判断是否与数据库的数据一致,如果通过验证则跳到首页,否则就会返回给客户端相应的错误。通过认证后,用户就会与之创建连接,就可以完成之后的后续操作了。

    具体实现代码如下所示:

    let adminUserList = await query(`

    SELECT id, username, name, phone

    FROM admin_use

    WHERE username='${username}' && password='${password}'

    `);

    if (adminUserList.length > 0) {

      let token = jwt.sign({ ...adminUserList[0] }, secret);

      ctx.body = {

       code: 1,

         data: {

           token,

               username: username

         },

    message: '登录成功'

    }

    具体的功能页面如下图4-2所示:

    image.gif编辑

    图4-2 登录界面

    4.2.3 入库界面

    每为确保公司货货物进出入库能得到管制,确保仓库库存数据的准确,必须规范好商品的出入库

    流程。最重要的就是入库管理,通过点击顶部的商品入库跳到对应页面

    具体代码如下:

    操作界面如图4-3:

     router.post('/instock', async function (ctx, next) {

       let { token } = ctx.request.header;

       let { name, phone, goodsName } = ctx.request.body;

       try {

         let userInfo = jwt.verify(token, secret);

         let time = dayjs().format('YYYY-MM-DD HH:mm:ss');

         console.log(name, phone, goodsName, userInfo);

         // 1. 先用手机号查customer表,是否有此用户

         let customerList = await query(`select id, phone from customer`);

         let curCustomer = customerList.find(item => item.phone == phone);

         let customerId;

       

         if (!curCustomer) {

           // 先加一下这个用户

           customerId = customerList.length + 1;

           await query(`insert into customer(id, name, phone, time) values(${customerId}, '${name}', '${phone}', '${time}')`);

         } else {

           customerId = curCustomer.id;

         }

       

         // 2. 找一个空的货架单元

         // 把所有库存的仓库都找出来

         let storehouseGoodsList = await query(`select storehouse_id from storehouse_goods where is_out<>1`);

         let storehouseList = await query(`select id from storehouse`);

         let emptyStoreId = '';

         if (storehouseGoodsList.length > 0) {

           let emptyStoreList = storehouseList.filter(item => !storehouseGoodsList.some(it => it.storehouse_id === item.id))

           if (emptyStoreList.length === 0) throw new Error('没有空余的货架,请出库以腾出空位!');

           emptyStoreId = emptyStoreList[0].id;

         } else {

           emptyStoreId = storehouseList[0].id;

         }

       

         // 写入出库

         let goodsList = await query(`select id from goods`);

         let goodsId = goodsList.length + 1;

         await query(`insert into goods(id, name, customer_id, admin_id) values(${goodsId}, '${goodsName}', ${customerId}, ${userInfo.id})`);

         await query(`insert into storehouse_goods(goods_id, storehouse_id, is_out, instock_time) values(${goodsId}, ${emptyStoreId}, 0 ,'${time}');`);

         ctx.body = {

           code: 1,

           data: null,

           message: '商品入库成功!'

         }

       } catch(err) {

         console.log(err);

         ctx.response.redirect('/login');

       }

     });

    image.gif编辑

    图4-3 商品入库

    4.2.4 出库界面

    仓当客户收到取件码后,通过扫码就可以获得对应的库存id(因为没有具体的物理设备,此操作通过查询步骤,给出库存id),通过检验身份信息,此功能通过点击顶部的商品出库跳到对应的页面完成

    相关代码如下:

    具体操作页面如图4-4:

     router.post('/outstock', async function (ctx, next) {

       let { token } = ctx.request.header;

       let { val } = ctx.request.body;

       try {

         let userInfo = jwt.verify(token, secret);

         let sgList = await query(`select id, goods_id, is_out from storehouse_goods where id=${val}`);

         if (sgList.length === 0) throw new Error('库存id无效');

         if (sgList[0].is_out === 1) throw new Error('该商品已经出库');

         let time = dayjs().format('YYYY-MM-DD HH:mm:ss');

         await query(`UPDATE storehouse_goods SET is_out=1, outstock_time='${time}' where id=${val}`);

         ctx.body = {

           code: 1,

           data: null,

           message: '出库成功'

         }

       } catch(err) {

         ctx.body = {

           code: -1,

           data: null,

           message: err.message

         }

       }

     });

    image.gif编辑

    图4-4 商品出库界面

    4.2.5 查询界面

    相关代码如下:

    具体操作页面如图4-5所示:

     router.get('/queryorder', async function (ctx, next) {

       let { token } = ctx.request.header;

       let { value } = ctx.request.query;

       try {

         let userInfo = jwt.verify(token, secret);

         let reg_tel = /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/;

         let arr = [];

       

         // , G.is_out, G.instock_time, G.outstock_time

         // 如果是手机号

         if (reg_tel.test(value)) {

           let customerList = await query(`SELECT id FROM customer WHERE phone='${value}'`);

     

           if (customerList.length === 0) throw new Error('没有这个手机号的记录');

           // 找到这个商品

           let goodsList = await query(`SELECT G.id, G.name AS 'good_name', A.name AS 'admin_name', C.name AS 'customer_name' FROM goods G, admin_user A, customer C WHERE G.customer_id=${customerList[0].id} AND C.id=${customerList[0].id} AND A.id=G.admin_id`);

         

           if (goodsList.length > 0) {

             for (let i=0; i<goodsList.length; i++) {

               let _item = { ...goodsList[i] };

             

               let sgList = await query(`SELECT * FROM storehouse_goods WHERE goods_id=${_item.id}`);

               if (sgList.length === 0) throw new Error('没有找到此库存');

               let storeList = await query(`SELECT * FROM storehouse WHERE id=${sgList[0].storehouse_id}`);

               if (storeList.length === 0) throw new Error('没有找到此仓库');

               // 找这个仓库

               _item.store_id = storeList[0].id;

               _item.store_code = storeList[0].name;

               _item.sg_id = sgList[0].id;

               _item.is_out = sgList[0].is_out;

               _item.instock_time = sgList[0].instock_time;

               _item.outstock_time = sgList[0].outstock_time;

               arr.push(_item);

             }

           

           }

           console.log(goodsList);

         } else {

           // 使用取件码查询

           // 1. 查询库存表是否有这个仓库

           let storeList = await query(`SELECT id, name FROM storehouse WHERE name='${value}'`);

           if (storeList.length === 0) throw new Error(`${value}这个取件码无效`);

           // 2. 找到这个库存

           let sgList = await query(`SELECT * FROM storehouse_goods WHERE storehouse_id=${storeList[0].id}`);

           if (sgList.length === 0) throw new Error(`没有找到这个库存`);

           // 3. 找到这个商品

           let goodsList = await query(`SELECT G.id, G.name AS 'good_name', A.name AS 'admin_name', C.name AS 'customer_name' FROM goods G, admin_user A, customer C WHERE G.id=${sgList[0].id} AND C.id=G.customer_id AND A.id=G.admin_id`);

           if (goodsList.length > 0) {

             arr.push(goodsList[0]);

             arr[0].store_id = storeList[0].id;

             arr[0].store_code = storeList[0].name;

             arr[0].sg_id = sgList[0].id;

             arr[0].is_out = sgList[0].is_out;

             arr[0].instock_time = sgList[0].instock_time;

             arr[0].outstock_time = sgList[0].outstock_time;

           }

         }

         ctx.body = {

           code: arr.length > 0? 1: -1,

           data: arr,

           message: arr.length > 0? 'query ok': '没有找到指定的库存'

         }

       

       } catch(err) {

         ctx.body = {

           code: -1,

           data: null,

           message: err.message

         }

       }

     })

    image.gif编辑

    图4-5 库存查询页面

    4.2.6 库存异常界面

    在常规的快递库存管理过程中,不可避免的会遇到快递长期无人领取,一方面有可能是客户工作繁忙等原因,也有可能是因为某些原因客户没有收到通知短信,导致库存长期被占用。这里有两个问题:第一、因为库存被占用,不能存放其他快递;第二、客户没有接收到快递,降低用户体验,并且有可能造成用户的经济损失。基于以上原因,特设库存异常功能,解决此类问题,相关代码如下:

         let arr = [];

         let timeWhere = '';

         switch (val) {

           case '1': // 超时一周

             timeWhere = `instock_time < '${ dayjs(dayjs() - 7*24*60*60*1000).format('YYYY-MM-DD HH:mm:ss') }'`;

             break;

           case '2': // 超时3周

             timeWhere = `instock_time < '${ dayjs(dayjs() - 3*7*24*60*60*1000).format('YYYY-MM-DD HH:mm:ss') }'`;

             break;

           case '3': // 超时一个月

             timeWhere = `instock_time < '${ dayjs(dayjs() - 30*24*60*60*1000).format('YYYY-MM-DD HH:mm:ss') }'`;

             break;

           case '4': // 超时三个月

             timeWhere = `instock_time < '${ dayjs(dayjs() - 90*24*60*60*1000).format('YYYY-MM-DD HH:mm:ss') }'`;

             break;

           case '5': // 超时一年

             timeWhere = `instock_time < '${ dayjs(dayjs() - 365*24*60*60*1000).format('YYYY-MM-DD HH:mm:ss') }'`;

             break;

         }

         let sgList = await query(`select * from storehouse_goods where is_out<>1 and ${timeWhere}`);

         for (let i=0; i<sgList.length; i++) {

           let item = { ...sgList[i], instock_time: dayjs(sgList[i].instock_time).format('YYYY-MM-DD HH:mm:ss') };

           let storeList = await query(`select id, name from storehouse where id=${item.storehouse_id}`);

           let goodsList = await query(`select G.id, G.name AS 'good_name', A.name AS 'admin_name', C.name AS 'customer_name' from goods G, admin_user A, customer C where G.id=${item.goods_id} AND C.id=G.customer_id AND A.id=G.admin_id`);

           if (goodsList.length > 0) {

             item.store_id = storeList[0].id;

             item.store_code = storeList[0].name;

             item.admin_name = goodsList[0].admin_name;

             item.customer_name = goodsList[0].customer_name;

             item.good_name = goodsList[0].good_name;

           }

           arr.push(item);

         }

    具体操作界面如图4-6所示:

    image.gif编辑

    图4-6 库存异常界面

    4.2.7 客户信息

    有些场景我们需要查找客户信息,比如某一快递异常,找客户的手机号,给客户发消息,这时就需要客户信息功能界面,可以模糊查询。

    具体代码如下:

    queryWhere = `where name like '%${val}%'`;

    let arr = await query(`select * from customer ${queryWhere}`);

    arr = arr.map(item => ({ ...item, time: dayjs(item.time).format('YYYY-MM-DD HH-mm-ss') }));

    具体界面如图4-7所示:

    image.gif编辑

    图4-7 客户信息界面

    四,项目总结

    5.1测试的目的

    系统测试(System Testing),系统测试是把已经完成的硬件、软件、外设、网络等所有组成部分结合在一起,对整个系统进行单元测试和总体测试,通过与系统的需求做比较,找到所开发的系统与用户需求之间的差别,进而优化系统的手段。目前无论大企业还是中小企业,都再利用互联网进行信息的管理和分享,所以一个软件系统进行系统的测试和总结,是必要的和必需的,而且通过测试工作的进行,可以反映出最初没有考虑到的细节或流程,也有查漏补缺的功能,进而提高软件的质量。

    5.2测试的方法

    5.2.1 白盒测试

    白盒测试又被称为:结构测试或者叫做逻辑驱动测试,这是一种需要基于代码的测试,白盒是一种形象的比喻,系统程序就像透明盒子一样,是可以看见的,也就是我们可以系统的各个模块是如何运行和调用的。比如:大部分公司首先会进行白盒测试,也就是按功能模块系统的对子模块进行系统的测试,包括运行的异常和文本域或模拟用户行为创建并不符合系统的输入,从而建立全面准确并具有说服力了的测试用例。虽然白盒测试有很多优点,但也有几个无法规避的问题,一个系统程序运行会有很多条类似于tree结构的不同路径,不可能测试所有的情况,也为程序不稳定埋下了伏笔。

    5.2.2 黑盒测试

    黑盒测试通常也成为数据驱动的测试方法,黑盒顾名思义就是,把系统程序看作看不见的黑盒子,完全不用考虑系统的流程,数据的流动,以及各个字段的类型。在完全不考虑程序本身的前提下,更多从用户使用情况或用户体验出发,测试每个模块是否可以正常稳定运行,按照程序需求文档,逐条验证是否可以输入数据而产生预期的正确结果,白盒测试着眼于内部,而黑盒子着眼于外部,当然这里有一个弊端,就是黑盒测试不能系统功能是否设计合理等细节问题。

    5.2.3 灰盒测试

    白盒测试和黑盒测试都有各自的优缺点,而灰盒测试介于黑盒测试和白盒测试之间,综合了各自的优点,有又规避了其中的缺点,不仅像白盒测试那样测试系统程序内部的功能逻辑,还会重点关注输入、输出的准确性。比如某个程序段运行时,通过外部的异常表现,转而进入程序内部,结合程序内部逻辑结构综合分析,这样就可以全面的诊断和测试系统程序。

    5.2.4 静态测试

    静态测试是比较独特,不像其他测试方法,需要运行被测试的系统程序,静态测试通过系统的分析程序结构,语法,接口规范,过程来检查程序的手段。

    5.2.5 动态测试

    动态测试是运行被测试的系统程序,分析程序运行的结果和预期达到的结果的差异,并总结出具体的程序性能指标,正确率等。

    5.3测试用例

    5.3.1 系统登录功能测试

    系统的测试是甲方验收的重要的依据,通过输入所需信息查看是否和预期一样。是否可以完整成功运行整个系统。如表5-1所示

    图5-1 测试用例

    名称

    功能

    操作

    期望结果

    实际结果

    测试状态

    用户注册

    注册管理员

    输入用户名:wxs;

    密码:12345678;

    确认密码:12345678

    真实名字:王先生

    手机号:18201107931

    注册成功

    编辑

    与期望相同

    用户登录

    管理员登录

    用户名:wxs;

    密码:12345678

    登录成功

    编辑

    与期望相同

    查询库存

    库存列表

    输入用户手机号:,查询它的商品快递

    查询成功

    编辑

    与期望相同

    商品入库

    商品入库

    收件人姓名:李先生;

    收件人手机号:18435250911;

    商品名称:小米手环S1

    入库成功

    编辑

    与期望相同

    商品出库

    商品出库

    输入库存id:6

    出库成功

    编辑

    与期望相同

    库存异常

    查询异常库存

    选择超时一年未取的选项

    查询成功

    编辑

    与期望相同

    客户信息

    客户信息

    输入用户姓名

    查询成功

    编辑

    与期望相同

    5.4测试总结

    时间不知不觉程序已经测试完成,虽然功能总体来说比较简单,但是通过自己的双手一步一步的完成此论文,非常的激动。系统总体达到了总目标,编码结果和测试结果完成预期规划,此次测试从系统的各个环节进行了全面测试,基本达到系统独立应用的能力,基本功能已经实现。

    通过测试,功能更加齐全和稳定,在测试中不断会有bug产生,通过不断的寻找解决方法,最终完成预期效果。


    相关实践学习
    如何在云端创建MySQL数据库
    开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
    全面了解阿里云能为你做什么
    阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
    相关文章
    |
    19天前
    |
    JavaScript 前端开发 API
    Vue.js:现代前端开发的强大框架
    【10月更文挑战第11天】Vue.js:现代前端开发的强大框架
    62 41
    |
    5天前
    |
    前端开发 JavaScript 开发者
    React与Vue:前端框架的巅峰对决与选择策略
    【10月更文挑战第23天】React与Vue:前端框架的巅峰对决与选择策略
    |
    5天前
    |
    前端开发 JavaScript 数据管理
    React与Vue:两大前端框架的较量与选择策略
    【10月更文挑战第23天】React与Vue:两大前端框架的较量与选择策略
    |
    10天前
    |
    JavaScript 前端开发 算法
    前端优化之超大数组更新:深入分析Vue/React/Svelte的更新渲染策略
    本文对比了 Vue、React 和 Svelte 在数组渲染方面的实现方式和优缺点,探讨了它们与直接操作 DOM 的差异及 Web Components 的实现方式。Vue 通过响应式系统自动管理数据变化,React 利用虚拟 DOM 和 `diffing` 算法优化更新,Svelte 通过编译时优化提升性能。文章还介绍了数组更新的优化策略,如使用 `key`、分片渲染、虚拟滚动等,帮助开发者在处理大型数组时提升性能。总结指出,选择合适的框架应根据项目复杂度和性能需求来决定。
    |
    17天前
    |
    前端开发 JavaScript 安全
    在vue前端开发中基于refreshToken和axios拦截器实现token的无感刷新
    在vue前端开发中基于refreshToken和axios拦截器实现token的无感刷新
    52 4
    |
    21天前
    |
    JavaScript 前端开发 API
    Vue.js:打造高效前端应用的最佳选择
    【10月更文挑战第9天】Vue.js:打造高效前端应用的最佳选择
    16 2
    |
    24天前
    |
    JavaScript 前端开发 Python
    django接收前端vue传输的formData图片数据
    django接收前端vue传输的formData图片数据
    23 4
    |
    22天前
    |
    JavaScript 前端开发 Java
    VUE学习四:前端模块化,ES6和ES5如何实现模块化
    这篇文章介绍了前端模块化的概念,以及如何在ES6和ES5中实现模块化,包括ES6模块化的基本用法、默认导出与混合导出、重命名export和import,以及ES6之前如何通过函数闭包和CommonJS规范实现模块化。
    59 0
    VUE学习四:前端模块化,ES6和ES5如何实现模块化
    |
    5天前
    |
    前端开发 JavaScript 开发者
    React与Vue:前端框架的巅峰对决与选择策略
    【10月更文挑战第23天】 React与Vue:前端框架的巅峰对决与选择策略
    |
    12天前
    |
    前端开发 JavaScript API
    2025年前端框架是该选vue还是react?有了大模型-例如通义灵码辅助编码,就不用纠结了!vue用的多选react,react用的多选vue
    本文比较了Vue和React两大前端框架,从状态管理、数据流、依赖注入、组件管理等方面进行了详细对比。当前版本和下载量数据显示React更为流行,但Vue在国内用户量增长迅速。Vue 3通过组合式API提供了更灵活的状态管理和组件逻辑复用,适合中小型项目;React则更适合大型项目和复杂交互逻辑。文章还给出了选型建议,强调了多框架学习的重要性,认为技术问题已不再是选型的关键,熟悉各框架的最佳实践更为重要。