技术规格说明书
项目 | 内容 |
---|---|
班级:2020春季计算机学院软件工程(罗杰 任健) | 博客园班级博客 |
作业:团队项目选择 | 技术规格说明书 |
我们在这个课程中的目标 | 写出令客户和自己都满意的代码同时变得更强 |
这个作业对我们实现目标的帮助 | 技术功能规格制定与说明 |
一、概述
前端框架
前端使用React Native,是React在原生移动应用平台的衍生产物,目前支持iOS和安卓两大平台。RN使用Javascript语言,类似于HTML的JSX,以及CSS来开发移动应用。
在前端部分我们决定沿用上一代产品开发的框架。由于iOS端开发的各种限制条件,我们产品仅支持Andriod系统。
RN设计的技术栈主要有Javascript(ES5,ES6),React,React Native 这三者。
RN能够支持仅使用JavaScript编写原生移动应用。比起传统原生应用漫长的编译过程,RN可以瞬间刷新编写的应用,让你可以快速迭代开发应用。开启Hot Reloading的话,甚至能在保持应用运行状态的情况下热替换新代码。同时RN可以完美兼容使用Objective-C、Java或是Swift编写的组件。
网络请求
使用Fetch API。Fetch等同于 XMLHttpRequest,它提供了许多与XMLHttpRequest相同的功能,但被设计成更具可扩展性和高效性。Fetch 的核心在于对HTTP接口的抽象,包括Request,Response,Headers,Body,以及用于初始化异步请求的global fetch。得益于JavaScript实现的这些抽象好的HTTP模块,其他接口能够很方便的使用这些功能。
自从1998年发布IE5以来,浏览器中异步网络请求都是通过 XMLHttpRequest (XHR)。直接使用XMLHttpRequest总是非常痛苦的,许多库都对这种方法进行了封装。Fetch API 已经作为现代浏览器中异步网络请求的标准方法,Fetch 在主流浏览器中都有很好的支持,使用 Promise 作为基本构造要素。其好处有:
- 语法简单
- 可以被使用到更多的应用场景
- 加强了代码的可维护性
- 避免回调地狱
二、整体架构
三、API规格(暂定)
博问部分API
名称 | 请求方式 | 请求地址 | 描述 |
---|---|---|---|
askQues | POST | https://api.cnblogs.com/api/questions | 在博问中提问 |
answerQues | POST | https://api.cnblogs.com/api/questions/{questionId}/answers?loginName={"XXX"} | 回答博问 |
getAnswerList | GET | https://api.cnblogs.com/api/questions/{questionId}/answers | 获得单个问题的回答列表 |
deleteAnswer | DELETE | https://api.cnblogs.com/api/questions/{questionId}/answers/{answerId} | 删除回答 |
getQuesByType | GET | https://api.cnblogs.com/api/questions/@{type}?pageIndex={pageIndex}&pageSize={pageSize} | 根据类型获取问题列表 |
modifyQues | PATCH | https://api.cnblogs.com/api/questions/{questionId} | 修改问题 |
getHomepageQues | GET | https://api.cnblogs.com/api/questions/@sitehome?pageIndex={pageIndex}&pageSize={pageSize} | 获得首页问题列表 |
getQuesDetail | GET | https://api.cnblogs.com/api/questions/{questionId} | 获得单个问题详情 |
首页部分API
名称 | 请求方式 | 请求地址 | 描述 |
---|---|---|---|
getBlogContent | GET | https://api.cnblogs.com/api/blogposts/{id}/body | 获取博文内容 |
getEssenceBlog | GET | https://api.cnblogs.com/api/blogposts/@picked?pageIndex={pageIndex}&pageSize={pageSize} | 分页获取精华区博文列表 |
getHomePageBlog | GET | https://api.cnblogs.com/api/blogposts/@sitehome?pageIndex={pageIndex}&pageSize={pageSize} | 分页获取网站首页博文列表 |
blogPostComments | POST | https://api.cnblogs.com/api/blogs/{blogApp}/posts/{postId}/comments | 添加博文评论 |
blogPostCommentsList | GET | https://api.cnblogs.com/api/blogs/{blogApp}/posts/{postId}/comments?pageIndex={pageIndex}&pageSize={pageSize} | 获取博文的评论列表 |
searchBlog | Get | https://api.cnblogs.com/api/ZzkDocuments/{category}?keyWords={keyWords}&pageIndex={pageIndex}&startDate={startDate}&endDate{endDate}&viewTimesAtLeast={viewTimesAtLeast} | 搜索博文 |
getPersonalBlogList | Get | https://api.cnblogs.com/api/blogs/{blogApp}/posts?pageIndex={pageIndex} | 获取个人博文 |
动态部分API
名称 | 请求方式 | 请求地址 | 描述 |
---|---|---|---|
getLatestStatuses | GET | https://api.cnblogs.com/api/statuses/recent | 获取最新一条动态内容 |
publishStatuses | POST | https://api.cnblogs.com/api/statuses | 发布动态 |
getStatusesById | GET | https://api.cnblogs.com/api/statuses/{id} | 根据id获取动态 |
getStatusesByType | GET | https://api.cnblogs.com/api/statuses/@{type}?pageIndex={pageIndex}&pageSize={pageSize}&tag={tag} | 根据类型获取动态列表 |
班级部分API
名称 | 请求方式 | 请求地址 | 描述 |
---|---|---|---|
getClass | GET | https://api.cnblogs.com/api/edu/member/schoolclasses | 获取用户班级列表 |
getClassInformation | GET | https://api.cnblogs.com/api/edu/schoolclass/{schoolClassId} | 根据id获取班级信息 |
getHomeworkInformation | GET | https://api.cnblogs.com/api/edu/homework/{homeworkId} | 根据id获取作业信息 |
getNoticeInformation | GET | https://api.cnblogs.com/api/edu/bulletin/{bulletinId} | 根据id获取公告信息 |
getClassBlogs | GET | https://api.cnblogs.com/api/edu/schoolclass/posts/{filter}/{schoolClassId}/{pageIndex}-{pageSize} | 分页获取班级博客列表 |
getClassNotice | GET | https://api.cnblogs.com/api/edu/schoolclass/bulletins/{schoolClassId}/{pageIndex}-{pageSize} | 分页获取班级公告列表 |
getClassHomework | GET | https://api.cnblogs.com/api/edu/schoolclass/homeworks/{withoutPostponed}/{schoolClassId}/{pageIndex}-{pageSize} | 分页获取班级作业列表 |
getClassMember | GET | https://api.cnblogs.com/api/edu/schoolclass/members/{schoolClassId}?filter={filter} | 分页获取班级成员列表 |
我的部分API
名称 | 请求方式 | 请求地址 | 描述 |
---|---|---|---|
getUserMessage | GET | https://api.cnblogs.com/api/users | 获取当前登录用户信息 |
editCollection | PATCH | https://api.cnblogs.com/api/bookmarks/{id} | 修改用户的收藏 |
addCollection | POST | https://api.cnblogs.com/api/Bookmarks | 添加用户的收藏 |
getCollectionList | GET | https://api.cnblogs.com/api/Bookmarks?pageIndex={pageIndex}&pageSize={pageSize} | 分页获取收藏列表 |
deleteCollection | DELETE | https://api.cnblogs.com/api/bookmarks/{id} | 根据id删除收藏 |
getPersonalEssayList | GET | https://api.cnblogs.com/api/blogs/{blogApp}/posts?pageIndex={pageIndex} | 获取个人博客随笔列表 |
getPersonalBlogMessage | GET | https://api.cnblogs.com/api/blogs/{blogApp} | 获取个人博客信息 |
getBlogContent | GET | https://api.cnblogs.com/api/blogposts/{id}/body | 获取博文内容 |
getClassHomeworkList | GET | https://api.cnblogs.com/api/edu/schoolclass/homeworks/{withoutPostponed}/{schoolClassId}/{pageIndex}-{pageSize} | 分页获取班级作业列表 |
三、设计中体现的原则
抽象
首先博客园的一些API就能很好地体现出抽象原则,将功能封装成接口供外部调用,调用后返回需要的底层数据信息,而并不能直接访问博客园中的数据信息。
其次,在前端的React native框架中,也有许多界面的跳转,比如首页、动态、博问、班级、我的,每一模块都有一个路由,将这些跳转时的路由封装成接口,而不必直接访问该模块的原始路由,也体现出抽象原则。
内聚/耦合/模块化
博客园的每个API都是高内聚的,只需要访问该接口即可获取到需要的数据信息,而不必拘泥于它的内部实现。
在前端的React native框架中,我们将5大功能分成5个模块,实现了模块化处理;每个模块内部仅实现自己内部的所有功能,比如班级模块仅实现与班级相关的所有功能,与其他模块的交互均需要通过API访问。这样划分后,每个模块各司其职,在进行测试时也方便许多。在与其他模块交互时也仅通过API访问,降低了模块之间的耦合度,也为今后项目的可扩展性作出保证。
错误处理
在Exception中定义错误类型并集中进行错误处理 | 描述 |
---|---|
StatuesAuthorityException | 用户并未登陆但访问相关动态信息的错误 |
BAskAuthorityException | 用户并未登陆但访问相关博问信息的错误 |
SearchContentException | 搜索内容有误或者格式错误 |
StatuesBlankException | 用户填写动态为空时出现的错误 |
BAskBlankException | 用户填写博问为空时出现的错误 |
MyAuthorityException | 用户并未登陆但访问我的内容 |
ResourceException | 资源加载错误 |
信息隐藏和封装
我们将app中用到的一些功能封装成了接口的形式,接口的内容和私密信息等是私有的,体现了信息隐藏的原则,在前端通过调用这些接口来实现前,后端之间的交互,前端不会关心接口的事情,接口也不会担心什么人会调用它.另外,在设计ui的时候,将一些功能封装进了一个大的模块之中,这些都体现出了信息的隐藏和封装的原则.
界面和实现的分离
关于功能的具体实现,我们将可能用到的功能封装成了接口的形式,这一方面的代码的编写,不会考虑前端的事情,不会考虑调用者是谁,而只考虑我需要实现什么样的功能,返回什么东西等.
关于app的ui,我们使用了React Native
,界面设计只需要考虑界面本身,以及需要调用的接口,不会关心接口的具体实现是怎样的.
关于前后端的交互,前端通过调用接口来实现和后端之间的交互,彼此的实现相互分离,不考虑对方的具体实现,只考虑提供什么样的接口或者调用什么样的接口.
应对变化的灵活性
由于我们的程序利用了博客园官方API的,因此在后端这一部分想要修改时其实只是一些API的增加和删除。
至于前段,我们采用了模块化的开发方式,同时尽力降低了内部耦合度。我们使用React native为开发工具,正如前面所介绍的,它是一种跨平台移动应用的开发框架,同时有着与多种原生语言通信的功能,因此比如我们一开始选择javascript,后来想移植到IOS上,需要使用ObjectC,其实只需要修改React native和这些原生语言的通信接口即可。
综上所述我们的前后端都具备一定的灵活性
(根据前两任开发者的经验,有时安卓版本的更新会导致程序的不可用,这确实让灵活性变得不那么好,我们只能让开发者去重写安卓更新版本后的程序来让程序能不断运行,这也是后期维护的一个难点)
对大量数据的处理能力
由于我们的数据和博客园官方的数据完全对接的,因此我们并不需要自己维护海量的数据,而是通过博客园提供的API将这些数据发给博客园官方的数据库,由博客园内部维护,因此可以说,在处理大规模的数据上我们是没有什么困难的。