论坛首页 Web前端技术论坛

JSF 与 "我的伟大发明" ---- 关于B/S UI开发的胡言乱语

浏览 67568 次
精华帖 (1) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2008-04-17  
我认为讨论事情还要有一定的场景和前提,不如假设你处在一个20-100人的中小公司中,也可以认为你是普通程序员或者是拥有技术选择权的架构师和技术经理,再假设你刚到公司,或者公司Java这一块刚起步,时间不算太长,还没有自己的AppFuse。

首先就是你的上级不管是技术出身还是管理出身,都会重视项目的时间成本和人力成本。作为架构师,把上述两项成本细分为主要是开发成本、维护成本、技术学习培训成本、人员流动成本,其中非常重要的一点,不管是国内还是国外客户,正式或者非正式的需求变更是家常便饭的,意思就是变更是比较容易出现的。

我就从这几点展开来说吧,其实不仅仅是JSF,其他技术一样可以这样分析。

大家比较认可的是在一般情况下,有IDE的支持JSF的开发速度还是令人满意的,如果小组中有一个人对JSF非常熟悉的话,也是可以考虑开发自定义组件的,这个是JSF支持认同的观点吧(感觉有些话和Hibernate推广的理由如出一辙啊,考虑和Hibernate类比了)。 但是这里面时有问题的,首先需求变更,Hibernate到了3.0以后,已经成熟很多年了,经过实践的检验是非常常熟的,对于不同的场景一般都有解决方案,JSF好像没有吧,大厂商强推的结果,更像是EJB3.0,现在不是J2EE刚开始的年代了,程序员们不再迷信大厂商的标准(这点很重要,是伏笔)。前面也有人说了,灵活性上,JSF是比不过纯客户端框架的,当然灵活往往也是要付出代价的,客户端的框架还没有能一统天下的(目前EXT不错),也没有好的IDE提供足够的效率上的支持,所以就开发效率(包括变更效率),可能打个平手吧(有前提的,前面提到过了)。

维护成本,如果公司里搞出个体系,不断培养JSF人才,貌似也不会太高,也还好吧,跳过。

技术学习培训成本,JSF相关的书好像没有JS相关的多吧,虽说学习曲线都不低,但是大部分人还是懂点JS的,但是JSF很多人是一点都没有入门的。当然JSF支持者会说,将来懂得人会越来越多,OK没意见,跳过。

人员流动成本,背后的意思是除了招聘成本以外,能不能留住员工,和员工对新技术使用的动力对于项目的效率、薪水(能留住他们的标准)是至关重要的,以人为本,员工认为这个技术路线是对的,不会影响他们的饭碗,他们很容易找到类似的工作,就会努力学习,薪水相对少点也能留住人。当然这是有前提的,刚才说了,不要和我讨论什么超过200人的500强之类的企业(据我了解,即使这些企业也在逐渐转变)。

好了,焦点回来了,又变成了要看大多数人对这个技术的认可程度。

再继续分析,程序员认为某项技术有前提,途经也是不太多的,无非就是以下几种:杂志、论坛、博客、大厂商的选资料、公司的牛人的意见等等。目前情况JSF不是太妙,主要因为EJB的前车之鉴,大家对JSF不是非常的感冒。然后流行的技术中,也不见有JSF的一席之地,有相当一部分的人认为JSF架构不够优秀,当然会有人跳出来说ASP.net和JS本身不够优秀,还不是这么多人学,哦,问题来了,纯客户端框架有一个非常大的优势就是,目前的情况下,服务端不管是Java还是其他的PHP都是能互通的,这个技术在近几年之内是不会淘汰的。

大家是不是感觉我扯了这么多和技术无关的事情,非也,我想在说我的技术观点之前,上述话是很有必要的。我是不赞同目前涉足JSF的,即使要涉足至少再观察1年以上吧,我还是认为2年后JSF也不会有多少改观。支持JSF的大厂商还是太少,和广大的开源社区相比,它的组件无论从质量还是数量还是功能都是远远还不够的(不要再在这里大脑中出现什么开发效率的问题,前面的话不是白讲的)。

