首页 > 编程语言 >Node.js+Express+Koa2开发接口学习笔记(三)

Node.js+Express+Koa2开发接口学习笔记(三)

时间:2023-12-26 21:56:09浏览次数:46  
标签:Node req return mysql Express js sql const id

数据库操作(创建和增删查)

  • 使用Navicat快速创建myblog数据库
  • 创建表

pi1XR6s.png
pi1X2lj.png

使用navicat快速建表

pi0y6bV.png

pi0y429.png

  • 使用sql语句进行简单的查询
-- show tables; -- 显示该数据库中的所有表 

INSERT INTO users(username,`password`,realname) VALUES('zhangsan','123','张三') 
INSERT INTO users(username,`password`,realname) VALUES('lisi','123','李四') 
-- 往users表添加数据,其中`password`由于password是mysql的关键字所以需要加``

SELECT * FROM users -- 查询users的所有数据的所有列
SELECT id,username from users -- 查询users的所有数据的id和username列

SELECT * FROM users WHERE username = 'zhangsan' and `password` = '123' -- 使用where查询符合条件的数据,可以使用and 或者 or对多条件进行拼接

SELECT * FROM users WHERE username like '%zhang%' -- 使用like进行模糊查询

SELECT * FROM users WHERE username like '%zhang%' ORDER BY id;-- ORDER BY用于排序,默认是升序,如果是order by id DESC  则是根据id倒序

UPDATE users set realname = '李四2' WHERE username = 'lisi' -- update 更新语句,通常会和where一起使用
DELETE from users where username = 'lisi'; -- DELETE 删除语句,通常会和where一起使用,否则会把表中的所有数据删除,实际业务不会使用该语句进行删除,而是在表中添加一个删除标志进行软删除,好处是可以数据恢复
UPDATE users SET state = 0 WHERE username = 'lisi' -- 在表中添加一个删除标志 1为存在 0为删除
select * from users WHERE state = 1 -- 查询表中未被删除的所有数据 =1 可以写成 <> 0
SELECT VERSION() -- 可以查询mysql版本

Nodejs操作Mysql

安装插件

npm i mysql

编写代码

const mysql = require("mysql");

// 创建mysql连接
const con = mysql.createConnection({
  host: "localhost", 
  user: "root",
  password: "123456",
  port: 3306,
  database: "myblog",
});

// 开始连接
con.connect();
// 执行sql语句
// const sql = "select * from users;";
// const sql = `update users set realname = '李四2' where username = 'lisi'`;
const sql = `INSERT INTO blogs(title,content,createtime,author) VALUES ('标题C','内容C',1700988977111,'钱五')`;
con.query(sql, (err, result) => {
  if (err) {
    console.error(err);
    return;
  }
  console.log("result", result);
});
// 关闭连接
con.end();

nodejs链接mysql做成工具

上述代码仅仅是一个demo,如果需要放入项目中,由于开发环境和线上环境的mysql配置不一样,我们需要将上面代码封装成一个工具文件,保证开发环境和线上环境都可以适应使用。

创建conf文件夹,在里面创建db.js文件用来获取当前环境的mysql配置。

const env = process.env.NODE_ENV; //环境变量

// 配置
let MYSQL_CONF;

if (env === "dev") {
  MYSQL_CONF = {
    host: "localhost",
    user: "root",
    password: "123456",
    port: 3306,
    database: "myblog",
  };
}

if (env === "production") {
  MYSQL_CONF = {
    host: "localhost",
    user: "root",
    password: "123456",
    port: 3306,
    database: "myblog",
  };
}

module.exports = {
  MYSQL_CONF,
};

在package.json中,我们配置了dev和prod命令用来开发运行和线上运行,通过nodejs的process可以获取到程序进程的环境变量为开发环境还是为线上环境。

"dev": "cross-env NODE_ENV=dev nodemon ./bin/www.js",
"prod": "cross-env NODE_ENV=production nodemon ./bin/www.js"

接着创建db文件夹,在里面创建mysql.js用来创建链接mysql的对象,并对外提供一个可以统一执行sql的函数

const mysql = require("mysql");
const { MYSQL_CONF } = require("../conf/db");

// 创建链接对象
const con = mysql.createConnection(MYSQL_CONF);

// 开始链接
con.connect();

// 统一执行sql的函数
function exec(sql) {
  const promise = new Promise((resolve, reject) => {
    con.query(sql, (err, result) => {
      if (err) {
        reject(err);
        return;
      }
      resolve(result);
    });
  });
  return promise;
}
module.exports = {
  exec,
};

API对接mysql(博客列表)

链接了数据库后,之前API返回的假数据都可以通过mysql查询语句返回结果,需要注意的是封装的sql执行函数返回的结果是一个promise对象,所以在controller和router文件夹都需要进行改动。

controller->blog.js

const { exec } = 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}%' `;
  }
  sql += `order by createtime desc`;
  // 返回promise
  return exec(sql);
};

