WEB开发: Node.js路由之由浅入深(三)自动配置路由 - 全栈工程师入门

news2024/12/16 22:38:06

前面我们一起学习了Node.js路由的两个进阶,

(1)WEB开发: Node.js路由之由浅入深(一) - 全栈工程师入门

(2)WEB开发: Node.js路由之由浅入深(二)自动路由 - 全栈工程师入门

在第二进阶中,我们已经通过将路由结构模块化,实现了比较方便的而路由方法。

一、进阶分析

但是,你会发现这个文件需要手工去编写:


/project
  /routes
    routesConfig.js

对,就是这个routesConfig.js,每次新增或者删除、修改路由的控制文件,可能都要更改这个文件。

它的内容是这样的:

// routesConfig.js
module.exports = [
    { method: 'get', path: '/auth/login', controller: 'authController', action: 'login' },
    { method: 'get', path: '/user/:id', controller: 'userController', action: 'getUserById' },
    { method: 'post', path: '/product', controller: 'productController', action: 'createProduct' },
    { method: 'post', path: '/auth/login', controller: 'authController', action: 'login' }
    // 更多路由...
];

/*
@method: 对应来自 访问端 的RESTful API 方法 
@path: 定义来自访问端的路径
@controller 根据method 和 path  来定位使用什么控制器
@action 定义使用控制器中的什么函数
*/

仔细观察你会发现,这里面的内容,和我们控制器以及控制器内的配置是存在对应关系的,也就是

method: 这个是api进来的请求方式

controller: 这个是我们控制器的文件名

action: 这个是我们控制器内的函数名

唯一一个没有对应关系的是 path。

那么搞清楚这个关系,就好办了。

二、更改控制器

既然path和控制器的文件名、内容都无关,那么我们是否可以将这个关系写到控制器内,然后通过自动读取文件夹、解析文件内容的方式,来自动生成这个routesConfig.js文件呢?

答案当然是可以的。

所以我们只需要修改下面两部分:

第一部分,修改控制器的写法,比如userController.js的写法,改成这样:


// userController.js
module.exports = {
    get: {
        getUserById: {
            path: '/user/:id',
            fn: (req, res) => {
                const userId = req.params.id;
                res.send(`User ID: ${userId}`);
            },
        }
    },
    post: {
        getUserById: {
            path: '/user/:id',
            fn: (req, res) => {
                const userId = req.params.id;
                res.send(`User ID: ${userId}`);
            }
        },
    }
    // 更多方法...
};

看到了吗 ,我们把控制器分成了 get 和post 两类,当然你也可以加put  delete。

然后我们这里面加入了 path。 也就是说当你写控制器的时候,你就顺手将path 写进去了,不需要去写其他的文件。fn就是我们之前的action。

所以这个路由的get调用就是: 控制器.get.getUserById.fn() ,路径就是: 控制器.get.getUserById.path

三、更改app.js

所以我们需要更改一下app.js 的动态路由方法,改动后如下:

// 动态加载路由
routesConfig.forEach(route => {
    const controller = require(`./controllers/${route.controller}`);  // 动态加载控制器
    app[route.method](route.path, controller[route.method][route.action].fn);  // 将路由与控制器方法绑定

    console.log('for review route:', route.method, route.path, controller[route.method][route.action].fn)

});

看到了吗,route.path, controller[route.method][route.action].fn 对应了我上面的解释。

四、自动生成路由配置

到这里,整个路由逻辑完成了,但是我们需要自动生成路由配置文件,而不是手写。

所以我们需要增加一个routesConfigMake 的脚本: rcMake.js:

const fs = require('fs');
const path = require('path');

const rcMake = () => {
    // 定义 controllers 目录
    const controllersDir = path.join(__dirname, 'controllers');

    // 获取 controllers 目录下的所有文件(同步方法)
    let files;
    try {
        files = fs.readdirSync(controllersDir);
    } catch (err) {
        console.error('无法读取 controllers 目录:', err);
        return;
    }

    // 用于保存所有路由信息的数组
    const routes = [];

    // 逐一处理每个文件
    files.forEach(file => {
        const filePath = path.join(controllersDir, file);
        const fileName = path.basename(file, '.js'); // 去掉文件扩展名

        // 只处理 .js 文件
        if (path.extname(file) === '.js') {
            let controller;
            try {
                controller = require(filePath);
            } catch (err) {
                console.error(`无法加载文件 ${file}:`, err);
                return;
            }

            // 遍历 controller 中的 HTTP 方法(get, post 等)
            Object.keys(controller).forEach(method => {
                const methodRoutes = controller[method];

                // 遍历每个方法的路由
                Object.keys(methodRoutes).forEach(action => {
                    const route = methodRoutes[action];
                    routes.push({
                        method: method,
                        path: route.path,
                        controller: fileName,
                        action: action
                    });
                });
            });
        }
    });

    // 生成 routes.js 文件的内容
    const routesContent = `// routes.js\nmodule.exports = ${JSON.stringify(routes, null, 2)};\n`;

    // 将生成的内容写入 routes.js 文件(同步方法)
    try {
        fs.writeFileSync(path.join(__dirname, '/routers/routesConfig.js'), routesContent);
        console.log('routesConfig.js 文件已生成');
    } catch (err) {
        console.error('写入 routesConfig.js 文件失败:', err);
    }
};

