nodejs+koa2 实现模仿springMVC框架


Posted in NodeJs onOctober 21, 2020

koa2-MVC架构

---------后端技术做前端

环境:nodejs

开发工具:Visual Studio Code(下文简称:VSC)

环境安装,工具安装及中文自行百度,环境调整好后开始进入正题。

1、在硬盘上新增一个文件夹,打开VSC,点击‘添加工作区文件夹',如果没有欢迎‘使用页面',点击--文件--新建窗口,效果如下图:

nodejs+koa2 实现模仿springMVC框架

nodejs+koa2 实现模仿springMVC框架

2、添加vsc调试。Shift+ctrl+p,输入框内输入:launch.json

nodejs+koa2 实现模仿springMVC框架

选择刚刚的文件夹

nodejs+koa2 实现模仿springMVC框架

nodejs+koa2 实现模仿springMVC框架

3、目录结构

nodejs+koa2 实现模仿springMVC框架

从低到高one by one

3-1、package.json

{
 "name": "koa2mcv",
 "version": "1.0.0",
 "description": "Hello Koa 2 example with MVC",
 "main": "app.js",
 "scripts": {
  "start": "node app.js"
 },
 "author": "baba",
 "dependencies": {
  "koa": "2.11.0",
  "koa-router": "8.0.8",
  "koa-bodyparser": "4.3.0",
  "koa-static-plus": "0.1.1",
  "koa-view": "2.1.3",
  "koa-jwt": "4.0.0",
  "koa-log4": "2.3.2",
  "jsonwebtoken": "8.5.1",
  "nunjucks": "3.2.1",
  "mime": "2.4.5",
  "mz": "2.7.0"
 }
}

参数介绍:name项目名称、version版本号、description项目描述、main项目启动文件、scripts启动快捷设置,author作者,dependencies第3方中间件名称及版本。

3-2、app.js

//启动服务
require('./config/init').startServer();

启动相关配置,封装到config/init.js中,启动文件直接引用即可。

3-3、views存放html页面

3-4、static存放静态文件,css,js,font等

3-5、src存放业务控制,类似于springMVC中的controller、service。

3-6、config存放核心配置文件。

3-6-1、init.js项目核心。

异常友好处理

function handler(){
 return async (ctx, next) => {

  const start = new Date().getTime();

  var urlReq=ctx.request.url;
  if(urlReq !== '/favicon.ico'){

   console.log(`请求地址:${ctx.request.method} ${urlReq}`);
   try {

    let params =Object.assign({}, ctx.request.query, ctx.request.body);

    if(config["token"].excludeUrl.indexOf(urlReq) == -1 && !tokenFunction.varifyToken(params.token)){
     ctx.status =401;
    }else{
     await next();
    }
   } catch (error) {
    ctx.status=401;
    console.log(`错误!无法获取token参数`);
   }finally{

     let err={};
     if(!ctx.status){
      err.status = 500;
     }else if(ctx.status==200){
      return;
     }else{
      err.status = ctx.status;
     }

     switch(err.status){
      case 404:
       err.url = config["server-name"]+'/static/public/404.html';
       err.message="资源不存在!";
       break;
      case 401:
       err.url = config["server-name"]+'/static/public/10000.html';
       err.message="登陆失效!请重新登陆!";
       break;
      case 500:
       err.url = config["server-name"]+'/static/public/500.html';
       err.message="系统内部错误!";
       break;
     }

     switch(ctx.request.type){
      case 'application/json':
       ctx.type = 'application/json';
       ctx.body = {errorCode:err.errorCode,message: err.message}
       break;
      default:

       ctx.type = 'text/html';
       ctx.redirect(err.url);
       break;
     }
   }
  }
  const ms = new Date().getTime() - start;
  console.log(`请求消耗时间: ${ms}ms`);
 }
}

路由配置

function controller(){

 const router = new koaRouter({
  prefix: config["server-name"]
 });

 function findJsonFile(rootpathStr){

  fs.readdirSync(rootpathStr).forEach(function (item, index) {

   let fPath = path.join(rootpathStr,item);

   let stat = fs.statSync(fPath);

   if(stat.isDirectory() === true) {
    findJsonFile(fPath);
   }

   if (stat.isFile() === true&&fPath.endsWith('.js')) {

    var mapping = require(fPath);
    for (var url in mapping) {
     if (url.startsWith('GET ')) {
      router.get(url.substring(4), mapping[url]);
     } else if (url.startsWith('POST ')) {
      router.post(url.substring(5), mapping[url]);
     } else if (url.startsWith('PUT ')) {
      router.put(url.substring(4), mapping[url]);
     } else if (url.startsWith('DELETE ')) {
      router.del(url.substring(7), mapping[url]);
     }
     console.log(`注册 URL: ${url}`);
    }
   }
  });
 }

 findJsonFile(rootpath + 'src');
 return router.routes();
}

