Node-Express数据库增删改查接口

举报
林太白 发表于 2024/11/22 09:41:17 2024/11/22
【摘要】 Node-Express数据库增删改查接口

1、前置知识

🍓认识接口

认识Node.js RESTful API接口

接下来我们先认识一些前置知识,看看Node.js里面的RESTful API是什么,如何帮助我们实现接口的

以下为REST基本架构的四个方法:

  • GET - 用于获取数据
  • PUT - 用于更新或添加数据
  • DELETE - 用于删除数据
  • POST - 用于添加数据

注:get和delete是在路径中传递数据,而post和put可以在request body中传递数据

🍓req.query  req.params的区别

req.query  req.params是 Express 框架中用于从 HTTP 请求中获取参数的两种常见方式。它们的区别在于获取参数的方式和用途不同。

  1. req.query
    • req.query 是 Express 中的一个对象,用于获取 URL 查询参数(即 URL 中以 ? 开头的参数),通常用于 GET 请求。
    • 它会将 URL 查询参数解析成一个对象,其中键值对分别对应参数的名称和值。
    • 在路由处理函数中,可以通过 req.query 直接访问这个对象,从而获取请求中的查询参数。

// 示例 URL:http://example.com/api/users?name=John&age=30
console.log(req.query);
// 输出:{ name: 'John', age: '30' }
  1. req.params
    • req.params 是 Express 中的一个对象,用于获取路由参数,通常用于动态路由。
    • 在定义路由时,通过在路由路径中使用冒号(:)定义参数,这些参数会被 Express 解析并放入 req.params 中。
    • 这种方式适用于从 URL 中获取动态部分,例如用户 ID 或者其他标识符。

// 示例路由:/api/users/:id
console.log(req.params.id);
// 输出:用户ID
  1. 区别和用途
    • req.query 用于获取 URL 查询参数,适用于获取客户端通过 URL 传递的数据。
    • req.params 用于获取路由参数,适用于获取客户端通过 URL 路径中的动态部分传递的数据。
    • 通常,如果参数是作为查询字符串出现在 URL 中,使用 req.query;如果参数是作为路由的一部分出现在 URL 中,使用 req.params

总之,req.query  req.params 分别用于获取不同类型的客户端传递的数据,具体根据请求中参数的形式来选择使用哪种方式

因为我这里采用的直接获取用户详情肯定是一个id,所以采用的就是req.params这种方式


node5-18.png



2、查询用户列表

接下来我们写一个查询用户列表的接口(/api/user--通过get查询的方式)

之前我们采用Node连接数据库并查询数据,现在我们使用本地的axios进行请求数据 本地进行调用


// 获取用户
function getUserList(row) { 
    axios.get('http://localhost:8888/api/user').then(res => {
         console.log(res, '/user/list');
        if (res.status == 200) {
             console.log(res,'res');
             tableData.value = res.data.data;
        }
    })
}

突然发现报错了:


node4-1.png



分析报错我们发现是由于跨域访问引起的,前端设置允许跨域 在app.js之中添加这段代码


app.all('*', function (req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
    res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
    res.header("X-Powered-By", ' 3.2.1')
    res.header("Content-Type", "application/json;charset=utf-8");
    next();
});

app.js完整过程如下:


const connection = mysql.createPool({
  host: 'localhost', // 数据库主机地址,如果是本地数据库则使用localhost
  user: 'root', // 数据库用户名
  password: '', // 数据库密码
  database: 'nexus' // 要连接的数据库名
});

const app = express();
//设置跨域访问
app.all('*', function (req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
    res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
    res.header("X-Powered-By", ' 3.2.1')
    res.header("Content-Type", "application/json;charset=utf-8");
    next();
});

app.get('/', (req, res) => {
  res.send('林太白数据库!');
});


// 创建路由
app.get('/api/user/list', (req, res) => {
  // 查询数据库并返回数据
  connection.query('SELECT * FROM user', (err, results) => {
    console.log(err,'err');
    console.log(results,'results');
    if (err) {
      console.error('Error querying database:', err);
      res.status(500).json({ error: 'Internal server error' });
      return;
    }
    res.json({
      code:'200',
      data:results,
    });
    // res.json(results);
  });
});

重启服务器:

node app.js


node4-2.png



查询成功!


node4-3.png



3、增加用户

增加用户接口(/api/user--post新增 )