router->blog.js

  // 获取博客列表
  if (method === "GET" && req.path === "/api/blog/list") {
    const author = req.query.author || "";
    const keyword = req.query.keyword || "";
    // const listData = getList(author, keyword);
    // return new SuccessModel(listData);
    const result = getList(author, keyword);
    return result.then((listData) => {
      return new SuccessModel(listData);
    });
  }

由于路由文件返回的也是个promise对象,所以在app,js也需要对返回的数据进行处理

const serverHandle = (req, res) => {
  // 设置返回格式 JSON
  res.setHeader("Content-type", "application/json");

  // 获取path
  const url = req.url;
  req.path = url.split("?")[0];

  // 解析query
  req.query = querystring.parse(url.split("?")[1]);

  //处理post data
  getPostData(req).then((postData) => {
    req.body = postData;
    // 处理blob路由
    // const blogData = handleBlogRouter(req, res);
    // if (blogData) {
    //   res.end(JSON.stringify(blogData));
    //   return;
    // }

    const blogResult = handleBlogRouter(req, res);
    if (blogResult) {
      blogResult.then((blogData) => {
        res.end(JSON.stringify(blogData));
      });
      return;
    }

    // 处理user路由
    const userData = handleUserRouter(req, res);
    if (userData) {
      res.end(JSON.stringify(userData));
      return;
    }
    // 未命中路由,返回404,同时将返回格式修改为纯文本
    res.writeHead(404, { "Content-type": "text/plain" });
    res.write("404 NOT FOUND\n");
    res.end();
  });
};

此时访问服务器http://localhost:8000/api/blog/list可以看到查询列表成功

API对接mysql(博客详情和新建)

获取博客详情: http://localhost:8000/api/blog/detail?id=2

// controller->blog.js
const getDetail = (id) => {
  const sql = `select * from blogs where id ='${id}' `;
  return exec(sql).then((rows) => {
    return rows[0];
  });
};

//router->blog.js
// 获取博客详情
if (method === "GET" && req.path === "/api/blog/detail") {
  // const detailData = getDetail(id);
  // return new SuccessModel(detailData);
  const result = getDetail(id);
  return result.then((data) => {
    return new SuccessModel(data);
  });
}

新建博客:

//controller->blog.js
const newBlog = (blogData = {}) => {
  // blogData是一个博客对象,包含title content author属性
  const title = blogData.title;
  const content = blogData.content;
  const author = blogData.author;
  const createTime = Date.now();

  const sql = `
    insert into blogs (title,content,createtime,author)
    values ('${title}','${content}',${createTime},'${author}');
  `;
  return exec(sql).then((insertData) => {
    console.log("insertData is ", insertData);
    return {
      id: insertData.insertId,
    };
  });
};

//router->blog.js
// 新建一篇博客
if (method === "POST" && req.path === "/api/blog/new") {
  // const data = newBlog(req.body);
  // return new SuccessModel(data);
  const author = "zhangsan"; // 假数据,待开发登录时再改成真实数据
  req.body.author = author;
  const result = newBlog(req.body);
  return result.then((data) => {
     return new SuccessModel(data);
  });
}

打开postman或者其他API调试工具,http://localhost:8000/api/blog/new,创建新博客。

API对接mysql(博客更新和删除)

更新博客:http://localhost:8000/api/blog/update?id=3 填写body参数

//controller->blog.js
const updateBlog = (id, blogData = {}) => {
  // id就是要更新博客的id
  // blogData是一个博客对象,包含title content属性
  const title = blogData.title;
  const content = blogData.content;
  const sql = `
    update blogs set title='${title}',content='${content}' where id=${id}
  `;
  return exec(sql).then((updateData) => {
    if (updateData.affectedRows > 0) {
      return true;
    }
    return false;
  });
};

