В этой статье мы будем использовать Nodejs для подключения к Mysql и реализации основных операций CRUD.
Основные технические моменты следующего примера кода включают
- базовая структура
- Koa
- Koa-router
- koa-nunjucks-2
- Пакет подключения MySQL
- mysqljs
Студенты, не знакомые с Mysql, могут обратиться к этой статье.Поиграйте с mysql на фронтэнде
0. Предпосылки
- Установите базу данных mysql и запустите
- Установите Nodejs (это не должно быть проблемой)
1. Узел подключается к базе данных
- Создать пустую папку
- воплощать в жизнь
yarn add koa koa-router mysql
- Создайте файл js (test.js) в корневом каталоге, чтобы проверить подключение к операции с базой данных.
- Сначала пишем кусок кода в test.js, выводим hello, чтобы программа запуска не сообщала об ошибках
const Koa = require("koa") // 导入koa const Router = require("koa-router") //导入koa-router const mysql = require("mysql") // 导入mysql,连接mysql 需要用到 const app = new Koa(); // 实例化koa const router = new Router(); // 实例化路由 // 创建一个路径为/hello的get请求 router.get("/hello", async ctx => { // 返回 字符串 hello ctx.body = "hello" }) // koa注册路由相关 app .use(router.routes()) .use(router.allowedMethods()) // 监听端口 .listen(3333,()=>{ console.log("server running port:" + 3333); })
- Выполнить в корневом каталоге проекта
node test.js
илиnodemon test.js
Стартовый проект - использовать
nodemon
Для запуска проекта требуется глобальная установкаyarn global add nodemon
илиnpm i -g nodemon
- использовать
nodemon
Стартовый проект,nodemon
Будет следить за файлами в каталоге запуска, и если какой-либо файл изменится,nodemon
автоматически перезапустит приложение узла, настоятельно рекомендуетсяnodemon
запустить проект узла - После запуска проекта входим в браузер
http://localhost:3333/hello
, вы можете увидеть выходной текст hello на странице
- После появления этого интерфейса это доказывает, что с запуском нашего проекта проблем нет.
- Далее мы используем узел для подключения к базе данных mysql.
- Выполнить в корневом каталоге проекта
- Сначала мы готовим волну данных
CREATE DATABASE db1; USE db1; CREATE TABLE user ( id INT PRIMARY KEY auto_increment, NAME VARCHAR(20) NOT NULL, age INT NOT NULL ); INSERT INTO user VALUES (null, "张三", 23), (null, "李四", 24), (null, "王五", 25), (null, "赵六", 26);
2. Подключитесь к базе данных mysql, чтобы реализовать функцию отображения таблицы.
-
Далее пишем код для подключения к mysql в test.js
const Koa = require("koa") // 导入koa const Router = require("koa-router") //导入koa-router const mysql = require("mysql") // 导入mysql,连接mysql 需要用到 const app = new Koa(); // 实例化koa const router = new Router(); -- 实例化路由 // mysqljs 连接 mysql数据库 let connection = mysql.createConnection({ host: '127.0.0.1', // mysql所在的主机,本地的话就是 127.0.0.1 或者 localhost, 如果数据库在服务器上,就写服务器的ip user: 'root', // mysql的用户名 password: '密码', // mysql的密码 database: 'db1' // 你要连接那个数据库 }) // 连接 mysql connection.connect(err=>{ // err代表失败 if(err) { console.log("数据库初始化失败"); }else { console.log("数据库初始化成功"); } }) // 创建一个路径为/hello的get请求 router.get("/hello", async ctx => { // 返回 字符串 hello ctx.body = "hello" }) // koa注册路由相关 app .use(router.routes()) .use(router.allowedMethods()) // 监听端口 .listen(3333,()=>{ console.log("server running port:" + 3333); })
- когда терминал выдает
数据库初始化成功
Текст означает, что подключение к базе данных прошло успешно. - Только что мы подготовили четыре фрагмента данных в базе данных db1, затем мы можем запросить данные и отобразить их на консоли.
- когда терминал выдает
-
Мы добавляем этот код запроса в метод connection.connect
-
Первый параметр метода connection.query — это строка типа
sql
Оператор, второй параметр является необязательным, как будет сказано далее, последний является методом, который содержит информацию об ошибке и данные о правильном ответеconst selectSql = "SELECT * FROM user" connection.query(selectSql, (err,res) => { if(err) console.log(err); console.log(res); })
-
-
Возвращаемые данные такие
- На данный момент данные в базе данных были запрошены, после чего мы можем вернуть данные во внешний интерфейс в формате JSON.
-
Верните данные в браузер в формате JSON, добавив этот код
// 因为 mysqljs不支持 Promise方式CRUD数据 // 所以我们做一个简单的封装 function resDb(sql) { return new Promise((resolve,reject) => { connection.query(sql, (err,res) => { if(err) { reject(err) }else { resolve(res) } }) }) } //请求 /userAll 的时候返回数据 router.get("/userAll", async ctx => { ctx.body = await resDb("SELECT * FROM user") })
- Вот эти данные то что нам нужно, ээээээ, данные возвращаются, делаем фронтенд, как тут не быть страницы, сначала добавить табличную страницу для отображения данных, вот
nunjucks
Движок шаблонов, давайте сначала установим егоyarn add koa-nunjucks-2
- Вот эти данные то что нам нужно, ээээээ, данные возвращаются, делаем фронтенд, как тут не быть страницы, сначала добавить табличную страницу для отображения данных, вот
-
Добавьте этот код в test.js
const koaNunjucks = require('koa-nunjucks-2'); const path = require('path'); // 注入 nunjucks 模板引擎 app.use(koaNunjucks({ ext: 'html', // html文件的后缀名 path: path.join(__dirname, 'views'), // 视图文件放在哪个文件夹下 nunjucksConfig: { trimBlocks: true // 自动去除 block/tag 后面的换行符 } })); //在 /userAll这个路由中我们不直接返回数据了,我们返回table.html页面 router.get("/userAll", async ctx => { const userAll = await resDb("SELECT * FROM user") await ctx.render("table",{userAll}) })
-
Через механизм шаблонов nunjucks мы помещаем все файлы html в папку представлений корневого каталога, затем нам нужно создать папку представлений в корневом каталоге и создать в папке файл table.html, код файла такой следует
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> .table{ width: 500px; } td{ text-align: center; } </style> </head> <body> <table class="table" border="1" cellspacing="0"> <thead> <tr> <th>id</th> <th>姓名</th> <th>年龄</th> </tr> </thead> <tbody> {% for user in userAll %} <tr > <td>{{user.id}}</td> <td>{{user.NAME}}</td> <td>{{user.age}}</td> </tr> {% endfor %} </tbody> </table> </body> </html>
Доступ после перезапуска сервера
http://localhost:3333/userAll
После того, как эта страница выйдет, часть отображения будет готова. -
Функция запроса завершена, и теперь мы можем реализовать новую функцию.
3. Добавьте данные в базу данных mysql
-
Давайте сначала закончим писать дополнительную часть страницы table.html.
<form action="/addUser"> <label for="name"> 用户名: <input type="text" name="name" placeholder="请输入用户名"> </label> <label for="age"> 年龄: <input type="number" name="age" min="0" placeholder="请输入年龄"> </label> <input type="submit" value="添加"> </form>
-
На этот раз страница выглядит так
-
После того как мы введем логин и возраст и нажмем кнопку добавить, браузер отправит данные на
/addUser
Далее в этом маршруте мы получаем параметры, переданные из внешнего интерфейса в test.js, и сохраняем параметры в базе данных. затем обновите страницу//请求 /addUser 接受前端传过来的数据,并且把数据持久化到数据库中 router.get("/addUser", async ctx => { const { name, age } = ctx.query // 判断 name 和 age是否有值,都有值时,数据存入数据库,刷新表格页面 // 否则直接返回到表格页面 if(name && age) { await resDb("INSERT INTO user values(null,?,?)",[name, age]) } //重定向路由,到 userAll ctx.redirect("/userAll") })
-
Улучшить
resDb
надежность, мы обновили этот методfunction resDb(sql, params) { return new Promise((resolve,reject) => { let sqlParamsList = [sql] if(params) { sqlParamsList.push(params) } connection.query(...sqlParamsList, (err,res) => { if(err) { reject(err) }else { resolve(res) } }) }) }
-
Этот способ после апгрейда подходит для промиса CRUD, о функциях модификации и удаления мы, конечно же, поговорим ниже.
-
На данный момент наша новая функция завершена, тогда давайте взглянем на волну скриншотов и разберемся в логике
4. Обновить данные по id
-
Для обновления фронтальной части данных мы не будем писать модальное окно, а напрямую напишем аналогичную новую форму для реализации операции обновления.На самом деле новая и обновленная функции очень похожи, разница только в способе написания sql
-
Давайте сначала преобразуем страницу table.html
<form action="/updateUser"> <label for="id"> id: <input type="number" name="id" placeholder="请输入要更新的ID"> </label> <label for="name"> 用户名: <input type="text" name="name" placeholder="请输入用户名"> </label> <label for="age"> 年龄: <input type="number" name="age" min="0" placeholder="请输入年龄"> </label> <input type="submit" value="修改"> </form>
-
Давайте посмотрим на код за кулисами
//请求 /updateUser 接受前端传过来的数据,并且把数据持久化到数据库中 router.get("/updateUser", async ctx => { const { id, name, age } = ctx.query // 判断 id, name 和 age是否有值,都有值时,更新数据库中的数据,刷新表格页面 // 否则直接返回到表格页面 if(id, name && age) { await resDb("UPDATE user SET name=?, age=? WHERE id=?",[name, age, id]) } //重定向路由,到 userAll ctx.redirect("/userAll") })
-
Логика кода такая же, как и логика новой части,
-
Я только что писал новый и обновленный код sql, вы увидите, что в нем есть операторы sql.
?
заполнитель, второй массив параметров?
Содержимое, соответствующее заполнителю. Так что на этот раз у всех точно возникнет такой вопрос, а почему бы нам напрямую не прописать параметры, переданные из фронтенда. Это должно быть так хлопотно. -
На самом деле это написано в виде заполнителей
sql
состоит в том, чтобы предотвратитьsql注入
,Связанныйsql注入
Вы можете обратиться к этой статьеПринцип и предотвращение SQL-инъекций
5. Удалить один фрагмент данных по идентификатору
-
Старые правила, давайте сначала преобразуем страницу table.html
<table class="table" border="1" cellspacing="0"> <thead> <tr> <th>id</th> <th>姓名</th> <th>年龄</th> <th>操作</th> </tr> </thead> <tbody> {% for user in userAll %} <tr > <td>{{user.id}}</td> <td>{{user.NAME}}</td> <td>{{user.age}}</td> <td> <a href={{'/delete/'+user.id}}>删除</a> </td> </tr> {% endfor %} </tbody> </table>
-
Посмотрите на эффект страницы
-
Старые правила, давайте посмотрим на код в фоновом режиме
//请求/delete/:id 接受前端传过来的数据,并且把对应的id的数据删掉 router.get("/delete/:id", async ctx => { const { id } = ctx.params // 判断 id否有值,有值时,根据id删除数据库中的数据,刷新表格页面 // 否则直接返回到表格页面 if(id) { await resDb("DELETE FROM user WHERE id=?",[id]) } //重定向路由,到 userAll ctx.redirect("/userAll") })
-
Пока что написаны добавления, удаления, ревизии (CRUD) таблицы.
6. Полный код
- Структура каталогов
- package.json
{ "koa": "^2.13.1", "koa-nunjucks-2": "^3.0.2", "koa-router": "^10.0.0", "mysql": "^2.18.1" }
- test.js
const Koa = require("koa")
const Router = require("koa-router")
const mysql = require("mysql")
const koaNunjucks = require('koa-nunjucks-2');
const path = require('path');
const app = new Koa();
const router = new Router();
// mysqljs 连接 mysql数据库
let connection = mysql.createConnection({
host: '127.0.0.1', // mysql所在的主机,本地的话就是 127.0.0.1 或者 localhost, 如果数据库在服务器上,就写服务器的ip
user: 'root', // mysql的用户名 默认root
password: 'mysql密码', // mysql的密码
database: 'db1' // 你要连接那个数据库
})
// 连接 mysql
connection.connect(err=>{
// err代表失败
if(err) {
console.log("数据库初始化失败");
}else {
console.log("数据库初始化成功");
}
})
// 因为 mysqljs不支持 Promise方式CRUD数据
// 所以我们做一个简单的封装
function resDb(sql, params) {
return new Promise((resolve,reject) => {
let sqlParamsList = [sql]
if(params) {
sqlParamsList.push(params)
}
connection.query(...sqlParamsList, (err,res) => {
if(err) {
reject(err)
}else {
resolve(res)
}
})
})
}
// 注入 nunjucks 模板引擎
app.use(koaNunjucks({
ext: 'html', // html文件的后缀名
path: path.join(__dirname, 'views'), // 视图文件放在哪个文件夹下
nunjucksConfig: {
trimBlocks: true // 自动去除 block/tag 后面的换行符
}
}));
//请求 /userAll 的时候返回数据
router.get("/userAll", async ctx => {
const userAll = await resDb("SELECT * FROM user")
await ctx.render("table",{userAll})
})
//请求 /addUser 接受前端传过来的数据,并且把数据持久化到数据库中
router.get("/addUser", async ctx => {
const { name, age } = ctx.query
// 判断 name 和 age是否有值,都有值时,数据存入数据库,刷新表格页面
// 否则直接返回到表格页面
if(name && age) {
await resDb("INSERT INTO user values(null,?,?)",[name, age])
}
//重定向路由,到 userAll
ctx.redirect("/userAll")
})
//请求 /updateUser 接受前端传过来的数据,并且把数据持久化到数据库中
router.get("/updateUser", async ctx => {
const { id, name, age } = ctx.query
// 判断 id, name 和 age是否有值,都有值时,更新数据库中的数据,刷新表格页面
// 否则直接返回到表格页面
if(id, name && age) {
await resDb("UPDATE user SET name=?, age=? WHERE id=?",[name, age, id])
}
//重定向路由,到 userAll
ctx.redirect("/userAll")
})
//请求/delete/:id 接受前端传过来的数据,并且把对应的id的数据删掉
router.get("/delete/:id", async ctx => {
const { id } = ctx.params
// 判断 id否有值,有值时,根据id删除数据库中的数据,刷新表格页面
// 否则直接返回到表格页面
if(id) {
await resDb("DELETE FROM user WHERE id=?",[id])
}
//重定向路由,到 userAll
ctx.redirect("/userAll")
})
//测试代码
router.get("/hello", ctx => {
ctx.body = "hello"
})
app
.use(router.routes())
.use(router.allowedMethods())
.listen(3333,()=>{
console.log("server running port:" + 3333);
})
-
views/table.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> .table { width: 500px; } td { text-align: center; } </style> </head> <body> <form action="/addUser" autocomplete="off"> <label for="name"> 用户名: <input type="text" name="name" placeholder="请输入用户名"> </label> <label for="age"> 年龄: <input type="number" name="age" min="0" placeholder="请输入年龄"> </label> <input type="submit" value="添加"> </form> <form action="/updateUser" autocomplete="off"> <label for="id"> id: <input type="number" name="id" placeholder="请输入要更新的ID"> </label> <label for="name"> 用户名: <input type="text" name="name" placeholder="请输入用户名"> </label> <label for="age"> 年龄: <input type="number" name="age" min="0" placeholder="请输入年龄"> </label> <input type="submit" value="修改"> </form> <table class="table" border="1" cellspacing="0"> <thead> <tr> <th>id</th> <th>姓名</th> <th>年龄</th> <th>操作</th> </tr> </thead> <tbody> {% for user in userAll %} <tr> <td>{{user.id}}</td> <td>{{user.NAME}}</td> <td>{{user.age}}</td> <td> <a href={{'/delete/'+user.id}}>删除</a> </td> </tr> {% endfor %} </tbody> </table> </body> </html>
7. Пишите в конце
- Когда вы это видите, во-первых, вы очень настойчивый человек.В этой статье нет иллюстраций.Все это реализация кода и скриншоты страниц.Если вы видите это от начала до конца, поставьте себе лайк.
- В этой статье подробно рассказывается, как nodejs подключается к базе данных mysql и реализует механизм шаблонов на основе
增删改查
функцию, и просто сделать промис-пакет для результата, возвращаемого базой данных, а также ввести соответствующие плагины, используемые в koa и его экземплярах