Mysql增加用户操作命令为


INSERT INTO user (name,sex) VALUES ('张三',1)

执行命令我们已经将数据添加进入数据库之中。


node4-4.png



接下来我们在我们的Node里面进行一下添加

Sql的插入语句为:
`INSERT INTO user (name, age) VALUES (?, ?)`

那我们手写的POST增加用户请求处理就是


// 新增用户 POST 请求处理程序 
app.post('/api/user', (req, res) => {
  console.log(req.body);
  const { name, age } = req.body; // 从请求体中获取数据
  const values = [name, age];
  // 准备 SQL 插入语句
  const insertSql = `INSERT INTO user (name, age) VALUES (?, ?)`;
  connection.query(insertSql, values, (err, results) => {
    console.log(err,'err');
    console.log(results,'results');
    if (err) {
      console.error('Error querying database:', err);
      res.status(500).json({ error: 'Internal server error' });
      return;
    }
    res.json({
      code:'200',
      data:results,
    });
  });
});


node4-5.png



增加用户成功!

4、修改用户

修改用户信息,然后提交修改(/api/user--put修改 )

Mysql更改用户操作命令为


UPDATE user SET name = '可爱', age = 18 WHERE id = 12

查看我们的sql数据库,数据库已经更改成功!


node4-6.png



使用axios之中的put方法提交更改的数据,用户有ID的时候根据id进行更改 更新用户数据 PUT请求处理程序


// 更新用户数据 PUT请求处理程序 
app.put('/api/user', (req, res) => {
  console.log(req.body);
  const { name, age ,id} = req.body; // 从请求体中获取数据
  const values = [name, age, id];
  // 准备 SQL 插入语句
  const sql = "UPDATE user SET name = ?, age = ? WHERE id = ?";
  connection.query(sql, values, (err, results) => {
    console.log(err,'err');
    console.log(results,'results');
    if (err) {
      console.error('Error querying database:', err);
      res.status(500).json({ error: 'Internal server error' });
      return;
    }
    res.json({
      code:'200',
      data:results,
    });
  });
});

数据已经更改成功!


node4-7.png



到这里我们已经实现了增改查,接下来下一节就是针对我们的删除进行处理。

5、删除用户

操作本地数据库实现删除用户

前置知识

注:get和delete是在路径中传递数据,而post和put可以在request body中传递数据

删除用户信息,我们也是使用这个接口来进行删除(/api/user--delete 删除)

(1)数据库语句

先试试数据库的删除语句,删除id为8的数据


DELETE FROM user WHERE id = 8


node5-1.png



id为8的数据我们已经删除成功!


node5-2.png



(2)手写删除方法

接下来我们手写我们的删除 先在node之中手写我们的删除delete方法


// 删除用户数据 DELETE请求处理程序  
app.delete('/api/user', (req, res) => {
  const {id} = req.body; // 从请求体中获取数据
  const values = [ id];
  const sql = "DELETE FROM user WHERE id = ?";
  connection.query(sql, values, (err, results) => {
    console.log(err,'err');
    console.log(results,'results');
    if (err) {
      console.error('Error querying database:', err);
      res.status(500).json({ error: 'Internal server error' });
      return;
    }
    res.json({
      code:'200',
      data:results,
    });
  });
});

(3)axio请求删除数据

接下来拿axio请求删除数据


node5-3.png



根据id来删除用户is为5的数据


// 删除用户信息
function handleDelete(row) {
    console.log(row, '删除');
    let id=row.id;
    let api = "http://localhost:8888/api/user";
    let data={id:row.id};

    console.log(row.id,'row.id');
    axios.delete(api,data).then(res => {
        if (res.status == 200) {
            console.log(res, 'res');
            centerDialogVisible.value = false;
        }
   })
}

点击删除以后删除成功,然后我们刷新数据库数据。


node5-4.png



我们的删除成功了,但是数据却依然存在,这是什么原因呢?


node5-5.png



查看node控制台输出我们可以发现,原来我们压根没有拿到用户的id



node5-6.png





这就需要提到我们一开始上面警示语句: 

注:get和delete是在路径中传递数据,而post和put可以在request body中传递数据

(4)优化删除

那我们尝试将用户的id放到我们的地址上试试,node删除方法就更改为:


// 删除用户数据 DELETE请求处理程序  
app.delete('/api/user/:id', (req, res) => {
  const {id} = req.body; // 从请求体中获取数据
  const values = [id];

  const userId = req.params.id;
  console.log(userId,'userId');

  const sql = "DELETE FROM user WHERE id = ?";
  connection.query(sql, values, (err, results) => {
    console.log(err,'err');
    console.log(results,'results');
    if (err) {
      console.error('Error querying database:', err);
      res.status(500).json({ error: 'Internal server error' });
      return;
    }
    res.json({
      code:'200',
      data:results,
    });
  });
});

再来调用我们的删除


// 删除用户数据 DELETE请求处理程序  
app.delete('/api/user/:id', (req, res) => {
  const id = req.params.id;
  const values = [id];
  const sql = "DELETE FROM user WHERE id = ?";
  connection.query(sql, values, (err, results) => {
    console.log(err,'err');
    console.log(results,'results');
    if (err) {
      console.error('Error querying database:', err);
      res.status(500).json({ error: 'Internal server error' });
      return;
    }
    res.json({
      code:'200',
      data:results,
    });
  });
});

请求发现我们地址已经成为了 http://localhost:8888/api/user/5 刷新数据库,果然我们删除已经成功了!


node5-7.png



到这里我们已经实现了增删改查,接下来下一节就是插入一些额外针对我们的增删改查进行优化和处理。

6、用户详情接口

根据用户ID查询用户详细信息

接下来我们做一个修改,但是之前要根据用户的iD做一个查询然后回显用户的详情数据


node5-12.png



先试试我们的sql查询语句:


SELECT * FROM user WHERE id = 13

查询结果没问题,接下来我们以地址的方式携带参数到get请求的最后: 最后的查询地址就是:http://localhost:8888/api/user/3

3是查询的用户 id


node5-13.png



我们的查询用户详情接口如下图:


// 查询用户详情 3
app.get('/api/user/:id', (req, res) => {
  console.log(req.query,'req.query');
  const { id } = req.query;
  const values =[id];
  let query = 'SELECT * FROM user WHERE id = ?';
  connection.query(query,values,(err, results) => {
    console.log(err,'err');
    // console.log(results,'results');
    if (err) {
      console.error('Error querying database:', err);
      res.status(500).json({ error: 'Internal server error' });
      return;
    }
    res.json({
      code:'200',
      data:results,
    });
  });
});

查询id为3 的,这边我们可以看到数据库是存在数据的,但是查出来的数据却为空。


node5-14.png



查看我们从接口拿到的数据可以发现: req.query压根没有参数


node5-15.png



在这里我们可以看一下req.query  req.params的区别

....

接下来就知道我为什么要将接收参数给换掉,我们使用req.params来拿到参数


node5-16.png



成功拿到参数,对于前端而言,接下来拿数组第一个数据这种操作肯定是不行的,所以我们从后台接口里面返回的数据进行一下优化


res.json({
      code:'200',
      data:results?results[0]:{},
 });

ok数据已经成功显示!


node5-17.png



7、优化用户查询接口

优化用户查询接口,根据用户条件查询我们的列表


node5-8.png



先拿sql数据命令试试


SELECT * FROM user WHERE name = 'san娟';



node5-9.png



我们的查询命令没问题,接下来把我们的传入的活数据给传入进去即可

传入查询参数之中的params参数进行携带参数的查询


// 获取用户
function getUserList() {
    let api = "http://localhost:8888/api/user";
    const params = {
      name: queryParams.value.name?queryParams.value.name:'',
    };
    axios.get(api,{
      params: params
    }).then(res => {
        // console.log(res, '/user/list');
        if (res.status == 200) {
            console.log(res, 'res');
            tableData.value = res.data.data;
        }
    })
}

app.js之中添加上对应的接收参数query


// 查询用户2
app.get('/api/user', (req, res) => {
  const { name } = req.query;
  const values =[name];
  const sql = `SELECT * FROM user WHERE name = ? `;  // 准备 SQL 插入语句
  // 查询数据库并返回数据
  connection.query(sql,values,(err, results) => {
    console.log(err,'err');
    // console.log(results,'results');
    if (err) {
      console.error('Error querying database:', err);
      res.status(500).json({ error: 'Internal server error' });
      return;
    }
    res.json({
      code:'200',
      data:results,
    });
  });
});

