如何横向比较不同js框架之间的优劣

JavaScript07

如何横向比较不同js框架之间的优劣,第1张

struts1与struts2本质区别

1 在Action实现类方面的对比:Struts 1要求Action类继续一个抽象基类;Struts 1的一个具体问题是使用抽象类编程而不是接口。Struts 2 Action类可以实现一个Action接口,也可以实现其他接口,使可选和定制的服务成为可能。Struts 2提供一个ActionSupport基类去实现常用的接口。即使Action接口不是必须实现的,只有一个包含execute方法的POJO类都可以用 作Struts 2的Action。

2 线程模式方面的对比:Struts 1 Action是单例模式并且必须是线程安全的,因为仅有Action的一个实例来处理所有的请求。单例策略限制了Struts 1 Action能做的事,并且要在开发时非凡小心。Action资源必须是线程安全的或同步的;Struts 2 Action对象为每一个请求产生一个实例,因此没有线程安全问题。

3 Servlet依靠方面的对比:Struts 1 Action依靠于Servlet API,因为Struts 1 Action的execute方法中有HttpServletRequest和HttpServletResponse方法。Struts 2 Action不再依靠于Serzvlet API,从而答应Action脱离Web容器运行,从而降低了测试Action的难度。 当然,假如Action需要直接访问HttpServletRequest和HttpServletResponse参数,Struts 2 Action仍然可以访问它们。但是,大部分时候,Action都无需直接访问HttpServetRequest和 HttpServletResponse,从而给开发者更多灵活的选择。

4 可测性方面的对比:测试Struts 1 Action的一个主要问题是execute方法依靠于Servlet API,这使得Action的测试要依靠于Web容器。为了脱离Web容器测试Struts 1的Action,必须借助于第三方扩展:Struts TestCase,该扩展下包含了系列的Mock对象(模拟了HttpServetRequest和HttpServletResponse对象),从而 可以脱离Web容器测试Struts 1的Action类。Struts 2 Action可以通过初始化、设置属性、调用方法来测试。

5 封装请求参数的对比:Struts 1使用ActionForm对象封装用户的请求参数,所有的ActionForm必须继续一个基类:ActionForm。普通的JavaBean不能用 作ActionForm,因此,开发者必须创建大量的ActionForm类封装用户请求参数。虽然Struts 1提供了动态ActionForm来简化ActionForm的开发,但依然需要在配置文件中定义ActionForm;Struts 2直接使用Action属性来封装用户请求属性,避免了开发者需要大量开发ActionForm类的烦琐,实际上,这些属性还可以是包含子属性的Rich 对象类型。假如开发者依然怀念Struts 1 ActionForm的模式,Struts 2提供了ModelDriven模式,可以让开发者使用单独的Model对象来封装用户请求参数,但该Model对象无需继续任何Struts 2基类,是一个POJO,从而降低了代码污染。

6 表达式语言方面的对比:Struts 1整合了JSTL,因此可以使用JSTL表达式语言。这种表达式语言有基本对象图遍历,但在对集合和索引属性的支持上则功能不强;Struts 2可以使用JSTL,但它整合了一种更强大和灵活的表达式语言:OGNL(Object Graph Notation Language),因此,Struts 2下的表达式语言功能更加强大。

7 绑定值到视图的对比:Struts 1使用标准JSP机制把对象绑定到视图页面;Struts 2使用“ValueStack”技术,使标签库能够访问值,而不需要把对象和视图页面绑定在一起。

8 类型转换的对比:Struts 1 ActionForm 属性通常都是String类型。Struts 1使用Commons-Beanutils进行类型转换,每个类一个转换器,转换器是不可配置的;Struts 2使用OGNL进行类型转换,支持基本数据类型和常用对象之间的转换。

9 数据校验的对比:Struts 1支持在ActionForm重写validate方法中手动校验,或者通过整合Commons alidator框架来完成数据校验。Struts 2支持通过重写validate方法进行校验,也支持整合XWork校验框架进行校验。

10 Action执行控制的对比:Struts 1支持每一个模块对应一个请求处理(即生命周期的概念),但是模块中的所有Action必须共享相同的生命周期。Struts 2支持通过拦截器堆栈(Interceptor Stacks)为每一个Action创建不同的生命周期。开发者可以根据需要创建相应堆栈,从而和不同的Action一起使用。

Hibernate优点

(1) 对象/关系数据库映射(ORM)

它使用时只需要操纵对象,使开发更对象化,抛弃了数据库中心的思想,完全的面向对象思想

(2) 透明持久化(persistent)

