引言
上课,上实验,写文档,终于有时间写博客了。
我觉得这学期的 Android 实验上的还是很有意义的,课上,与我的舍友张一帆 (自学 Android 及相关框架,有过 Android 比赛项目经验) 一起讨论了 Android 的架构分层设计,以及对 Retrofit 和 RxAndroid 框架的封装。
经过在实验中的学习,以及请教了一些在 Android 界算是有小有经验的人之后,发现自己年初对 Android 实验设计的有些问题:
年初计划使用 Data-Binding 与 Fragmentation 实现单 Activity 架构,后来发现这样并不好。
Data-Binding 学习成本太高,且对原项目结构破坏性较大,对新人学习并理解 Android 无益。
单 Activity 架构虽然很优秀,但实际项目中仍然是多 Activity+ 多 Fragment 架构,去追求单 Activity 意义不大,手动管理 Fragment 会十分麻烦。
发现错误,就改吧。目前已经在实验中引入并应用了 ButterKnife、Litepal、Retrofit、RxAndroid 等框架,感觉技术上应该不会有太大变化。以后再一起和大家分享一下我在 Android 方面的学习收获。
同时,华软虚拟化管理系统 1.0 版本正式完成,本周花费整三天完成了项目发布及部署文档的撰写(感谢潘佳琦,为了尽快交付,MySQL 的安装与配置文档是他帮我写的,写得非常好)。
现在再回想华软项目,还是存在很多细节当时没有考虑到,在此进行反思与总结。
反思
笨拙的异常处理
后台设计得没什么问题:当发生错误时,后台会抛出异常,全局异常处理处理掉该异常,并将错误信息返回给前台。
笨拙在前台的拦截器这里:
起初设计的是拦截器处理掉所有异常,并给予用户友好的提示,这样订阅时就不用处理 error 了。
当需要的时候,再去写 error 方法,比如登录时要在 error 里提示用户名或密码错误的提示信息。
拦截器处理异常,为了拦截器能准确地提示错误信息,所以扩展了 HTTP 状态码,对 512 等状态码扩展了新的含义。
switch (error.status) {
case 401:
if (this.router.url !== ‘/passport/login’) {
this.msg.error(‘ 用户认证发生错误 ’);
// noinspection JSIgnoredPromiseFromCall
this.router.navigateByUrl(‘/passport/login’);
}
break;
case 403:
this.msg.error(‘ 访问被拒绝, ‘ + error.error);
break;
case 404:
this.msg.error(‘ 资源不存在, ‘ + error.error);
break;
case 502:
this.msg.error(‘ 服务器网关错误,请联系系统管理员 ’);
break;
case 504:
this.msg.error(‘ 服务器网关请求超时,请联系系统管理员 ’);
break;
case 512:
this.msg.error(‘ 数据同步异常,’ + error.error);
break;
case 513:
this.msg.error(‘ 主机操作异常,’ + error.error);
break;
case 514:
this.msg.error(‘ 访问被拒绝异常,’ + error.error);
break;
}
当时写完这个拦截器的时候心里还是挺爽的,心想,以后可再也不用管理 error 了,多省事。现在再看看这个拦截器,说不上来什么原因,就是感觉怪怪的。
因为拦截器中是一个通用的提示信息,所以就出现了有时候需要在拦截器里加提示,有时候需要在 error 里提示,不想拦截器提示信息。
后来反思了一下,自定义状态码应该是合理的,也就是后台返回 512、513 之类的,前台能直接通过状态码准确地判断当前后台到底哪错了。
但是这个拦截器这样写,就变成了,后台一个状态码对应一个提示信息,相当于我这个拦截器和后台抛出的异常绑定了,所以有时候虽然也是那个错,但是在这个界面提示出来就显得格格不入。
奇怪就奇怪在前台误解了自定义状态码的本质,自定义的状态码其实不是我后台有什么,前台就要拦截什么,新加一个状态码,就是为了前台可以更准确地提示信息,而不是一个 500 的服务器错误。
改正:以后拦截器只处理通用的状态码,如:401 跳转到登录,403 提示访问被拒绝。而一些涉及到具体业务的状态码,还是应该放到 onError 方法中处理。
不完善的 Loading
这是上次开会的时候晨澍提出来的,友好起见,当网络请求的时候应该显示 Loading 的动画。
想起来 NG-ALAIN 其实是为我们封装好了的,只是没有启用。
其实自己实现原理也简单,就是装饰器模式:
对原生的 HttpClient 进行装饰一下,组合一个带 Loading 的 YunzhiHttpClient。
以后 Service 请求就使用 YunzhiHttpClient,发起时,将 Loading 置为 true,数据回来的时候,将 Loading 置为 false。
组件中如果想用怎么办呢?直接注 YunzhiHttpClient,因为在同一个模块中是单例的,所以直接使用注入的 YunzhiHttpClient 的 Loading 来控制加载动画是否显示。
改正:使用此方式添加 Loading 动画。
字段名与数据结构分离
@Entity
public class HostGroup {
…
// 和电脑多对多
@ManyToMany
@JsonView({NoneJsonView.class,
HostGroupJsonView.getAllGroups.class,
HostGroupJsonView.getGroupById.class,
UserJsonView.getCurrentLoginUser.class
})
private List<Host> hostList = new ArrayList<>();
…
}
HostGroup 中有字段是 hostList,存储计算机列表。
具体的场景忘了,好像是潘佳琦在写功能的时候,我给提了点思路,突然一想,如果这个计算机存的是个 Set,那就不用这样费事了。
假设我们这样改:
private Set<Host> hostSet = new HashSet<>();
后台是简单了,前台表示很无辜。
List 和 Set,都是 Json 里的[],前台绑定的都是 Array,我不管你后台怎么存,但是请你改数据结构的时候不要牵连前台。
既然 List 和 Set 在前台看起来一样,那为什么不改成 hosts 呢?后台数据结构随便改,对前台无影响。
改正:以后再有新实体,字段名与数据结构分离。
使用 HTTPS
使用 BASIC 认证方式进行登录,前台将用户名和密码进行 Base64 加密传给后台。
HTTP 请求,在网络传输过程中黑客可以直接拦截数据,并查看 header,Base64 解密很容易。
既然大势所趋,那以后要求安全的项目还是使用 HTTPS 吧。
简单学习了一下,SpringBoot 配置 SSL 需要证书,证书可以买也可以自己生成。既然能自己生成,为什么还要买呢?HTTPS 证书好像还挺贵呢?
无意间点开天猫的 cookie,发现里面只认识 XSRF-TOKEN,其他的都不知道。仔细想了一下,应该是天猫对安全的要求很高,不光是 HTTPS 保证数据传输的安全,更重要的是要保证发起请求的一定是客户本人,可能有好多算法的验证,保证用户不受损失。
想想我写的,用户的 token 如果被窃取了,谁访问都行。
看来在数据安全的道路上,我们还有很多路要走。
团队文档仓库
写华软部署文档的时候发现,写一个软件如何安装的教程真的是太困难了,并且如何再有项目,再写文档,还需要再写一遍。
可以直接建一个软件安装的文档仓库,再写部署文档,直接说我需要 mysql,需要 nginx。
直接在 adoc 中使用文件包含,将网上的这个 adoc 文件包含到我的文档中,就好像是自己写的一样,其实是外部引进来的。
Angular 架构
大家看图,这是我的前台设计思路。
多模块主要是在 NG-ALAIN 那里学习的,此架构设计适用于权限分配系统,因为采用 loadChildren 动态加载模块,也就是说,只有当用户访问 /student 这个路由时,才会加载学生管理 Module,而不是不管有没有这个模块的权限,直接都交给浏览器去加载。
Core Module,被学生管理等实际的业务 Module 引用,该模块引入外部第三方组件。
包含基础实体,即与后台对应的实体,拓展实体,实际项目中发现不仅需要基础实体,还需要根据组件要的数据结构自己构建实体并传过去。
基础组件、基础过滤器、Service,都放在这里,这样在业务组件里想用就用,很方便。
设计出来了,感觉付诸实践时应该还是有所困难,毕竟目前用的是 NG-ALAIN 现成的,以后需要自己搭。
点赞 Angular
最后为 Angular 点个赞,经过一个项目的洗礼,发现技术选型是正确的,选择 Angular 是多么的明智。
我们追随的一直是国外的脚步,VAR 三者,肯定不用 Vue,毕竟 TypeScript 都不支持。
所以国外的主流技术一直是 Angular 和 React,两者都支持 TypeScript,只是在设计思想上有所不同。
Google 和 Facebook 都是互联网巨头,我们中国的互联网企业与之相比根据不算什么。(去年 Facebook 的股票跌了 6 个京东)
Angular 是框架,完善,直接把 Angular 一安装,什么网络请求,什么路由都有了,直接拿来用。
React 是库,小巧灵活,需要整合其他库才能开发应用,在 Facebook 改协议之前,React 当之无愧的前端第一框架。
Facebook 改了开源协议,就被 Apache 基金会封杀,同时国内全面弃用 React,所以国内涌现了无数类 React 框架。
即在不修改原 React 项目的前提下,只修改依赖的框架,框架对外提供的 api 相同,即可实现无缝切换。
最优秀的类 React 框架要数京东的 Nerv,性能非常好。京东主页采用该框架构建。
之前看到过经过前端的性能优化博客,采用自己设计的链表优化性能,现在也算是明白了面试官的真意。能当上面试官的,肯定都是通读开源项目源码或自己写框架级别的人物,人太多,基础的框架使用是个人学习学习官方文档都会,怎么筛选呢?然后面试官写框架的技术功底就用上了。
所以,你进不去阿里,不是你不够优秀,是你不适合写框架。
总结
总有一天,我们也要写一款属于自己的框架。