这里写目录标题
- express-generator作用
- 安装(全局安装)
- 局部安装 nodemon 热更新
- 使用步骤
- 二级路由
- 练习:用post请求获取到用户输入的账户,密码
- 路由模块封装
- 数据库连接池
- 实例:服务端(后端)实现分页请求步骤
- 实例登录注册的存数据库逻辑
项目开发:(这是一种规范)
1. 开发环境 dev(development) : npm run dev
2. 生产环境 build(production): npm run build
3. 测试环境 test(test): npm run test (了解, 后期专门的测试工具, 测试岗位)
Express 和 Express-generator的区别
Express 是一个基于 Node.js 平台的极简、灵活的 web 应用开发框架,它提供一系列强大的特性,帮助你创建各种 Web 和移动设备应用。
Express-generator是Express的应用生成器,通过使用生成器工具,可以快速创建一个Express的应用骨架。
“express-generator是app engerator,即骨架生成器。以前的版本中,express-generator和express是在一块的,最近版本已经独立开来了。”
express-generator作用
通过应用生成器工具 express-generator 可以快速创建一个应用的骨架
安装(全局安装)
npm i express-generator -g
(全局安装后,在这台电脑就不用重复输入这个命令)
安装完成后,可以使用 express 命令 搭建项目; 会自动生成一个项目结构
// 语法规则
express 模板引擎 项目名称
// 案例
express -e myapp
这里的-e指的是ejs模板引擎的简写
接着按照它的指示操作
cd myapp
安装依赖
npm install
npm i (简写)
运行项目是如下
npm run start
会生成如下一个文件夹
如果还需要什么插件可以后续在下载 npm i 包名 --save
局部安装 nodemon 热更新
- 安装
npm i nodemon --save
- 安装完成,需要配置 启动命令, 在package.json文件中的“scripts”字段中配置启动命令
"scripts":{
"dev":"nodemon ./bin/www"
}
- 配置完成后可以使用
npm run dev
启动服务
功能介绍
使用步骤
更改服务器默认的端口号在bin>www (文件里面)
首先引入路由配置文件,进行路由匹配
app.js文件是一个总页面是顶级路由,可以在里面引入你需要的页面
req是客户端向服务器(黑窗口)请求
res是服务器(黑窗口)像客户端进行响应
next是放行
var router = express.Router();
创建一个路由容器
res.render(' ejs模板引擎名')
会进入这个模板名的ejs文件
(这里res.send()方法是服务器像客户端响应的数据)
这样就完成了一个基础的运行机制(这是一个对一个模块的导出.app.use中,routes文件夹有几个js文件就引入了几次)
可以在ejs模板引擎中书写主体,这是前后端不分离的做法
二级路由
下一篇文章有动态路由介绍
:如果我们在list.js文件下在建立一个admin路由,就要这样访问,相当于二级路由`
http://localhost:3000/list/admin
只有index.js文件夹中的路由是可以直接匹配使用,除了index.js以外的路由模块中的路由都需要和app.js中的路由进行拼接使用
练习:用post请求获取到用户输入的账户,密码
app.js部分 引入路由配置文件
var listRouter = require('./routes/login');
app.use('/login', loginRouter);
ejs部分
小知识:当你直接就在自己本项目请求的,就不用写http://localhost:3000,可以直接写你的路由地址/login/dologin
当然你如果写完整,也不会出错
url: 'http://localhost:3000/login/dologin',
<body>
<p class="err"></p>
<p>
<input type="text" name="user" class="user">
</p>
<p>
<input type="password" name="pwd" class="pwd">
</p>
<p>
<button>登录</button>
</p>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
$('button').click(function() {
$.ajax({
url: 'login/dologin',
type: 'post',
data: {
user: $('.user').val(),
pwd: $('.pwd').val(),
},
success: function(data) {
console.log(data);
if (data.code == 400) {
$('.err').text(data.message)
} else if (data.code == 200) {
console.log(data);
// 存储用户信息
localStorage.setItem('user', data.data.name)
// 页面重定向
location.href = '/'
}
}
})
})
</script>
二级路由部分
因为从连接池传过来的query(数据库)是一个promise对象,所以它有then方法
var express = require('express');
const query = require('../utils/query')
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('login');
});
// next 放行
router.post('/dologin', (req, res, next) => {
console.log(req.body);
let {user, pwd} = req.body;
query('select * from admin where name = ? and pwd = ?', [user, pwd]).then(data => {
if(data.length){
delete data[0].pwd
res.send({
code:200,
message:'登录成功',
data:data[0]
})
}else{
res.send({
code:400,
message:'用户名或密码错误',
data:[]
})
}
})
})
module.exports = router;
使用 console.log(req.body); //将用户信息输出到控制台
对后端如何使用数据库连接池的解释
路由模块封装
解决二级路由的嵌套
这样就不用在app.js里面多次引入路由配置文件
打开服务器后
可以通过api来测试接口是否畅通
数据库连接池
对数据库的封装
通常会在app.js同级文件夹下建一个utils文件夹里面放query.js文件,这是一种规范,不是必须的
本来可以连接10个 connectionLimit: 10,下面释放资源的目的connection.release()是让别人还可以继续使用连接
const mysql = require('mysql');
// 创建连接池
const pool = mysql.createPool({
host: 'localhost',
user: 'root',
password: 'root',
database: 'yunmeng',
connectionLimit: 10
})
module.exports = (sql, value = []) => {
return new Promise((resolve, reject) => {
// 从连接池中获取连接
pool.getConnection((err, connection) => {
if (err) {
reject(err);
throw err;
}
// 连接成功 执行查询
connection.query(sql, value, (err, result) => {
// 立刻释放资源(连接)
connection.release()
if (err) {
reject(err);
throw err;
}
// sql执行成功
resolve(result)
})
})
})
}
这是没学连接池前的写法
数据库模块讲过query
方法可以执行数据库的增删改查
module.exports = (sql, value = []) => {
return new Promise((resolve, reject) => {
pool.query(sql, value, (err, result) => {
if (err) {
reject(err);
throw err;
}
resolve(result)
})
})
}
不论哪种写法;在用到数据库的地方都要引入模块
(自定义的·模块引用时需要加点斜杠,内置模块和第三方模块引入时,直接引入名字
const query = require('../utils/query')
实例:服务端(后端)实现分页请求步骤
首先是服务端把页分好,然后把数据传到客户端,下面是初步的想法
currentPage可以返回当前页码
currentPage: page
后端
var express = require('express');
const query = require('../utils/query');
var router = express.Router();
/* GET home page. */
router.get('/', async function(req, res, next) {
//请求第一页的1页的数据
let { page = 1 } = req.query;
let length = 10;
//总数据条数
let total_sql = 'select * from t_order'
let pageNum = await query(total_sql);
// console.log(pageNum);输出所有的数据完整的
//换算一共显示多少页
let num = Math.ceil(pageNum.length / length)
console.log(num);
let sql = `select * from t_order limit ${(page-1)*length},${length}`
let datalist = await query(sql);
// console.log(datalist);
res.render('index', { data: datalist, pageNum: num, currentPage: page });
});
module.exports = router;
数据库
const mysql = require('mysql');
//创建连接池
const pool = mysql.createPool({
host: 'localhost',
user: 'root',
password: 'root',
database: 'yunmeng',
connectionLimit: 10
})
module.exports = (sql, value = []) => {
//执行成功调用resolve.执行失败调用reject
return new Promise((resolve, reject) => {
// 从连接池中获取连接
pool.getConnection((err, connection) => {
if (err) {
reject(err);
throw err;
}
// 连接成功 执行查询
connection.query(sql, value, (err, result) => {
// 立刻释放资源(连接)
connection.release()
if (err) {
reject(err);
throw err;
}
// sql执行成功
resolve(result)
})
})
})
}
//旧写法
// const mysql = require('mysql');
// const conn = mysql.createConnection({
// host: 'localhost',
// user: 'root',
// password: 'root',
// database: 'yunmeng'
// })
// module.exports = (sql, value = []) => {
// return new Promise((resolve, reject) => {
// conn.query(sql, value, (err, result) => {
// if (err) {
// reject(err);
// throw err;
// }
// resolve(result)
// })
// })
// }
ejs模板
<style>
.pagebean a {
font-size: 20px;
color: #333;
float: left;
padding: 10px;
border: 1px solid #333;
margin: 5px;
text-decoration: none;
}
.pagebean .active {
color: red;
border-color: red;
}
</style>
<body>
<!-- 页面首次加载,渲染第一页数据 -->
<div class="wrap">
<ul>
<% data.forEach((item,index)=>{%>
<li>
<p>
作者:
<%= item.title%>
</p>
<p>
类型:
<%= item.classify%>
</p>
</li>
<% })%>
</ul>
</div>
<div class="pagebean">
<!-- 页面数量 分页按钮的数量(根据数据库内容的条数来定) -->
<% for(let i = 0;i<pageNum;i++) {%>
<a href="/?page=<%= (i + 1)%>" class="<%= currentPage == (i+1)?'active':''%>">
<%= (i+1)%>
</a>
<% }%>
</div>
</body>
这样就从服务端完成了分页请求
补充:
如果ejs模板需要引入外部的样式css
就在public里面的stylesheets里面新建css样式文件
使用时不需要加…/public前缀,加了会链接不上
实例登录注册的存数据库逻辑
const query = require('../utils/query')
module.exports = (router) => {
//登录部分
router.post('/dologin', async(req, res, next) => {
let { phone, pwd } = req.body;
let sql_phone = 'select * from user where phone = ?'
let result_name = await query(sql_phone, [phone])
if (result_name.length) {
let sql = 'select * from user where phone = ? and password = ?';
let result = await query(sql, [phone, pwd]);
if (result.length) {
delete result[0].password
res.send({
code: 200,
message: 'success',
data: result
})
} else {
res.send({
code: 400,
message: '用户名或密码错误',
data: []
})
}
} else {
res.send({
code: 400,
message: '用户名或密码错误',
data: []
})
}
})
//注册部分
.post('/doregister', (req, res, next) => {
let { user, pwd, phone } = req.body;
console.log(req.body);
let sql = 'insert into user set ?';
query(sql, { nickname: user, password: pwd, phone }).then(result => {
if (result.affectedRows) {
res.send({
code: 200,
message: '注册成功'
})
} else {
res.send({
code: 400,
message: '注册失败'
})
}
})
})
}
result.affectedRows 是改变的行,所以有affectedRows方法
let sql = 'insert into user set ?';
query(sql, { nickname: user, password: pwd, phone }).then(result=>{})
这里面可以传一个值,也可以传对象
send
前后端分离传递的参数在send里面
不分离的是render匹配页面和放传递的参数
你别搞混了