module.exports = rcMake;

这个脚本放在和app.js 中 ,在app.js的最开始调用,自动将我们控制器内的配置写在这个配置文件中,执行后生成routesConfig.js文件,内容如下:

// routes.js
module.exports = [
  {
    "method": "get",
    "path": "/auth/login",
    "controller": "authController",
    "action": "login"
  },
  {
    "method": "post",
    "path": "/auth/login",
    "controller": "authController",
    "action": "login"
  },
  {
    "method": "get",
    "path": "/product",
    "controller": "productController",
    "action": "createProduct"
  },
  {
    "method": "post",
    "path": "product",
    "controller": "productController",
    "action": "createProduct"
  },
  {
    "method": "get",
    "path": "/user/:id",
    "controller": "userController",
    "action": "getUserById"
  },
  {
    "method": "post",
    "path": "/user/:id",
    "controller": "userController",
    "action": "getUserById"
  }
];

请注意,这时候你必须所有的控制器都按照我前面提到的方式来改写,这里包括了 get 和post 两类,其他自己可以加。,app.js 会自动调用这个配置的。

五、更新app.js

最后,app.js 需要加上这个脚本:

const express = require('express');
const app = express();

//加上脚本 自动生成路由配置文件
const rcMake = require('./rcMake.js')
rcMake()

const routesConfig = require('./routers/routesConfig');  // 导入路由配置文件


// 动态加载路由
routesConfig.forEach(route => {
    const controller = require(`./controllers/${route.controller}`);  // 动态加载控制器
    app[route.method](route.path, controller[route.method][route.action].fn);  // 将路由与控制器方法绑定

    console.log('for review route:', route.method, route.path, controller[route.method][route.action].fn)

});

// 启动服务
const port = 3000;
app.listen(port, () => {
    console.log(`Server is running on port ${port}`);
});

好了,这样,你的工作就只需要关注在写控制器上,而无需关注路由配置,因为路由配置都自动化了。这样多方便?

需要完整的项目文件,请给我留言。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2260722.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

详解下c语言下的多维数组和指针数组

在实际c语言编程中,三维及以上数组我们使用的很少,二维数组我们使用得较多。说到数组,又不得关联到指针,因为他们两者的联系太紧密了。今天我们就详细介绍下c语言下的多维数组(主要是介绍二维数组)和指针。 一、二维数组 1.1&am…

EXCEL的各种图形,统计图形

目录 0 EXCEL的各种图形,统计图形 1 统计图形 / 直方图 / 其实叫 频度图 hist最合适(用原始数据直接作图) 1.1 什么是频度图 1.2 如何创建频度图,一般是只选中1列数据(1个数组) 1.3 如何修改频度图的宽度 1.4 hist图的一个特…

npm内存溢出

项目过大运行项目内存溢出 报错代码 运行内存溢出 increase-memory-limit ‘“node --max-old-space-size8192”’ 不是内部或外部命令,也不是可运行的程序 FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of m…

快速部署一套K8s集群-v1.28

快速部署一套K8s集群-v1.28 1.前置知识点 1.1 生产环境可部署Kubernetes集群的两种方式 目前生产部署Kubernetes集群主要有两种方式: kubeadmKubeadm是一个K8s部署工具,提供kubeadm init和kubeadm join,用于快速部署Kubernetes集群。 二进制包从github下载发行版的二进…

Y3编辑器教程5:触发器进阶使用(镜头、UI、表格、函数库、排行榜、游戏不同步)

文章目录 一、游戏声音设计二、 游戏镜头设计2.1 镜头的基本参数2.2 镜头时间轴动画 三、界面编辑3.1 界面编辑器设置3.2 添加按钮事件3.3 触发编写 四、 表格编辑器(实现对话UI)4.1 一维表和多维表4.2 数据验证、搜索、保存与撤销4.3 Excel导入导出4.4 …

vue3实现页签

功能点: 新增和删除页签拖拽页签 需要引入插件"vue-draggable-plus": "^0.6.0", 代码已注释右键弹框操作页签左右点击滚动页签和鼠标滑轮滚动页签 注意点 useStore涉及的部分是pina的缓存,需要改成自己的;userStore.tab…

