|
|
1. 路由想实现这个功能,那首先要做的是添加一个路由。在 Express 中的路由文件,是我们开发项目的最核心的部分,整个接口的主要逻辑部分都是写在这里的。
我们的项目,默认已经存在了两个路由文件,index和users。我们这里先不管它们,丢一边就好。
因为我们现在要完成一整套的增删改查接口,那这种功能是给管理后台使用的,而不是前台用的。所以,我们后台的接口,就不要直接放在routes目录下了。可以在routes目录下,再新建一个admin文件夹。在这个里面,就专门放后台的接口。
因为我们要做的是文章相关的接口,那就在admin里,再建一个叫做articles.js的路由文件。可以参考其他路由文件,先引用express,并定义好router,最后导出出去。
请注意,课程修改的始终是routes/admin/articles.js。千万不要改到models/article.js上了!!!
const express = require('express');const router = express.Router();// ...module.exports = router;
2. 第一个请求中间部分,我们来写一个 get 请求。先直接响应一个简单的 json 数据试试
/** * 查询文章列表 * GET /admin/articles */router.get('/', function (req, res) { res.json({ message: '这儿是后台的文章列表接口哟~' });});接着还要到 app.js 中引入路由
// 后台路由文件const adminArticlesRouter = require('./routes/admin/articles');这样 articles.js 这个路由文件才会生效。因为是后台路由,所有我们命名的时候,可以加上admin用以作为区分。
还要再来use一下
// 后台路由配置app.use('/admin/articles', adminArticlesRouter);这里的意思就是说,当访问 /admin/articles 这个路径时, 就会对应到articles.js 这个路由文件上。
npm start启动服务后,现在就来访问一下吧 http://localhost:3000/admin/articles,果然可以看到输出的内容了。

3. 读取数据库但是现在输出的内容,并不是数据库里面保存的数据。如果要读取数据库,模型就要正式登场了。
要使用模型,首先要去引用一下模型文件。
const { Article } = require('../../models');然后将中间部分代码,做一个修改。那么我们现在就使用模型来查询到所有的数据,查询到的数据就放在articles里。
然后,我们规定一下,接口返回的形式。每个公司返回的接口格式都不一样,那这里呢,我希望它返回的数据,由status、message和data三部分组成。其中
| 返回数据的结构 | 说明 | 值 | | status | 表明当前接口是否是成功的 | 它就两个值,true就是成功了,false就是失败了。 | | message | 就是给用户的提示信息 | 例如:查询成功,之类的 | | data | 里放的就是查询出来,最终要显示给用户看的数据了 | 一般来说,是对象形式 | 依照这个思路,我们就改为
router.get('/', function (req, res) { // 查询数据 const articles = Article.findAll(); // 返回查询结果 res.json({ status: true, message: '查询文章列表成功。', data: { articles } });});再去刷新页面,发现并没有把想要的数据查询出来。

4. 数据库操作是异步操作这就很奇怪了,在数据库里,明明有 100 篇文章的啊,为什么查出来是空呢?
千万注意,这是因为这里的查询是异步操作。也就说 Node 不会等findAll()运行完成后,再执行res.json。findAll()刚一开始跑起来,数据还没返回呢,就先运行了res.json输出东西了,那么当然就是空白了。
要解决也非常简单,我们可以通过promise或者用async/await来写。我这里是推荐大家用async/await的,因为这样不用写then,也不用写一堆括号。代码整体看上去要比promise好看一万倍。那我们一起调整一下,加上async和await
router.get('/', async function (req, res) { // 查询数据 const articles = await Article.findAll(); // 返回查询结果 res.json({ status: true, message: '查询文章列表成功。', data: { articles } });});再次刷新页面,这也太棒了吧,我们一下子就把数据库的东西全部查出来了,非常简单的就做好了第一个接口了。

这时候我们来看看命令行,可以看到虽然我们写的是Article.findAll(),但实际上运行的是select语句。因为MySQL就只认识SQL语句,只有通过SQL语句才能正确的返回给我们所查询的数据。
所以之前和大家说过,我们开发中,可以不写SQL语句,但你一定不能看不懂。不然哪里出错了,给你提示了,你也看不懂的。

5. 排序接着我们再来看排序问题,现在查出来的数据特别多,一共有一百条。在正常浏览文章列表的时候,最好是让最后发表的文章,在最上面。以前的老文章,在最下面。这样用户点进来后,才能一眼看见最新的内容。
要来实现这个功能,大家要回忆一下排序的SQL怎么写的?各个小伙伴们,你们还记得吗?当然就是用order by了。这里要求从大到小排序,那就是倒序,千万要记住了,倒序是order by id desc。现在我们用代码来实现倒序排列。
先来定义一个条件,里面写明,order要按照id倒序
// 定义查询条件const condition = { order: [['id', 'DESC']]};注意一下,这里在数组里又嵌套了数组。这就说明,排序可能不止按一个字段来排序,也可能同时按多个字段来排序。
接着在调用findAll的时候,把这个条件丢里面。这就完成了
const articles = await Article.findAll(condition);再来刷新页面,的确是从大到小排序了

可以再看看命令行里,果然运行的是通过id desc来查询的

6. 使用 try...catch 处理异常到这里,这个接口已经完全可用了,但是在安全性上还差那么一点点儿。很多时候可能有各种未知的异常错误,最简单的,例如代码本身有问题,就会导致整个Node服务崩溃,而且会让其他的接口也全都无法使用。
我们可以做一个简单的尝试,故意将Article模型,写错为Article1。这样是肯定找不到数据的,而且整个服务会崩溃。
const articles = await Article1.findAll(condition);刷新一下,浏览器是直接报错了。再来看命令行,提示我们,程序崩了,在修改好代码前都无法运行了

这只是一个故意写错的问题,这种小问题检查检查还是很容易发现的。但很多时候,有很多问题很难以发现,甚至有些问题根本就不是代码的错误,比方说MySQL数据库自身出错了。那么最好的办法就是给代码加上try...catch...来处理异常问题。
router.get('/', async function (req, res) { try { // ... } catch (error) { // 返回错误信息 res.status(500).json({ status: false, message: '查询文章列表失败。', errors: [error.message] }); }});刷新看看,可以正确的提示错误信息了。我们这里使用了一个500的状态码,它表示服务器错误。具体的错误信息就在errors里面,之所以这里用了一个数组,那是因为可能会有多个错误信息。这个等我们学到表单验证的时候,再和大家详细说明。
那为什么成功查询里面的res.json我们不写状态码呢?这是因为成功的状态码是200,如果你不写,它默认状态码是200,所以就不用多此一举去写status(200)了。

然后就将模型名改回Article,第一个接口,最终的代码就彻底完成了
const express = require('express');const router = express.Router();const { Article } = require('../../models');/** * 查询文章列表 * GET /admin/articles */router.get('/', async function (req, res) { try { // 定义查询条件 const condition = { order: [['id', 'DESC']] }; // 查询数据 const articles = await Article.findAll(condition); // 返回查询结果 res.json({ status: true, message: '查询文章列表成功。', data: { articles } }); } catch (error) { // 返回错误信息 res.status(500).json({ status: false, message: '查询文章列表失败。', errors: [error.message] }); }});module.exports = router;
7. 本章小结- 因为是做后台接口,所以要把路由文件放在admin文件夹中。并且访问的路径也多了/admin
- 查询数据,是异步操作,记住:千万不要忘了要用async/await
- 查询使用模型名.findAll()即可,要排序就加上id desc
- 为了确保程序能正确处理异常,务必加上try...catch...
|
|