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 相关文章推荐
使用forever管理nodejs应用教程
Jun 03 NodeJs
nodejs教程之制作一个简单的文章发布系统
Nov 21 NodeJs
Nodejs初级阶段之express
Nov 23 NodeJs
深入浅析NodeJs并发异步的回调处理
Dec 21 NodeJs
详解nodejs中的process进程
Mar 19 NodeJs
Nodejs中Express 常用中间件 body-parser 实现解析
May 22 NodeJs
nodejs爬虫初试superagent和cheerio
Mar 05 NodeJs
nodejs 简单实现动态html的方法
May 12 NodeJs
Nodejs 发布自己的npm包并制作成命令行工具的实例讲解
May 15 NodeJs
typescript nodejs 依赖注入实现方法代码详解
Jul 21 NodeJs
NodeJs crypto加密制作token的实现代码
Nov 15 NodeJs
NodeJS实现一个聊天室功能
Nov 25 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 array_map()数组函数使用说明
2011/07/12 PHP
php+ajax+json 详解及实例代码
2016/12/12 PHP
Laravel 批量更新多条数据的示例
2017/11/27 PHP
使用vs code编辑调试php配置的方法
2019/01/29 PHP
PHP超级全局变量【$GLOBALS,$_SERVER,$_REQUEST等】用法实例分析
2019/12/11 PHP
JS 时间显示效果代码
2009/08/23 Javascript
浅析JavaScript中两种类型的全局对象/函数
2013/12/05 Javascript
与Math.pow 相反的函数使用介绍
2014/08/04 Javascript
JS简单操作select和dropdownlist实例
2014/11/26 Javascript
jQuery stop()用法实例详解
2016/07/28 Javascript
浅析BootStrap Treeview的简单使用
2016/10/12 Javascript
vue-router2.0 组件之间传参及获取动态参数的方法
2017/11/10 Javascript
JavaScript实现百度搜索框效果
2020/03/26 Javascript
详解React 元素渲染
2020/07/07 Javascript
python和C语言混合编程实例
2014/06/04 Python
python统计日志ip访问数的方法
2015/07/06 Python
pandas重新生成索引的方法
2018/11/06 Python
解决Python对齐文本字符串问题
2019/08/28 Python
用python爬取历史天气数据的方法示例
2019/12/30 Python
TensorFlow tf.nn.max_pool实现池化操作方式
2020/01/04 Python
浅谈pytorch中torch.max和F.softmax函数的维度解释
2020/06/28 Python
如何利用input事件来监听移动端的输入
2016/04/15 HTML / CSS
洲际酒店集团美国官网:IHG美国
2017/11/16 全球购物
美国眼镜网站:LensCrafters
2020/01/19 全球购物
在浏览器端如何得到服务器端响应的XML数据
2012/11/24 面试题
怎么写有吸引力的自荐信
2013/11/17 职场文书
机电一体化专业求职信
2014/07/22 职场文书
党的群众路线教育实践活动领导班子对照检查材料
2014/09/25 职场文书
房屋维修协议书范本
2014/09/25 职场文书
新员工考核评语
2014/12/31 职场文书
民事答辩状范本
2015/05/21 职场文书
2016年幼儿园教师政治学习心得体会
2016/01/23 职场文书
高效课堂教学反思
2016/02/24 职场文书
公司年会主持词范文!
2019/05/07 职场文书
Python re.sub 反向引用的实现
2021/07/07 Python
Python实现查询剪贴板自动匹配信息的思路详解
2021/07/09 Python