带有持久化状态的、具有业务功能的单线程对象,此对象生存期很短。这些对象可能是普通的JavaBeans/POJO,这个对象没有实现第三方框架 或者接口,唯一特殊的是他们正与(仅仅一个)Session相关联。一旦这个Session被关闭,这些对象就会脱离持久化状态,这样就可被应用程序的任 何层自由使用。(例如,用作跟表示层打交道的数据传输对象。)

(3) 事务Transaction(org.hibernate.Transaction)

应用程序用来指定原子操作单元范围的对象,它是单线程的,生命周期很短。它通过抽象将应用从底层具体的JDBC、JTA以及CORBA事务隔离 开。某些情况下,一个Session之内可能包含多个Transaction对象。尽管是否使用该对象是可选的,但无论是使用底层的API还是使用 Transaction对象,事务边界的开启与关闭是必不可少的。

(4) 它没有侵入性,即所谓的轻量级框架

(5) 移植性会很好

(6) 缓存机制,提供一级缓存和二级缓存

(7) 简洁的HQL编程

Hibernate缺点

(1) Hibernate在批量数据处理时有弱势

(2) 针对单一对象简单的增删查改,适合于Hibernate,而对于批量的修改,删除,不适合用Hibernate,这也是OR框架的弱点;要使用数据库的特定优化机制的时候,不适合用Hibernate

Hibernate和iBATIS 优缺点比较

(注意:iBATIS 是MyBATIS的前生,也就是1.0版本)

Hibernate的特点:

Hibernate功能强大,数据库无关性好,O/R映射能力强, Hibernate对数据库结构提供了较为完整的封装,Hibernate的O/R Mapping实现了POJO 和数据库表之间的映射,以及SQL 的自动生成和执行。程序员往往只需定义好了POJO 到数据库表的映射关系,即可通过Hibernate 提供的方法完成持久层操作。程序员甚至不需要对SQL 的熟练掌握, Hibernate/OJB 会根据制定的存储逻辑,自动生成对应的SQL 并调用JDBC 接口加以执行。Hibernate的缺点就是学习门槛不低,要精通门槛更高,而且怎么设计O/R映射,在性能和对象模型之间如何权衡取得平衡,以及怎样用 好Hibernate方面需要你的经验和能力都很强才行,但是Hibernate现在已经是主流O/R Mapping框架,从文档的丰富性,产品的完善性,版本的开发速度都要强于iBATIS。

iBATIS的特点:

iBATIS入门简单, 即学即用,提供了数据库查询的自动对象绑定功能,而且延续了很好的SQL使用经验,对于没有那么高的对象模型要求的项目来说,相当完美。iBATIS的缺 点就是框架还是比较简陋,功能尚有缺失,虽然简化了数据绑定代码,但是整个底层数据库查询实际还是要自己写的,工作量也比较大,而且不太容易适应快速数据 库修改。当系统属于二次开发,无法对数据库结构做到控制和修改,那iBATIS的灵活性将比Hibernate更适合。系统数据处理量巨大,性能要求极为 苛刻,这往往意味着我们必须通过经过高度优化的SQL语句(或存储过程)才能达到系统性能设计指标。在这种情况下iBATIS会有更好的可控性和表现。

对于实际的开发进行的比较:

1. iBATIS需要手写sql语句,也可以生成一部分,Hibernate则基本上可以自动生成,偶尔会写一些Hql。同样的需求,iBATIS的工作量比 Hibernate要大很多。类似的,如果涉及到数据库字段的修改,Hibernate修改的地方很少,而iBATIS要把那些sql mapping的地方一一修改。

2. iBatis 可以进行细粒度的优化

比 如说我有一个表,这个表有几个或者几十个字段,我需要更新其中的一个字段,iBatis 很简单,执行一个sql UPDATE TABLE_A SET column_1=#column_1# WHERE id=#id# 但是用 Hibernate 的话就比较麻烦了,缺省的情况下 hibernate 会更新所有字段。 当然我记得 hibernate 有一个选项可以控制只保存修改过的字段,但是我不太确定这个功能的负面效果。

例 如:我需要列出一个表的部分内容,用 iBatis 的时候,这里面的好处是可以少从数据库读很多数据,节省流量SELECT ID, NAME FROM TABLE_WITH_A_LOT_OF_COLUMN WHERE …一般情况下Hibernate 会把所有的字段都选出来。比 如说有一个上面表有8个字段,其中有一两个比较大的字段,varchar(255)/text。上面的场景中我为什么要把他们也选出来呢?用 hibernate 的话,你又不能把这两个不需要的字段设置为lazy load,因为还有很多地方需要一次把整个 domain object 加载出来。这个时候就能显现出ibatis 的好处了。如果我需要更新一条记录(一个对象),如果使用 hibernate,需要现把对象 select 出来,然后再做 update。这对数据库来说就是两条sql。而iBatis只需要一条update的sql就可以了。减少一次与数据库的交互,对于性能的提升是非常重 要。

