`
robbin
  • 浏览: 4821624 次
  • 性别: Icon_minigender_1
  • 来自: 上海
博客专栏
377a9ecd-1ea1-34ac-9530-9daa53bb2a7b
robbin谈管理
浏览量:137078
社区版块
存档分类
最新评论

发现JBoss Seam很棒呀!有用Seam做过项目的吗?

    博客分类:
  • Java
阅读更多
上周去见了一个朋友Mark,他应邀在Red Hat的研讨会上面介绍他曾经用JBoss Seam做过的一个大的项目。因为听了他的演讲,对JBoss Seam多了一点认识,有点出乎意料的方便。所以周末在家下载了JBoss Seam摆弄了一下,把Seam自带的examples都浏览了一遍,也大致看了一下Seam的Reference,感觉挺惊艳的。于是又在JavaEye上面搜索了一下Seam,这才发现自从去年下半年开始,JavaEye已经有大量关于Seam的讨论了,这都一年多过去了,看来自己对Java社区已经有点孤陋寡闻了。

写这个文章的目的是和大家一起交流一下JBoss Seam,虽然我通过文档和代码,已经对Seam有了不少了解,但是毕竟没有用Seam写过项目,希望有这方面经验的朋友多谈谈自己的体会。那么作为抛砖引玉,结合与Spring的对比,我先谈谈自己的感觉吧:


一、Seam适应快速开发、简化框架的趋势

在RoR流行之前,Java社区的主流还是非常讲究分层、架构、复用和模式,而比较忽视快速开发和简化架构的,其结果就是代码量大、开发周期长、架构相当烦琐。以比较常见的Struts/Spring/Hibernate为例,从大的分层来说就有Web层、业务层和持久层,从细的分层就从前到后有:View(JSP) -> Struts Action -> Spring Business Object Bean -> Spring DAO Bean -> Hibernate Persistent Object。如果有Remoting调用,那么还需要相应的Service Facade层。每层都是用不同的技术框架或者模式、各层之间整合的方式也是五花八门。把整个项目的架构搭建起来,已经是非常麻烦的事情了。

Seam给我的感觉像是一个异常简单的MVC框架,他实际上只有两层:JSF View和 Seam Component。而Seam Component有两类:一类是Entity Bean,另一类就是Session Bean。Entity Bean映射数据库表,Session Bean完成所有的业务逻辑,包括可能的持久化,事务,响应页面请求、商业逻辑,页面流控制等等。配置文件也不多,除了一堆基础的配置文件,唯一一个需要不断修改的就是pages.xml了,即配置JSF的view映射。

所以Seam开发项目看起来很简单、很直接,无分层之苦恼。相应的也会让程序员把精力主要放在业务逻辑组件的实现上,而不是把精力浪费在架构、分层、模式和基础设施搭建的工作上面。


二、Seam的数据绑定做的很出色

由于是一个简单的两层结构,View和Component之间的数据绑定做的很出色,看起来比我欣赏的Webwork的数据绑定方式更胜一筹。官方的说法叫做双向依赖注入,在component里面可以直接取到页面提交的数据,在页面也可以直接访问component数据。

另外持久化数据的校验也直接集成好了,在EntityBean里面声明数据的约束,在页面就可以直接校验了,和RoR的数据校验方式是一样的,当然这也得益于Gavin King是Seam和Hibernate两个项目的作者的缘故。


三、Seam的组件机制看起来相当好用

既然Seam简化了分层,实际上把主要的工作都推到组件层去完成了。但是Seam的组件层看起来很简单,这得益于Seam的组件机制设计了很多的组件状态,根据不同的组件状态,天然的划分了不同组件的功能和逻辑。

Seam的组件有点类似于把传统MVC的Action和Spring的Bean合二为一了,但还是不同于传统的MVC框架下面的Action:传统的MVC Action是基于页面请求的,无法复用,而Seam的组件是事件驱动方式,它只需要捕获和实现事件代码就可以了,至于怎么触发它并不需要知道,他和Web层可以不绑定,因此理论上面来说是可以实现组件复用的。我个人认为Seam的这个组件机制非常巧妙,既可以用来实现响应页面事件,绑定页面数据的所谓Web Bean,也可以用来实现和Web没有任何关系的纯业务逻辑组件,一个很漂亮的实现。

另外Seam的组件注入机制看起来也很简单,不像Spring那样麻烦,而且内置了很多现成的组件进来,直接用Annotation声明一下就可以用了,感觉写组件真的很方便、很灵活、很强大。


四、Seam把数据库资源的管理和事务的封装完全隐藏起来了

Spring的数据库资源管理和事务封装是通过提供了一系列的代理类以及配置文件来实现的,程序员还是要通过配置文件的方式来手工管理事务,访问数据库也必须通过Template编写匿名内部类来实现,而且在Spring/Hibernate框架下面,OpenSessionInView是一个很讨厌的问题。

但是Seam已经把数据库资源的管理和事务的封装全部都隐藏起来了,程序员完全不需要知道,也不需要操心这些事情,这真是个大大的解放。当然Seam可以做到这一点,也无非是因为Seam提供了一套上至View层,下至持久层完整的框架,因此可以把实现细节隐藏在框架内部,不暴露给程序员。Spring之所以做不到这一点,也因为他只充当了一个黏合剂,不能够直接修改View层和持久层带来的限制。


五、Seam对第三方框架的整合看起来比Spring更深入

原来印象当中只有Spring才提供了一站式的解决方案,这次一看Seam文档,呵!发现Seam也都齐全了,什么邮件啦、工作流啦、页面流啦、规则引擎啦、异步任务调度啦、消息系统啦、Web服务啦、远程调用啦、甚至全文检索啦全部都集成了。而且集成的比Spring更深入一些,例如Java EE本身的JMS,MDB自然是Seam的强项,而JBoss自家的JBPM,JPDL,Rules集成的更加没得说。

从整合角度来说,感觉Spring和Seam的出发点不同:Spring更像一个平台,我提供整合的可能性,然后程序员你自家去整合,我提供一些写好的整合bean,对于这些你通过XML配置一下就整合进来了,如果我没有提供bean的,那么你也可以自己写bean来整合。而Seam更像一个完整的框架而不是平台,我这个框架想提供的功能,框架自身就已经整合好了,你直接用就是了,你也可以自己写扩展来整合,但是这个不是Seam希望程序员做的事情。

因此对于程序员的感觉来说,Spring给你提供了一切的零件和半成品,但你要自己动手来组装,而Seam已经给你装好了一个成品,你就别自己改装了,直接拿去用吧。


六、Seam提供了方便的代码生成器

和appfuse类似,可以直接用ant task来生成一个完整项目的骨架,以及相应的组件代码生成器,利用seam-gen可以快速生成一个完整的、带有AJAX功能的CRUD项目,而且还是一个eclipse或者netbeans工程,你可以直接用IDE打开编辑了。这功能虽然不太难做,但是对于程序员来说,帮助是很大的。Seam做的相当不错。


以上是我对Seam的一点小小的赞许,当然我也有一点疑问:

一、Seam的View实现是JSF,看页面代码还是密密麻麻的Tag

我是非常反感JSP Tag的,看看页面密密麻麻的Tag就头皮发麻,能不能弄一个Template呀,例如freemarker啥的?这些Tag既不直观,也不方便扩展。需要扩展页面组件,总不能让我自定义Tag去干活吧?不清楚这个问题怎么办?像freeamarker还可以方便的自定义页面宏呢。

二、每次修改都要重新打包发布,太麻烦了吧

就算修改一个页面,也要整个打包deploy成为一个ear去拷贝到jboss的应用目录下面,这个要是改页面,不是得烦死? 我以前都是在项目里面直接内嵌Jetty,作为一个application启动,修改页面根本无需重起呀,更不要说deploy了。


总体来说,我觉得Seam框架非常出色,尤其是他的组件机制设计的很有匠心,真不愧是Gavin King精心打造的框架了,虽然看起来还是有些缺陷,但是做企业应用项目的话,Seam是一个很棒的选择,作为程序员来说,要比用Spring/Hibernate/Struts省心的多,更能够把精力放在业务逻辑的编写上面,开发效率也很不错,可能是Java开源框架里面最优秀的快速开发框架之一了。
分享到:
评论
120 楼 dengyin2000 2008-07-22  
fireflyc 写道
JSF是我比较痛恨的。以前觉得还能凑合,但是现在在感觉越来越差了。
如果没有了JSF那么为什么还要Seam呢?使用Seam的长会话吗?Spring也能。还有什么理由让我们用Seam呢?我一直在找这个问题的答案。



jbosstools 会是一个理由, 我也是不喜欢JSF的。 搞过一段时间后 对SEAM也有所看法。

seam用来做些项目还是可以的
119 楼 fireflyc 2008-07-22  
JSF是我比较痛恨的。以前觉得还能凑合,但是现在在感觉越来越差了。
如果没有了JSF那么为什么还要Seam呢?使用Seam的长会话吗?Spring也能。还有什么理由让我们用Seam呢?我一直在找这个问题的答案。
118 楼 comeofage 2008-07-19  
我觉得jsf+seam是如虎添翼了,我用他们做了个比较复杂的ajax ui,感觉很不错,感觉特别爽的是jsf有许多ajax控件可用,我相信jsf会成为主流的,毕竟功能强大才是王道
117 楼 comeofage 2008-07-19  
发布的时候可以用explode啊,这样就可以不打成ear包了,而且还只是把修改了的文件发到服务器,用eclipse,很爽的呢
116 楼 vangelee 2008-07-17  
使用一下Grails吧!
115 楼 little51 2008-07-17  
我已用jboss seam2.0.2开发了三个项目,jboss tools + eclipse很方便,jsf文件中用了richfaces,很清晰。
seam做企业应用很不错。
114 楼 andyhan 2008-07-16  
现在RichFaces和IceFaces提供的JSF的实现已经足够好了,自定义JSF标签也不是必须的。
问题是如何让现有的页面开发人员熟悉JSF的开发流程才是问题的根源。JSF上手慢也确实是事实。

http://livedemo.exadel.com/richfaces-demo/welcome.jsf
http://component-showcase.icefaces.org/component-showcase/showcase.iface
113 楼 cyberblue 2008-07-16  
无论MyFaces还是Seam自带的元件根本不够用,JSF如果要做出好一些的效果需要自己定制页面元件,甚至要写一些标签和Component,但大部分制作UI的人并不喜欢这种方式,认为这是做业务逻辑的程序员的事情,但程序员认为这是UI Team的事情,所以JSF两头不讨好。
112 楼 差沙 2008-07-16  
大批的人说JSF不说,就算有偏差,也说明JSF确实存在问题。希望牛人们能总结一下JSF的优缺点。客观点说。
111 楼 allaneiaaa 2008-07-15  
楼上的说的好。俗话说,客户就是上帝,而上帝只关心的的是功能性,功能性主要体现在ui的呈现上。 所以一个应用最主要的是ui,其次才是可扩展 可维护性,所以说不要过于在追求新的技术,了解关注即可。 很多企业应用还是建立在成熟稳定的架构上的。
110 楼 jameswxx 2008-07-15  
    我不知道robbin以前有没有了解过JSF,其实你所说的这些快速开发、简化框架,数据绑定,事件驱动是JSF本身的特性,我看到seam有这些特性,一点都不惊讶,它是以JSF规范和EJB3规范为中心的一个产品的延伸。JSF和ejb3的结合可以解决你80%的问题,JSF控制VIEW层,session bean业务层,entit bean持久层(ejb3的规范已经建议不要叫entity bean了,叫 persistence unit),贯穿从请求到响应纵向生命周期,seam提供的诸如工作流,邮件,消息驱动bean等等则横向拓展了seam可以控制的业务范围,让开发人员有更多的选择。seam的产品结构,我觉得就像一个十字架一样。
     我短时间内不太看好seam,因为并没有多少人喜欢用JSF,虽然数据绑定和事件驱动机制可以节省很多时间,让人觉得很轻便,但是JSF的弊端也有很多。
     JSF的tag非常繁琐,导致美工与开发人员之间很难协调,有时候还不能正确的呈现css的效果。 所谓的tag,我一直认为,在关键的或者数据繁多的地方,用一个tag解决,那确实是一件让人感觉惬意的事情,可以如果整个页面,就连一个小小的输入框都要用tag,那真让人觉得头疼,有人说为什么你一定要用JSF tag呢,因为有的地方你的输入框和数据绑定了,你还要使用时间驱动,事件驱动又要靠JSF去实现,你说能不用JSF tag吗?而且JSF的页面布局也是非常的难搞,页面布局一个很小的改动你都要调试半天,常用的网页编辑工具又对它没什么用,因为它都是自己的tag,dreamweaver傻眼了,不知道怎么办,页面效果面目全非,这个对于web系统来说,是非常伤脑筋的。而且JSF的生命周期也有些奇怪,有些问题不太可控,我不知道seam里的JSF实现的如何,05年刚毕业的时候,我们项目组用sun的JSF的一个标准实现开发项目,出现了很多问题,导致最后不得不放弃JSF,我从此对JSF印象就不太好。时至今日,不知道JSF的实现是否精益求精了。如果有一个很完美的JSF页面插件,直接拖拽,相信喜欢JSF的人越来越多,SEAM的粉丝也会越来越多。
109 楼 phoenixup 2008-07-15  
nbaertuo 写道
一、Seam的View实现是JSF,看页面代码还是密密麻麻的Tag

我是非常反感JSP Tag的,看看页面密密麻麻的Tag就头皮发麻,能不能弄一个Template呀,例如freemarker啥的?这些Tag既不直观,也不方便扩展。需要扩展页面组件,总不能让我自定义Tag去干活吧?不清楚这个问题怎么办?像freeamarker还可以方便的自定义页面宏呢。

二、每次修改都要重新打包发布,太麻烦了吧

就算修改一个页面,也要整个打包deploy成为一个ear去拷贝到jboss的应用目录下面,这个要是改页面,不是得烦死? 我以前都是在项目里面直接内嵌Jetty,作为一个application启动,修改页面根本无需重起呀,更不要说deploy了。

举个例子:如果不用tag方式的话,我们写一个ajax调用,使用js框架的话,我们需要导入js文件,写ajax连接,操作,关闭。难道这些js代码比tag代码更容易看懂?
每次打包发布是因为没有集成到ide开发工具中去,我用red-hat developer开发工具大部分情况下不能重启的,所需要重启的只是在添加了类,方法的时候需要。

我对jsf的template不满的是,他的文件不能写道web-inf下面,不能像struts那样写虚拟路径,例如我要访问webapp下面的a/b/a.xhtml的话我必须使用sss.com/a/b/a.seam都必须使用绝对路径,这样写道话css调用很不方便。



一、Seam推荐的View是用Facelets代替JSP(JSF?可能笔误吧),说道Template,最通用的Template是html,的确freemarker很优秀,但是不足以扳倒xhtml,各有特色。再有Tag的写法不是JSP才有,所有的模板文件本质上都是Tage的组合。

二、每次修改不要重新打包(说了很多次了。。。自己认真看看)

三、使用Facelets template文件可以写在Context的任意位置,包括WEB-INF中。
108 楼 phoenixup 2008-07-15  
zhongshigang 写道
phoenixup 写道


1.Seam 2的版本中默认的视图展现是Facelets的xhtml,配合jsfc标签,完全不存在robbin你说的问题,不过jsp遗留的tag确实是不能避免,但是有了Faceltes这个貌似不是问题了。



请教:我用seam 2(使用JBossTools-2.1.1或seam-gen),它没有生成jsfc标签,还是用的tag。有什么开关选项没打开?
我说的是工具生成时自带jsfc,而不是手工生成让它来支持。

另:seam能很好地和flex集成,用tide(http://www.graniteds.org/confluence/display/DOC11/2.8.+Tide+integration+for+Seam),flex程序可以直接调用seam的组件,如同rmi。更妙的是flex可以监听seam的事件(这可是两个世界之间的事哟),flex可以绑定seam的组件中的属性,让seam充当flex的model层。

Seam有自生成jsfc标签,不过不是用开关项打开的,好像是在某个脚本生成的页面中,有一个jsfc标签的演示代码,正确的写法如果Taglib不想记,就先用标准标签写(可以使用代码提示),完成之后在统一修改成jsfc标签就OK了~~seam-gen工作不能完成所有的事情。。不过如果想做也没问题,你把Seam的模板修改成jsfc就可以了。。。呵呵
107 楼 nbaertuo 2008-07-14  
一、Seam的View实现是JSF,看页面代码还是密密麻麻的Tag

我是非常反感JSP Tag的,看看页面密密麻麻的Tag就头皮发麻,能不能弄一个Template呀,例如freemarker啥的?这些Tag既不直观,也不方便扩展。需要扩展页面组件,总不能让我自定义Tag去干活吧?不清楚这个问题怎么办?像freeamarker还可以方便的自定义页面宏呢。

二、每次修改都要重新打包发布,太麻烦了吧

就算修改一个页面,也要整个打包deploy成为一个ear去拷贝到jboss的应用目录下面,这个要是改页面,不是得烦死? 我以前都是在项目里面直接内嵌Jetty,作为一个application启动,修改页面根本无需重起呀,更不要说deploy了。

举个例子:如果不用tag方式的话,我们写一个ajax调用,使用js框架的话,我们需要导入js文件,写ajax连接,操作,关闭。难道这些js代码比tag代码更容易看懂?
每次打包发布是因为没有集成到ide开发工具中去,我用red-hat developer开发工具大部分情况下不能重启的,所需要重启的只是在添加了类,方法的时候需要。

我对jsf的template不满的是,他的文件不能写道web-inf下面,不能像struts那样写虚拟路径,例如我要访问webapp下面的a/b/a.xhtml的话我必须使用sss.com/a/b/a.seam都必须使用绝对路径,这样写道话css调用很不方便。
106 楼 sp42 2008-07-13  
其实有不少纯粹把Seam当作Data Center,不用Facelet/JSF,前端Ext/dojo,这样的配搭一样用得很好
105 楼 zhongshigang 2008-07-13  
phoenixup 写道


1.Seam 2的版本中默认的视图展现是Facelets的xhtml,配合jsfc标签,完全不存在robbin你说的问题,不过jsp遗留的tag确实是不能避免,但是有了Faceltes这个貌似不是问题了。



请教:我用seam 2(使用JBossTools-2.1.1或seam-gen),它没有生成jsfc标签,还是用的tag。有什么开关选项没打开?
我说的是工具生成时自带jsfc,而不是手工生成让它来支持。

另:seam能很好地和flex集成,用tide(http://www.graniteds.org/confluence/display/DOC11/2.8.+Tide+integration+for+Seam),flex程序可以直接调用seam的组件,如同rmi。更妙的是flex可以监听seam的事件(这可是两个世界之间的事哟),flex可以绑定seam的组件中的属性,让seam充当flex的model层。
104 楼 wm920 2008-07-11  
每一种技术都有它的长处和短处,各取所长吧!
103 楼 aya331 2008-07-11  
jsf1.x没有达到宣称的那么好。
102 楼 nihongye 2008-07-10  
Anatorian 写道
Extended persistence context和openSessionInView的最大的不同是,Extended persistence context的session的存活时间要比OpensessionInView要长得多。前者能够跨越多次http request,而OpenSessionInView只能让session存活在一次请求之中。

这个讨论的主题是说jboss seam的。不对这个话题继续深入讨论了吧。感兴趣不妨查下jpa规范里面关于extended per...的定义。个人觉得conversation->conversasion persistence scope,OpensessionInView->request scope。都是在extended这个长命鬼的基础上做进一步的控制。
seam的特点是渲染阶段也启动了事务,关于这点,在我给出的hibenrate的链接上,对它的优点做了说明。
关于使用ThreadLocal绑定session。印象中jpa规范对ejb组件间的调用,context如和传播做了规定,猜测具体的实现离不开TheadLocal。
101 楼 iceframe 2008-07-10  
可怜的是现在不能下载了……

相关推荐

    JBoss Seam

    《JBoss Seam:超越Java EE的简易与强大》是一本深度探索JBoss Seam框架的权威著作,由Michael Yuan和Thomas Heute共同撰写。本书聚焦于JBoss Seam框架,旨在为读者提供一个全面、深入的理解,以掌握其在企业级应用...

    Jboss seam3 实战

    标题中的“Jboss seam3 实战”表明,本文将重点介绍JBoss Seam框架的第三个版本的实际应用。JBoss Seam是一个开源的Java EE框架,它通过依赖注入和会话模型,简化了基于Java EE的企业级应用开发。Seam框架为开发者...

    JBoss Seam入门介绍

    标题:JBoss Seam入门介绍 描述:本文将详细介绍JBoss Seam框架的核心概念、关键特性以及如何构建基于Seam的应用程序。Seam作为一个企业级Java Web应用框架,它将Java EE和JSF无缝集成,旨在填补Java EE 5.0中缺失...

    JBOSS SEAM组件中文手册

    **JBoss Seam组件中文手册** **一、Seam框架概述** Seam是一个开源的企业级Java框架,由JBoss公司开发,旨在简化Java EE应用程序的开发。它将多种技术如JavaServer Faces (JSF),Java Persistence API (JPA),EJB 3...

    Jboss Seam中文版

    ### JBoss Seam中文版知识点详解 #### JBoss Seam简介 JBoss Seam是一个强大的企业级应用开发框架,基于Java EE标准,特别强调简化Web应用的开发流程。它通过整合多种技术如JSF、EJB 3.0等,提供了一种更为高效、...

    jboss seam 中文文档集合

    **JBoss Seam 中文文档集合概述** JBoss Seam 是一个开源的应用框架,它结合了JavaServer Faces (JSF)、Java Persistence API (JPA)、Enterprise JavaBeans (EJB) 3.0 和其他Java EE组件,旨在简化企业级开发。这个...

    jbossseam eclipse安装 例子学习.doc

    ### JBoss Seam Eclipse 安装与配置详解 #### 一、引言 本文将详细介绍如何在 Windows XP 系统环境下,使用 Eclipse IDE 进行 JBoss Seam 的开发准备工作及环境配置。JBoss Seam 是一款基于 Java 的企业级应用框架...

    Jboss Seam 三本最受欢迎的教材

    【JBoss Seam】是Java企业级应用开发框架,它整合了JSF(JavaServer Faces)、EJB(Enterprise JavaBeans)3.0、JPA(Java Persistence API)以及一系列其他技术,为开发人员提供了一个强大的全栈式解决方案。Seam...

    jboss seam 2.0 中文手册

    整理自jboss seam 中文站,压缩为chm格式,便于广大jboss seam爱好者阅读,所有版权归jboss seam中文站所有。

    jboss seam 2.01GA REF DOC

    ### JBoss Seam 2.01GA REF DOC #### 引言:JBoss Seam概览与功能介绍 JBoss Seam 是一个为简化企业级 Java 应用开发而设计的框架。它结合了 JavaServer Faces (JSF)、Java Persistence API (JPA) 和 Java ...

    深入浅出JBoss Seam.pdf

    ### 深入浅出JBoss Seam:整合与强化Java EE框架 #### 一、引言 JBoss Seam是一款基于Java EE 5.0的轻量级框架,它旨在简化企业级Web应用的开发过程,并增强应用的可扩展性和开发者的生产力。本文将详细介绍JBoss ...

    JBOSS_SEAM配置

    JBOSS_SEAM配置

    jboss seam 教程

    - **本教程**:主要介绍了JBoss Seam的基本概念、核心组件以及通过一系列示例项目来学习Seam的实际应用。 #### 二、Seam基础知识与实例分析 ##### 2.1 第一个Seam应用:注册示例 - **实体类**:`User.java`定义了...

    jboss seam

    这是中文手册,Seam为持久化集成了JPA和Hibernate 3,为轻量化的异步性集成了EJB Timer Service和Quartz,为工作流集成了jBPM,为业务规则集成了JBoss规则,为电子邮件集成了Meldware Mail,为完整的文本搜索集成了...

    jboss-seam2.0文档

    【JBoss Seam 2.0文档详解】 JBoss Seam 是一个开源的企业级开发框架,它旨在简化Java EE应用的开发过程,特别是在Web和富互联网应用程序(Rich Internet Applications, RIA)领域。Seam 2.0是其重要的版本,提供了...

    深入浅出JBoss Seam

    《深入浅出JBoss Seam》 JBoss Seam是一个旨在简化企业级Web应用开发的轻量级框架,它补充和完善了Java EE 5.0的标准。Java EE 5.0虽然包含了EJB 3.0和JSF 1.2等核心框架,但它们各自独立,缺乏统一的编程模型。...

    jboss-seam-selectitems

    java jboss seam jboss-seam-selectitems

    [JBoss] JSF & Facelets & JBoss Seam 核心技术 (英文版)

    [TipTec Development] JSF & Facelets & JBoss Seam 核心技术 (英文版) [TipTec Development] Essential JSF, Facelets & JBoss Seam (E-Book) ☆ 出版信息:☆ [作者信息] Kent Ka Iok Tong [出版机构] TipTec ...

Global site tag (gtag.js) - Google Analytics