基于nodejs+express+knex+mysql搭建一个后台服务

前言

首先,我们对nodejs、express、knex、mysql进行说明:

  1. Node.js:Node.js 是一个开源的、跨平台的 JavaScript 运行时环境。
  2. express:Node.js web application framework 基于nodejs的web应用框架
  3. Knex:SQL Query Builder for Javascript 适用于 Javascript 的 SQL 查询生成器
  4. MySQL:关系型数据库

可见,者就是一个使用JavaScript搭建的后台系统。实现总共包括以下几步:

  1. 安装依赖
  2. 编写启动文件
  3. 封装kenx类进行数据库操作
  4. 编写接口

按照以上步骤,我们对每一个过程进行介绍:

1. 安装依赖

基于该技术栈搭建一个基础的后台系统,需要安装的依赖有:

npm i ts-node --save
npm i ts-loader --save
npm i typescript --save
npm i express --save
npmp i knex --save
npm i mysql2 --save

安装这些依赖之前,首先要确定正确下载安装nodejs,并配置环境变量。查看是否具有Nodejs的命令为:node --version

  1. 安装typescript ts-nodets-loader是因为本实例中我们使用的是typescript编写的。您也可以不使用typescript,就不需要安装上述三个依赖;
  2. mysql2是用来链接数据库的依赖包。据本次项目的经验,使用knex时,如果使用mysql客户端,在部署到服务器的容器中会出现客户端版本不兼容的报错,所以我们选择了使用 mysql2。您也可以根据自己的需要和安装部署的基本条件,选择使用mysql客户端。

2.编写服务启动文件

启动文件是用于服务启动的入口,包括监听服务启动端口、注入路由(接口文件)及后端服务的其它设置。我们假设启动文件的名称为app.ts,则ts的启动命令就为ts-node app.ts。启动文件的内容如下:

import express from 'express'
import bodyParser from 'body-parser'import UserRouter from './router/user'
import RoleRouter from './router/role'const app = express()const BASE_ROUTER = '/router-base-url'app.use(bodyParser.json()).use(bodyParser.urlencoded({ extended: false }))app.use(`${BASE_ROUTER}`, UserRouter)
app.use(`${BASE_ROUTER}`, RoleRouter)app.listen('8080', () => {console.log('server started at 8080')
})

在启动文件中:

  1. 首先引入express,并初始化和监听服务启动端口,本示例中使用的是8080端口
  2. body-parser是express的一个中间件,用于对post请求的请求体进行解析
  3. 我们引入了两个接口文件./router/user./router/role,并注入到框架中,使用的是app.use()方法

这样一来,只需要执行ts-node app.ts命令,我们就可以启动该服务了。下面我们开始编写接口文件。

3. 数据库连接

在编写接口文件之前,首先需要确定数据库的连接,使用knext框架。

import config from "../config/db";
import knex from "knex";const kenxConfig = {client: 'mysql2',connection: {host: config.host,port: config.port,user: config.user,password: config.password,database: config.database,timezone: '+08:00'},log: {error(message: any) {console.log('[knex] error', message)},warn(msg:any) {const ignore = '.returning() is not supported by mysql and will not have any effect.'if (msg.indexOf(ignore) === -1) {console.info('[knex] warn', msg)}},debug(msg:any) {console.log('[knex] debug', msg)},deprecate(method: string, alternative: string) {console.log(method, alternative)}}
}export default knex(kenxConfig)

引入knex包,在连接时需要指定mysql客户端、配置连接信息(包括数据库域名、端口号、用户名、密码、时区等),还可以设置数据库连接的日志信息,本次示例中我们添加了errorwarndebugdeprecate。其中:

  • warn中,我们配置了.returning() is not supported by mysql and will not have any effect.日志不打印,这是kenx的日志。

最后将knex(kenxConfig)导出,用于在数据库查询方法中调用。

4. 数据库查询

knex内置了很多基础方法,如数据库.select().insert().del()等,可以直接使用。也可以直接编写sql传入,对于复杂的数据库语言,就需要我们编写sql语言或将多个knex方法结合使用。knex中直接使用sql语言可以使用.raw()方法。