然后从封装上来讲,你可以说Hibernate封装的不是SQL么,封装没什么不好,我认为SQL语句很多年没有大变,非常稳定是能够很好封装的基础,客户端JS有这么稳定么,不可能的。UI展现技术、UI交互模式(想WEB2.0)、UI变化程度一直在变化(我没有说现在UI是进步,单纯从UI上来说,从以前的CS到现在的BS是倒退,当时出现这种现象时有很多历史原因的,升级成本和大厂商宣传推新技术是主要的),在如此高的变化程度下,还没到封装的时候,等到JS客户端技术相对稳定了,才可以考虑良好的封装,否则灵活性肯定是很差的,新功能的支持上也一定是非常滞后的。但是谁说JS技术能稳定下来么?Flex、SL都是虎视眈眈啊,单技术结构上来讲FLex等RIA技术确实是不错的,只不过目前还不成熟而已。

再说到性能,性能不佳一方面说明架构本身设计不够优秀(现在不是EJB时代,EJB在9年前的当时确实是比较优秀的)的表现特征之一,再者不能说企业应用就不考虑性能,将来的趋势是服务器应该能够支持更多的并发和负载,平白无故为了客户端的显示和逻辑增加服务段的资源消耗是没有道理的,应该充分利用客户端的计算资源,这也是大方向的问题之一,类似的还有就是太多的有状态的东西对集群是很不利的,叉出一句,想自己创业的程序员们,千万别去学什么性能不佳的JSF,哈哈(是不是笑得太阴险了)。

感觉自己技术方面说的话还是太少,但是现实很残酷,很多时候决定技术的未来不完全是技术的好坏,很多因素都会影响未来的技术走向。
已被评为好帖!
   发表时间:2008-04-18  
一看你就是搞JavaScript出身,对JSF知之甚少,还真敢在这里"胡言乱语". He He.
只是你的观点偏颇的一塌糊涂,很容易误导了别人. 我今天认真批一下,主要是为了不想让别人受你误导(有些人一见你那5颗星,会肃然起敬的) . 同时也希望楼主能开阔一下自己的眼界,不要被自己熟悉的东西所局限了,对某些事物进行无情批判的时候,不要在”知之甚少”的情况下进行.

此文是 "初看jsf后的胡言乱语"http://fins.iteye.com/blog/181093 一文的延伸
同样是在我对JSF知之甚少的情况下写的, 如有不当,请见谅


如我所见,你确实对JSF是知之甚少.

先来看看一个"我的伟大发明":
汤匙用来喝汤,刀子用来切牛扒. 多麻烦啊. 我设计了这样一个东西:
一头是勺子, 一头是刀子, 这样餐具就可以少一件了, 为我们的采购 摆放 整理 清洗, 提供了极大的方便.
相信不久的将来,这样的产品一定会彻底的淘汰掉现有的汤匙和刀子.

什么?你早想到了? 哦 那好吧 算作"英雄所见略同"好了.
========================================

我的伟大发明说完了, 该说说JSF了.


这个伟大发明纯属你的臆想,不会有人想发明这样一个东西,而是为一个特定的场合和目的,发明一样特定的工具.不要搞错,以为我和你的最后结论英雄所见略同.而是你的这个比喻错了,你的"伟大发明用起来",比一刀一匙用起来麻烦,而且会挺难看. JSF相对来说比较优雅一些,也好用一些.

以前写过一篇文章:
"世上没有B/S系统,只有B系统和S系统"http://fins.iteye.com/blog/123265.

当时对jsf一点也不了解 所以没有谈及更多
(那篇文章里说的更多的是 错误的---我眼中的错误的---使用ajax 所引起的一些我的思考)

但是现在看看 用那篇文章里的观点来表达我对jsf的态度 也许会更合适.


我写那篇文章被很多人说是"标题党,唱高调"
其实 我真的希望我的那篇文章是"标题党,唱高调", 因为那就说明,我所说的已经是废话,已经是尽人皆知的事情.


看过你那篇东西,虽然楼层垒的高了点,不过还是脱不了标题党的干系.

但事实恰恰相反.有太多太多的人 依然固守着传统的桌面开发模式,并且企图把这种模式强加到B/S系统中.
希望用一种语言 一种模式 来解决B/S里的所有问题.
这种想法是好的, 但是那是多么多么多么的不现实啊.
和前面提到的"我的伟大发明"是多么多么多么的相像啊.

