项目地址:https://github.com/Nealyang/R...

本想等项目做完再连载一波系列博客,随着开发的进行,也是的确遇到了不少坑,请教了不少人。遂想,何不一边记录踩坑,一边分享收获呢。分享当然是好的,
如果能做到集思广益,那岂不是更美。我们的口号是:坚决不会烂尾

本博客为连载代码博客同步更新博客,随着项目往后开发可能会遇到前面写的不合适的地方会再回头修改。如有不妥~欢迎兄弟们不啬赐教。谢谢!

前面内容修改部分

由于该博客内容是开发和发文同步连载,所以在随着开发的进行,会修改之前的开发代码。

权限认证

对于权限认证之前我们只做了一部分权限管理,在前端页面发生跳转的时候,我们通过检测state的userInfo来确定当前登录用户是否有权访问。

但是,这里存在一个隐患,就是我登录到一个管理界面以管理员身份,但是知道我身份过期之前都没进行操作和跳转,一直在后端管理界面。然后当我身份过期以后,我进行了admin的一些管理操作(增删改查),且不涉及到页面的跳转。前端没法通过url来判断。

所以,这里我们修改了前后端内容,拦截所有的/admin的api操作,来判断身份是否过期。

admin.js

//admin请求后台验证router.use( (req,res,next) =>{if(req.session.userInfo){next()}else{res.send(responseClient(res,200,1,'身份信息已过期,请重新登录'));}
});

在前端saga里我们需要判断接口返回的信息。

export function* delTagFlow() {while (true){let req = yield take(ManagerTagsTypes.DELETE_TAG);let res = yield call(delTag,req.name);if (res.code === 0) {yield put({type: IndexActionTypes.SET_MESSAGE, msgContent: res.message, msgType: 1});yield put({type:ManagerTagsTypes.GET_ALL_TAGS});} else if (res.message === '身份信息已过期,请重新登录') {yield put({type: IndexActionTypes.SET_MESSAGE, msgContent: res.message, msgType: 0});setTimeout(function () {location.replace('/');}, 1000);} else {yield put({type: IndexActionTypes.SET_MESSAGE, msgContent: res.message, msgType: 0});}}}

目前我没有想到可以一劳永逸不要每个saga都做处理的方法,如果兄弟们有好的想法,望不啬赐教,提issue,我们一起讨论

前端路由抽出组件

之前我们在前端页面中,front组件直接写的一个函数,后来发现不是很合理,因为front我需要将他变为容器组件。所以这里我们需要把它抽出来一个class作为container


const {get_all_tags} = actions;class Front extends Component{constructor(props){super(props);}render(){const {url} = this.props.match;return(<div><div className={`${animationStyle.animated} ${animationStyle.fadeInDown}`}><Banner/><Menus categories={this.props.categories} history={this.props.history}/></div><Switch><Route exact path={url} component={Home}/><Route path={`/detail/:id`} component={Detail}/><Route path={`/:tag`} component={Home}/><Route component={NotFound}/></Switch></div>)}componentDidMount() {this.props.get_all_tags();}
}Front.defaultProps = {categories:[]
};Front.propTypes = {categories:PropTypes.array.isRequired
};function mapStateToProps(state) {return{categories:state.admin.tags}
}
function mapDispatchToProps(dispatch) {return{get_all_tags:bindActionCreators(get_all_tags,dispatch)}
}
export default connect(mapStateToProps,mapDispatchToProps
)(Front)

Home.js 路由判断重定向

return (tags.length>1&&this.props.match.params.tag && (tags.indexOf(this.props.match.params.tag) === -1 || this.props.location.pathname.lastIndexOf('\/') > 0)?<Redirect to='/404'/>:<div className={style.container}><div className={style.contentContainer}><div className={`${style.newsContainer} ${anStyle.animated} ${anStyle.fadeInUp}`}><ArticleList/><div className={style.paginationContainer}><Pagination defaultCurrent={6} total={500}/></div></div><div className={`${style.loginContainer} ${anStyle.animated} ${anStyle.fadeInRight}`}>{this.props.userInfo.userId?<Logined history={this.props.history} userInfo={this.props.userInfo}/>:<Login  login={login} register={register}/>}</div></div></div>)