3. 开发方面:

开发效率上,我觉得两者应该差不多。可维护性方面,我 觉得 iBatis 更好一些。因为 iBatis 的 sql 都保存到单独的文件中。而 Hibernate 在有些情况下可能会在 java 代码中保sql/hql。相对Hibernate“O/R”而言,iBATIS 是一种“Sql Mapping”的ORM实现。(iBatis 是将sql写在配置文件中的,而hibernate是自己生成的) 而iBATIS 的着力点,则在于POJO 与SQL之间的映射关系。也就是说,iBATIS并不会为程序员在运行期自动生成SQL 执行。具体的SQL 需要程序员编写,然后通过映射配置文件,将SQL所需的参数,以及返回的结果字段映射到指定POJO。使用iBATIS 提供的ORM机制,对业务逻辑实现人员而言,面对的是纯粹的Java对象,这一层与通过Hibernate 实现ORM 而言基本一致,而对于具体的数据操作,Hibernate会自动生成SQL 语句,而iBATIS 则要求开发者编写具体的SQL 语句。相对Hibernate而言,iBATIS 以SQL开发的工作量和数据库移植性上的让步,为系统设计提供了更大的自由空间。

4. 运行效率

在不考虑 cache 的情况下,iBatis 应该会比hibernate 快一些或者很多。

Spring 框架的优缺点

Spring的优势不言而喻:

1. 提供了一种管理对象的方法,可以把中间层对象有效地组织起来。一个完美的框架“黏合剂”。

2. 采用了分层结构,可以增量引入到项目中。

3. 有利于面向接口编程习惯的养成。

4. 目的之一是为了写出易于测试的代码。

5. 非侵入性,应用程序对Spring API的依赖可以减至最小限度。

6. 一致的数据访问介面。

6. 一个轻量级的架构解决方案

缺点也显而易见

1. 中断了应用程序的逻辑,使代码变得不完整,不直观。此时单从Source无法完全把握应用的所有行为。

2. 将原本应该代码化的逻辑配置化,增加了出错的机会以及额外的负担。

3. 时光倒退,失去了IDE的支持。在目前IDE功能日益强大的时代,以往代码重构等让人头痛的举动越来越容易。而且IDE还提供了诸多强大的辅助功能,使得 编程的门槛降低很多。通常来说,维护代码要比维护配置文件,或者配置文件+代码的混合体要容易的多。

4. 调试阶段不直观,后期的bug对应阶段,不容易判断问题所在。

经典架构S(Struts)SH的优缺点

Struts、Spring、Hibernate能流行这么多年经久不衰,自然有它的道理。J2EE最先出现的时候,我们一般是采用 JSP+Servlet+JavaBean+EJB的架构,尤其是1998年~2000年这段时间,互联网的泡沫从兴起到破裂,其波澜壮阔程度,丝毫不亚 于2008年开始的这次经济危机,在那个年代,是否掌握EJB开发技术将直接决定你的薪水能否翻一倍或者几倍。不过,Spring的作者Rod Johnson在2002年根据多年经验撰写了《Expert o-ne-on-One J2EE Design and Development》,其后又发表了著名的《Expert o-ne-on-one J2EE Development without EJB》一书,则彻底地改变了传统的J2EE一统天下的开发架构,基于Struts+Hibernate+Spring的J2EE架构也逐渐得到人们的认 可,甚至在大型的项目架构中也逐渐开始应用。下面我们分别说说Spring、Struts和Hibernate的优缺点。

Spring 是一个开源框架,是为了解决企业应用程序开发复杂性而创建的。框架的主要优势之一就是其分层架构,使得每个层之间和类与类之间的关系,由原来的强绑定与强 耦合转变为不绑定和松耦合,直接面向接口编程,把设计与实现相分离的原则发挥到极致,对于单元测试也产生了很深远的影响。在Spring出现之前,如果某 个模块没有完成,做单独模块的单元测试还是很困难的。Spring同时也是 J2EE 应用程序开发的集成框架,因为J2EE是讲究分层理念的,Spring使得J2EE每个层之间的模块职能更加清晰。

