简介
本篇文章主要讲解使用NodeJS开发Web服务器(一个小型的博客项目)及NodeJS 如何连接 MySQL。
本文参考:NodeJS 连接 MySQL【NodeJS】_哔哩哔哩_bilibili
node服务器搭建
创建项目文件下,执行如下npm命令
js
npm init -y
npm i nodemon
创建如下文件夹及文件
入口文件 www.js
js
//引入http模块
const http = require('http')
const serverHandler = require('../app.js')
const PORT = 5000
//创建服务器
const server = http.createServer(serverHandler)
server.listen(PORT,() => {
console.log('服务运行在5000端口...');
})
app.js
js
const serverHandler = (req,res) => {
//设置返回的报文格式
res.setHeader('Content-Type',"application/json")
//返回内容
res.end()
}
module.exports = serverHandler
配置文件package.json
js
{
"name": "11",
"version": "1.0.0",
"description": "",
"main": "bin/www.js",
"scripts": {
"test": "echo "Error: no test specified" && exit 1",
"dev":"nodemon bin/www.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"nodemon": "^2.0.19"
}
}
启动项目
js
npm run dev
路由初始化
创建博客处理模块 根目录 src\routes\blog.js
js
//处理博客相关路由
const handelBlogRoute = (req,res) => {
//定义路由的处理逻辑
const method = req.method
if(method === "GET" && req.path === "/api/blog/list"){
return {
message:"获取博客接口列表"
}
}
if(method === "GET" && req.path === "/api/blog/detail"){
return {
message:"获取博客详情接口"
}
}
if(method === "POST" && req.path === "/api/blog/new"){
return {"新建博客接口"
}
}
if(method === "POST" && req.path === "/api/blog/update"){
return {
message:"更新博客接口"
}
}
if(method === "POST" && req.path === "/srcapi/blog/delete"){
return {
message:"删除博客列表接口"
}
}
}
module.exports = handelBlogRoute
app.js中优化部分代码
js
const handelBlogRoute = require("./src/routes/blog")
const serverHandler = (req,res) => {
//设置返回的报文格式
res.setHeader('Content-Type',"application/json")
const url = req.url
req.path = url.split("?")[0]
let blogData = handelBlogRoute(req,res)
//返回内容
if(blogData){
res.end(JSON.stringify(blogData))
}
//匹配不到路由时的处理
res.writeHead(404,{'Content-Type':'text/plain'})
res.write("404 Not FOund")
res.end()
}
module.exports = serverHandler
开发第一个路由
首先我们开发获取博客列表接口
1.创建src\contrllers\blog.js文件,用于设置返回接口数据
js
//博客相关方法
const getList = (author , keyword) => {
//从数据库获取数据
//先返回假数据
return [
{ id:1, title:'标题1', content:"内容2",author:"张三", createAt:123456 },
{ id:2, title:'标题1', content:"内容2",author:"张三", createAt:1234567 },
{ id:3, title:'标题1', content:"内容2",author:"张三", createAt:12345678 },
]
}
module.exports = {
getList
}
这个接口需要参数author , keyword关键词,用来返回匹配的数据。参数author , keyword是通过url的query参数获取的,因此需要解析url的query参数
2.解析url的query参数
app.js中
js
const handelBlogRoute = require("./src/routes/blog")
//node 原生的属性
const querystring = require("querystring")
//这里主要进行一些服务器的设置
const serverHandler = (req,res) => {
//设置返回的报文格式
res.setHeader('Content-Type',"application/json")
//获取path /api/blog/list
const url = req.url
req.path = url.split("?")[0]
//解析query
req.query = querystring.parse(url.split("?")[1])
//路由匹配
let blogData = handelBlogRoute(req,res)
//返回内容
if(blogData){
res.end(JSON.stringify(blogData))
}else{
//匹配不到路由时的处理
res.writeHead(404,{'Content-Type':'text/plain'})
res.write("404 Not FOund")
res.end()
}
}
module.exports = serverHandler
3.完善路由内容
src\routes\blog.js
js
const { SuccessModel } = require("../model/responseModel")
const { getList } = require("../contrllers/blog")
//处理博客相关路由
const handelBlogRoute = (req,res) => {
//定义路由的处理逻辑
const method = req.method
if(method === "GET" && req.path === "/api/blog/list"){
//可能的请求路径 api/blog/list?query=zhangsan&keyword=123
const author = req.query.author || ""
const keyword = req.query.keyword || ""
//根据自定义的关键词,返回列表数据
const listData = getList(author,keyword)
//使用模型返回规范的文件格式
return new SuccessModel(listData)
}
if(method === "GET" && req.path === "/api/blog/detail"){
return {
message:"获取博客详情接口"
}
}
if(method === "POST" && req.path === "/api/blog/new"){
return {
message:"新建博客接口"
}
}
if(method === "POST" && req.path === "/api/blog/update"){
return {
message:"更新博客接口"
}
}
if(method === "POST" && req.path === "/srcapi/blog/delete"){
return {
message:"删除博客列表接口"
}
}
}
module.exports = handelBlogRoute
注意,为了使返回值更加规范方便,我们创建了一个类。
4.创建返回值模型
src\model\responseModel.js
js
class BaseModel {
constructor(data,message) {
if(typeof data == "string") {
this.message = data;
data = null
message = null
}
if(data) {
this.data = data
}
if(message) {
this.message = message
}
}
}
//成功模型 实例化后 产生一个 { data:data , errno : 0 }格式的对象
class SuccessModel extends BaseModel {
constructor ( data ,message) {
super(data,message)
this.errno = 0
}
}
//失败模型
class ErrorModel extends BaseModel {
constructor ( data ,message) {
super(data,message)
this.errno = -1
}
}
module.exports = {
SuccessModel,
ErrorModel
}
此时,访问接口,是可以获取数据的。
开发获取博客详情接口
逻辑如同获取博客列表
src\contrllers\blog.js
js
//博客相关方法
const getList = (author , keyword) => {
.......
}
//获取博客详情数据
const getDetail = (id) => {
//先返回假数据
return { id:1, title:'标题1', content:"内容2",author:"张三", createAt:123456 }
}
module.exports = {
getList,
getDetail
}
src\routes\blog.js
js
const { SuccessModel } = require("../model/responseModel")
const { getList ,getDetail} = require("../contrllers/blog")
//处理博客相关路由
const handelBlogRoute = (req,res) => {
//定义路由的处理逻辑
const method = req.method
//获取接口列表 .....
//获取接口详情
if(method === "GET" && req.path === "/api/blog/detail"){
const id = req.query.id
const detailData = getDetail(id)
return new SuccessModel(detailData)
}
......
}
module.exports = handelBlogRoute
访问接口
处理post请求
原生node的post请求是一个异步函数
我们需要在app.js中进行post请求处理
js
const handelBlogRoute = require("./src/routes/blog")
//node 原生的属性
const querystring = require("querystring")
//处理post数据
const getPostData = (req) => {
const promise = new Promise((resolve,reject) => {
if(req.method !== "POST"){
resolve({})
return
}
if(req.headers['conten-type'] !== 'application/json'){
resolve({})
return
}
let postData = ""
req.on('data',(chunk) => {
postData += chunk.toString()
})
req.on('end', ()=> {
if(!postData) {
resolve({})
return
}
resolve(
JSON.parse(postData)
)
})
})
}
//这里主要进行一些服务器的设置
const serverHandler = (req,res) => {
//设置返回的报文格式
res.setHeader('Content-Type',"application/json")
//获取path /api/blog/list
const url = req.url
req.path = url.split("?")[0]
//解析query
req.query = querystring.parse(url.split("?")[1])
//处理post数据
getPostData(req).then((postData) => {
//将post数据绑定在req的body上
req.body = postData
//路由匹配
let blogData = handelBlogRoute(req,res)
//返回内容
if(blogData){
res.end(JSON.stringify(blogData))
return
}
//匹配不到路由时的处理
res.writeHead(404,{'Content-Type':'text/plain'})
res.write("404 Not FOund")
res.end()
})
}
module.exports = serverHandler
完善接口
src\routes\blog.js
js
const { SuccessModel,ErrorModel } = require("../model/responseModel")
const { getList ,getDetail,createNewBlog, deleteBlog,updataBlog} = require("../contrllers/blog")
//处理博客相关路由
const handelBlogRoute = (req,res) => {
//定义路由的处理逻辑
const method = req.method
const id = req.query.id
const postData = req.body
//获取接口列表
if(method === "GET" && req.path === "/api/blog/list"){
//可能的请求路径 api/blog/list?query=zhangsan&keyword=123
const author = req.query.author || ""
const keyword = req.query.keyword || ""
//根据自定义的关键词,返回列表数据
const listData = getList(author,keyword)
//使用模型返回规范的文件格式
return new SuccessModel(listData)
}
//获取接口详情
if(method === "GET" && req.path === "/api/blog/detail"){
const detailData = getDetail(id)
return new SuccessModel(detailData)
}
//新建接口
if(method === "POST" && req.path === "/api/blog/new"){
const newBlogData = createNewBlog(postData)
return new SuccessModel(newBlogData)
}
//更新博客路由
if(method === "POST" && req.path === "/api/blog/update"){
const updateBlogData = updataBlog(postData)
if(updateBlogData){
return new SuccessModel("更新博客成功")
}else{
return new ErrorModel("更新博客失败")
}
}
//删除博客路由
if(method === "POST" && req.path === "/srcapi/blog/delete"){
const deleteBlogData = deleteBlog(id)
if(deleteBlogData){
return new SuccessModel("删除博客成功")
}else{
return new ErrorModel("删除博客失败")
}
}
}
module.exports = handelBlogRoute
src\contrllers\blog.js
js
//博客相关方法
const getList = (author , keyword) => {
//从数据库获取数据
//先返回假数据
return [
{ id:1, title:'标题1', content:"内容2",author:"张三", createAt:123456 },
{ id:2, title:'标题1', content:"内容2",author:"张三", createAt:1234567 },
{ id:3, title:'标题1', content:"内容2",author:"张三", createAt:12345678 },
]
}
//获取博客详情数据
const getDetail = (id) => {
//先返回假数据
return { id:1, title:'标题1', content:"内容2",author:"张三", createAt:123456 }
}
//创建新博客
const createNewBlog = (blogData) => { return { id:1 } }
//更新boke
const updataBlog = (id,blogData = {}) => { return true }
//删除博客
const deleteBlog = (id) => { return true }
module.exports = {
getList,
getDetail,
createNewBlog,
updataBlog,
deleteBlog
}
使用mysql
1.创建数据库连接
2.创建myblog数据库,然后创建blogs数据表,表中按如图方式增加字段
数据表操作
查
基本的查找语句为:
js
SELECT * from blogs
查找时,也可以指定字段
js
select id,title from blogs
sql语句不区分大小写
注:语句前增加"--"可以注释语句
也可以进行筛选查询
js
SELECT * from blogs where title='标题1'
SELECT * from blogs where title='标题1' and author='gcshi'
SELECT * from blogs where title='标题1' or author='gcshi'
-- 模糊查询,查询标题包含1的内容
SELECT * from blogs WHERE title like '%1%'
-- 对查找的内容进行排序 默认为正序
SELECT * from blogs WHERE title like '%1%' order by id
-- 对查找的内容进行排序 倒序
SELECT * from blogs WHERE title like '%1%' order by id desc
增
sql
insert into blogs(title,content,author,createdAt) value ('标题1','内容1','gcshi',1234567890123)
我们可以选择我们的增加语句,然后点击【运行已选择的】
改
js
update blogs set title='11111'
这种方法会将所有数据的标题修改成111
我们可以增加筛选条件
js
update blogs set title='222' where content='内容1'
删
js
-- 这会删除整张表
delete from blogs
上述命令会删除整张表,这是危险操作。我们应该加上条件
js
delete from blogs WHERE title='222'
node连接数据库
js
npm i mysql
js
├─ mysql-demo
│ └─ index.js
js
//引入mysql
const mysql = require('mysql')
// 创建连接对象
const connection = mysql.createConnection({
host:'localhost',
user:'root',
password:'root',
port:3306,
database:'myblog'
})
//开始连接
connection.connect();
//执行sql语句
const sql = 'select * from blogs'
connection.query(sql,(err,result) => {
if(err){
return console.log(err);
}
console.log('reult',result);
})
//关闭连接
connection.end()
我们在mysql-demo文件夹中运行一下 node index.js,可以看到返回的数据结果(一个json数据格式)
sql语句封装
全局调用sql语句会很乱,我们将sql语句进行封装,便于我们在项目中使用。
src下创建db文件夹,创建mysql.js文件
js
└─ src
├─ config //数据库配置文件夹
│ └─ db.js
├─ contrllers
│ └─ blog.js
├─ db
│ └─ mysql.js
├─ model
│ └─ responseModel.js
└─ routes
└─ blog.js
js
//引入mysql
const mysql = require('mysql')
const { MYSQL_CONFIG } = require('../config/db')
// 创建连接对象
const connection = mysql.createConnection( MYSQL_CONFIG )
//开始连接
connection.connect();
//执行sql语句,封装成一个promise函数
function execSQL(sql) {
const promise = new Promise((resolve, reject) => {
connection.query(sql,(err,result)=>{
if(err){
return reject(err)
}
resolve(result)
})
})
return promise
}
module.exports = {
execSQL
}
为了方便数据库不同环境下的配置的修改,我们将其单独配置src\config\db.js
js
let MYSQL_CONFIG = {}
MYSQL_CONFIG = {
host:'localhost',
user:'root',
password:'root',
port:3306,
database:'myblog'
}
module.exports = {
MYSQL_CONFIG
}
获取博客列表对接Mysql
src\contrllers\blog.js
js
const { execSQL } = require("../db/mysql")
//获取博客列表
const getList = (author , keyword) => {
let sql = "select * from blogs where 1=1 "
if( author ){
sql += `and author=${author} `
}
if( keyword ){
sql += `and title like '%${keyword}%' `
}
return execSQL(sql)
}
//获取博客详情数据
//创建新博客
//更新boke
//删除博客
module.exports = {
getList,
getDetail,
createNewBlog,
updataBlog,
deleteBlog
}
src\routes\blog.js
js
const { SuccessModel,ErrorModel } = require("../model/responseModel")
const { getList ,getDetail,createNewBlog, deleteBlog,updataBlog} = require("../contrllers/blog")
//处理博客相关路由
const handelBlogRoute = (req,res) => {
//定义路由的处理逻辑
const method = req.method
const id = req.query.id
const postData = req.body
//获取接口列表
if(method === "GET" && req.path === "/api/blog/list"){
//可能的请求路径 api/blog/list?query=zhangsan&keyword=123
const author = req.query.author || ""
const keyword = req.query.keyword || ""
//根据自定义的关键词,返回列表数据
return getList(author,keyword).then(res => {
//使用模型返回规范的文件格式
return new SuccessModel(res)
})
}
//获取接口详情
//新建接口
//更新博客路由
//删除博客路由
}
module.exports = handelBlogRoute
app.js
js
const handelBlogRoute = require("./src/routes/blog")
//node 原生的属性
const querystring = require("querystring")
//处理post数据
const getPostData = (req) => {
const promise = new Promise((resolve,reject) => {
if(req.method !== "POST"){
resolve({})
return
}
if(req.headers['conten-type'] !== 'application/json'){
resolve({})
return
}
let postData = ""
req.on('data',(chunk) => {
postData += chunk.toString()
})
req.on('end', ()=> {
if(!postData) {
resolve({})
return
}
resolve(
JSON.parse(postData)
)
})
})
return promise
}
//这里主要进行一些服务器的设置
const serverHandler = (req,res) => {
//设置返回的报文格式
res.setHeader('Content-Type',"application/json")
//获取path /api/blog/list
const url = req.url
req.path = url.split("?")[0]
//解析query
req.query = querystring.parse(url.split("?")[1])
//处理post数据
getPostData(req).then((postData) => {
//将post数据绑定在req的body上
req.body = postData
//路由匹配
let promiseBlogData = handelBlogRoute(req,res)
//返回内容
if(promiseBlogData){
promiseBlogData.then(promiseBlogData =>{
res.end(JSON.stringify(promiseBlogData))
})
return
}
//匹配不到路由时的处理
res.writeHead(404,{'Content-Type':'text/plain'})
res.write("404 Not FOund")
res.end()
})
}
module.exports = serverHandler
博客详情、新建博客对接Mysql
src\contrllers\blog.js新建博客
js
//创建新博客
const createNewBlog = (blogData = {}) => {
const title = blogData.title
const content = blogData.content
const author = blogData.author
const createdAt = Date.now()
const sql = `
insert into blogs (title, content ,author ,createdAt) values ('${title}', '${content}', '${author}', ${createdAt});
`
return execSQL(sql).then(res => {
console.log(res);
})
}
插入成功后的返回结果
因此,我们的更新博客和获取博客详情接口如下
src\contrllers\blog.js
js
//获取博客详情数据 通过id获取内容
const getDetail = (id) => {
let sql = `select * from blogs where id=${id} `
return execSQL(sql)
}
//创建新博客
const createNewBlog = (blogData = {}) => {
const title = blogData.title
const content = blogData.content
const author = blogData.author
const createdAt = Date.now()
const sql = `
insert into blogs (title, content ,author ,createdAt) values ('${title}', '${content}', '${author}', ${createdAt});
`
return execSQL(sql).then(res => {
return { id: res.insertId}
})
}
src\routes\blog.js
js
//获取接口详情 g根据id获取内容
if(method === "GET" && req.path === "/api/blog/detail"){
return getDetail(id).then( res => {
return new SuccessModel(res)
})
}
//新建接口
if(method === "POST" && req.path === "/api/blog/new"){
return createNewBlog(postData).then(res => {
return new SuccessModel(res)
})
}