这里我们需要判断tags的长度,因为现在tags是异步获取的。所以存在时差。比如命名可以访问/Html标签,但是由于是异步获取的tags,当在当前页面刷新的时候,tags并没有加载完全,所以会直接重定向到404页面。

标签管理运行效果展示

因为gif是在太大了所以这里就放两张图片,大家略微感受下。

  • 初始状态

  • 添加tag

状态]

  • 前端标签变化

  • 删除tag

态]

  • 回到初始状态,/Vue刷新会Redirect到404

g)

后端代码部分

//删除标签
router.get('/delTag', function (req, res) {let {name} = req.query;Tags.remove({name}).then(result => {if(result.result.n === 1){responseClient(res,200,0,'删除成功!')}else{responseClient(res,200,1,'标签不存在');}}).catch(err => {responseClient(res);});
});//添加标签
router.post('/addTag', function (req, res) {let {name} = req.body;Tags.findOne({name}).then(result => {if (!result) {let tag = new Tags({name});tag.save().then(data => {responseClient(res, 200, 0, '添加成功', data);}).catch(err => {throw err})} else {responseClient(res, 200, 1, '该标签已存在');}}).catch(err => {responseClient(res);});
});module.exports = router;

为了代码清晰,方便管理,这里直接就分路由到/tag下。操作很常规,就是删除和添加标签。

对于获取全部标签,我放到admin外面,因为毕竟前端页面也需要这个接口。如果都放到/api/admin/getAllTags的话,在/admin请求的时候会进行身份验证。所以将获取全部标签接口放到tags下是不合理的。

这里我们选择放在main.js中

//获取全部标签
router.get('/getAllTags', function (req, res) {Tags.find(null,'name').then(data => {responseClient(res, 200, 0, '请求成功', data);}).catch(err => {responseClient(res);})
});

前端部分修改

对于前端组织结构部分的修改上面已经说完了。这里说下saga中的处理

adminTag界面编码:

class AdminManagerTags extends Component{constructor(props){super(props);this.state={tags: ['首页', 'HTML', 'CSS','JAVASCRIPT'],inputVisible: false,inputValue: '',}}handleClose = (removedTag) => {//删除标签this.props.deleteTag(removedTag)};showInput = () => {this.setState({ inputVisible: true }, () => this.input.focus());};handleInputChange = (e) => {this.setState({ inputValue: e.target.value });};handleInputConfirm = () => {// 添加标签this.props.addTag(this.state.inputValue);this.setState({inputVisible: false,inputValue: '',});};saveInputRef = input => this.input = input;render(){const { inputVisible, inputValue } = this.state;const {tags} = this.props;return(<div><h2 className={style.titleStyle}>标签管理</h2>{tags.map((tag, index) => {const isLongTag = tag.length > 20;const tagElem = (<Tag className={style.tagStyle} key={index} closable={index !== 0} afterClose={() => this.handleClose(tag)}>{isLongTag ? `${tag.slice(0, 20)}...` : tag}</Tag>);return isLongTag ? <Tooltip key={tag} title={tag}>{tagElem}</Tooltip> : tagElem;})}{inputVisible && (<InputclassName={style.tagStyle}ref={this.saveInputRef}type="text"size="small"style={{ width: 108 }}value={inputValue}onChange={this.handleInputChange}onBlur={this.handleInputConfirm}onPressEnter={this.handleInputConfirm}/>)}{!inputVisible && <Button className={style.tagStyle} size="small" type="dashed" onClick={this.showInput}>+ New Tag</Button>}</div>)}componentDidMount() {this.props.getAllTags();}
}function mapStateToProps(state) {return{tags:state.admin.tags}
}function mapDispatchToProps(dispatch) {return{getAllTags : bindActionCreators(get_all_tags,dispatch),deleteTag : bindActionCreators(delete_tag,dispatch),addTag : bindActionCreators(add_tag,dispatch),}
}export default connect(mapStateToProps,mapDispatchToProps
)(AdminManagerTags)

saga的处理:

export function* delTag(name) {yield put({type: IndexActionTypes.FETCH_START});try {return yield call(get, `/admin/tags/delTag?name=${name}`);} catch (err) {yield put({type: IndexActionTypes.SET_MESSAGE, msgContent: '网络请求错误', msgType: 0});} finally {yield put({type: IndexActionTypes.FETCH_END})}
}
... ...export function* delTagFlow() {while (true){let req = yield take(ManagerTagsTypes.DELETE_TAG);let res = yield call(delTag,req.name);if (res.code === 0) {yield put({type: IndexActionTypes.SET_MESSAGE, msgContent: res.message, msgType: 1});yield put({type:ManagerTagsTypes.GET_ALL_TAGS});} else if (res.message === '身份信息已过期,请重新登录') {yield put({type: IndexActionTypes.SET_MESSAGE, msgContent: res.message, msgType: 0});setTimeout(function () {location.replace('/');}, 1000);} else {yield put({type: IndexActionTypes.SET_MESSAGE, msgContent: res.message, msgType: 0});}}
}

操作和之前的都没有两样,需要注意的就是这里返回信息我们多判断了一层用户信息是否过期以及在saga中的处理。

结束语

至此,标签管理也基本完事了。对于前端页面路由的Link还是history.push这里就不做解释了。大家可以多看看代码。

下一篇我们将进行文章的操作的。发文,增删改查等功能。

项目实现步骤系列博客