下列是我们所封装的knex基础类,其中只包括了.select().insert().update(),其它方法可以参考Knex官网进行自行封装,我们将该文件命名为base.ts

import knex from "./knex";class Base {table: stringconstructor(props: any) {this.table = props}// 查找all() {return knex(this.table).select()}// 更新update(update: Record<string,any>, params: Record<string,any>) {return knex(this.table).where(update).update(params)}insert(params: Record<string, any>) {return knex(this.table).insert(params)}
}
export default Base

这是一个基于ES6的类,调用该类可以传入一个参数,并将其赋值给table,所以应该传入数据库表名。

  1. knex(this.table).select()this.table中查询全部数据
  2. knex(this.table).where(update).update(params)用于对数据库update。update是更新条件的参数,params是跟新参数,均为对象格式。
  3. knex(this.table).insert(params)向表中插入数据,params是插入参数,也为对象格式。

上述是封装的基础类,还可以封装一些复杂的方法。如下列代码封装了一个联表查询的方法queryList,这是一个.ts文件,可以看到,该查询中分别关联了三个表table1table2table3,并且进行的分页查询。

将该文件命名为base-query.ts

import Base from "./base";
import knex from "./knex";class QueryModule extends Base {constructor(props = '') {super(props)}async queryList(page: number, pageSize: number, params: Record<string, any>) {return new Promise(async(resolve, reject) => {const start = (page - 1) * pageSizeconst { id } = paramsconst sql_params: Object | Boolean  = !!params ? { 'table1.id': id } : 1==1let list = await knex('table1').where(sql_params).where('table1.flag', '=', 1).where('table1.statue', '=', 1).limit(pageSize).offset(start).leftJoin('table3', function() {this.on(`table1.id`, '=', 'table3.id ')}).leftJoin('table2', function() {this.on('table3.group_id', '=', 'table2.id')}).select('table1.*', 'table2.name as name2', 'table2.description as description2', 'table2.id as groupId').orderBy('table1.created_at', 'desc')resolve(list)})}
}const query = new QueryModule()
export default query

在上述方法中,我们还借助了promise,将查询到的结果通过resolve方法返回,便于在接口实现部分进行调用。

5. 编写接口

下面的代码我们封装了一个query-list的post请求接口。首先引入上一步封装好的类,并调用该方法即可。

import express from "express";
import queryModule from './base-query'const router = express.Router()router.post('/query-list', async(req:any, res:any, next: any) => {const { page, pageSize, param } = req?.bodylet data = await queryModule.queryList(page * 1, pageSize * 1, param)const list = JSON.parse(JSON.stringify(data))const r = new R()res.send(r.ok(list))
})

说明:

  • R类是一个封装的接口响应格式的类,可以自行封装。从代码中可以看出,该类的.ok方法是用于响应正确的结果,还有.err方法对失败结果进行响应。
  • 这个文件就是接口请求的controller类,你也可以将具体实现封装为单独的module进行调用,上述代码是我们简化过的一个方法。

总结

在这个过程中,你还需要:

  1. 使用ts的一个好处就是,可以明确的知道每个方法的参数格式、返回格式。如在封装kenx类时,每一个.select().insert().del()的参数都可以很明确的知道是对象格式Record<string,any>。毕竟是使用经封装过的框架,对于不熟悉的人或时间太久再次阅读代码,这种格式可以很方便的提示开发者,该方法中的参数是什么格式。
  2. 该项目的启动需要正确配置typescript,才能够使用。否则无法使用importexport等命令。
  3. knex封装了很多个基础的方法,可以查看它的官方文档(地址:knex操作指南)。我们还使用了它的很多高级用法,在本示例中没有体现,如使用事务knex.transaction等。
  4. knex是一个方便的数据库操作库,可以多多使用它的一些方法

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

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

相关文章

ES Kibana 安装