从这里开始,你开始断言了,开始臆想出了JSF的目的是要解决所有B/S的问题. 我的理解是: 1)JSF这个发明不是想一统江湖,而是简化开发,减少代码量,降低开发成本,是想对Web层开发进行规范化;2)JSF会适用很大部分B/S系统, 但不可能适用所有的B/S系统,比如某些系统对客户端体验有很高的要求,操作交互频繁. 3)JSF的出现会使一些开发模式被淘汰或改变,正如Ajax的出现也会改变传统的B/S开发(form提交模式以Struts为代表),但不会成为唯一,也不可能.

我承认java很好很强大, 它有如下优点:...(此处省去四万五千六百七十八个字)
但是 但是 但是, 他那四万五千六百七十八个字才能说完的优点里,偏偏不包括 编写web-ui.

而jsf 就是要利用各种手段,来让java去做它本就不擅长的事情.
用java费了 九百头犀牛二百只华南虎的力气(简称九牛二虎之力) 做出来的事情,
换作别的语言来做,也许只要九只蜗牛二只壁虎的力气(简称九牛二虎之力) 便能搞定.
引用
用java来生成html+js+css层面的东西, 然后用java来处理发生在 html+js+css层面上的事件.
怎么可能比在html+js+css层面内部做这件事 更好呢??

关于jsf的ui层的实现有多么拙劣 我就不多说了,
如果有哪位能找出一个做的很好的 效果比ext qooxood dojo 之类的更好的东西请告诉我.
那些商业的 大公司 用jsf做出来的东西 什么 ICEfaces RCFaces RichFaces ... , 在ext面前, 你们不觉得你们的face很红吗?


首先你根本没有搞懂JSF的两种状态: 运行态和开发态. 在运行状态JSF通过RenderKit,根据页面UI组件,生成Html+Javescript,传递给Browser运行.java根本没有处理发生在 html+js+css层面上的事件,只是处理Http Request.
另外,使用JSF开发,你根本不需要去关心生成的Html+javascript长什么样,而是去关心其结果,程序员要做的
是简单地在页面里面使用组件.

我发现你所谓的"拙劣,需要为此脸红”,其实你只有一个标准,那就是"效果"好,进一步讲是"好看”.而根本不知道一个大系统最重要的是要提高开发效率,降低维护成本.

对JSF来说,重中之重不是要有漂亮的界面,而是组件重用,统一完善的 Http request(form submit,event)的处理机制,其生命周期如下:
1. Restore view
2. Apply request values; (process events)
3. Process validations; (process events)
4. Update model values; (process events)
5. Invoke application; (process events)
6. Render response

也许有人会说
JSF也可以和EXT dojo相整合啊 JSF UI也是解耦的 可替换的啊,
如果一个产品能够整合一个优秀的产品,那么到底是这个产品优秀 还是被整合的优秀?
而且整合还要看成本呢,
用jsf完全的封装ext有意义吗 有必要吗 有完美的实现吗? 封装出来的东西还具备ext原有的灵活吗?

关于jsf的"可替换", 这里我们要弄明白一件事, ext可以换成dojo,我们就能说jsf的ui层是高度解耦了?
jsf在封装ext的时候,肯定要写很多标签啊 java类啊, 那些东西也是 jsf 的一部分.
我把ext换成dojo, 那些为ext封装的标签啊 java类啊还能用吗???


能想出JSF和Ext dojo整和之类的点子,充分证明了你对JSF和Ext等Js框架的根本区别在于什么地方还是不清楚. JSF在服务端生成所有html+javascript, Browser只是执行而已;而Ext等JS框架是在Broswer端动态生成html. 整合什么?JSF组件里整点Ext漂亮的CSS?
“jsf在封装ext的时候,肯定要写很多标签啊 java类啊”这句话是我见过的最具有想象力的一句,你也真敢想.

也许有人会说:
UI组件只是JSF的一部分, 并不是JSF的全部. JSF还有很多 例如:某某模型,某某规范,某某架构,某某机制....
一味的批评JSF的UI, 从而否定整个JSF的做法是错误的

但是 但是 但是 JSF UI这部分和JSF的其他部分---那无数个"某某"----完全紧密的结合在一起,
没有UI的JSF,根本就毫无生命力,根本就不再是一个可运行的框架,
而JSF UI孤立的拿出来, 也根本就不是一个能被称为UI的东西.