  • 实战react技术栈+express前后端博客项目(0)-- 预热一波
  • 实战react技术栈+express前后端博客项目(1)-- 整体项目结构搭建、state状态树设计
  • 实战react技术栈+express前后端博客项目(2)-- 前端react-xxx、路由配置
  • 实战react技术栈+express前后端博客项目(3)-- 后端路由、代理以及静态资源托管等其他配置说明
  • 实战react技术栈+express前后端博客项目(4)-- 博客首页代码编写以及redux-saga组织
  • 实战react技术栈+express前后端博客项目(5)-- 前后端实现登录功能
  • 实战react技术栈+express前后端博客项目(6)-- 使用session实现免登陆+管理后台权限验证
  • 实战react技术栈+express前后端博客项目(7)-- 前端管理界面用户查看功能+后端对应接口开发
  • 实战react技术栈+express前后端博客项目(8)-- 前端管理界面标签管理功能+后端对应接口开发
  • 实战react技术栈+express前后端博客项目(9)-- 前端管理界面评论管理功能+后端对应接口开发
  • 实战react技术栈+express前后端博客项目(10)-- 前端管理界面发表文章功能
  • 实战react技术栈+express前后端博客项目(11)-- 后端接口对应文章部分的增删改查
  • 实战react技术栈+express前后端博客项目(12)-- 前端对于发文部分的完善(增删改查、分页等)
  • 实战react技术栈+express前后端博客项目(13)-- 前端对于发文部分的完善(增删改查等)
  • 实战react技术栈+express前后端博客项目(14)-- 内容详情页以及阅读数的展示
  • 实战react技术栈+express前后端博客项目(15)-- 博客添加评论功能以及对应后端实现
  • 实战react技术栈+express前后端博客项目(16)-- pm2 的使用说明
  • 实战react技术栈+express前后端博客项目(17)-- 收工

## 交流

倘若有哪里说的不是很明白,或者有什么需要与我交流,欢迎各位提issue。或者加群联系我~

扫码关注我的个人微信公众号,直接回复,必有回应。分享更多原创文章。点击交流学习加我微信、qq群。一起学习,一起进步

---

欢迎兄弟们加入:

Node.js技术交流群:209530601

React技术栈:398240621

前端技术杂谈:604953717 (新建)

---

实战react技术栈+express前后端博客项目(8)-- 前端管理界面标签管理+后端对应接口开发...相关推荐

  1. 实战react技术栈+express前后端博客项目(3)-- 后端路由、代理以及静态资源托管等配置说明...

    项目地址:github.com/Nealyang/Re- 本想等项目做完再连载一波系列博客,随着开发的进行,也是的确遇到了不少坑,请教了不少人.遂想,何不一边记录踩坑,一边分享收获呢.分享当然是好的, ...

  2. Go后端博客项目实战_持续更新ing

