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教程之入门
Nov 21 NodeJs
NodeJS使用formidable实现文件上传
Oct 27 NodeJs
详解Nodejs的timers模块
Dec 22 NodeJs
windows 下安装nodejs 环境变量设置
Feb 02 NodeJs
深入nodejs中流(stream)的理解
Mar 27 NodeJs
详解nodejs express下使用redis管理session
Apr 24 NodeJs
NodeJs中express框架的send()方法简介
Jun 20 NodeJs
nodejs微信扫码支付功能实现
Feb 17 NodeJs
NodeJS使用Range请求实现下载功能的方法示例
Oct 12 NodeJs
Nodejs核心模块之net和http的使用详解
Apr 02 NodeJs
基于nodejs的微信JS-SDK简单应用实现
May 21 NodeJs
nodejs中的异步编程知识点详解
Jan 17 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 根据IP地址控制访问的代码
2010/04/22 PHP
php垃圾代码优化操作代码
2010/08/05 PHP
php获取后台Job管理的实现代码
2011/06/10 PHP
php cURL和Rolling cURL并发方式比较
2013/10/30 PHP
PHP动态生成指定大小随机图片的方法
2016/03/25 PHP
php有效防止图片盗用、盗链的两种方法
2016/11/01 PHP
运用Windows XP附带的Msicuu.exe、Msizap.exe来彻底卸载顽固程序
2007/04/21 Javascript
jquery与google map api结合使用 控件,监听器
2010/03/04 Javascript
js获取单选框或复选框值及操作
2012/12/18 Javascript
如何实现修改密码时密码框显示保存到cookie的密码
2013/12/10 Javascript
js操作输入框中选择内容兼容IE及其他主流浏览器
2014/04/22 Javascript
js中使用replace方法完成某个字符的转换
2014/08/20 Javascript
textarea不能通过maxlength属性来限制字数的解决方法
2014/09/01 Javascript
针对初学者的jQuery入门指南
2015/08/15 Javascript
多个js毫秒倒计时同时进行效果
2016/01/05 Javascript
基于javascript html5实现多文件上传
2016/03/03 Javascript
JS模拟实现方法重载示例
2016/08/03 Javascript
vue.js数据绑定的方法(单向、双向和一次性绑定)
2017/07/13 Javascript
关于Vue Webpack2单元测试示例详解
2017/08/14 Javascript
浅谈FastClick 填坑及源码解析
2018/03/02 Javascript
使用wxapp-img-loader自定义组件实现微信小程序图片预加载功能
2018/10/18 Javascript
python zip文件 压缩
2008/12/24 Python
教你用Python写安卓游戏外挂
2018/01/11 Python
python 在threading中如何处理主进程和子线程的关系
2020/04/25 Python
利用Python如何制作贪吃蛇及AI版贪吃蛇详解
2020/08/24 Python
五款漂亮的纯CSS3动画按钮的实例教程
2014/11/21 HTML / CSS
做一个能自适应高度的textarea的示例代码
2019/09/06 HTML / CSS
英国亚马逊官方网站:Amazon.co.uk
2019/08/09 全球购物
ASICS印度官方网站:日本专业运动品牌
2020/06/20 全球购物
PHP高级工程师面试问题推荐
2013/01/18 面试题
大学开学计划书
2014/04/30 职场文书
驾驶员培训方案
2014/05/01 职场文书
优秀班组申报材料
2014/12/25 职场文书
外贸采购员岗位职责
2015/04/03 职场文书
2016年员工年度考核评语
2015/12/02 职场文书
使用HTML+Css+transform实现3D导航栏的示例代码
2021/03/31 HTML / CSS