ES & Kibana 本文基于Docker安装部署使用 Kibana的版本和ElasticSearch的版本&#xff0c;以及IK分词器的版本一一对应 Kibana 安装 安装Kibana # 创建网络 [rootiZ2zeg7mctvft5renx1qvbZ ~]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway …

UE5 - ArchvizExplorer - 数字孪生城市模板 -学习笔记

1、学习资料 https://www.unrealengine.com/marketplace/zh-CN/product/archviz-explorer https://karldetroit.com/archviz-explorer-documentation/ 官网下载的是一个简单版&#xff0c;需要下载扩展&#xff0c;并拷贝到项目录下&#xff0c;才有完整版 https://drive.googl…

力扣104. 二叉树的最大深度(java,DFS,BFS解法)

Problem: 104. 二叉树的最大深度 文章目录 思路和解法复杂度Code 思路和解法 DFS 递归处理&#xff0c;退出条件为节点为空&#xff0c;归的过程每次取出当前节点左右子树的最大深度加一 BFS 经典的借助一个队列实现的BFS&#xff0c;用一个变量记录当前的最大层数&#xff0c…

Python集成学习和随机森林算法

大家好&#xff0c;机器学习模型已经成为多个行业决策过程中的重要组成部分&#xff0c;然而在处理嘈杂或多样化的数据集时&#xff0c;它们往往会遇到困难&#xff0c;这就是集成学习&#xff08;Ensemble Learning&#xff09;发挥作用的地方。 本文将揭示集成学习的奥秘&am…

指针详解【C语言】

1第一步&#xff1a; 学生 *pstu; 这里学生是类型*是解地址 pstu是地址容器语法里 学生 学生1&#xff1b;就会开辟内存。 这里【学生1】和 【*pstu】等效那这里【pstu】是带类型的指针容器*pstu是解地址&#xff0c;还原出类型对象。这里【*】只是解地址的操作符【pstu】…

组合式API_模板引用

虽然 Vue 的声明性渲染模型为你抽象了大部分对 DOM 的直接操作&#xff0c;但在某些情况下&#xff0c;我们仍然需要直接访问底层 DOM 元素。要实现这一点&#xff0c;我们可以使用特殊的 ref attribute&#xff0c;组合式API的实现更为简洁 选项式API_模板引用 <template…

交易者最看重什么?anzo Capital这点最重要!

交易者最看重什么&#xff1f;有人会说技术&#xff0c;有人会说交易策略&#xff0c;有人会说盈利&#xff0c;但anzo Capital认为Vishal 最看重的应该是眼睛吧&#xff01; 29岁的Vishal Agraval在9年前因某种原因失去了视力&#xff0c;然而&#xff0c;他的失明并未能阻…

python文件读写练习题--随机出10套试卷

要求就是&#xff1a;10套试卷题目顺序不同&#xff0c;答案顺序不同 import random import os city {河北省:石家庄市,山西省:太原市,辽宁省:沈阳市,吉林省:长春市,黑龙江省:哈尔滨市,江苏省:南京市,浙江省:杭州市,安徽省:合肥市,福建省:福州市,江西省:南昌市}#在当前路径下…

【C语言从入门到放弃 7】内存管理和命令行参数详解

在C语言中&#xff0c;内存管理和命令行参数处理是非常重要的技术&#xff0c;它们直接关系到程序的性能和灵活性。本文将深入探讨C语言中的内存管理和命令行参数处理&#xff0c;并提供相关示例代码。 内存管理 1.内存分配与释放 在C语言中&#xff0c;我们可以使用malloc函…

Zookeeper Java 开发,自定义分布式锁示例

文章目录 一、概述二、导入依赖包三、创建锁的过程3.1 通过 create 创建节点信息3.2 AsyncCallback.StringCallback 回调函数3.3 AsyncCallback.Children2Callback 的回调函数3.4 Watcher 的回调函数 四、完整示例4.1 完整分布式锁代码4.2 测试类 如果您还没有安装Zookeeper请看…

切换阿里云ES方式及故障应急处理方案