不过,对于大型项目的开发,Spring使得原来难以维护的类与类之间的强耦合关系,转变为更加难以维护的XML文件配置,这个工作量也是非常巨大 的,而且更容易出错。而且,随着每个应用 模块的升级,这些模块之间的版本,也不会是同步更新的,对于同一个公共组件,有的模块用的可能是1.0版本,而另 外一个功能模块用的可能是2.0版本,可怕的是1.0版本和2.0版本之间,可能还不兼容,Spring对于这些需求,就无能为力了。所以,有人说 Spring不适合大型项目开发,也是有一定道理的。最近Spring也加入了OSGI标准的实现,也是为了解决不同版本之间同时存在的这些问题。不过, 随着Spring加入的功能越来越多,Spring也就失去了轻量开源框架的特点,变得越来越笨重。

虽然Spring现在也支持了所谓的免配置,可以通过@Autowired标签自行绑定,还可以通过 设置自动绑定加载所有的Hibernate对象,但是如果这些上百个或者数十个中的任何一个Entity对象加载失败,则整个Spring服务就启动不起 来了,这与难于部署的EJB有啥区别呢?而且,令人可笑的是,由于使用了@Autowired标签,相当一部分开发人员不再面向接口编程了,对于 Class A的实例,美其名曰由Spring自行绑定,接口也好,实际实现类也好,就在Spring配置一下就可以了。而Spring最核心的就是面向接口编程和 IOC,没有了面向接口编程,用一个 A a=new A() 来实例化一个Class,有什么不可以呢?少写了一行代码,引入了一个重量级的Spring,究竟为啥使用Spring呢?

对于Hibernate的流行,则是由于开发人员和客户,对于Entity EJB(实体EJB)臃肿的身材及部署的困难,是在极度失望情绪下造成的。既然是轻量级解决方案,那么分布式就不是可选项,没有分布式,那么EJB就无用 武之地了。话又说回来了,Rod Johnson前些年就因为强调绝大部分企业应用是不需要分布式的,从而推出了自己轻量级的Spring解决方案。但是最近一年,随着云计算架构的兴起, 架构是否支持分布式,又是必选项了。技术架构的选型,就跟法国巴黎流行时装一样,今年流行短袖,明年流行下摆,真是典型的十年河东,十年河西。所以,像 SOA、云计算、SaaS、物联网这些大名词,不仅会给客户带来很大的困惑,同样也会给程序员、系统分析师、系统架构师、技术总监带来困惑。从肯定到否 定,再到自我否定,真是符合大自然螺旋式上升的发展规律。

而对于Struts,它一经推出,几乎打败了当时的所有竞争对手。Struts的伟大之处,在于它对网页数据的动态绑定。虽然数据绑定不是一个新名 词,微软在1991年推出Visual Basic1.0的时候,就创造性地发明了让VB程序员又爱又恨的数据绑定,但是对于Web 编程,Struts也还是把数据绑定首次应用到了Web编程上。它能够让人们用Set和Get的形式取得网页数据,而不是单一的黑盒式的 request.getParameter(),从而使得网页数据取值进入面向对象(OO)化时代。

Struts、Hibernate以及Spring本身都是制作精良的框架,但是对于自己产品和项目的应用,一经整合在一起,却不一定很适用。比如 说,对于数据库相关的MIS(管理信息系统)系统中,增加、修改、删除、查询功能是最基本、最常见、必不可少的。对于这些最基本的功能,不同的架构师,则 会做出不同的选择。有的架构师,选择了自动生成的理念,做一个代码自动生成器,设计好数据库表结构,单击一个脚本,或者用Eclipse插件的形式,做个 图形化生成界面,自动生成SSH框架,完成数据库的增加、修改、删除、查询操作。这么做的好处是数据库修改了,代码自动生成就可以了,使得程序员不用再维 护这些无聊的代码。不过缺陷也是致命的,一是随着Struts、Hibernate、Spring的升级,这个工具也不得不跟着升级,而做这个工具的程序 员,可能早就离开公司了,后续版本无法维护;二是如果有的业务逻辑跟这些生成的代码有交叉,数据库变更后,代码也无法再次生成了。三是公司的系统架构,则 被严重限制在SSH架构基础上,再也无法改变。有人会问:即使限制在这三种架构上,有何不好吗?假设有客户问,你的框架支持云计算吗?你总不能说”由于 Struts、Hibernate、Spring 不支持云计算架构,所以我也不支持”以此取得客户谅解吧。因此,依赖于第三方架构的产品体系架构,随着时间的推移,受到的限制会越来越大。

其实jqueryValidate是可以自定义错误信息的。请参考它的文档。

这里可以使用showErrors属性:

$(".selector").validate({

    showErrors: function(errorMap, errorList) {

        $("#summary").html("Your form contains "

            + this.numberOfInvalids() + " errors, see details below.")

        this.defaultShowErrors()  

    }

})