所以,我怎么可能单独的去评价JSF的ui?怎么可能脱离JSF UI单独的评价JSF身上UI以外的东西??


能做出这个假设”有人也许会说”,并有这么一大段评论,又见你对JSF的知之甚少.
JSF本身就是以UI为核心的Web框架,没有UI,谈JSF一点意义没有,所以根本就没有这个”有人会说…”.

引用
我再表达一下 我的观点(可能过于理想化):
引用
在B/S系统中
UI层与系统其他层面的东西的唯一联系应该是"数据"
UI层应该是在后台系统不变的情况下可切换的

总之两个字"解耦"
.

你先是断言了一个准则: B/S系统要”解耦”,否则都不是好系统. 其实,你应该明确的讲出这样做的好处. “UI层应该在后台系统不变的情况下可切换”,这个是好处吗? 显然不是. “UI层与系统其他层面的东西的唯一联系应该是"数据"”,这个也不是.这个顶多是为了得到那些”解耦”要遵守的原则.

那你认为的好处是什么呢? 是效果好?界面漂亮?还是就是要分开? 我试图从你下面的陈述悟出点东西:

其实服务端 与 客户端 就是两个独立的系统,而且是两个独立的异构系统.
处理他们之间的关系和处理两个大型的异构系统的关系非常类似,应该咬住"服务"二字不放.
所谓"服务"应该是: 生产者提供,消费者享用.
而不是: 你告诉我我每一步要怎样做,然后我再一步步的做给你看. 这不叫服务,这叫"奴役".
任何企图在一端生成另一端代码的做法都是欠妥当的.


发现你又在断言: 任何企图在一端生成另一端代码的做法都是欠妥当的.为啥欠妥?不得而知. Browser和Server之间”非常类似两个大型的,独立的异构系统”,更是不知从何说起.

从JSF的观点看,不存在B系统,S系统,本来就是一个系统. Browser只是执行html(就是一傻终端), Server负责处理,生成html,就是想借用桌面系统的理念,以近乎C/S的方式开发系统. 目的是什么? 提高开发效率,重用组件,减少代码,易于测试. 所以,这里根本不需要解耦,因为他们都属于展现层,在一个JSF请求生命周期内完成任务,不需要代码负责Browser到Server的数据转化,数据验证,等等. JSF负责把Browser端的任何提交转换成Server端的 Application 调用.

“解耦”被你借用来描述B/S系统实在是不妥, 解耦适合于出现在"展现层和业务逻辑层”之间,或者是不同的"模块之间",不同"系统之间".

任何违背这个准则的框架我都不认为是好的框架. JSF WICKET DWR 都不是.
事实上,我不认为有哪个框架 可以同时做好 后台和前台两个层面的工作.
既然做不好 那就别做.

整齐划一是好的,但是 我们应该 必须 一定 永远都要承认"分工"的存在.


我猜一下,你理想的B/S系统应该是这样: 前台用Ext (或YUI, DoJo之类),后台用SpringMVC之类UI不强,做个Controller能胜任的框架.

其实,不瞒你说,我现在的公司用的就是这个架构(YUI+SpringMVC+EJB). www.igindex.co.uk

优点:
1) 给客户的感觉象是桌面系统(大量使用Ajax,用Json传递数据,基本不刷新,跳转页面).
2) 界面美观,动态,用户操作灵活.

缺点:
1) 程序代码量大,很难维护,开发调试复杂
2) 需要考虑各种不同版本Browser
3) 运行稍慢

选择这种架构最主要的原因是: 客户体验要求非常高, 系统功能复杂,但功能数量不多.

但是一般的B/S系统(ERP等各类信息系统),通常都是功能繁多,但是客户体验要求不高的,绝对不适合上面的模式,而会适合用Struts, JSF之类的框架的.

所以,承认有"分工”,但不是在Browser和Server之间,不是在是否"一端生成另一端代码"之间,而是分析不同的技术适合什么样的客户需求和系统特点,去找到最适合的.


最后简单总结一下JSF:

