Node — 第九天 (大事件项目接口实现三)

文章管理接口

设计数据表

在这里插入图片描述

添加文章接口

编写接口,使用postman模拟提交formdata类型的数据

  • 在article.js 中,加入 /add 路由

  • postman模拟提交formdata类型的数据

在这里插入图片描述

multer处理文件上传

  • 下载安装multer

  • 加载模块 const multer = require('multer')

  • 配置上传文件的存放目录 const upload = multer({ dest: '路径' })

  • 路由(接口)使用

    router.post('/add', upload.single('接口文档规定的图片名字'), async (req, res) => {req.body  获取文本类型的数据req.file  获取文件的信息
    });
    

实现发布文章

  • 前面已经可以通过req.body 和 req.file 获取到客户端提交的数据了
  • 自己组装数据表所需的字段
  • 通过db,执行insert语句,完成添加
router.post('/add', upload.single('cover_img'), async (req, res) => {// 如何接收POST请求体。必须使用第三方模块multer来处理POST请求体// console.log(req.body); // 获取文本类型的数据/**   {title: '哈哈哈',content: '哈哈哈哈哈哈哈哈',cate_id: '3',state: '已发布'}* */// console.log(req.file); // 获取文件的信息/***  {fieldname: 'cover_img',originalname: '1.jpg',encoding: '7bit',mimetype: 'image/jpeg',destination: '/Users/tangfengpo/Study/bj97+sh60/Node-09/big-event-server/uploads',filename: '0c86456393a6bd78cb860968a53a089d', // 文件名path: '/Users/tangfengpo/Study/bj97+sh60/Node-09/big-event-server/uploads/0c86456393a6bd78cb860968a53a089d',size: 35774}*/// 组装数据let obj = req.body;obj.cover_img = req.file.filename;obj.pub_date = '2020-03-11 23:15:25';obj.author_id = req.user.id; // 要求登录之后,必须在token中保存用户的id// 添加入库let r = await db('insert into article set ?', obj);if (r && r.affectedRows > 0) {res.json({status: 0,message: '添加文章成功'});} else {res.json({status: 1,message: '添加文章失败'});}
});

moment处理添加时间

  • 把上述添加代码中,时间的处理,修改如下
// obj.pub_date = '2020-03-11 23:15:25';
// obj.pub_date = moment('任何类型的时间/不填表示处理当前时间').format('处理成你想要的格式');
obj.pub_date = moment().format('YYYY-MM-DD hh:mm:ss');

MySQL中的连接查询

在这里插入图片描述

-- MySQL中的连接查询
-- 能够连接查询的两张或多张表,必须有关系才行-- 语法
select 字段 from1 join2 on 两表的关系 [where ... order by .... limit ...]
select 字段 from1 join2 on 两表的关系 join3 on 表的关系 .... [where ... order by .... limit ...]-- select * from article join category on article.cate_id=category.Id
-- 给表名定义别名,简化SQL
-- select * from article a join category c on a.cate_id=c.Id 
-- 指定字段查询
-- select a.Id, a.title, a.pub_date, a.state, c.name cate_name from article a
--  join category c
--  on a.cate_id=c.Id-- 加入user表,实现每个用户只能查看自己的文章
select a.Id, a.title, a.pub_date, a.state, c.name cate_name from article ajoin category c on a.cate_id=c.Idjoin user u on u.id=a.author_idwhere u.id = 14

获取文章列表接口

判断必须有必要的参数