//router->blog.js
// 更新一篇博客
if (method === "POST" && req.path === "/api/blog/update") {
   const result = updateBlog(id, req.body);
   return result.then((val) => {
     if (val) {
       return new SuccessModel("更新博客成功");
     } else {
       return new ErrorModel("更新博客失败");
     }
});

删除博客:http://localhost:8000/api/blog/del?id=8&&author=zhangsan

传入author参数是为了确保别人无法删除其他人的文章

//controller->blog.js
const delBlog = (id, author) => {
  // id 就是要删除博客的id
  const sql = `
    delete from blogs where id=${id} and author = '${author}'
  `;
  return exec(sql).then((delData) => {
    if (delData.affectedRows > 0) {
      return true;
    }
    return false;
  });
};
//router->blog.js
// 删除博客
if (method === "POST" && req.path === "/api/blog/del") {
   const author = "zhangsan"; // 假数据,待开发登录时再改成真实数据
   const result = delBlog(id, author);
   console.log("result", result);
   return result.then((val) => {
     if (val) {
       return new SuccessModel();
     } else {
        return new ErrorModel("删除博客失败");
     }
   });
}

API对接mysql(登录)

controller->user.js

const { exec } = require("../db/mysql");
const loginCheck = ({ username, password }) => {
  const sql = `
    select username,realname from users where username='${username}' and password='${password}'
  `;
  return exec(sql).then((rows) => {
    return rows[0] || {};
  });
};
module.exports = {
  loginCheck,
};

router->user.js

const { loginCheck } = require("../controller/user");
const { SuccessModel, ErrorModel } = require("../model/resModel");
const handleUserRouter = (req, res) => {
  const method = req.method; // GET POST

  // 登录
  if (method === "POST" && req.path === "/api/user/login") {
    const result = loginCheck(req.body);
    return result.then((data) => {
      if (data.username) {
        return new SuccessModel();
      }
      return new ErrorModel("登录失败");
    });
  }
};
module.exports = handleUserRouter;

同样地还需要修改app.js里对于user路由的处理

    // 处理user路由
    // const userData = handleUserRouter(req, res);
    // if (userData) {
    //   res.end(JSON.stringify(userData));
    //   return;
    // }

    const userResult = handleUserRouter(req, res);
    if (userResult) {
      userResult.then((userData) => {
        res.end(JSON.stringify(userData));
      });
      return;
    }

总结

①使用nodejs链接mysql,执行sql语句

②根据NODE_ENV区分当前环境的mysql配置

③封装exec函数,APi使用exec函数操作数据库

源码:https://github.com/DaneOvO/Nodejs-Express-Koa2-Learning/tree/learning-three

标签:Node,req,return,mysql,Express,js,sql,const,id
From: https://www.cnblogs.com/Small-Windmill/p/17929448.html

相关文章

  • Python+Selenium4自动化之JS属性
     应用场景在自动化中,能对JS代码进行增、删、改的话,可以帮助我们解决很多问题,如:修改<a>标签的target属性,让它不打开新的窗口(_blank),从而不用频繁使用switch_to进行窗口之间的切换。如:日期的输入框被锁定无法直接输入,需要点开日历控件后,从日历控件上点击日期,这时就可以删除......
  • P5333 [JSOI2019] 神经网络
    题面传送门本来以为\(m\)这么小是\(m\sumk_i\logk\)的NTT的,写完发现一点不用(首先我们发现,这样的图上面的一个哈密顿回路可以表示成原森林若干条链,每个点都在其中一条链上,且相邻两条链不在同一棵树上。先跑一个DP把\(f_{i,j}\)表示用\(j\)条链覆盖\(i\)的方案数......
  • 记录--工程化第一步这个package.json要真的搞明白才行
    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助工程化最开始就是package.json开始的,很多人学了很多年也没搞清楚这个为什么这么神奇,其实有些字段是在特定场景才有效的,那每个属性的适用场景和作用是什么,又牵扯很多知识点,今天先解读一些常见的属性,关注我,后期在遇到......
  • html jquery from 表单提交 application/x-www-form-urlencoded 改成 json
    htmljqueryfrom表单提交$(form).ajaxSubmitapplication/x-www-form-urlencoded改成json<formclass="formform-horizontal"id="form-admin-add"><divclass="rowcl"><labelclass="form-labelcol-xs-4col-......
  • vs 使用 jsonschema
    使用jsonschema限制json配置文件内容vs配置文件中,添加\(schema,映射对应的json文件,此文件可以根据现有json文件通过工具生成基础的内容"\)schema":"http://127.0.0.1/webapibase.json",jsonschema文档https://json-schema.apifox.cn/工具https://hellosean1025.gith......
  • Voc2Json--挑选voc中的类别生成json文件
      importargparseimportjson,shutilimportos,sysimportxml.etree.ElementTreeasETparent=os.path.dirname(os.path.realpath(__file__))gadent=os.path.dirname(parent)sys.path.insert(0,gadent)sys.path.append(gadent)fromutils.toolimportlis......
  • JS判断数据类型的9种方法
    JS的数据类型检测是一道经典的八股文面试题。相信大家都能条件反射的回答出4种方法:typeof、constructor、instanceof和Object.prototype.toString,并且对它们各自的优缺点也是张口就来。本文对这些方法做了简单归纳,同时又补充了其他5种和数据类型检测有关的方法,供诸君食用。t......
  • js 把对象存入数组中
    js把对象存入数组中  varparams=[];varinfo={"张三":"21","李四":"32","王五":"14","小红":"31","小兰":"24",......
  • java爬虫(jsoup)如何设置HTTP代理ip爬数据
    前言在Java中使用Jsoup进行网络爬虫操作时,有时需要使用HTTP代理IP来爬取数据。本文将介绍如何使用Jsoup设置HTTP代理IP进行爬取,并提供相关代码示例。什么是HTTP代理IPHTTP代理IP是一种允许我们通过代理服务器访问互联网的方式。一般情况下,我们访问网站时,直接使用自己的IP地址进行通......
  • 无涯教程-Java9 - JShell(REPL)
    REPL代表"Read-Eval-PrintLoop"。使用JShell,java具有REPL函数。使用REPL,无涯教程可以对基于Java的逻辑进行编码和测试,而无需使用javac进行编译,并且可以直接查看计算输出。运行JShell打开命令提示符,然后键入jshell。$jshell|WelcometoJShell--Version9-ea|Forani......