又来给大家更文了,今天是微服务网关实战的第六篇。
今天的内容比较偏前端一点,主要是给大家换换口味,毕竟学一个东西学久了就想学点新东西休息一点,俗称换换脑子。
其实早就想学学前端看了,不过碍于工作繁忙,也可能是懒癌发作一直没有成行,直到在做OKR的时候有些东西需要前端的支持,而我们又没有多余前端的时候,我就知道,我需要开始学前端了~
在往下讲之前,我忽然想起来我有一位前端网友,在我们之前都还特贫穷的时候(现在升级到贫穷),时常会在一块讨论问题,有时候我会说你们前端怎么怎么样,他就会非常反感,因为他觉得自己不是 front 而是 developer。
虽然我被怼了,但是从心底我是同意他的说法的,开发者不应该给自己受限,我们大家都只是在做前端 or 后端这份工作而已,毕竟有的人招进来的时候是前端,现在连运维的活都干呢,你说是吧?@CookieBoty
所以,本文的内容会夹杂前端和后端,前端的可以看看后端内容,后端的可以看看前端内容,换换脑子嘛~
1. Vue
我还依稀记得,三四年前刚学 Java 的时候还要学 CSS、HTML和JS三板斧,做后端工作三年后,我连怎么操作 DOM 都忘记了,可能许多后端小伙伴也和我一样,除了会 HTML 的一点标签,其他前端相关的知识早就忘完了,这也是很多后端迟迟不愿意接触前端的原因,太费心力了。
所以在我决定开始学习前端的第一个问题就是,我应该先学什么?
在我略微思考了三分钟之后,我得出一个结论:我应该先学一个前端框架。
我知道任何一门语言的技术栈都是有一个庞大的生态在支撑的,前端所涉及的东西除了前端框架之外还有打包工具,依赖管理工具,ES6新特性(可能它已经老了,对我来说是新的),卷的狠的再来点拆入拆解浏览器等等等。
这些八股文和 Java 有的一拼,但是我知道我不需要学这些的所有东西,我要学的时候只有一个:用一个工具帮我做成一个东西。
所以,虽然我连解构赋值、和操作DOM都不会,但是这不妨碍我学前端,我要先选中一个前端框架进行熟悉,然后利用这个框架的生态帮我做东西。
扯远了,说回正题,在两三年前的时候,前端还是 Vue、React 和 Angular 三足鼎立,但是到今年 Angular 除了外企似乎已经用的不多了,所以我的学习目标就放在 Vue 和 React 这两个身上了。
怎么选,其实我是纠结的,最终我听从好大哥@CookieBoty和众多网友的建议,学了 Vue。
网上很多人都说 Vue 上手好、文档全,我感觉完美符合我的预期,再加上火影完结之后我就开始追海贼王了,尤大的 onepiece 起名方式甚合我意,所以我就开始学起来了 Vue3。
怎么学呢?我想到了程序员的梦工厂某课网,找了一个教程来看,上面先教了我模板语法,又教了我单页组件,最后又学了 Vue 路由系统,前后花费一个多小时,看了十几节视频,我觉得我行了,就开始实践了~
最终,三天没写完一个页面。
2. React
Vue3
的难度让我有点触不及防,可能也是因为我没有抛弃后端的代码习惯。
我习惯用 TS 定义好数据结构去接收值和处理值,但是我发现 Vue3 中的所有对象都是一个代理对象,当我尝试将一个 Map 数据直接转换为一个 JSON 字符串的时候我发现不行,我也无法理解一个 Map 为啥不能在转 JSON 的时候把里面的 KV 带上,还需要我手动转换成一个对象然后再转一次,我很苦恼。
我更苦恼的是,当我尝试用一个数组对象循环生成某段模板的时候,我发现很麻烦,我感觉这不是我想要的前端,作为一个后端,我学了脚本语言,但是它却让我感觉到很多的枷锁在身上,这比我写 Java 还困难。
此时我意识到,Vue3的上手难度和Vue2不是一样的,这是一个成熟的前端框架了,它需要一个成熟的前端来操作,而不是我这种玩完就扔的二流开发。
当然,Vue 还是有很多好处的,从我可以看见的一点来说就是,ele-plus 这个组件库是真的漂亮。
Vue3 玩不转了,我就想换 React 了,再次来到某课网,找了个 React17 的视频来看,又花了我一个多小时,好在我已经有一些前置知识了,吸收起来还是蛮快的,学习的过程中,我觉得 React 给了我想要的东西:自由,脚本语言写起来的自由感。
在 React 中我不再拘泥于单页组件,统统都是函数式组件,单向数据流也让我更容易理解数据运行的方式,而且会 React 据说B格要比会 Vue 的高一点,这一切都让我觉得转 React 是正确的。
不过有利有弊,在我写 React 的过程中,我发现我在用 Vue3 写代码时候的问题就是 JS 独有的问题,比如我前面提到过的 Map 转 JSON 的问题,它不会因为某个框架就能让我更舒服。
可能有的前端小伙伴会想:你为啥要用 Map?
因为 Map 更符合我这个后端的认知,某些不确定的多选参数我装在一个容器里面,然后序列化后给后端我觉得这是一件极其合理的事情,它符合我的心智模式,但是 JS 或者 TS 都没有做到。
在使用 TS 的过程中,我几乎没有感觉到好处,TS 的类型检查反而让我觉得更不像脚本语言了,这一点我觉得比后端 Kotlin 差很多。
虽然有种种限制,但是好在 React 这个框架并没有让我感觉到有什么不适,反而是无缝衔接,我几乎是上手就写了。
最后总结一下我 React 都学了哪些东西才开始写东西的:
- 使用脚手架安装 react with ts。
声明类组件和函数式组件
:函数式组件是主流,类组件稍微看看就行,主要就是写起来麻烦。理解 render
:render 其实就是通过执行组件代码生成一个HTML片段,然后挂载到DOM上面。CSS 模块化
:通过 CSS 模块化,加样式的时候会非常方便,懒癌患者直接在代码上加行内样式也没问题,玩的就是随心所欲。State 和 props
:state 是重点,它代表了组件中状态,比如按钮是否显示之类的,props 则是不可变参数,由外部传递进来供组件使用。Hooks
:Hooks 我一般只使用到 useState、useEffect、useContext这三个,它们分别代表了声明状态变量,声明副作用钩子和全局数据传递。路由
:按照我的理解路由是通过占位符和浏览器的锚点来完成的,通过锚点定位到指定代码,通过占位符将组件代码生成到占位符占据的DOM处,当然这只是个人拙见,希望评论区大佬能给出更多细节。
学完上面几项,我觉得你写一个小的管理系统也是没问题的,啊对了,说到管理系统,那必然要用到 http 相关的东西,虽然由 axios 珠玉在前,但是 fetch 用起来也还行。
最后,我觉得 React 的文档比 Vue 的文档强上不少,这句话希望 JYM 别喷我。
3. 组件库
写前端的过程中,想要提效,组件库是必不可少的,我先后体验了 Ant Design、Material UI、Semi Design、Arco Design。
最终在做项目的时候用了 Semi Design
,因为它不用引入全局样式表就能按需加载,虽然我的好大哥告诉我 Ant Design 也可以做到这个效果,但是当时确实没有实践成功,还是我的功力太过薄弱。
从目前看来,我用过最舒服最方便的还是 ele-plus 可惜没有 React 版本。
虽然组件库是一个好东西,但是我觉得太过依赖组件库是一件很糟糕的事情,当你要做的功能组件库中有但是恰好达不到你要的效果时,就会很难受,怪不得很多人都要做一个自己的组件库了~
比如 Semi Design,在我使用的过程中我其实很不喜欢它的按钮效果,按钮上面总要有一个底色:
我想要一个无底色的图标按钮,但是 Semi Design 的图标按钮全部都是这样的:
可能这就是它独有的设计风格问题吧,还有一些随时可能遇到会违反自己的直觉的事情,让我意识到,组件库虽然不错,但是过度依赖也为自己的扩展留下很多问题。
写到这,突然就明白了为啥前端有时候会告诉我:” 这个效果我用的组件库做不了 “,我心想你的页面还不是你做主吗,居然能让组件库把开发者给拿捏了,等我也被拿捏的时候,我仿佛理解了他当时的情况,原来我的页面真不是我做主😟
4. 页面效果
虽然我学前端只花了几个小时,但是写页面却花了好久的时间,大部分时间都在调一些样式和排查错误,而且我还自己学了一手 Flex 布局,做了整体的页面布局。
在有时候感觉组件效果不好的时候还自己写了一下鼠标悬浮的阴影之类的小效果:
一套页面做下来整体感觉还是不错的,怪不得前端也被称为交互体验工程师了。
接下来给大家看一下整体效果,这是主页面:
我的这个网关控制台总共分为两个页面:看板和路由表。
路由表就是上图展示的这个,主要是把 Nacos 中的配置拉下来解析成数组对象展示在表格里面,然后在表格里面可以进行编辑和新增,然后通过 openApi 同步到 Nacos 远端去,这样就不用手动去在一堆配置里面改了。
这里要小小的吐槽一下 Nacos 的 Api,它们的这种发布配置居然是 Get 接口的,导致我要现在后端做一层包装,不然数据量大了很容易被浏览器拦截掉,它们新版的 api 接口我也看了相关的代码,居然不是常用的 JSON 传参,就此还和相关开发者对了一次线。
扯远了,说回正题,我的编辑和新增页面如下:
看板则是使用网关做了一些流量指标的记录,比如请求总量、日活总量、每小时在线人数、每小时请求人数之类的基础指标,并且把它们做成了一个图表的形式,有饼状图和折线图:
当然,对我来说最重要的还是路由表的查看页面和新增编辑页面,这几个页面花费了我最多的心力,而且页面的数据结构比较复杂,做起来对我这个新手来说是有点吃力的。
值得一提的是,图表是我做的最轻松的一个页面,用的是蚂蚁的图标组件。
5. 后端
最后,简简单单说一下后端我都做了什么吧。
由于这是后台系统,所以我将它和网关分开,新建了一个 admin 项目来处理相关请求,但是呢?加上前端那我的网关整体就要有三个部署的服务了:网关 API、网关控制台前端、网关控制台后端。
为了节省资源,我通过插件的方式把前端输出的代码copy到网关后端这个应用里面来,这样网关后端和前端的代码就可以打包在一个应用里面了。
其具体做法主要就是在后端应用编译打包的时候用插件先编译前端,然后对前端资源进行复制,具体插件如下:
<build>
<plugins>
<!-- 调用npm命令插件 -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<!-- 先执行前端依赖下载 -->
<execution>
<id>exec-npm-install</id>
<phase>package</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>npm</executable>
<arguments>
<argumnet>install</argumnet>
</arguments>
<workingDirectory>../admin-ui/</workingDirectory>
</configuration>
</execution>
<!-- npm打包 -->
<execution>
<id>exec-npm-run-build</id>
<phase>package</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>npm</executable>
<arguments>
<argumnet>run</argumnet>
<argumnet>build</argumnet>
</arguments>
<workingDirectory>../admin-ui/</workingDirectory>
</configuration>
</execution>
</executions>
</plugin>
<!-- 把 react 编译后的 dist目录下的所有文件拷贝到resource目录下 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-static</id>
<phase>validate</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>src/main/resources/static</outputDirectory>
<overwrite>true</overwrite>
<resources>
<resource>
<!-- 因为react打包目录在项目根目录,所以从这里复制 -->
<directory>../admin-ui/build</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
复制代码
平时调试和开发的时候依然可以像前后端分离那样,启动一个后端服务和一个前端服务,只在最终打包的时候打包在一块,所以这种方式哪怕是让一个专职前端来帮你写页面,对他来说也是无感知的,不需要关心后端干了啥。
6. 最后
好了,今天的文章就是以上这些内容了,本篇主要内容没有涉及到太多技术(当然也分享了一个前后端联合打包技巧),主要是分享了我自己在为项目写一些前端代码的心路历程,相信现在有很多工程师都对全栈很有兴趣,我也是想借此告诉大家,其实前端并没有太难学,几个小时完全可以上手写页面了。
Just do it.
最后,如果大家觉得本文还不错的话就可以点赞以示支持,对前端这块内容有更好的建议和说法也可以在评论区留言,我会积极对线的,下篇见。