一、阿里云es服务相关问题及答解 1.1 ES7.10扩容节点时间 增加节点数量需要节点拉起和数据Rebalance两步,拉起时间7.16及以上的新版本大概10分钟以内,7.16以前大概一小时,数据迁移的时间就看数据量了,一般整体在半小时以内 (需进行相关测试验证) 1.2 ES7.10扩容数据节点…

在 Node.js 中发出 HTTP 请求的 5 种方法

在 Node.js 中发出 HTTP 请求的 5 种方法 学习如何在 Node.js 中发出 HTTP 请求可能会让人感到不知所措&#xff0c;因为有数十个可用的库&#xff0c;每个解决方案都声称比上一个更高效。一些库提供跨平台支持&#xff0c;而另一些库则关注捆绑包大小或开发人员体验。 在这篇…

云轴科技ZStack信创云平台支撑长江航务管理局35套航运管理系统

信创是数字中国建设的重要组成部分&#xff0c;也是数字经济发展的关键推动力量。作为云基础软件企业&#xff0c;云轴科技ZStack产品矩阵全面覆盖数据中心云基础设施&#xff0c;ZStack信创云首批通过可信云《一云多芯IaaS平台能力要求》先进级&#xff0c;是其中唯一兼容四种…

二百零三、Flume——Flume实时采集数据频率为1s的高频率Kafka数据直接写入ODS层表的HDFS文件路径下

一、目的 在离线数仓中&#xff0c;需要用Flume去采集Kafka中的数据&#xff0c;然后写入HDFS中。 由于每种数据类型的频率、数据大小、数据规模不同&#xff0c;因此每种数据的采集需要不同的Flume配置文件。玩了几天Flume&#xff0c;感觉Flume的使用难点就是配置文件 二、…

AOF是什么?

目录 一、AOF是什么&#xff1f; 二、使用AOF 三、命令写入 四、重写机制 4.1 触发AOF 4.2 AOF执行流程 一、AOF是什么&#xff1f; AOF是Append Only File&#xff0c;是Redis中实现持久化的一种方式。以独⽴⽇志的⽅式记录每次命令&#xff0c;重启时再重新执⾏ AOF ⽂件中的…

小程序富文本图片大小问题

文章目录 概要uniapp小程序情况解决方法及完整示例 概要 在小程序使用富文本或者在nuiapp&#xff08;小程序的&#xff09;使用富文本都会转为 <rich-text nodes"<p class"p class">内容</p>”></rich-text>如果是这种情况的话在css…

自动驾驶-BEV感知综述

BEV感知综述 随着自动驾驶传感器配置多模态化、多源化&#xff0c;将多源信息在unified View下表达变得更加关键。BEV视角下构建的local map对于多源信息融合及理解更加直观简洁&#xff0c;同时对于后续规划控制模块任务的开展也更为方便。BEV感知的核心问题是&#xff1a; …

飞书开发学习笔记(八)-开发飞书小程序Demo

飞书开发学习笔记(八)-开发飞书小程序Demo 一.小程序开发概述 1.1 小程序开发概述 飞书开发文档中查看&#xff1a;小程序开发概述 飞书小程序是指可以运行在飞书客户端中的小程序&#xff0c;小程序的一套代码可以适配 Android、iOS、PC 多平台&#xff0c;且用户体验与飞书…

VUE基础的一些实战总结

目录 创建一个 Vue 应用 步骤 1&#xff1a;安装 Node.js 和 npm 步骤 2&#xff1a;安装 Vue CLI 步骤 3&#xff1a;创建 Vue 项目 步骤 4&#xff1a;启动开发服务器 步骤 5&#xff1a;访问应用程序 步骤 6&#xff1a;编辑 Vue 应用 步骤 7&#xff1a;构建和部署…

python3.8 安装 ssl 模块 和 _ctypes 模块

这文章目录 前情提要安装 openssl-1.1.1重新编译安装 python3.8-rpath 编译选项介绍python3.8 跟 python3.10 的区别那要怎么解决这个问题呢&#xff0c;我想到有四种解决方案&#xff1a; 前情提要 我在之前给 python3.10 安装 ssl 模块后以为该步骤 “对于 python3.6、pytho…