湖北省网站备案,济南网站建设哪家便宜,美橙域名查询网站,网页设计论文引言文章管理接口
设计数据表 添加文章接口
编写接口#xff0c;使用postman模拟提交formdata类型的数据 在article.js 中#xff0c;加入 /add 路由 postman模拟提交formdata类型的数据 multer处理文件上传 下载安装multer 加载模块 const multer require(multer) 配置上…文章管理接口
设计数据表 添加文章接口
编写接口使用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/bj97sh60/Node-09/big-event-server/uploads,filename: 0c86456393a6bd78cb860968a53a089d, // 文件名path: /Users/tangfengpo/Study/bj97sh60/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 字段 from 表1 join 表2 on 两表的关系 [where ... order by .... limit ...]
select 字段 from 表1 join 表2 on 两表的关系 join 表3 on 表的关系 .... [where ... order by .... limit ...]-- select * from article join category on article.cate_idcategory.Id
-- 给表名定义别名简化SQL
-- select * from article a join category c on a.cate_idc.Id
-- 指定字段查询
-- select a.Id, a.title, a.pub_date, a.state, c.name cate_name from article a
-- join category c
-- on a.cate_idc.Id-- 加入user表实现每个用户只能查看自己的文章
select a.Id, a.title, a.pub_date, a.state, c.name cate_name from article ajoin category c on a.cate_idc.Idjoin user u on u.ida.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_idc.Idjoin user u on u.ida.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_idc.Idjoin user u on u.ida.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.affectedRows0) {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.affectedRows0) {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 typetext/html idtpl-categoryoption 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[namestate]).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 typetext/html idcate{{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};修改添加文章的接口为更新文章的接口即可其他都不需要修改。