查询可以看出,我们查询参数已经传进去了


node5-10.png



返回参数也可以正常显示


node5-11.png




到这里我们就实现了根据name查询的功能

这里可以留一个小的测试,进一步对多个查询参数进行查询,并且在数据为空的时候也可以进行正常的查询!

8、分页查询

分页查询参数

之前我们的接口并没有进行分页的参数设置,在大批量的数据之中一般我们为了性能以及用户的体验,一般还是需要对于表格数据进行分页和优化。因此我们查询接口的分页是十分有必要的,接下来我们就优化一下我们分页查询的方式:

分页参数设置(前端的参数)

分页参数有两个,一个是当前页的页数,另一个是当前页有多少条。


pageNum: 1 //页码数(也就是当前是多少页)
pageSize:10 //页条数(也就是当前页是多少条)

我们可以先打印出来看看我们查询蚕食,这边我们可以看到前台传过来的查询参数里面加了 pageNum: '1', pageSize: '10' }的参数,我们把这个参数打印如下图:


console.log(req.query,'req.query');

{ name: '', age: '', pageNum: '1', pageSize: '10' } req.query
查询条件 SELECT * FROM user LIMIT ?, ? [ 0, 10 ]
{ name: '', age: '', pageNum: '1', pageSize: '10' } req.query
查询条件 SELECT * FROM user LIMIT ?, ? [ 0, 10 ]
{ name: '', age: '', pageNum: '1', pageSize: '10' } req.query
查询条件 SELECT * FROM user LIMIT ?, ? [ 0, 10 ]

先看看我们的数据库查询语句是否正确


SELECT * FROM user WHERE age = 18 LIMIT 0, 10


node6-2.png



拼接分页查询参数

当我们pageNum:1 pageSize10 的时候返回数据如图


{
    "total": 10,
    "code": 200,
    "data": [
        {
            "id": 1,
            "name": "管理员",
            "age": "1888",
            "sex": 1,
            "address": "地址",
            "state": 1,
        },
        {
            "id": 2,
            "name": "后台开发人员",
            "age": "18",
            "sex": 2,
            "createtime": null,
            "address": null,
            "state": 1,
            "phone": null,
            "username": null,
           
        },
        {
            "id": 3,
            "name": "教师",
            "age": "18",
            "sex": 2,
            "createtime": null,
            "address": null,
            "state": 1,
            "phone": null,
            "username": null,
           
        },
        {
            "id": 4,
            "name": "普通人员",
            "age": "20",
            "sex": 1,
            "createtime": null,
            "address": null,
            "state": 1,
            "phone": null,
            "username": null,
           
        },
        {
            "id": 7,
            "name": "张三",
            "age": "18",
            "sex": 1,
            "createtime": null,
            "address": null,
            "state": 1,
            "phone": null,
            "username": null,
           
        },
        {
            "id": 12,
            "name": "可爱",
            "age": "18",
            "sex": 2,
            "createtime": null,
            "address": null,
            "state": 1,
            "phone": null,
            "username": null,
           
        },
        {
            "id": 20,
            "name": "san娟",
            "age": "20",
            "sex": 1,
            "createtime": null,
            "address": null,
            "state": 2,
            "phone": null,
            "username": null,
           
        },
        {
            "id": 21,
            "name": "乐乐",
            "age": "8",
            "sex": 1,
            "createtime": null,
            "address": null,
            "state": 1,
            "phone": null,
            "username": null,
           
        },
        {
            "id": 38,
            "name": "lin",
            "age": "19",
            "sex": null,
            "createtime": null,
            "address": null,
            "state": 1,
            "phone": null,
            "username": null,
           
        },
        {
            "id": 39,
            "name": "童年的自己",
            "age": "80",
            "sex": null,
            "createtime": null,
            "address": null,
            "state": 1,
            "phone": null,
            "username": null,
        }
    ]
}

修改查询的分页为2,这个时候发现页码已经更改为2 了,查询无误


{
    "total": 10,
    "code": 200,
    "data": [
        {
            "id": 1,
            "name": "管理员",
            "age": "1888",
            "sex": 1,
            "address": "地址",
            "state": 1,
        },
        {
            "id": 2,
            "name": "后台开发人员",
            "age": "18",
            "sex": 2,
            "createtime": null,
            "address": null,
            "state": 1,
            "phone": null,
            "username": null,
        }
    ]
}