视图渲染

function templating() {
 var
  autoescape = config['templating-autoescape'] === null ? true : config['templating-autoescape'],
  noCache = config['templating-noCache'] === null ? false : config['templating-noCache'],
  watch = config['templating-watch'] === null ? false : config['templating-watch'],
  throwOnUndefined = config['templating-throwOnUndefined'] === null ? false :config['templating-throwOnUndefined'],
  env = new nunjucks.Environment(
   new nunjucks.FileSystemLoader(rootpath+'views', {
    noCache: noCache,
    watch: watch,
   }), {
    autoescape: autoescape,
    throwOnUndefined: throwOnUndefined
   });
 if (config['templating-filters'] != null) {
  for (var f in config['templating-filters']) {
   env.addFilter(f, config['templating-filters'][f]);
  }
 }
 return async (ctx, next) => {
  ctx.render = function (view, model) {
   ctx.response.body = env.render(view, Object.assign({}, ctx.state || {}, model || {}));
   ctx.response.type = 'text/html';
  };
  await next();
 };
}

启动构建

function startServer(){

 const app = new koa();

 app.use(koaStaticPlus(rootpath+'static', {
  pathPrefix: config["server-name"]+'/static'
 })
 );
 
 app.use(koaBodyParser());
 
 app.use(handler());
 
 app.use(templating());
 
 app.use(controller());
 
 app.listen(config["server-port"]);

}

3-6-2、config.js项目参数配置。

module.exports ={
 'server-name':'/koa',
 'server-port':3000,
 "templating-noCache":true,
 "templating-watch":true,
 "templating-autoescape":null,
 "templating-throwOnUndefined":null,
 "templating-filters":null,
 "token":{
  "excludeUrl":[
  "/koa/login",
  "/koa/dologin"
  ],
  "timeout":1000 * 60 * 60 * 24 * 7,
  "secret":"jiaobaba"
 }
 

}

3-6-3、token.js项目token相关方法封装。

const jwt = require("jsonwebtoken");
const config = require('./config');
/**
 * 创建token的方法
 */
let createToken = (data)=>{
 let obj = {};
 //存入token的数据
 obj.data = data || {};
 //token的创建时间
 obj.ctime = (new Date()).getTime();
 return jwt.sign(obj,config["token"].secret);
}
/**
 * 验证token是否合法的方法
 * @param {*} token 
 */
let varifyToken = (token)=>{
 let result = null;
 try{
  let {data,ctime,expiresIn} = jwt.verify(token,config["token"].secret);
  let nowTime = (new Date()).getTime();
  if(nowTime-ctime<config["token"].timeout){
   result = data;  
  }
 }catch(error){

 }
 return result;
}

module.exports = {
 createToken,
 varifyToken
};

3-6-4、logger.js项目日志配置文件。

4、项目结构构建结束,接着引入所有依赖包,在终端中执行‘npm install' ,会下载package.json中dependencies所有包,以及这些包所依赖的包。

nodejs+koa2 实现模仿springMVC框架

执行后项目结构会增加两个文件

nodejs+koa2 实现模仿springMVC框架

5、编写测试用例,在src下新建hello.js。

//token
const token = require('../config/token');

var fn_hello = async (ctx, next) => {
 var name = ctx.params.name;
 ctx.response.body = `<h1>Hello, ${name}!</h1>`;
};


var fn_index = async (ctx, next) => {
 ctx.response.body = `<h1>Index</h1>
  <form action="/koa/signin" method="post">
   <p>Name: <input name="name" value=""></p>
   <p>Password: <input name="password" type="password"></p>
   <p><input type="submit" value="Submit"></p>
  </form>`;
};

var fn_signin = async (ctx, next) => {
 var
  name = ctx.request.body.name || '',
  password = ctx.request.body.password || '';
 console.log(`登陆名: ${name}, 密码: ${password}`);
  ctx.response.body = `<h1>Welcome, ${name}!</h1><br/>you token:<br/>${token.createToken({user: name,password: password})}`;
 
};

module.exports = {
 'GET /hello/:name': fn_hello,
 'GET /login': fn_index,
 'POST /dologin': fn_signin
};

6、启动项目

nodejs+koa2 实现模仿springMVC框架

启动成功

nodejs+koa2 实现模仿springMVC框架

测试访问:http://127.0.0.1:3000/koa/login

nodejs+koa2 实现模仿springMVC框架

输入值获取token

nodejs+koa2 实现模仿springMVC框架

nodejs+koa2 实现模仿springMVC框架

先不用带token进行访问

