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实现的一个简单聊天室功能分享
Dec 06 NodeJs
nodejs中实现路由功能
Dec 29 NodeJs
windows 下安装nodejs 环境变量设置
Feb 02 NodeJs
nodejs爬虫遇到的乱码问题汇总
Apr 07 NodeJs
详解nodejs操作mongodb数据库封装DB类
Apr 10 NodeJs
深入理解Nodejs Global 模块
Jun 03 NodeJs
nodejs mysql 实现分页的方法
Jun 06 NodeJs
nodejs读取并去重excel文件
Apr 22 NodeJs
详解Nodejs内存治理
May 13 NodeJs
nodejs图片处理工具gm用法小结
Dec 12 NodeJs
nodejs对项目下所有空文件夹创建gitkeep的方法
Aug 02 NodeJs
nodejs nedb 封装库与使用方法示例
Feb 06 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 从数据库提取二进制图片的处理代码
2009/09/09 PHP
php中将汉字转换成拼音的函数代码
2012/09/08 PHP
基于PHP读取TXT文件向数据库导入海量数据的方法
2013/04/23 PHP
配置php网页显示各种语法错误
2013/09/23 PHP
windows服务器中检测PHP SSL是否开启以及开启SSL的方法
2014/04/25 PHP
PHP实现表单提交数据的验证处理功能【防SQL注入和XSS攻击等】
2017/07/21 PHP
心扬JS分页函数代码
2010/09/10 Javascript
一个关于jqGrid使用的小例子(行按钮)
2011/11/04 Javascript
javascript中使用new与不使用实例化对象的区别
2015/06/22 Javascript
js实现完美兼容各大浏览器的人民币大小写相互转换
2015/10/29 Javascript
JavaScript事件类型中UI事件详解
2016/01/14 Javascript
基于javascript bootstrap实现生日日期联动选择
2016/04/07 Javascript
jQuery元素选择器实例代码
2017/02/06 Javascript
深入理解js中的加载事件
2017/02/08 Javascript
Node.js中 __dirname 的使用介绍
2017/06/19 Javascript
JavaScript实现的搜索及高亮显示功能示例
2017/08/14 Javascript
vue proxy 的优势与使用场景实现
2020/06/15 Javascript
vue中echarts引入中国地图的案例
2020/07/28 Javascript
基于vue 动态菜单 刷新空白问题的解决
2020/08/06 Javascript
vue实现简单加法计算器
2020/10/22 Javascript
vue 中的动态传参和query传参操作
2020/11/09 Javascript
phpsir 开发 一个检测百度关键字网站排名的python 程序
2009/09/17 Python
python发送邮件功能实现代码
2016/07/15 Python
Python做文本按行去重的实现方法
2016/10/19 Python
python中requests库session对象的妙用详解
2017/10/30 Python
分享vim python缩进等一些配置
2018/07/02 Python
实例分析python3实现并发访问水平切分表
2018/09/29 Python
对Django的restful用法详解(自带的增删改查)
2019/08/28 Python
sklearn+python:线性回归案例
2020/02/24 Python
压铸汽车模型收藏家:Diecastmodelswholesale.com
2016/12/21 全球购物
美国珠宝店:Helzberg Diamonds
2018/10/24 全球购物
索引覆盖(Index Covering)查询含义
2012/02/18 面试题
企业党的群众路线教育实践活动学习心得体会
2014/10/31 职场文书
个人求职信格式范文
2015/03/20 职场文书
学校艾滋病宣传活动总结
2015/05/09 职场文书
python编程简单几行代码实现视频转换Gif示例
2021/10/05 Python