版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Node.js数据库编程与ORM实践CONTENTS目录01MySQL操作02数据库操作的异步控制03ORM框架04数据库事务管理05数据库连接池管理与性能优化1.MySQL操作使用mysql2库连接MySQL数据库,需要创建连接对象并配置参数。核心方法:createConnection()。使用createConnection()配置连接,完成后需用end()关闭连接。配置项说明:{host:'localhost', //数据库服务器地址(默认位于本地:localhost)user:'root', //数据库用户名password:'123456', //用户密码database:'mydb', //要连接的数据库名(可选)port:3306, //端口号(默认3306)waitForConnections:true //是否等待连接(默认为true)}连接MySQL
1.MySQL操作【操作要求】在文件夹Unit06中创建文件conn06.js,在该文件中创建一个公共的数据库连接对象connection,在其他程序中可以直接导入并使用该数据库连接对象。【实现过程】【训练实例6-1】创建数据库连接对象connection1.MySQL操作核心方法:query(sql,[values],callback)。通过query()执行SQL,用?作为参数占位符,结果通过回调获取。增删改查操作可能的返回值如下。SELECT返回结果数组。INSERT返回insertId,即新插入的ID。UPDATE/DELETE返回affectedRows,即受影响行数。增删改查操作1.MySQL操作1.插入数据(Create)增删改查操作1.MySQL操作2.查询数据(Read)增删改查操作1.MySQL操作3.更新数据(Update)增删改查操作1.MySQL操作4.删除数据(Delete)增删改查操作1.MySQL操作1.什么是SQL注入SQL注入是指恶意用户通过构造特殊输入,篡改SQL语句的逻辑。例如,对于下面的SQL语句:SELECT*FROMusersWHEREusername='admin'--'ANDpassword='...'由于--是SQL的注释符,会注释掉后面的密码验证逻辑。安全写法(预处理)示例:connection.execute('SELECT*FROMusersWHEREid=?',[userId],//参数会被自动转义(err,rows)=>{if(err)throwerr;console.log('安全查询结果:',rows);});mysql2通过?占位符实现预处理,防止SQL注入。预处理语句防止SQL注入1.MySQL操作预处理语句防止SQL注入1.MySQL操作2.如何防止SQL注入所有用户输入必须通过execute(sql,[values])进行预处理,禁止拼接SQL字符串,分离SQL指令与参数,数据库会自动对参数进行转义,防止恶意注入攻击,确保参数作为数据而非SQL代码进行处理。预处理语句防止SQL注入1.MySQL操作【操作要求】编写程序,向数据表products中插入商品数据,要求使用execute(sql,[values])进行预处理,分离SQL指令与参数,防止SQL注入。【实现过程】【训练实例6-2】使用execute()进行预处理与防止SQL注入2.数据库操作的异步控制数据库操作的异步控制是处理高并发和I/O密集型任务的关键。在Node.js中,异步操作通常通过回调、Promise或async/await实现,以避免阻塞事件循环。连接池(如generic-pool)优化资源复用,降低连接建立的延迟。错误处理需结合try/catch或.catch()捕获异常,防止未处理的拒绝(UnhandledRejection)。异步流控工具(如Promise.all)可并行执行查询,提升效率,但需注意数据库负载。整体上,异步控制平衡了性能与代码可维护性,是现代数据库编程的核心实践。数据库操作异步控制的两种方式如下。①Generator函数+co模块:ES7前的异步控制方案,现已被async/await取代。②Promise:将MySQL操作封装为Promise,支持async/await语法,优先使用mysql2/promise配合async/await。2.数据库操作的异步控制Generator函数+co模块是ES7前的异步控制方案,现已被async/await原生支持取代。现推荐使用async/await,不需要额外依赖。其核心组件如下。①Generator函数:function*()。②yield关键字:暂停执行。③co模块:自动执行生成器。Generator函数+co模块的核心组件的工作流程如图6-1所示。Generator与co模块2.数据库操作的异步控制本节介绍Generator函数+co模块这个历史方案的主要原因有以下3条。①
有助于理解异步编程演进历程。②
维护旧代码库时可能遇到此方案。③
有助于理解async/await的底层思想。1.Generator函数Generator函数是ES6引入的特殊函数,使用function*声明,通过yield暂停执行,使用next()恢复执行。Generator与co模块2.数据库操作的异步控制2.co模块co是由TJHolowaychuk开发的库,它可自动执行Generator函数并处理异步。co模块接收Generator函数,自动调用next(),遇到yield语句后跟随的Promise时,等待Promise完成后继续执行,异常通过catch()捕获。Generator与co模块2.数据库操作的异步控制原生mysql2使用回调函数处理异步操作,多层嵌套会导致回调地狱。Promise提供更优雅的异步控制方式,可以避免回调地狱,实现链式调用。1.手动实现Promise化(兼容旧版)将MySQL查询封装为返回Promise的函数。使用Promise包装MySQL操作2.数据库操作的异步控制2.使用mysql2/promise模块mysql2原生支持Promise,无须手动封装。使用“connection.execute(sql,values)”执行预处理语句,返回[rows,fields]。使用Promise包装MySQL操作2.数据库操作的异步控制【操作要求】编写程序,使用mysql2/promise模块从users数据表中获取数据,并添加必要的错误处理代码和结果处理代码。【实现过程】在文件夹Unit06中创建JavaScript文件case0603.js,在该文件中输入代码。从本书配套的教学资源中打开“训练实例6-3”对应的程序文件case0603.js,浏览相应代码。运行文件case0603.js的代码,输出结果如下:【训练实例6-3】使用mysql2/promise模块从数据表中获取数据3.ORM框架模型定义与数据类型映射模型是对数据表的抽象,通过“类”定义字段和数据类型映射。ORM通过将数据表映射为程序中的对象,实现数据的持久化操作。下面以Sequelize为例,介绍模型定义与数据类型映射。Sequelize通过简洁的API和强大的功能,大大提高了Node.js应用与数据库交互的开发效率,是Node.js后端开发的首选ORM工具之一。3.ORM框架模型定义与数据类型映射1.模型定义语法格式模型定义语法格式如下:constModel=sequelize.define('modelName',{attribute:{type:DataTypes.STRING,allowNull:false,unique:true,defaultValue:'defaultvalue',validate:{isEmail:true}}});3.ORM框架模型定义与数据类型映射配置项说明如下。①type:字段类型。②allowNull:字段是否可为NULL,默认值为true。③unique:字段是否唯一。④defaultValue:默认值。⑤validate:字段验证规则,如isEmail、isNumeric等。2.Sequelize与SQL常用的数据类型映射Sequelize与SQL常用的数据类型映射如表6-1所示。3.ORM框架模型定义与数据类型映射3.Sequelize的关键方法Sequelize的关键方法如下。Model.sync({force:true}):强制同步表结构,即删除现有数据表后重建。Model.sync({alter:true}):智能修改表结构(生产环境慎用)。示例代码:constUser=sequelize.define('user',{username:DataTypes.STRING,birthday:DataTypes.DATE,isAdmin:{type:DataTypes.BOOLEAN,defaultValue:false}});3.ORM框架【训练实例6-4】使用Sequelize工具对数据表进行插入与查询操作【操作要求】编写程序,使用Sequelize工具将数据表映射为JavaScript对象,使用面向对象的方式对数据表进行插入与查询操作,主要功能包括数据库连接管理(创建与MySQL数据库的连接)、数据模型定义(定义User模型对应my_users表)、表结构同步、数据操作、资源与错误管理。【实现过程】(1)创建JavaScript文件与编写程序。在文件夹Unit06中创建JavaScript文件case0604.js,在该文件中输入代码。(2)关键参数说明。findAll()参数如下:{attributes:['name'],//指定返回字段raw:true//简化返回结果为纯JS对象}3.ORM框架【训练实例6-4】使用Sequelize工具对数据表进行插入与查询操作findAll()参数的字段选项如表6-2所示。实现条件过滤语法格式如下:constactiveUsers=awaitUser.findAll({attributes:['name'],where:{status:'active',age:{[Sequelize.Op.gt]:18}}});3.ORM框架【训练实例6-4】使用Sequelize工具对数据表进行插入与查询操作(3)运行程序与输出结果。在终端执行以下命令安装依赖:npminstallsequelizemysql2在终端执行以下命令运行程序代码:nodecase0604.js预期输出结果如下:
尝试连接MySQL数据库...
数据库连接成功
表"my_users"已创建/重置
已插入3条示例数据
所有用户名称:['张珊','李斯','王武']
数据库连接已关闭3.ORM框架关联关系Sequelize支持一对一(One-to-One)、一对多(One-to-Many)、多对多(Many-to-Many)3种关联关系。1.一对一关联关系示例代码://用户和档案的一对一关系Profile.belongsTo(User,{foreignKey:'userId'});//档案属于用户User.hasOne(Profile,{foreignKey:'userId'});//用户有一个档案//使用示例constuser=awaitUser.create({name:'Alice'});awaituser.createProfile({bio:'Developer'});//自动创建关联数据3.ORM框架关联关系2.一对多关联关系示例代码://用户和文章的一对多关系Post.belongsTo(User,{foreignKey:'authorId'});//文章属于用户User.hasMany(Post,{foreignKey:'authorId'});//用户有多篇文章//使用示例constuser=awaitUser.findByPk(1);constposts=awaituser.getPosts();//获取所有关联文章awaituser.createPost({title:'ORM指南'});//创建关联文章3.ORM框架关联关系3.多对多关联关系示例代码://文章和标签的多对多关系Post.belongsToMany(Tag,{through:'PostTags'});//通过中间表Tag.belongsToMany(Post,{through:'PostTags'});//使用示例constpost=awaitPost.create({title:'Node.js'});consttag=awaitTag.create({name:'Backend'});awaitpost.addTag(tag);//建立关联//查询带标签的文章constposts=awaitPost.findAll({include:{model:Tag,through:{attributes:[]}//隐藏中间表字段}});3.ORM框架Sequelize数据迁移与种子脚本通过数据迁移和种子脚本,可以实现数据库结构和数据变更的版本控制,确保开发、测试与生产环境的结构和数据保持一致,避免手动修改数据表结构。1.数据迁移数据迁移(Migrations)用于管理数据库结构变更,其作用类似版本控制。(1)创建迁移文件。在终端执行以下命令创建迁移文件:npxsequelize-climigration:generate--namecreate-users(2)迁移文件结构。(3)执行迁移。在终端执行以下命令,执行迁移。npxsequelize-clidb:migrate#执行所有待迁移npxsequelize-clidb:migrate:undo#回滚最后一次迁移3.ORM框架Sequelize数据迁移与种子脚本2.种子脚本种子脚本(Seeders)用于填充测试数据或初始数据。(1)创建种子脚本文件。在终端执行以下命令创建种子脚本文件:npxsequelize-cliseed:generate--namedemo-user(2)种子脚本文件结构。(3)执行种子脚本。在终端执行以下命令执行,种子脚本:npxsequelize-clidb:seed:all#执行所有种子脚本npxsequelize-clidb:seed:undo:all#回滚所有种子脚本4.数据库事务管理数据库事务管理概述
1.事务定义数据库事务是由一组数据库操作组成的逻辑单元,这组数据库操作要么全部成功执行,要么全部失败回滚,确保数据库从一个一致状态转变为另一个一致状态。2.事务四大特性(1)原子性(Atomicity)。事务中的操作要么全部完成,要么都不完成,不可分割。(2)一致性(Consistency)。事务执行前后,数据库的完整性约束不会被破坏,事务前后数据库状态必须一致。(3)隔离性(Isolation)。多个事务并发执行时,相互之间互不干扰,每个事务仿佛在独立操作数据库。(4)持久性(Durability)。事务一旦提交,其对数据库的修改结果会永久保存,即使系统发生故障也不会丢失。如订单提交后,相关数据会持久化存储,不会因服务器重启而消失。4.数据库事务管理数据库事务管理概述
3.事务操作命令(1)开始事务:STARTTRANSACTION或BEGIN,用于标记一个事务的开始。(2)提交事务:COMMIT,将事务中的所有操作永久保存到数据库。(3)回滚事务:ROLLBACK,撤销事务中的所有未提交的操作,使数据库回到事务开始前的状态。4.数据库事务管理MySQL事务管理与隔离级别1.事务管理指令(1)BEGIN/STARTTRANSACTION。语法格式:BEGIN[WORK];//或STARTTRANSACTION[WORK];其作用是显式启动一个事务,WORK为可选关键字,可省略。(2)COMMIT。语法格式:COMMIT[WORK];//或COMMITANDCHAIN;COMMIT[WORK]用于提交当前事务,使事务中的修改生效。COMMITANDCHAIN用于提交当前事务,并启动一个与当前事务具有相同隔离级别的新事务。(3)ROLLBACK。语法格式:ROLLBACK[WORK];//或ROLLBACKANDCHAIN;ROLLBACK[WORK]用于回滚当前事务,撤销所有未提交的修改。ROLLBACKANDCHAIN用于回滚当前事务并启动一个新事务,新事务的隔离级别与当前事务的相同。4.数据库事务管理MySQL事务管理与隔离级别2.隔离级别MySQL支持4种隔离级别,通过SETTRANSACTIONISOLATIONLEVEL进行设置。MySQL中设置当前会话隔离级别的标准语法格式如下:SET[SESSION]TRANSACTIONISOLATIONLEVEL<READCOMMITTED>;其中,SESSION(可选项)用于显式声明作用域为当前会话(可省略);<READCOMMITTED>用于指定隔离级别,支持READUNCOMMITTED、READCOMMITTED、REPEATABLEREAD(MySQL默认级别)和SERIALIZABLE4种值。4种隔离级别(由低到高,性能递减)的比较如表6-3所示。4.数据库事务管理MySQL事务管理与隔离级别4种隔离级别说明如下。(1)读未提交(READUNCOMMITTED)。该级别允许事务读取未提交的数据,但可能读到“脏数据”。设置READUNCOMMITTED隔离级别的语法格式如下:SETTRANSACTIONISOLATIONLEVELREADUNCOMMITTED;(2)读已提交(READCOMMITTED)。该级别只能读取已提交的数据,不存在脏读问题。这是大多数数据库的默认级别。问题:同一事务中两次查询结果可能不同(不可重复读)。设置READCOMMITTED隔离级别的语法格式如下:SETTRANSACTIONISOLATIONLEVELREADCOMMITTED;(3)可重复读(REPEATABLEREAD)。该级别确保同一事务内多次查询结果一致,解决不可重复读问题,但可能出现“幻读”(新增数据无法屏蔽)。这是MySQL的默认级别。4.数据库事务管理MySQL事务管理与隔离级别(4)串行化(SERIALIZABLE)。这是最高级别,事务排队执行(加锁),解决所有并发问题(脏读、不可重复读、幻读),但性能最差。设置SERIALIZABLE隔离级别的语法格式如下:SETTRANSACTIONISOLATIONLEVELSERIALIZABLE;查看当前会话隔离级别的语句如下:SELECT@@transaction_isolation;--MySQL8.0+或SELECT@@tx_isolation;--MySQL5.x查看全局隔离级别的语句如下:SELECT@@global.transaction_isolation;4.数据库事务管理MySQL事务管理与隔离级别(4)串行化(SERIALIZABLE)。这是最高级别,事务排队执行(加锁),解决所有并发问题(脏读、不可重复读、幻读),但性能最差。设置SERIALIZABLE隔离级别的语法格式如下:SETTRANSACTIONISOLATIONLEVELSERIALIZABLE;查看当前会话隔离级别的语句如下:SELECT@@transaction_isolation;--MySQL8.0+或SELECT@@tx_isolation;--MySQL5.x查看全局隔离级别的语句如下:SELECT@@global.transaction_isolation;4.数据库事务管理MySQL事务管理与隔离级别事务管理确保数据操作安全,通过BEGIN/COMMIT/ROLLBACK控制事务原子性,确保数据一致性。根据业务需求选择隔离级别:①
高并发场景(如电商库存)使用READCOMMITTED;②
高风险系统(如银行系统)建议使用REPEATABLEREAD或SERIALIZABLE。默认级别REPEATABLEREAD在MySQL中通过多版本并发控制(Multi-VersionConcurrencyControl,MVCC)避免大部分幻读。5.数据库连接池管理与性能优化连接池参数调优
在数据库连接池的管理中,连接池参数的调优至关重要,尤其是最大连接数和最小空闲连接数这两个参数,它们直接影响着数据库连接池的性能和资源利用效率。1.最大连接数最大连接数(maxPoolSize)是指连接池中能同时存在的最大连接数量,用于限制同时使用的最大连接数,避免数据库过载。该参数若设置得过小,当并发请求较多时,后续请求可能会因无空闲连接而阻塞,导致响应时间变长,甚至出现请求超时的情况;若设置得过大,会占用过多的系统资源,可能导致数据库服务器负载过高,影响整体性能。以常见的Java数据库连接池HikariCP为例,其设置最大连接数的方法如下:HikariConfigconfig=newHikariConfig();config.setMaximumPoolSize(50);//设置最大连接数为50DataSourcedataSource=HikariCPDataSource(config);参数说明:setMaximumPoolSize(intmaximumPoolSize)用于设置最大连接数,参数maximumPoolSize为期望的最大连接数量,通常根据系统的并发量、数据库服务器的性能等因素来确定。例如,对于一个中等并发量的Web应用,可先将最大连接数设置为50,然后通过压测来调整优化。5.数据库连接池管理与性能优化连接池参数调优
2.最小空闲连接数最小空闲连接数是指连接池中保持的最小空闲连接数量。保持一定数量的空闲连接可以减少创建连接的开销,提高响应速度。该参数若设置得过小,可能会在高并发时频繁创建连接,增加连接建立的时间开销;若设置得过大,会导致空闲连接过多,占用过多的系统资源。同样以HikariCP为例,设置最小空闲连接数的方法如下:HikariConfigconfig=newHikariConfig();config.setMinimumIdle(10);//设置最小空闲连接数为10DataSourcedataSource=HikariCPDataSource(config);参数说明:setMinimumIdle(intminimumIdle)用于设置最小空闲连接数,参数minimumIdle为期望保持的最小空闲连接数量。在实际应用中,可根据系统的平均负载来设置,比如对于一个长时间有稳定请求的系统,设置10个左右的最小空闲连接数较为合适。5.数据库连接池管理与性能优化连接泄漏检测与处理连接泄漏是指应用程序在使用数据库连接后,没有正确释放连接,导致连接池中的连接被长期占用,无法被其他请求使用,最终可能导致连接池空闲连接不足,系统无法正常访问数据库。以下为未关闭连接的示例代码。try(Connectionconn=dataSource.getConnection()){Statementstmt=conn.createStatement();ResultSetrs=stmt.executeQuery("SELECT*FROMorders");//执行后未关闭rs/stmt//缺少conn.close()}//仅自动关闭Connection,但rs/stmt泄漏5.数据库连接池管理与性能优化连接泄漏检测与处理1.连接泄漏检测不同的连接池提供了不同的检测方法。以HikariCP为例,可以通过其提供的监控指标来检测连接泄漏。HikariDataSourcedataSource=(HikariDataSource)dataSource;intactiveConnections=dataSource.getActiveConnections();//获取活跃连接数2.连接泄漏处理一旦检测到连接泄漏,首先要检查代码中获取连接和释放连接的部分。确保在使用完连接后,通过connection.close()释放连接,或者使用try-with-resources语句来自动关闭连接,避免因异常导致连接未释放。//正确释放连接的示例(使用try-with-resources语法)try(Connectionconnection=dataSource.getConnection();PreparedStatementstatement=connection.prepareStatement(sql)){//执行数据库操作}catch(SQLExceptione){//处理异常}编写程序,使用mysql2库连接MySQL数据库,实现完整的博客文章增删改查操作。任务6-1使用mysql2库连接MySQL数据库实现增删改查操作任务描述任务实施1.操作准备(1)安装mysql2库。在终端执行以下命令安装mysql2库:npminstallmysql2(2)创建数据库数据表。任务6-1使用mysql2库连接MySQL数据库实现增删改查操作任务实施2.创建JavaScript文件与编写程序在文件夹Unit06中创建JavaScript文件task0601.js,在该文件中编写代码。从本书配套的教学资源中打开“实战任务6-1”对应的程序文件task0601.js,浏览相应代码。3.运行程序与查看结果在终端执行以下命令:nodetask0601.js输出结果如下:CreatedArticle:{id:1,title:'我的第一篇博客文章',content:'欢迎浏览博客文章!这是我的第一篇博客文章。',author:'安静',created_at:2025-06-01T09:56:12.000Z}数据库连接池已关闭编写程序,使用mysql2库连接MySQL数据库,通过数据库事务处理分别实现转出与转入指定金额。任务6-2通过数据库事务处理实现转出与转入指定金额任务描述任务实施1.操作准备(1)创建数据表。执行以下语句创建accounts数据表:任务6-2通过数据库事务处理实现转出与转入指定金额任务实施(2)向数据表accounts中插入账户数据。执行以下语句向数据表accounts中插入账户数据:INSERTINTO'accounts'('user_id','balance','currency')VALUES(1,15000.00,'CNY'),(2,8000.50,'CNY'),(3,25000.75,'CNY'),(4,5000.00,'CNY'),(5,1200.00,'CNY'),(6,300.00,'CNY');任务6-2通过数据库事务处理实现转出与转入指定金额任务实施2.创建JavaScript文件与编写程序3.运行程序与查看结果编写程序,使用Sequelize操作SQLite内存数据库,并实现事务(Transaction)操作。任务6-3使用Sequelize操作SQLite内存数据库实现事务操作任务描述任务实施1.安装Sequelize工具和SQLite3库在终端执行以下命令安装Sequelize工具和SQLite3库:npminstallsequelizesqlite32.创建JavaScript文件与编写程序在文件夹Unit06中创建JavaScript文件task0603.js,在该文件中编写代码。3.运行程序与查看结果在终端执行以下命令:nodetask0603.js输出结果如下:数据库连接成功事务已提交转账结果:{accountA:200,accountB:300}基于Express的Web应用编程与工程化开发CONTENTS目录01项目初始化02基于Express的路由系统03基于Express的中间件生态04模板引擎与布局管理05会话管理与认证06Express集成07安全与性能优化1.项目初始化使用Express生成器可以快速搭建Express应用骨架。1.使用Express生成器创建项目的主要步骤使用Express生成器创建项目的主要步骤如下。(1)全局安装Express生成器。在终端执行以下命令全局安装Express生成器:npminstall-gexpress-generator其语法格式为npminstall-g<包名>。其中-g表示全局安装,可在任意文件夹使用该命令。(2)创建项目[使用EJS(EmbeddedJavaScript)模板引擎示例]。在终端执行以下命令创建项目:express--view=ejsmy-project或者express-emy-project使用Express生成器创建项目1.项目初始化参数说明:--ejs/-e:指定使用EJS模板引擎(可选项),也可通过--view=hbs指定Handlebars等。其他常用参数如下。--no-view:不生成视图层(适用于API项目)。--port/-p:指定默认端口号,如-p3001。(3)安装依赖。在终端执行以下命令安装依赖:cdmy-projectnpminstall#安装package.json中的依赖#更新mkdirpnpminstallmkdirp@latest(4)启动项目。在终端执行以下命令启动项目:npmstart#启动项目,默认监听3000端口使用Express生成器创建项目1.项目初始化2.生成的项目结构生成的项目结构如下。my-project/├──bin/ #启动脚本文件夹│
└──www #主启动文件(设置端口)├──public/ #静态资源文件夹(CSS、JS、图片等)├──routes/ #路由文件夹│
├──index.js #根路由(首页路由)│
└──users.js #用户相关路由├──views/ #视图模板文件夹(若使用模板引擎)│
├──index.ejs #首页模板│
└──error.ejs #错误信息页模板├──package.json #项目依赖和脚本配置└──app.js #应用入口文件,配置中间件和路由1.项目初始化【验证示例7-1】在文件夹Unit07中执行以下命令创建Web应用项目demo0701。express--view=ejsdemo0701cddemo0701npminstall#安装package.json中的依赖创建项目demo0701时,会默认生成文件入口文件app.js的代码。从本书配套的教学资源中打开“验证示例7-1”对应的程序文件app.js,浏览默认生成的代码。关键代码说明如下。express.static(root):root为静态资源目录路径,例如'public'。app.use([path],middleware):path为路由前缀(可选项),middleware为中间件函数。1.项目初始化创建数据库连接会消耗较多的系统资源,连接池通过复用已有连接,避免频繁创建/销毁连接,提升系统性能并减少系统资源消耗。1.MySQL数据库连接池集成MySQL数据库连接池集成的实现步骤如下。(1)安装MySQL驱动。在终端执行以下命令安装MySQL驱动:npminstallmysql2(2)创建pool.js连接池配置文件。MySQL数据库连接池集成
1.项目初始化(3)在路由中使用连接池。MySQL数据库连接池集成
1.项目初始化【操作要求】在文件夹Unit07中创建Web应用项目case0701,从数据表users中查询用户数据并渲染到视图模板users.ejs中。【实现过程】(1)创建Web应用项目case0701的骨架。在文件夹Unit07中执行以下命令创建Web应用项目case0701。express--view=ejscase0701cdcase0701npminstall#安装package.json中的依赖(2)安装依赖包。npminstallexpressmysql2ejs(3)准备数据库。在MySQL中执行以下命令创建数据库与数据表(4)创建文件db.js(数据库连接池)与编写代码。【训练实例7-1】从数据表中查询用户数据并渲染到视图模板1.项目初始化(8)运行应用程序。在终端执行以下命令运行应用程序:nodeapp.js(9)访问测试。打开浏览器访问http://localhost:3000/users。网页输出的用户列表如下:用户列表张珊李斯【训练实例7-1】从数据表中查询用户数据并渲染到视图模板1.项目初始化2.数据库连接池集成的使用要点获取连接:通过pool.query()自动从连接池获取连接,无须手动创建。释放连接:查询完成后,连接自动归还给连接池,无须手动释放。错误处理:使用try/catch捕获连接池操作中的异常(如数据库断开、查询错误)。生产环境将配置放在环境变量中的代码如下:password:process.env.DB_PASSWORD2.基于Express的路由系统查询参数是URL中?后面的键值对,用于传递额外的请求参数,如过滤条件、分页参数等。查询参数通过“?key=value”传递数据,从URL的?后面解析键值对参数。示例代码(Express.js框架):constexpress=require('express');constapp=express();//解析查询参数:http://localhost:3000/products?category=electronics&page=2app.get('/products',(req,res)=>{constcategory=req.query.category;//获取category参数lectronicsconstpage=Number(req.query.page)||1;//获取page参数2,默认值为1res.send('查询类别:${category},第${page}页');});app.listen(3000);查询参数解析2.基于Express的路由系统基础路由定义URL与处理函数的映射关系;参数捕获用于动态匹配URL中的变量,例如用户ID、文章ID。路径参数使用“/path/:var”捕获动态值,动态匹配URL中的变量。关键代码解读如下。动态参数用:paramName标记(如:id),:paramName用于定义占位符。匹配结果存储在req.params对象中,通过req.params可获取参数对象。路径中的参数名可自定义,如:postId,但需符合变量命名规则。支持正则表达式约束参数格式,如/users/:id(\\d+),仅匹配数字ID。基础路由定义与参数捕获
2.基于Express的路由系统【验证示例7-2】在文件夹Unit07中创建JavaScript文件demo0702.js,在该文件中编写以下代码,实现基础路由应用:constexpress=require('express');constapp=express();app.get('/',(req,res)=>{res.send('HelloExpress!');});app.get('/users',(req,res)=>{res.json([{name:'张珊'},{name:'李斯'}]);});app.listen(3000,()=>{console.log('服务器运行在http://localhost:3000');});基础路由定义与参数捕获
2.基于Express的路由系统在终端执行以下命令运行应用程序:nodedemo0702.js打开浏览器访问:http://localhost:3000。网页输出的内容如下:HelloExpress!在浏览器中访问:http://localhost:3000/users。网页输出的内容如下:[{"name":"张珊"},{"name":"李斯"}]基础路由定义与参数捕获
2.基于Express的路由系统中间件是处理请求的函数,可在路由处理前拦截请求,用于权限验证、日志记录等;权限控制通过中间件验证用户身份和权限。中间件通过next()控制执行流程链,在路由处理前执行验证/预处理逻辑。其常用场景包括身份认证、日志记录请求、数据预处理等。路由中间件与权限控制2.基于Express的路由系统在文件夹Unit07中创建JavaScript文件demo0703.js,在该文件中编写以下代码:【验证示例7-3】2.基于Express的路由系统程序的执行流程如下:客户端请求→中间件1→中间件2→……→路由处理函数。关键代码解读如下。中间件函数接收req(请求)、res(响应)、next(下一个处理函数)3个参数。next():调用后将请求传递给下一个中间件或路由处理函数;若不调用,请求会被阻塞。中间件可串联使用,如authMiddleware、adminOnlyMiddleware,按顺序执行。【验证示例7-3】2.基于Express的路由系统RESTfulAPI通过HTTP方法(GET、POST等)和资源路径设计接口,遵循“资源导向”原则,例如用户资源对应/users路径。REST使用“HTTP方法+资源路径”定义完整的操作语义,HTTP方法表示操作,资源路径定位资源。标准路由设计如表7-2所示。RESTfulAPI路由设计
2.基于Express的路由系统资源命名:用名词复数表示资源,例如/users,而非/getUsers。代码实现://使用express.Router组织路由constrouter=express.Router();router.get('/',(req,res)=>{/*获取资源*/});router.post('/',(req,res)=>{/*创建资源*/});router.get('/:id',(req,res)=>{/*获取部分资源*/});router.put('/:id',(req,res)=>{/*全量更新资源*/});router.delete('/:id',(req,res)=>{/*删除资源*/});app.use('/api/users',router);//挂载到路径其优势如下。接口语义清晰。降低URL设计复杂度。遵循HTTP标准。RESTfulAPI路由设计
2.基于Express的路由系统在文件夹Unit07中创建JavaScript文件demo0704.js,在该文件中编写以下代码:RESTfulAPI路由设计
3.基于Express的中间件生态中间件是按顺序执行的函数,Express中间件是处理HTTP请求的函数,接收req、res和next3个参数,通过next()控制流程走向。示例代码:app.use((req,res,next)=>{console.log('Middleware1');next();//必须调用next()才能进入下一层});app.use((req,res,next)=>{console.log('Middleware2');next();});app.get('/',(req,res)=>{res.send('HelloWorld');});中间件机制与执行顺序3.基于Express的中间件生态(1)创建JavaScript文件与编写代码。在文件夹Unit07中创建JavaScript文件demo0705.js,在该文件中编写以下代码:【验证示例7-5】3.基于Express的中间件生态(2)安装express。在终端执行以下代码安装express:npminstallexpress(3)启动服务器。打开一个终端,将之称为终端1,然后在终端1中执行以下命令启动服务器:nodedemo0705.js此时,终端1输出以下信息:服务器运行在http://localhost:3000(4)使用curl命令测试API。①
未授权请求(返回401)。打开另一个终端,将之称为终端2,在终端2执行以下命令:curlhttp://localhost:3000/user终端2的响应信息如下:未授权此时,终端1输出以下信息:[17:08:01]GET/user-2003.基于Express的中间件生态打开浏览器,访问http://localhost:3000,此时,页面输出以下内容:未授权②
授权请求(返回用户信息)。在终端2执行以下命令:curl-H"Authorization:valid-token"http://localhost:3000终端2的响应信息如下:你好!中间件此时,终端1输出以下信息:[17:13:05]GET/user-200在终端2执行以下命令:curl-H"Authorization:valid-token"http://localhost:3000/user终端2的响应信息如下:用户信息此时,终端1输出以下信息:[07:23:55]GET/-200请求头必须包含Authorization:valid-token才能通过验证。3.基于Express的中间件生态1.body-parser该中间件用于解析请求体,如JSON、表单数据等。示例代码:constbodyParser=require('body-parser');app.use(bodyParser.json());//解析JSON格式app.use(bodyParser.urlencoded({extended:true}));//解析表单数据参数说明:extended:true:使用qs库解析,允许解析嵌套对象。extended:false:使用原生querystring库解析,仅解析简单结构。常用中间件3.基于Express的中间件生态2.cookie-parser该中间件用于解析请求中的Cookie。示例代码:constcookieParser=require('cookie-parser');app.use(cookieParser('secret'));//'secret'是签名密钥//使用示例res.cookie('user','admin',{maxAge:900000,httpOnly:true});constuser=req.cookies.user;//读取Cookie值常用中间件3.基于Express的中间件生态3.helmet该中间件用于设置HTTP头部,增强安全性。示例代码:consthelmet=require('helmet');app.use(helmet());//启用所有安全策略//自定义策略(例如禁用X-Powered-By头)app.use(helmet({xPoweredBy:false}));支持contentSecurityPolicy、xssFilter等策略。常用防护:XSS(跨站脚本攻击防护、禁止iframe嵌入、隐藏X-Powered-By头)。常用中间件3.基于Express的中间件生态morgan是HTTP请求日志中间件,可自定义格式。基础使用示例代码:constmorgan=require('morgan');app.use(morgan('dev'));//'dev'格式显示状态码和响应时间自定义日志格式示例代码:morgan.token('custom-time',()=>newDate().toISOString());app.use(morgan(':custom-time-:method:url:status'));输出示例:2025-10-01T12:00:00Z-GET/api/users200定制日志中间件3.基于Express的中间件生态JWT原理:生成包含用户信息的令牌(Token),客户端携带令牌访问,服务器端验证合法性。1.生成Token示例代码:constjwt=require('jsonwebtoken');//生成jwt令牌consttoken=jwt.sign({userId:123},'your_secret_key',{expiresIn:'1h'}//有效期1小时);JWT身份认证中间件
3.基于Express的中间件生态2.验证中间件示例代码:functionauthenticate(req,res,next){//从请求中获取客户端携带的令牌consttoken=req.headers.authorization?.split('')[1];if(!token)returnres.status(401).send('Accessdenied');//服务器端验证令牌合法性jwt.verify(token,'your_secret_key',(err,decoded)=>{if(err)returnres.status(403).send('Invalidtoken');req.user=decoded;//将解码数据附加到reqnext();});}//保护路由app.get('/profile',authenticate,(req,res)=>{res.json({user:req.user});});3.基于Express的中间件生态【操作要求】编写程序,生成与验证JWT,包括Token验证流程、中间件权限控制、安全密钥管理等功能。【实现过程】(1)创建JavaScript文件与编写代码。在文件夹Unit07中创建子文件夹case0702,然后在文件夹case0702中创建JavaScript文件case0702.js,在该文件中编写代码。从本书配套的教学资源中打开“训练实例7-2”对应的程序文件case0702.js,浏览相应代码。(2)安装依赖。在终端执行以下命令安装依赖:npminit-ynpminstallexpressjsonwebtoken【训练实例7-2】生成与验证JWT3.基于Express的中间件生态(3)启动服务器。在终端执行以下命令启动服务器:nodecase0702.js(4)测试API。①
获取Token(模拟登录)。在终端执行以下命令:#使用-d参数(自动转为POST)curl-d"""http://localhost:3000/login?username=admin"或者#显式指定POST方法curl-XPOST"http://localhost:3000/login?username=admin"响应示例如下:{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwicm9sZSI6ImFkbWluIiwiaWF0IjoxNzQ4ODM2MDg0LCJleHAiOjE3NDg4Mzk2ODR9.KQTh3sO9RvwGDBlxMDGtWY8EWP2PmPAz-0MxL5GL13s"}3.基于Express的中间件生态②
使用Token访问受保护路由。在终端执行以下命令:curl-H"Authorization:Bearer<复制上面的Token>"http://localhost:3000/admin返回信息有以下几种情况。对于管理员用户:返回管理员专属内容。对于普通用户:返回“无管理员权限”。对于无效Token的用户:返回“令牌无效”。③
用表单数据模拟真实登录场景。在终端执行以下命令:#发送JSON格式的用户名和密码curl-XPOST\-H"Content-Type:application/json"\-d'{"username":"admin","password":"admin123"}'\http://localhost:3000/login3.基于Express的中间件生态错误处理函数必须包含4个参数(err、req、res、next),且注册在所有路由之后。(1)定义错误处理函数。示例代码:app.use((err,req,res,next)=>{console.error('错误日志:',err);res.status(500).send('ServerError!');});(2)触发错误。示例代码:app.get('/error',(req,res,next)=>{try{thrownewError('Somethingbroke!');}catch(err){next(err);//传递错误给错误中间件}});Express错误处理中间件
3.基于Express的中间件生态(3)异步错误处理。示例代码:app.get('/async-error',async(req,res,next)=>{try{awaitsomeAsyncOperation();}catch(err){next(err);//必须通过next传递}});注意:错误处理中间件需定义在所有路由之后。调用next(err)会跳过后续中间件,直接进入错误处理部分。Express错误处理中间件
3.基于Express的中间件生态【验证示例7-6】在文件夹Unit07中创建JavaScript文件demo0706.js,在该文件中编写以下代码:Express错误处理中间件
4.模板引擎与布局管理模板引擎的核心作用是将动态数据与HTML模板结合生成最终页面。小型项目首选EJS(降低学习成本),中大型项目考虑Pug(提高开发效率)。1.EJS模板引擎EJS的语法与HTML的类似,接近标准原生HTML,允许在HTML中直接内嵌并执行原生JavaScript代码。在终端执行以下命令安装EJS:npminstallejsEJS/Pug模板引擎
4.模板引擎与布局管理示例代码:EJS/Pug模板引擎
4.模板引擎与布局管理2.PugPug支持缩进式语法,无标签闭合,更注重逻辑与结构分离。在终端执行以下命令安装Pug:npminstallpug示例代码:EJS/Pug模板引擎
4.模板引擎与布局管理1.视图渲染视图渲染的核心方法:res.render(viewName,[locals],[callback])参数说明:viewName:视图文件名(不含扩展名,如'user')。locals:传递给视图的数据对象(可选项)。callback:渲染完成后的回调函数(可选项)。全局数据:通过app.locals设置(如网站标题、导航菜单)。页面专属数据:通过res.render()的第2个参数传递。视图渲染与布局管理
4.模板引擎与布局管理2.布局管理(1)使用EJS实现布局模板。EJS布局实现需express-ejs-layouts支持。①
布局文件<!--views/layout.ejs-->。②
主视图文件<!--views/index.ejs-->。(2)使用Pug实现布局模板。Pug布局实现原生支持extend/block。①
布局文件//-views/layout.pug。②
主视图文件//-views/index.pug。视图渲染与布局管理
5.会话管理与认证Cookie是存储在客户端浏览器中的小型文本数据,用于跟踪用户状态。会话(Session)则是服务器端存储的用户数据,通常通过Cookie中的SessionID关联。服务器通过Set-Cookie响应头将SessionID发送给浏览器,浏览器后续请求自动携带该Cookie,服务器据此识别用户会话。关键代码示例(PythonFlask版)基于Cookie的会话实现
5.会话管理与认证基于Cookie/Session的认证方式由服务器端完全控制会话数据,适用于传统Web应用场景。认证流程如下。①
用户提交登录表单(用户名+密码)。②
服务器验证凭证:创建Session存储用户ID。③
服务器通过Cookie将SessionID返回给客户端。④
后续请求中,客户端携带Cookie,服务器通过SessionID验证用户状态。Python示例代码(用户退出登录):@app.route('/logout')deflogout():session.pop('user_id',None)#移除Session中的用户IDreturn"Loggedout"基于Cookie/Session的认证5.会话管理与认证OAuth第三方登录具有无须管理密码、用户体验佳的优势,适用于快速注册/登录。核心流程(以GitHub登录为例)如下。(1)用户单击“GitHub登录”链接,重定向到GitHub授权页面。示例代码:/login/oauth/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=/callback&scope=user:email(2)用户同意授权后,GitHub重定向回用户的应用,返回临时授权码code给应用。示例代码:/callback?code=XYZ123(3)用户的服务器用code换取访问令牌(AccessToken)。(4)用AccessToken获取用户信息,完成登录。OAuth第三方登录集成6.Express集成Sequelize是Node.js中流行的ORM库,支持MySQL、PostgreSQL等关系数据库。通过ORM库连接数据库,将数据库操作转化为JavaScript对象操作。【训练实例7-3】使用Sequelize实现Express与数据库的集成【操作要求】编写程序,使用Sequelize实现Express与数据库的集成,实现简单用户管理系统的后端部分。【实现过程】(1)在文件夹Unit07中创建子文件夹case0703。(2)安装依赖。将文件夹case0703设置为当前文件夹,然后执行以下命令安装依赖:npminstallexpresssequelizemysql2#以MySQL为例(3)初始化连接。(4)定义数据模型。Express与数据库集成
6.Express集成(5)在路由中使用。(6)创建server.js文件。关键代码解读如下。①
依赖导入。express:创建HTTP服务器。sequelize(从database.js导入):管理数据库连接。userRoutes(从routes/userRoutes.js导入):处理用户相关的API请求。②
中间件使用。app.use(express.json()):解析客户端发送的JSON请求体,例如POST请求中的req.body。③
路由挂载。app.use('/users',userRoutes):将所有用户相关的路由(如POST/users)挂载到/users路径下。Express与数据库集成
6.Express集成④
数据库和服务器启动。sequelize.authenticate():测试数据库连接是否正常。sequelize.sync():将模型同步到数据库,如果数据表不存在,自动创建users表。app.listen():启动Express服务器。核心方法说明如下。Model.create():创建新记录。Model.findAll():查询所有记录。Model.findByPk():通过主键查询。Model.update():更新记录。Model.destroy():删除记录。(7)创建文件data.js
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026文旅国企面试题及答案
- 2026秋招:山西焦煤面试卷及答案
- 2025-2026学年河北省邯郸市肥乡区三年级数学下学期期末综合测试模拟试题(含答案解析)
- 2025-2026学年河北省保定市顺平县数学三年级下学期期中检测试题含答案解析
- 延安市宝塔区圣地小学招聘教职工笔试真题2025
- 北海市海城区招聘城镇公益性岗位人员笔试真题2025
- 苏州市吴中区招聘森林消防队员考试真题2025
- 河南信阳市五校协作体2027届高三上学期学情综合检测 化学试卷(解析版)
- 广东省江门市2027年高考考前模拟物理试题(含答案解析)
- 2025-2026学年江苏省宿迁市宿豫区三年级数学第二学期期末调研模拟试题(含答案)
- 2026年新上岗护士测试题及答案
- 【新教材】人教版(2024)八年级下册物理期末质量监测试卷1(含答案)
- 沪粤版八年级物理上册期末考试卷及答案解析(100分版)
- 2025四川九洲电器集团有限责任公司招聘光电系统总体工程师(校招)等岗位测试笔试历年参考题库附带答案详解
- 2025江苏南京栖霞区中考一模数学试卷及答案
- 广西卫生职业技术学院招聘考试真题2025
- 《电气控制与S7-1200PLC应用》课件 第6章S7-1200 PLC程序块
- 2026镇江市护士招聘考试题及答案
- 钢结构更换构件施工工艺流程
- 2026年河南省安阳市重点学校初一新生入学分班考试试题及答案
- 医疗器械设计转换管理手册
评论
0/150
提交评论