当前位置: 首页 > 后端技术 > Node.js

Egg实现一个mTime

时间:2023-04-03 16:22:41 Node.js

先放出项目地址:https://github.com/OrangeXC/m...有段时间没更新博客了,今天的文章主要围绕egg展开,一直沉浸在长期在前端框架中,实在不适应传统的MVC开发模式,也很久没有写过MVC项目了。说说今天的主角蛋。前几天在TencentIMwebConf2017大会上的第一个演讲就是egg。Egg是一个基于koa的node框架,意思是孵化新同学。这个项目的logo有点奇怪,是一个煎鸡蛋,这个嘛,没有新同学,因为这个项目并没有过多的利用鸡蛋。之所以这么说,是因为我调用了三方API。为啥不用vue、react、angular等直接请求接口,因为这里涉及到一点数据库操作,不废蛋。不用写科普文章,直接上egg官网,从简单的文档层面讲一下项目的搭建。Egg提供了cli,项目目录也遵循约定规范,不可随意篡改。egg-project├──package.json├──app.js(可选)├──agent.js(可选)├──app|├──router.js│├──控制器│|└──home.js│├──服务(可选)│|└──user.js│├──中间件(可选)│|└──response_time.js│├──时间表(可选)│|└──my_task.js│├──public(可选)│|└──reset.css│├──视图(可选)│|└──home.tpl│└──扩展(可选)│├──helper.js(可选)│├──request.js(可选)│├──response.js(可选)│├──上下文。js(optional)│├──application.js(optionaloptional)│└──agent.js(optional)├──config|├──plugin.js|├──config.default.js│├──config.prod.js|├──配置测试。js(可选)|├──config.local.js(可选)|└──config.unittest.js(可选)└──测试├──中间件|└──response_time.test.js└──controller└──home.test.js的初始配置主要看配置文件config/config.default.js和app目录先看config/config.default.js文件module.exports=appInfo=>{constconfig={};//应该改成你自己的config.keys=appInfo.name+'_1504252356337_1029';//查看config.view={defaultViewEngine:'nunjucks',mapping:{'.tpl':'nunjucks',},};config.sequelize={dialect:'mysql',//支持:mysql,mariadb,postgres,mssql数据库:'mtime',主机:'127.0.0.1',端口:'3306',用户名:'root',密码:'',};config.mysql={client:{host:'127.0.0.1',port:'3306',user:'root',password:'',database:'mtime',},app:true,agent:false,};返回配置;};这里指定注意这里不生效是因为我们没有指定插件对应的npm包,前提是安装好这些依赖。在config/plugin.jsexports.nunjucks={enable:true,package:'egg-view-nunjucks',};exports.sequelize={enable:true,package:'egg-sequelize',};exports.mysql={enable:true,package:'egg-mysql',};网页publicheader里面有城市选择,如下,api是非官方的api,所以只能自己整理城市列表,保存在本地init目录下的location.json是问题。每次都调用本地文件显然不合理,以后还会涉及到城市信息的变化。这里将第一次导入的init数据写入mysql,然后从myspl统一获取location。.初始化代码按照约定放在app.js中,让我们进行初始化。constfs=require('fs');module.exports=app=>{app.beforeStart(async()=>{//应用程序将等待此函数完成后再开始awaitapp.model.sync({force:true});app.database=awaitapp.mysql.createInstance(app.config.mysql.client);constlocations=JSON.parse(fs.readFileSync('./init/location.json'));awaitapp.mysql.insert('locations',位置.data);});};虽然egg-mysql和egg-sequelize文档都介绍了,这里简单介绍一下awaitapp.model.sync({force:true});是同步到数据库的模型,主要是同步数据库表和字段app.database=awaitapp.mysql.createInstance(app.config.mysql.client);就是在应用运行时从配置中心动态获取实际参数,然后初始化一个实例。注意:这里官网上的代码有点小。下面官网代码的configCenter没有fetch方法。如果遇到同样的坑,可以使用上面的代码。constmysqlConfig=yieldapp.configCenter.fetch('mysql');app.database=app.mysql.createInstance(mysqlConfig);constlocations=JSON.parse(fs.readFileSync('./init/location.json'));这句话就不解释了,不懂就学nodebasicawaitapp.mysql.insert('locations',locations.data);这句话是直接将Array保存到数据库locations表中。下面介绍官网CRUD语句的写法。官网上的例子是插入单条数据(Object格式)。当然这里也可以创建多个数组。注意:在第一句话中,我们创建了位置表。表中有两个默认字段,分别是created_at和updated_at。批量导入数据中没有这两个字段,所以报错。解决方法是在模型的location.js中给这两个字段默认值,如下:created_at:{type:DATE,default:newDate(),},updated_at:{type:DATE,default:newDate(),}上面的代码依赖两个库,egg-sequelize和egg-mysql,这两个库都和mysql的运行有关。当然,您可以根据您的业务需要选择一种。至于这两个库的功能,大家可以直接去Github上看文档。到这里mysql看看一切准备就绪路由构建页面整体分为三个部分。headerrouterfooterrouter是根据路由动态渲染的,也是主要的业务逻辑块。首页的电影列表分为三类。/new,当然考虑到城市的因素(不同城市上映的电影略有不同),在本项目的query里面写的,所有的routes后面都跟着一个query。实在是看着不舒服,移到下一步cookie或localStorage,代码约定在app/router.js中写成如下app.get('/','home.index');app.get('/hot','hot.index.index');应用程序。get('/new','new.index.index');解释路由对应的控制器的语法。规则是文件名/函数名或文件夹/文件名/函数名。当然,这是我个人的猜测,而且有效,官网的写法可以去howtodefinetherouter。还有详情页、短评页、热评页、剧照和海报页预览花絮页,对应如下路由app.get('/movie/:id','movie.index.index');app.get('/comment/:movieId','comment.normal.index');app.get('/hot_comment/:movieId','comment.hot.index');app.get('/stills/:movieId','stills.index.index');app.get('/video/:movieId','video.index.index');路由介绍到这里就没什么好说的了,不用网站上这个项目的概况也一目了然了。接下来是控制器调用模型数据并将其呈现到页面。下面对控制器不再一一描述,可以分开控制器的构造。按照约定,我们直接找到controller目录。查看所有控制器constlocations=awaitctx.model.Location.findAll();这句话找到所有位置数组。仔细看的会发现每个controller都有如下代码。我们需要获取所有位置列表并在查询中查找数据。默认为北京。页面公共部分的header中总有一个location下拉列表,所以每次都要往页面丢数据。更好的方案是点击下拉列表异步拉取所有位置,然后渲染。ctx.query.location?location=locations.find(({id})=>id===Number(ctx.query.location)):location={id:290,name:'北京',};这里完全没有前端层面的ajax获取数据。原谅我的懒惰,导致所有控制器代码冗余。剩下的就是调用mtime的api了。egg给我们封装了全局的http方法,感觉不错。HttpClient使用方便,参数简单,可以媲美axios的方便。让我们亲自体验一下。视图构建说到视图层,就是大前端的天下了。如果玩6,这一层可以无限延伸,从最简单的模板(pug、ejs、swig、nunjucks等)到(vue、react、angular等),再到(Andriod、IOS),再到(RN,weex),甚至是小程序界面。我喜欢服务层的地方在于它可以渲染模板并吐出数据。本来想前后端分离的,后来气得调用了别人的API,却没有直接写视图层。做个蛋没用——蛋用。不知不觉聊起了笑话,索性回到了10年前的前端,抛开了MVVM,甚至拿起了jquery。吐槽的很多,这里用的是nunjucks,官网上的例子用的就是这个模板。至此我们的页面就完成了。..虽然我什么都没说,但我想大家都能看懂模板。至于Bulma的初衷,不想用Jquery(bootStrap大家懂的),但是找不到自己喜欢的轮播。我一直在寻找轮播很长一段时间,它仍然依赖于jquery。..这里声明不充分,mTime的接口没有正式开放,来自https://github.com/jokermonn/...,mTime的服务器禁止跨域请求MP4资源,尝试以下方法解决iframe,失败成功,访问失败,没有解决问题,但是奇怪的是复制mp4url??到新标签页回车就可以访问了,但是当atag跳转到新的tab,js的window.open()我没有尝试把node请求的mp4buffer转成stream再丢给前端。能力有限没能解决问题。一方面是因为作者的能力,另一方面又违背了mTime节省视频服务器流量的思路,在视频页面给了一个跳转真正mTime官网的链接。真遗憾。如果有在节点端转发视频请求的经验,请赐教。综上所述,项目完成时间较短,很多细节考虑不到位。希望你多抱怨。写这篇文章的目的是给想了解egg的开发者做一个小demo。真正的生产模型比这复杂得多。这篇文章也自然不值一提。文章来自orange的个人博客http://orangexc.xyz/