offset分页偏移量参数

这里需要注意的就是这个offset参数 offset是偏移量,通过计算偏移量 (pageNum - 1) * pageSize 来动态生成偏移量,然后将 age、name、偏移量和每页的行数作为参数传递给 SQL 查询的 LIMIT 子句和 WHERE 子句。

我们将查询语句放进去尽心查询,这个时候报错了,查询语句如下:


if (pageNum !== undefined&&pageSize !== ''&&pageSize !== null) {
    query += params.length ? ' AND' : ' WHERE';
    query += ' LIMIT ?, ?';
    let offset = (pageNum - 1) * pageSize;
    params.push(offset);

    params.push(parseInt(pageSize));
  }

查询语句之中我们多加了' AND' : ' WHERE',排查修改以后我们更改我们的分页查询方式:


const { name, age,sex,pageNum,pageSize } = req.query;
if (pageNum !== undefined&&pageSize !== ''&&pageSize !== null) {
    query += ' LIMIT ?, ?';
    let offset = (pageNum - 1) * pageSize;
    params.push(offset);
    params.push(10);
  }

查询无误!

这个时候我将pageSize也给添加的时候发现错误

这个时候一直报错提示我You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''10'' at line 1", sqlState: '42000', index: 0, sql: "SELECT * FROM user LIMIT 0, '10'" }

大致意思就是因为我的数据类型为字符串,转化方式有以下三种,我选择了parseInt 方式


parseInt  
parseFloat
Number
  • 需要注意的是查询方式,这里需要使用O,10的限制页码条数:

code: 'ER_PARSE_ERROR',
errno: 1064,
sqlMessage: "You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '10' at line 1",
sqlState: '42000',
index: 0,
sql: "SELECT * FROM user LIMIT O,'10'"

ok更改以后查询无误!


{ name: '', age: '', pageNum: '1', pageSize: '10' } req.query
查询条件 SELECT * FROM user LIMIT ?, ? [ 0, 10 ]
{ name: '', age: '', pageNum: '1', pageSize: '10' } req.query
查询条件 SELECT * FROM user LIMIT ?, ? [ 0, 10 ]
{ name: '', age: '', pageNum: '1', pageSize: '10' } req.query
查询条件 SELECT * FROM user LIMIT ?, ? [ 0, 10 ]

返回总条数total

先试试我们的Sql查询语句


SELECT COUNT(*) AS total FROM user;

查询效果如下

node6-7.png

接下来我们把这个查询加到我们的查询条件里面去


connectionpool.query(query,params,(err, results) => {
    // console.log(err,'err');
    // console.log(results,'results');

    if (err) {
      console.error('Error querying database:', err);
      res.status(500).json({ error: 'Internal server error' });
      return;
    }else{
       let sqltotal = `SELECT COUNT(*) AS total FROM user;`
        // 查询数据库并返回数据
        connectionpool.query(sqltotal,(errtotal, total) => { 
          if (err) {
            console.error('Error querying database:', err);
            res.status(500).json({ error: 'Internal server error' });
            return;
          }else{
             res.json({
              total,
              code:'200',
              data:results,
            });
          }
        });
    }
  });

查询以后可以看出我们的查询结果如下,这里的返回结果条数是嵌套在数组里面。


{
    "total": [{"total": 12}],
    "code": 200,
    "data": [
        {
            "id": 1,
            "name": "管理员",
            "age": "1888",
            "sex": 1,
            "address": "地址",
            "state": 1,
        },
        ...
    ]
}

优化一下我们的查询方式


connectionpool.query(sqltotal,(errtotal, rows) => { 
          let total = rows[0]['total'];
          if (err) {
            console.error('Error querying database:', err);
            res.status(500).json({ error: 'Internal server error' });
            return;
          }else{
             res.json({
              total:total,
              code:'200',
              data:results,
            });
          }
  });

查询成功!


{
    "total": 12,
    "code": 200,
    "data": [
        {
            "id": 1,
            "name": "管理员",
            "age": "1888",
            "sex": 1,
            "address": "地址",
            "state": 1,
        },
        {
            "id": 2,
            "name": "后台开发人员",
            "age": "18",
            "sex": 2,
            "createtime": null,
            "address": null,
            "state": 1,
            "phone": null,
            "username": null,
           
        },
        ...
    ]
}
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。