nodejs+koa2 实现模仿springMVC框架

拦截成功

带上token 进行访问

nodejs+koa2 实现模仿springMVC框架

测试成功!

到此这篇关于nodejs+koa2 实现模仿springMVC的文章就介绍到这了,更多相关nodejs+koa2 springMVC内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

NodeJs 相关文章推荐
轻松创建nodejs服务器(5):事件处理程序
Dec 18 NodeJs
NodeJS学习笔记之Connect中间件模块(二)
Jan 27 NodeJs
nodejs实例解析(输出hello world)
Jan 03 NodeJs
nodejs 终端打印进度条实例代码
Apr 22 NodeJs
NodeJS、NPM安装配置步骤(windows版本) 以及环境变量详解
May 13 NodeJs
nodejs实现简单的gulp打包
Dec 21 NodeJs
nodejs使用http模块发送get与post请求的方法示例
Jan 08 NodeJs
nodeJs爬虫的技术点总结
May 13 NodeJs
监控Nodejs的性能实例代码
Jul 02 NodeJs
nodejs读取图片返回给浏览器显示
Jul 25 NodeJs
Nodejs环境实现socket通信过程解析
Jul 03 NodeJs
如何利用nodejs实现命令行游戏
Nov 24 NodeJs
nodejs使用Sequelize框架操作数据库的实现
Oct 21 #NodeJs
用Nodejs实现在终端中炒股的实现
Oct 18 #NodeJs
Nodejs在局域网配置https访问的实现方法
Oct 17 #NodeJs
NodeJS开发人员常见五个错误理解
Oct 14 #NodeJs
浅谈vue websocket nodeJS 进行实时通信踩到的坑
Sep 22 #NodeJs
基于NodeJS开发钉钉回调接口实现AES-CBC加解密
Aug 20 #NodeJs
浅谈使用nodejs搭建web服务器的过程
Jul 20 #NodeJs
You might like
显示程序执行时间php函数代码
2013/08/29 PHP
部署PHP项目应该注意的几点事项分享
2013/12/20 PHP
如何阻止网站被恶意反向代理访问(防网站镜像)
2014/03/18 PHP
JavaScript对象之间的转换 jQuery对象和原声DOM
2011/03/07 Javascript
jQuery实现仿QQ在线客服效果的滚动层代码
2015/10/15 Javascript
Jquery实现的简单轮播效果【附实例】
2016/04/19 Javascript
全面了解javascript三元运算符
2016/06/27 Javascript
使用JavaScript判断用户输入的是否为正整数(两种方法)
2017/02/05 Javascript
JS+HTML5实现图片在线预览功能
2017/07/22 Javascript
vue事件修饰符和按键修饰符用法总结
2017/07/25 Javascript
layui中layer前端组件实现图片显示功能的方法分析
2017/10/13 Javascript
jquery中有哪些api jQuery主要API
2017/11/20 jQuery
微信小程序云开发如何使用云函数生成二维码
2019/05/18 Javascript
关于ckeditor在bootstrap中modal中弹框无法输入的解决方法
2019/09/11 Javascript
vant时间控件使用方法详解
2020/12/24 Javascript
[51:53]完美世界DOTA2联赛循环赛 LBZS vs DM BO2第二场 11.01
2020/11/02 DOTA
Python实现分割文件及合并文件的方法
2015/07/10 Python
python 查找字符串是否存在实例详解
2017/01/20 Python
python命令行解析之parse_known_args()函数和parse_args()使用区别介绍
2018/01/24 Python
详解python中的线程
2018/02/10 Python
kaggle+mnist实现手写字体识别
2018/07/26 Python
在Pytorch中使用样本权重(sample_weight)的正确方法
2019/08/17 Python
Python生成验证码、计算具体日期是一年中的第几天实例代码详解
2019/10/16 Python
Python分析微信好友性别比例和省份城市分布比例的方法示例【基于itchat模块】
2020/05/29 Python
解决pytorch下出现multi-target not supported at的一种可能原因
2021/02/06 Python
Numpy ndarray 多维数组对象的使用
2021/02/10 Python
英国专业美容产品在线:Mylee(从指甲到脱毛)
2020/07/06 全球购物
英国著名药妆店:Superdrug
2021/02/13 全球购物
Python中pass语句的作用是什么
2016/06/01 面试题
技术副厂长岗位职责
2013/12/26 职场文书
30年同学聚会邀请函
2014/01/25 职场文书
优秀老师事迹材料
2014/02/05 职场文书
2014小学年度工作总结
2014/12/20 职场文书
销售督导岗位职责
2015/04/10 职场文书
欠条样本
2015/07/03 职场文书
apache虚拟主机配置的三种方式(小结)
2022/07/23 Servers