    前言 因为是仿写他人的优秀博客后端,已经把博客代码拉下,进行分析. 但是在分析的过程中自己理解的很困难. 所以想出了一种解决方法: 将原项目代码拉下后,大概研究一下该项目实现的基本功能有哪些?自己能不 ...

  3. 夺命雷公狗---node.js---20之项目的构建在node+express+mongo的博客项目5mongodb在项目中实现添加数据...

    我们上一步就引入了mongodb了,那么下一步就要开始写添加数据了,不过有个前提是先将表单的数据处理好: 最基本的这部现在已经成功了,因为最基本的这步就是先将表单处的提交方式和提交地址给处理好,这里和 ...

  4. SpringBoot个人博客项目搭建—前端页面功能介绍(一)

    SpringBoot个人博客-前端页面功能介绍(一) 项目首页地址:https://blog.csdn.net/weixin_45019350/article/details/108869025 一. ...

  5. 记录从前端到后端--博客项目

    mongodb学习笔记 1.下载:http://www.mongodb.org/downloads 2.安装 3.启动mongodb 3.1mongod 设置数据库路径 mongod --dbpath ...

  6. 夺命雷公狗---node.js---21之项目的构建在node+express+mongo的博客项目6之数据的遍历...

    首先还是来链接数据库,然后就查找,如下所示: /*** Created by leigood on 2016/8/31.*/var express = require('express'); var ...

  7. 【Node.js实战】一文带你开发博客项目之初识Koa2(koa2安装使用、搭建开发环境、测试路由)

    个人简介

  8. 视频教程-React全栈:前后端分离的招聘Web App项目(含资料)-ReactJS

    React全栈:前后端分离的招聘Web App项目(含资料) 张长志技术全才.擅长领域:区块链.大数据.Java等.10余年软件研发及企业培训经验,曾为多家大型企业提供企业内训如中石化,中国联通,中国 ...

  9. 【第0篇】从0-1自建个人博客系统【web端,admin管理端,express后端,Nginx部署】--vue3技术 reac+hook技术 umi4

    [第0篇]从0-1自建个人博客系统[web端,admin管理端,后端] 文章完整地址:http://huxunxun.top/lookArtical?artical_id=18 [序言] 我是一个微小 ...

最新文章

  1. 计算机二级周小丹,亲爱的设计丨周小丹:始终认真,才能保持“天真”
  2. 神器与经典--sp_helpIndex
  3. NCBI-SRA数据下载
  4. 4 . 2 存储系统
  5. com+ 三层布署[未成功验证]
  6. 【Groovy】闭包 Closure ( 闭包作为函数参数 | 代码示例 )
  7. 什么是控制单元?—Vecloud微云
  8. 设置 JAVA_HOME
  9. php开发客服系统(持久连接+轮询+反向ajax)
  10. 【linux系统编程】linux用户及权限管理
  11. 彩色手绘情节人插画装饰素材,psd分层利于应用!
  12. Linux下 FFmpeg 编译安装
  13. 聚类算法实践——层次、K-means聚类
  14. 太阳天顶角和方位角计算
  15. Python3实现的m3u8批量下载器 解密合并多线程
  16. 树莓派开发—语音识别功能
  17. 自己总结出三种进入加密QQ空间的方法
  18. 弗拉基米尔·多罗宁_罗紫琳新欢俄亿万富豪 女星与老外的那些事儿
  19. 【Unity Shader】 CubeMap(立方体贴图)
  20. 性价比高的国产蓝牙耳机有哪些?盘点几款口碑比较好的国产蓝牙耳机

热门文章

  1. VTK:可视化算法之PineRootConnectivity
  2. VTK:可视化之ExtrudePolyDataAlongLine
  3. VTK:PolyData之CellEdgeNeighbors
  4. VTK:相互作用之Picking
  5. VTK:几何对象之ColoredLines
  6. OpenCV使用Sobel或Scharr OpenCV函数进行边缘检测的实例(附完整代码)
  7. OpenCV支持向量机SVM简介
  8. OpenCV在浏览器中运行深度网络
  9. C语言实现最小堆minheap(附完整源码)
  10. QT的QScriptEngineAgent类的使用