ARCGIS国土超级工具集1.2更新说明

ARCGIS国土超级工具集V1.2版本,功能已增加至47 个。在V1.1的基础上修复了若干使用时发现的BUG,新增了"矢量分割工具"菜单,同时增加及更新了了若干功能,新工具使用说明如下: 一、勘测定界工具栏更新界址点成果…

element-ui实现table表格的嵌套(table表格嵌套)功能实现

最近在做电商类型的官网,希望实现的布局如下:有表头和表身,所以我首先想到的就是table表格组件。 表格组件中常见的就是:标题和内容一一对应: 像效果图中的效果,只用基础的表格布局是不行的,因…

图像分割数据集石头rock分割数据集labelme格式2602张3类别

数据集格式:labelme格式(不包含mask文件,仅仅包含jpg图片和对应的json文件) 图片数量(jpg文件个数):2602 标注数量(json文件个数):2602 标注类别数:3 标注类别名称:["claystone","silt","…

语音芯片赋能可穿戴设备:开启个性化音频新体验

在科技日新月异的今天,语音芯片与可穿戴设备的携手合作,正引领我们步入一个前所未有的个性化音频时代。这一创新融合,用户可以享受到更加个性化、沉浸式的音频体验。下面将详细介绍语音芯片与可穿戴设备合作的优点和具体应用。 1. 定制化音效…

数据挖掘之聚类分析

聚类分析(Clustering Analysis) 是数据挖掘中的一项重要技术,旨在根据对象间的相似性或差异性,将对象分为若干组(簇)。同一簇内的对象相似性较高,而不同簇间的对象差异性较大。聚类分析广泛应用…

【iOS】OC高级编程 iOS多线程与内存管理阅读笔记——自动引用计数(四)

目录 ARC规则 规则 对象型变量不能作为C语言结构体的成员 显式转换id和void* 属性 数组 ARC规则 规则 在ARC有效的情况下编译源代码必须遵守一定的规则: 主要解释一下最后两条 对象型变量不能作为C语言结构体的成员 要把对象型变量加入到结构体成员中时&a…

Java-25 深入浅出 Spring - 实现简易Ioc-01 Servlet介绍 基本代码编写

点一下关注吧!!!非常感谢!!持续更新!!! 大数据篇正在更新!https://blog.csdn.net/w776341482/category_12713819.html 目前已经更新到了: MyBatis&#xff…

微服务SpringCloud链路追踪之Micrometer+Zipkin

视频教程: https://www.bilibili.com/video/BV12LBFYjEvR 效果演示 当我们发送一个请求给 Gateway 的时候,由 Micrometer trace 进行链路追踪和数据收集,由 Zipkin 进行数据展示。可以清楚的看到微服务的调用过程,以及每个微服务…

【Java】Iterator迭代器相关API

Iterator 是 Java 集合框架中用于遍历集合(List、Set 等)的工具,它提供了访问集合中每个元素的统一接口,避免直接操作集合的实现细节。 Iterator的基本使用和方法 基本方法 hasNext():检查是否还有元素可供迭代。ne…

Android 系统应用重名install安装失败分析解决

Android 系统应用重名install安装失败分析解决 文章目录 Android 系统应用重名install安装失败分析解决一、前言1、Android Persistent apps 简单介绍 二、系统 persistent 应用直接安装需求分析解决1、系统应用安装报错返回的信息2、分析解决 三、其他1、persistent系统应用in…

java基础概念49-数据结构2

一、树 1-1、树的基本概念 1、树的节点 2、二叉树 3、树的高度 1-2、二叉查找树 普通二叉树没有规律,不方便查找,没什么作用。 1、基本概念 2、添加节点 此时,该方式添加形成的二叉查找树,根节点就是第一个节点。 3、查找节点 4…

数据仓库工具箱—读书笔记01(数据仓库、商业智能及维度建模初步)

数据仓库、商业智能及维度建模初步 记录一下读《数据仓库工具箱》时的思考,摘录一些书中关于维度建模比较重要的思想与大家分享🤣🤣🤣 博主在这里先把这本书"变薄"~有时间的小伙伴可以亲自再读一读,感受一下…

说说你对java lambda表达式的理解?

大家好,我是锋哥。今天分享关于【说说你对java lambda表达式的理解?】面试题。希望对大家有帮助; 说说你对java lambda表达式的理解? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Java Lambda 表达式是 Java 8 引入的一项重要特性&#…

ambari-server页面错位问题解决

背景: 项目新安装的ambari集群页面错位如下 解决办法(临时): 修改ambari-server的前端文件:/usr/lib/ambari-server/web/javascripts/app.js 原代码: initNavigationBar: function () {if (App.get(r…