1) 已经相当成熟(如果struts算是成熟的话,JSF能完成Struts的任何功能)
2) 开发速度(相对JSP,Struts)快很多.
3) 运行速度(相对Struts)慢一些.
4) Struts最大的问题是Form驱动,不是Event驱动,有挺多时侯写东西要绕弯子. 所以,如果还没有用过Struts的人应该直接用JSF.
5) JSF的任何事件都要提交服务器,刷新页面,比如做级联操作,没有Ajax支持有时会比较难受.不过现在有比较理想的解决方案,是JBoss RichFace(已经合并了AJAX4JSF),有很好的Ajax支持及很好的组件.最重要的是它是运行在JSF之上,不影响原有的JSF应用,可以和任何JSF实现(Myface等)同时运行.
3 请登录后投票
   发表时间:2008-04-18  
to:fxy1949
  支持你的反驳和观点!
  楼主一直想把jsf和某种页面技术混淆在一起评价,这是很容易形成误导的!
0 请登录后投票
   发表时间:2008-04-18  
不高兴引用楼上的长篇大论,我看出你的问题了,我的这个回帖肯定是偏题了,专门针对你的这个回帖而回帖。

我们公司现在就是EXT2.0+SpringMVC+Spring+Hibernate,当然为了降低风险,我们从传统的SpringMVC+JSP+JSTL->SpringMVC+FreeMarker->SpringMVC(代码精简)+FreeMarker(代码精简)+EXT2.0,虽说是慢慢过渡,随时能因为一些特殊需求退回到传统模式,但是整个过程只用了半年多。

不是我不谦虚,毫不客气的说,身为架构师,我在带领人进入EXT领域的时候,时时刻刻想着两大准则,对于某项EXT效果,一,增加页面多少代码(很多时候还是减少代码)的情况下,我们能减少多少其他环节(SpringMVC+FreeMarker)的代码,二会不会造成非常高的学习曲线(也就是是否非常怪异,相对的不太规范)。

我在使用一个EXT的解决方案的时候,会通盘考虑,每前进一步,基本上都是前台和后台的代码量同时减少的,只是适当增加员工的学习量,少数情况,适当增加客户端的代码(当然这种情况下无非是非常好的页面功能效果或者是能大量减少服务段的代码)。

多以我可以说,你们公司的技术方向向Ajax迈进的过程是不佳的,新技术要很平稳很高校的落地有时候非常不容易的,这点上我只能说你们做得比较差了。

引用

缺点:
1) 程序代码量大,很难维护,开发调试复杂
2) 需要考虑各种不同版本Browser
3) 运行稍慢


1.代码量大,难维护,呵呵,说过了。开发调试复杂,首先要确保兼容FireFox,然后利用FireBug调试。(我还想说VS2008的JS调试功能非常强大呢,虽然我鄙视微软)
2.我们用EXT2.0没碰到太多的不兼容情况。
3.运行稍慢,强烈抗议,不要把客户端计算和服务端计算混为一谈。慢的是客户端不是服务端。以后说速度请分开说。而且慢的是客户端的渲染,也不是网络传输量。
4.还有个隐藏问题,每个项目总有些东西是你之前没有积累到的或者现成组件不存在的,或多或少总会在客户端的JS上做定制开发,也就说EXT的效果看你用多少了,我们只用了10%都不到,不是为了效果而效果,因为这10%中大部分是传统方式也必须要实现的,不存在什么代码大增的情况。就因为功能重复,使用封装好的客户端框架,代码量比传统方式反而是减少的,不会比JSF的封装多到哪里去,但是JS规范、EXT灵活性都要远胜任何服务端生成为主的框架。

引用

最后简单总结一下JSF:

1) 已经相当成熟(如果struts算是成熟的话,JSF能完成Struts的任何功能)
2) 开发速度(相对JSP,Struts)快很多.
3) 运行速度(相对Struts)慢一些.
4) Struts最大的问题是Form驱动,不是Event驱动,有挺多时侯写东西要绕弯子. 所以,如果还没有用过Struts的人应该直接用JSF.
5) JSF的任何事件都要提交服务器,刷新页面,比如做级联操作,没有Ajax支持有时会比较难受.不过现在有比较理想的解决方案,是JBoss RichFace(已经合并了AJAX4JSF),有很好的Ajax支持及很好的组件.最重要的是它是运行在JSF之上,不影响原有的JSF应用,可以和任何JSF实现(Myface等)同时运行.