// 获取文章列表数据
router.get('/list', async (req, res) => {// 接收所有的请求参数// let pagenum = req.query.pagenum;// let pagesize = req.query.pagesize;// let cate_id = req.query.cate_id;// let state = req.query.state;// 使用解构的方式,获取请求参数let {pagenum, pagesize, cate_id, state} = req.query;// 判断必填参数是否存在if (!pagesize || !pagenum) {return res.json({status: 1,message: '缺少必要参数'});}});

多表连查,查询结果

// 下面查询数据,把结果响应给客户端// 下面是SQL比较长,可以先在 Navicat中查询,没问题,复制过来let sql = `select a.Id, a.title, a.pub_date, a.state, c.name cate_name from article ajoin category c on a.cate_id=c.Idjoin user u on u.id=a.author_idwhere u.id = ?`;let r = await db(sql, req.user.id);if (r) {res.json({status: 0,message: '获取数据列表成功',data: r});} else {res.json({status: 1,message: '查询失败'});}

此时,可以使用postman来测试了

在这里插入图片描述

如果你看到结果了,说明没有问题。

相同条件查询总记录数

必须和查询数据的条件一致

// 查询总记录数
let r2 = await db('select count(*) as total from article where author_id=?', req.user.id);
if (r && r2) {res.json({status: 0,message: '获取数据列表成功',data: r,total: r2[0].total});
} else {res.json({status: 1,message: '查询失败'});
}

加入limit,完成分页查询

  • pagenum 表示当前的页码,比如 1、2、3…

  • pagesize 表示每页显示多少条,由你自己来定(老师使用的是2)

  • 根据上述两个参数,可以完成SQL语句中limit的部分

    limit ${(pagenum-1) * pagesize} , ${pagesize}

使用postman的账号和使用页码登录的账号最好统一。否则使用postman添加的文章页面中可能看不见。

加入where条件,完成筛选查询

对于获取文章接口来说,请求参数 cate_id 和 state,用于完成筛选。

如果服务器端,接收到了 cate_id 和 state,我们只需要加where条件即可。

// 获取文章列表数据
router.get('/list', async (req, res) => {// 接收所有的请求参数// let pagenum = req.query.pagenum;// let pagesize = req.query.pagesize;// let cate_id = req.query.cate_id;// let state = req.query.state;// 使用解构的方式,获取请求参数let {pagenum, pagesize, cate_id, state} = req.query;// 判断必填参数是否存在if (!pagesize || !pagenum) {return res.json({status: 1,message: '缺少必要参数'});}// 生成where条件,完成筛选工作let w = '';if (cate_id) {w += ' and cate_id=' + cate_id; // 注意前面有空格}if (state) {w += ` and state = '${state}'`; // 注意前面有空格}// 下面查询数据,把结果响应给客户端// 下面是SQL比较长,可以先在 Navicat中查询,没问题,复制过来let sql = `select a.Id, a.title, a.pub_date, a.state, c.name cate_name from article ajoin category c on a.cate_id=c.Idjoin user u on u.id=a.author_idwhere u.id = ? ${w}limit ${(pagenum-1)*pagesize}, ${pagesize}`;let r = await db(sql, req.user.id);// 查询总记录数let r2 = await db('select count(*) as total from article where author_id=?' + w, req.user.id);if (r && r2) {res.json({status: 0,message: '获取数据列表成功',data: r,total: r2[0].total});} else {res.json({status: 1,message: '查询失败'});}
});

根据Id删除文章接口

// 根据Id完成删除文章接口
router.get('/delete/:id', async (req, res) => {let id = req.params.id;let r = await db('delete from article where Id=?', id);if (r && r.affectedRows>0) {res.json({status: 0,message: '删除文章成功'});} else {res.json({status: 1,message: '删除文章失败'});}
});

根据Id获取文章详情接口

// 根据Id获取文章详情接口
router.get('/:id', async (req, res) => {let id = req.params.id;let r = await db('select * from article where Id=?', id);// console.log(r);if (r && r.length > 0) {res.json({status: 0,message: '获取文章详情成功',data: r[0]});} else {res.json({status: 1,message: '获取文章详情失败'});}
});

根据 Id 更新文章信息接口

  • 修改文章的时候,可以不选择修改图片,这是比较合理的
// 根据Id更新文章
router.post('/edit', upload.single('cover_img'), async (req, res) => {// req.body;// req.file;// console.log(req.file); // 如果没有选择图片,req.file === undefinedlet obj = req.body; // 这样的话,obj中有 Id、title、cate_id、content、state// 判断,修改的时候,客户端是否重新选择了图片(选择了图片,req.file是对象;没有选择图片,req.file是undefined)if (req.file) {obj.cover_img = req.file.filename;}// obj.pub_date = moment().format('YYYY-MM-DD HH:mm:ss');let r = await db('update article set ? where Id=?', [obj, req.body.Id]);if (r && r.affectedRows>0) {res.json({status: 0,message: '更新文章成功'})} else {res.json({status: 1,message: '更新文章失败'});}
});

前端

回顾文章列表分页实现

完成文章列表搜索功能

先显示分类

// 获取分类,渲染到下拉菜单位置
$.ajax({url: '/my/article/cates',success: function (res) {let str = template('tpl-category', res);$('#category').html(str);form.render('select'); // ---------------  一定要更新渲染 --- }
});

模板代码:

<!-- 分类的模板 -->
<script type="text/html" id="tpl-category"><option value="">所有分类</option>{{each data val}}<option value="{{val.Id}}">{{val.name}}</option>{{/each}}
</script>

完成筛选

思路:

  • 监听搜索区的表单,如果提交表单
  • 判断并设置请求参数
    • 如果选择了某个分类,设置请求参数 data.cate_id = cate_id
    • 如果是所有分类,则删除这个请求参数 delete data.cate_id
    • 文章状态一样的操作
  • 修改页码为1,因为搜索完毕,应该先看到第1页的数据
  • 调用 renderArticle() 重新获取数据并渲染到页面中即可。
// --------------  实现筛选功能 ---------------
// 筛选之后,一定要重置 pagenum = 1;
// 自己设置表单的id
$('#search_form').on('submit', function (e) {e.preventDefault();let cate_id = $('#category').val();let state = $('select[name="state"]').val();if (cate_id) {data.cate_id = cate_id;} else {delete data.cate_id;}if (state) {data.state = state;} else {delete data.state;}// 修改页码为1data.pagenum = 1;// 更新渲染renderArticle();
})

回顾文章添加实现

  • 自己随便写个表单
  • 使用formdata收集数据
  • 提交给接口,就可以完成添加

后续,为了有更好的效果:

  • 获取分类
  • 使用富文本编辑器 tinymce
  • 使用图片剪裁插件

完成文章编辑

  • 复制 publish.html 为edit.html (编辑页面)

  • 文章列表页面,给 ”编辑“ 挂超链接,链接到 edit.html ,并且传递 id参数

    // 点击了编辑,应该跳转到 edit.html
    $('body').on('click', '.edit', function () {let id = $(this).attr('data-id');location.href = "/article/edit.html?id=" + id;
    })
    
  • 复制publish.js 为edit.js ,修改edit.html页面,引入edit.js

  • 获取地址栏的id,根据id查询一篇文章详情,然后完成表单数据渲染

    // ------------------ 新加入的代码 ----------------// 获取地址栏的id,根据id获取一篇文章详情。快速为表单赋值let id = new URLSearchParams(location.search).get('id');$.ajax({url: '/my/article/' + id,success: function (res) {console.log(res);if (res.status === 0) {form.val('editForm', res.data); // 标题、内容// 销毁剪裁区,更换图片,重新创建剪裁区$image.cropper('destroy').attr('src', 'http://localhost:3007/' + res.data.cover_img).cropper(options);// 这里完成了文章获取,下面开始查询分类// 获取所有的分类,渲染到下拉列表中$.ajax({url: '/my/article/cates',success: function (r) {if (r.status === 0) {// 使用模板引擎,渲染数据到页面中// 把当前分类的id,分配到模板r.cate_id = res.data.cate_id;let str = template('cate', r);$('select').html(str);// 执行更新渲染方法form.render('select');}}});}}});
  • 模板加入判断,控制哪个分类是默认勾选

    <script type="text/html" id="cate">{{each data val}}<option value="{{val.Id}}" {{if val.Id == cate_id}}selected{{/if}}>{{val.name}}</option>{{/each}}
    </script>
    
  • 图片剪裁默认铺满整个区域

    let options = {// 宽高比aspectRatio: 400 / 280,autoCropArea: 1, // 让剪裁框铺满整个剪裁区// 设置预览区的选择器preview: '.img-preview'};
    
  • 修改添加文章的接口为更新文章的接口即可,其他都不需要修改。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/247980.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Node — 第九天 (ES6降级 and 发布属于自己的[第三方模块]包)

ES6降级处理 因为 ES 6 有浏览器兼容性问题&#xff0c;可以使用一些工具进行降级处理&#xff0c;例如&#xff1a;babel 降级处理 babel 的使用步骤 安装 Node.js命令行中安装 babel配置文件 .babelrc运行命令&#xff0c;完成降级 项目初始化 (项目文件夹不能有中文) npm …

Vue — 第一天(极速入门)

基本介绍 vue是什么 目标&#xff1a;了解vue的一些基础概念。 官方网站&#xff1a; https://cn.vuejs.org/ vue是&#xff1a;渐进式javascript框架。 两组概念 &#xff08;1&#xff09;框架 库。只提供一些API给开发者使用。jquery 是一个js库框架。拥有自己的规则和…

Vue — 第二天(v-model和过滤器)

VUE-02-v-model和过滤器 昨日反馈与回顾 代码仓库的问题 不要修改你克隆下来的仓库中任意代码&#xff0c;否则&#xff0c;下次pull时&#xff0c;可能会报错&#xff0c;从而得到不到最新的代码。 如果已经遇到了这个冲突&#xff1a; 解决冲突(git 中解决冲突)把关键代码…

牛人iOS开发系列--音频播放、录音、视频播放、拍照、视频录制

概览 随着移动互联网的发展&#xff0c;如今的手机早已不是打电话、发短信那么简单了&#xff0c;播放音乐、视频、录音、拍照等都是很常用的功能。在iOS中对于多媒体的支持是非常强大的&#xff0c;无论是音视频播放、录制&#xff0c;还是对麦克风、摄像头的操作都提供了多套…

Vue — 第三天(计算属性和json-server)

计算属性 使用场景 如果一个结果需要依赖data中的数据&#xff0c;但是需要经过一些逻辑处理&#xff0c;才能得到你想要的数据。此时就可以使用计算属性。 例如&#xff1a;要对给定的字符串做翻转处理之后再来显示。 <div id"app"><!-- 此处逻辑复杂 …

Vue — 第四天(components组件)

问题导入 下面的代码是一个折叠面板的效果。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Docu…

iOS开发常用的RGB色值和宏

iOS中RGB常用的色值,同时可将对颜色的设置定义成宏,方便开发应用,如: // name 颜色相关 // 参数格式为&#xff1a;0xFFFFFF #define kColorWithRGB(rgbValue) \ [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16)) / 255.0 \ …

防火墙综合实验

防火墙技术综合实验 一、实验目的&#xff1a;本次实验是将多种访问控制列表以及防火墙部分的知识做一个汇总 二、实验内容 A&#xff1a;Established控制列表 拓扑图 配置步骤 1:配置各端口ip地址&#xff0c;配置登陆密码 R4: 登陆账号&#xff1a;ys 密码&#xff1a;123 2:…

iOS获取当前设备型号等信息总结 包含iPhone7和iPhone7P

#include <sys/types.h> #include <sys/sysctl.h>//获得设备型号(NSString *)getCurrentDeviceModel {int mib[2];size_t len;char *machine;mib[0] CTL_HW;mib[1] HW_MACHINE;sysctl(mib, 2, NULL, &len, NULL, 0);machine malloc(len);sysctl(mib, 2, mac…

Vue — 第五天(路由)

前端路由 问题导入 在前面完成的资产管理案例中&#xff0c; 我们是把列表区域和添加表单区域实现在了一个区域。当页面功能比较复杂时&#xff0c;我们需要它们拆分开来&#xff1a;一个页面中只显示一个区域。 一个比较直观的解决方案是把它们分别做成两个独立的网页文件&…

Vue — 第六天(vue-cli-介绍)

vue-cli-介绍 vue-cli是官方提供的开发vue项目的脚手架工具。 脚手架是为了保证各施工过程顺利进行而搭设的工作平台。 在开发过程中&#xff0c;脚手架工具是有用的&#xff0c;开发完成&#xff08;项目上线&#xff09;&#xff0c;它就没有用了。 vue-cli可以提供基于vue项…

Vue — 第七天(vue-cli-案例)

资料获取地址&#xff1a; github: https://gitee.com/wang_yu5201314/VUE_vuecli SSH&#xff1a; gitgitee.com:wang_yu5201314/VUE_vuecli.git hero案例-项目介绍 功能介绍&#xff1a; 三个模块 英雄列表(只做这个)装备列表技能列表 英雄列表 列表组件删除功能添加组件编…

postman测试工具

做文件上传测试的时候可以选择输入方式为文件 做文件下载测试的时候&#xff0c;可以选择 转载于:https://www.cnblogs.com/thesun/p/10853226.html

webpack — 概述介绍

webpack概述 webpack是一个流行的前端项目构建工具&#xff08;打包工具&#xff09;&#xff0c;可以解决当前web 开发中所面临的困境。 webpack提供了友好的模块化支持&#xff0c;以及代码压缩混淆、处理js兼容问题、性能优化等强大的功能&#xff0c;从而让程序员把工作的…

彻底解决iOS项目中 _OBJC_CLASS_$_XXXService, referenced from: 的类似问题

这是大家熟悉的开发过程中可能遇到的问题 这是提交源码到appStore不支持64位设备的提示 本人在提交项目到appStore时发生的的错误&#xff0c;提示必须要支持64的设备&#xff0c;然后自己赶紧进行相关的适应&#xff0c;出现了类似标题的问题&#xff0c;解决方法如下: 1、…

THUPCCTSAPIO2019:Far Away

流水账~ THUPC nmdwsmduliu&#xff01; THUPC Day -INF~Day -2 大概就是自己做题和每周两次的考试&#xff0c;lsy和fcw两个外校的来吊打我们qwqqq THUPC Day -1 Z208 长沙->北京 在车上看gzy/tjj/xzz打摆&#xff1f; THUPC Day 0 从火车站出来做地铁的时候和tjj做反了可海…

UIDocumentInteractionController之程序间文档共享

iOS中的沙盒可以让平台更加的安全&#xff0c;这也是沙盒给用户带来的最主要好处。不过由于沙盒的严格限制&#xff0c;导致程序之间共享数据比较麻烦。一般在程序间共享文档可以通过UIDocumentInteractionController类实现通讯。它支持在你的app中用其他app预览和显示文档。同…

c#基础知识梳理(四)

上期回顾 - https://www.cnblogs.com/liu-jinxin/p/10826971.html 一、类 当你定义一个类时&#xff0c;你定义了一个数据类型的蓝图。这实际上并没有定义任何的数据&#xff0c;但它定义了类的名称意味着什么&#xff0c;也就是说&#xff0c;类的对象由什么组成及在这个对象…

UIButton设置圆角和边框及边框颜色

UIButton *testButton [UIButton buttonWithType:UIButtonTypeSystem];[testButton setFrame:CGRectMake(self.view.frame.size.width/2, self.view.frame.size.height/2, 100,100)];[testButton setTitle:"获取屏幕尺寸" forState:UIControlStateNormal];[testButt…

Objective-C 深复制和浅复制与NSCopying协议

1.简单复制只能实现浅拷贝&#xff1a;指针赋值&#xff0c;使两个指针指向相同的一块内存空间&#xff0c;操作不安全。 2. Foundation类已经遵守了<NSCopying>和 <NSMutableCopying>协议,即实现了copy和mutableCopy方法,因此Foundation对象可以使用这些方法创建对…