也可以参考这些属性:errorLabelContainer,errorContainer,wrapper,errorElement,validClass,errorClass。只需要自定义错误提示的HTML结构,浮动框可以使用CSS控制。

看文章之前,强烈建议先把项目拉取下来!案例来自小弟的开源项目 「项目Github」

文章内容只是个人学习的一些总结经验,不具有权威性,这是 Node 服务端的实现,后面会写前端的实现

常见的 Token 验证方式种:

推荐阅读:

JWT 超详细分析

说一说几种常用的登录认证方式,你用的哪种

推荐阅读:

JSON Web Token 入门教程

JSON Web Token - 在Web应用间安全地传递信息

首先我们先安装 jsonwebtoken 和 express-jwt 这两个中间件

jsonwebtoken : 用于生成 Token 。它也有解析 Token 的功能

express-jwt : 用于解析 Token(比 jsonwebtoken 解决方便) , 它把解析之后的数据,存放到 requset.user 中

如果你看了上面 JWT 介绍的文章,就知道 JWT 是由三部分组成的,分别是 载荷(Payload) 、 头部(Header) 、 签名(Signature) 。

jsonwebtoken 给我们提供了 sign(payload, secretOrPrivateKey, [options, callback]) 方法。sign 方法对应的其实就是 JWT 签名(Signature) 的动作

payload:荷载 ,参数类型:对象secretOrPrivateKey:自定义的密钥,密钥属于敏感信息。参数类型:字符串options:可以配置 header 、荷载、指定算法类型。参数类型:对象callback:回调

眼尖的朋友应该发现, payload 和 options 两个 参数 都可以配置荷,下面有例子。根据自己的习惯选择就好

Payload 部分 JWT 规定了7个官方字段,这些字段都是可选字段。可直接以对象的形式传给 payload 参数。

options 中也可以接受以上七个字段,不过字段名称有所区别。

除此之后 options 提供了 algorithm 和 header ,分别对应使用的加密算法和 JWT 的 Header 部分,其实 algorithm 应该也是属于 Header 部分的。

说了这么多,其实我们一般常用的只有 exp(expiresIn) 和 algorithm 这两个字段,

例子一:

token 的有效时间是配置在 option 里

例子二:

我们也可以在 payload 里配置有效时间

jsonwebtoken 除了生成 token 外,还提供了解析验证 token 的方法, jwt.verify(token, secretOrPublicKey, [options, callback]) 。

这里就不演示了, 感兴趣的朋友可以参考文档: 「JsonWebToken」

express-jwt 是针对 express 框架开发的 JWT Token 验证中间件。我先来简单说以下它的用法。

主要有两种方式,一种是哪些请求需要验证就往哪里加验证;另外一种是先给全部请求加上验证,再给不需要验证的请求配置 白名单 。

方式一:

看完上面的例子,很显然不符合我们的逾期,一个正常的项目有个几十个 api 是分分钟的事。我们不可能一个个给他加上检验

方式二:

这种方式是不是方便很多,而且更美观,维护起来也更方便

Token 解析出来的用户信息,默认存放在 req.user , 可以直接 req.user.userId 来使用生成 Token 时填进去的用户id

你也通过 requestProperty 和 resultProperty 来设置用户信息存放的对象。

这里就不展开,详细文档参考: express-jwt

可以使用 app.use() 来注册处理验证不通过的情况

到这里 Token 的生成、验证、检验不通过错误处理就完成了。 Token 生成一般是在登录之后生成,并返回给前端,前端拿到 Token ,并在每次请求 api 的时候携带上 Token , Token 就相当于这个用户的身份,不要轻易泄露。

Token一旦签发,不能主动让它失效,只能等待它有效期过才能失效。也就是说就算你修改了密码,之前的 Token 也还是有效的。你可以修改后端生成 Token 时使用的密钥,不让之前的 Token 检验通过,但是这就表示之前所有生成 Token 都失效了,做不到针对某个用户进行注销。这显然也不合适的。 所以用户修改密码时,前端一般都要清除之前保存的 Token,再重获取新的 Token

有朋友应该会想到在后端把 Token 储存起来,每一个用户对应一个 token。修改账号时,再生成一个新的 Token 覆盖之前的 Token,但这就违背了使用 Token 的目的,Token 的使用很大程度就为了减少服务器的压力。把尽可能多的信息存储在客户端而不是服务端。

使用 Token 可以防御 CSRF 攻击,之前写过一篇关于网络安全的文章,感兴趣的朋友可以看一下 「XSS 攻击、CSRF 攻击、SQL 注入、流量劫持(DNS 劫持、HTTP 劫持)—— 浏览器安全」