1.现在是框架都比Struts1.x强。
2.是框架开发速度都比JSP,Struts快很多。(其实前两点你都没说那些必要的JS工作量的问题,等于白扯)
3.运行速度不再重复说了。
4.Form驱动很早就有了,不是Struts发明的。
5.我怎么感觉这个就是JSF的先天不足呢,呵呵。
  基于这点继续介绍我们公司的结构,为了兼顾某些特殊需求和减少不必要的Ajax请求,我们的结构仍然是很少的FreeMarker+JS文件,基本上Ajax请求种类数量是页面跳转的3-10倍左右,也就是服务端要更多地考虑会客户端的Ajax请求提供更多的支持,这是根本。
0 请登录后投票
   发表时间:2008-04-18  
To:fxy1949 ...

ls两位说了等于没说,你指出的东西楼主都知道,只是你是在强调jsf的优点,说了那么多只说了一个tag的功能

补充一下:你对struts的认识也很不到位 建议搜索一下坛子里讨论truts1的老帖 再搜索一下讨论webwork2/struts2的老帖
0 请登录后投票
   发表时间:2008-04-18  
To:fxy1949

看来做人不能太谦虚

谦虚一下不要紧 被你当白痴了

你压根没明白我在说什么

0 请登录后投票
   发表时间:2008-04-18  
fangshun :

你理解错了

我不是要把 jsf 和 某种页面技术混合评价

我哪句话让你有这种错觉了呢?

我知道 jsf在ui层是一个很有包容性的东西 ext之类的页面层技术完全可以理解为是jsf的一个子集, jsf本身是一个一体化的 一站式的解决方案 不仅仅关注前台技术.....

而我质疑的就是jsf这种做法  同时 我的观点很明确, 你可以前台后台都处理都涉及,
但是不能像现在这样 拙劣的将两者糅合在一起 使其无法分离.

再举个例子吧

大家见过那样的显示器吧: 显示器左右两边或者是上下是和音箱整合的.

我不反对显示器生产厂商提供这样一体化的产品 而且我也承认这在一定程度上简化了用户的购买电脑外设的流程 为搬运 使用提供了一定的便捷.

但是我不能容忍那音箱是无法拆卸的. 
音箱坏了不好修 我觉得音箱不好 或者是显示器不好时 无法单独更换.

总之 问题多多

不知道大家明白我的意思没
0 请登录后投票
   发表时间:2008-04-18  
LZ说的太多,估计,看的人都没只是对某些部分有些印象了。建议LZ能不能整理一下你的文章观点,理清一下思路。我也想搞明白一些。虽然我现在JSF是想向往,其他的,如Ext也没用过,只是看过它的Demo。
0 请登录后投票
   发表时间:2008-04-18  
qjzhyf 写道
LZ说的太多,估计,看的人都没只是对某些部分有些印象了。建议LZ能不能整理一下你的文章观点,理清一下思路。我也想搞明白一些。虽然我现在JSF是想向往,其他的,如Ext也没用过,只是看过它的Demo。

另外,我现在开发用的,基本上也是一种传统的Servlet + jsp + html + 少量的js脚本submit的开发方式。技术层面遇到的也不少,但是感觉,还是开发过程和需求变更等这方面的问题更加重要(有点偏题了),处理用户不断的业务需求,添加或者加在原有的业务逻辑里面,非常的难受。
0 请登录后投票
   发表时间:2008-04-18  
qjzhyf 写道
qjzhyf 写道
LZ说的太多,估计,看的人都没只是对某些部分有些印象了。建议LZ能不能整理一下你的文章观点,理清一下思路。我也想搞明白一些。虽然我现在JSF是想向往,其他的,如Ext也没用过,只是看过它的Demo。

另外,我现在开发用的,基本上也是一种传统的Servlet + jsp + html + 少量的js脚本submit的开发方式。技术层面遇到的也不少,但是感觉,还是开发过程和需求变更等这方面的问题更加重要(有点偏题了),处理用户不断的业务需求,添加或者加在原有的业务逻辑里面,非常的难受。

严重同意,需求导向很重要,处理用户不断的业务需求,JSF是不够灵活的,额外增加的成本最终会抵消一开始减少的时间成本(重要原因是灵活度欠缺导致的时间成本的增加量,抵不过减少的时间成本量。技术选择其实就是找平衡点)。
0 请登录后投票
论坛首页 Web前端技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics