高手支招 Java经验分享(九)

开发 后端
本篇文章是作者Ant_Yan在CSDN论坛上发布的自己对Java学习的一些经验分享。这是他经验分享的第九部分。

  这篇是笔者Java学习经验分享的第九篇,这期的主题是Struts,直译过来是支架。

  Struts的第一个版本是在2001年5月发布的,它提供了一个Web应用的解决方案,如何让Jsp和servlet共存去提供清晰的分离视图和业务应用逻辑的架构。在Struts之前,通常的做法是在Jsp中加入业务逻辑,或者在Servlet中生成视图转发到前台去。Struts带着MVC的新理念当时退出几乎成为业界公认的Web应用标准,于是当代IT市场上也出现了众多熟悉Struts的程序员。即使有新的框架再出来不用,而继续用Struts的理由也加上了一条低风险,因为中途如果开发人员变动,很容易的招进新的会Struts的IT民工啊,^_^!

  笔者之前说的都是Struts-1,因为新出了Struts-2,使得每次谈到Struts都必须注明它是Struts-1还是2。笔者先谈比较熟悉的Struts-1,下次再介绍一下与Struts-2的区别:

  1. Struts框架整体结构

  Struts-1的核心功能是前端控制器,程序员需要关注的是后端控制器。前端控制器是是一个Servlet,在Web.xml中间配置所有Request都必须经过前端控制器,它的名字是ActionServlet,由框架来实现和管理。所有的视图和业务逻辑隔离都是应为这个ActionServlet, 它就像一个交通警察,所有过往的车辆必须经过它的法眼,然后被送往特定的通道。所有,对它的理解就是分发器,我们也可以叫做Dispatcher,其实了解Servlet编程的人自己也可以写一个分发器,加上拦截request的Filter,其实自己实现一个struts框架并不是很困难。主要目的就是让编写视图的和后台逻辑的可以脱离紧耦合,各自同步的完成自己的工作。

  那么有了ActionServlet在中间负责转发,前端的视图比如说是Jsp,只需要把所有的数据Submit,这些数据就会到达适合处理它的后端控制器Action,然后在里面进行处理,处理完毕之后转发到前台的同一个或者不同的视图Jsp中间,返回前台利用的也是Servlet里面的forward和redirect两种方式。所以到目前为止,一切都只是借用了Servlet的API搭建起了一个方便的框架而已。这也是Struts最显著的特性——控制器。

  那么另外一个特性,可以说也是Struts-1带来的一个比较成功的理念,就是以xml配置代替硬编码配置信息。以往决定Jsp往哪个servlet提交,是要写进Jsp代码中的,也就是说一旦这个提交路径要改,我们必须改写代码再重新编译。而Struts提出来的思路是,编码的只是一个逻辑名字,它对应哪个class文件写进了xml配置文件中,这个配置文件记录着所有的映射关系,一旦需要改变路径,改变xml文件比改变代码要容易得多。这个理念可以说相当成功,以致于后来的框架都延续着这个思路,xml所起的作用也越来越大。

  大致上来说Struts当初给我们带来的新鲜感就这么多了,其他的所有特性都是基于方便的控制转发和可扩展的xml配置的基础之上来完成它们的功能的。

  下面将分别介绍Action和FormBean, 这两个是Struts中最核心的两个组件。

  2. 后端控制器Action

  Action就是我们说的后端控制器,它必须继承自一个Action父类,Struts设计了很多种Action,例如DispatchAction、DynaValidationAction。它们都有一个处理业务逻辑的方法execute(),传入的request, response, formBean和actionMapping四个对象,返回actionForward对象。到达Action之前先会经过一个RequestProcessor来初始化配置文件的映射关系,这里需要大家注意几点:

  1) 为了确保线程安全,在一个应用的生命周期中,Struts框架只会为每个Action类创建一个Action实例,所有的客户请求共享同一个Action实例,并且所有线程可以同时执行它的execute()方法。所以当你继承父类Action,并添加了private成员变量的时候,请记住这个变量可以被多个线程访问,它的同步必须由程序员负责。(所有我们不推荐这样做)。在使用Action的时候,保证线程安全的重要原则是在Action类中仅仅使用局部变量,谨慎的使用实例变量。局部变量是对每个线程来说私有的,execute方法结束就被销毁,而实例变量相当于被所有线程共享。

  2) 当ActionServlet实例接收到Http请求后,在doGet()或者doPost()方法中都会调用process()方法来处理请求。RequestProcessor类包含一个HashMap,作为存放所有Action实例的缓存,每个Action实例在缓存中存放的属性key为Action类名。在RequestProcessor类的processActionCreate()方法中,首先检查在HashMap中是否存在Action实例。创建Action实例的代码位于同步代码块中,以保证只有一个线程创建Action实例。一旦线程创建了Action实例并把它存放到HashMap中,以后所有的线程会直接使用这个缓存中的实例。

  3) <action> 元素的<roles>属性指定访问这个Action用户必须具备的安全角色,多个角色之间逗号隔开。RequestProcessor类在预处理请求时会调用自身的processRoles()方法,检查配置文件中是否为Action配置了安全角色,如果有,就调用HttpServletRequest的isUserInRole()方法来判断用户是否具备了必要的安全性角色,如果不具备,就直接向客户端返回错误。(返回的视图通过<input> 属性来指定)

  3. 数据传输对象FormBean

  Struts并没有把模型层的业务对象直接传递到视图层,而是采用DTO(Data Transfer Object)来传输数据,这样可以减少传输数据的冗余,提高传输效率;还有助于实现各层之间的独立,使每个层分工明确。Struts的DTO就是ActionForm,即formBean。由于模型层应该和Web应用层保持独立。由于ActionForm类中使用了Servlet API, 因此不提倡把ActionForm传递给模型层, 而应该在控制层把ActionForm Bean的数据重新组装到自定义的DTO中, 再把它传递给模型层。它只有两个scope,分别是session和request。(默认是session)一个ActionForm标准的生命周期是:

  1) 控制器收到请求 ->

  2) 从request或session中取出ActionForm实例,如不存在就创建一个 ->

  3) 调用ActionForm的reset()方法 ->

  4) 把实例放入session或者request中 ->

  5) 将用户输入表达数据组装到ActionForm中 ->

  6) 如眼张方法配置了就调用validate()方法 ->

  7) 如验证错误就转发给<input>属性指定的地方,否则调用execute()方法

  validate()方法调用必须满足两个条件:

  1) ActionForm 配置了Action映射而且name属性匹配

  2) <aciton>元素的validate属性为true

  如果ActionForm在request范围内,那么对于每个新的请求都会创建新的ActionForm实例,属性被初始化为默认值,那么reset()方法就显得没有必要;但如果ActionForm在session范围内,同一个ActionForm实例会被多个请求共享,reset()方法在这种情况下极为有用。

  4. 验证框架和国际化

  Struts有许多自己的特性,但是基本上大家还是不太常用,说白了它们也是基于JDK中间的很多Java基础包来完成工作。例如国际化、验证框架、插件自扩展功能、与其他框架的集成、因为各大框架基本都有提供这样的特性,Struts也并不是做得最好的一个,这里也不想多说。Struts的验证框架,是通过一个validator.xml的配置文件读入验证规则,然后在validation-rules.xml里面找到验证实现通过自动为Jsp插入Javascript来实现,可以说做得相当简陋。弹出来的JavaScript框不但难看还很多冗余信息,笔者宁愿用formBean验证或者Action的saveErrors(),验证逻辑虽然要自己写,但页面隐藏/浮现的警告提示更加人性化和美观一些。

  至于Struts的国际化,其实无论哪个框架的国际化,java.util.Locale类是最重要的Java I18N类。在Java语言中,几乎所有的对国际化和本地化的支持都依赖于这个类。如果Java类库中的某个类在运行的时候需要根据Locale对象来调整其功能,那么就称这个类是本地敏感的(Locale-Sensitive), 例如java.text.DateFormat类就是,依赖于特定Locale。

  创建Locale对象的时候,需要明确的指定其语言和国家的代码,语言代码遵从的是ISO-639规范,国家代码遵从ISO-3166规范,可以从

  http://www.unicode.org/unicode/onlinedat/languages.html

  http://www.unicode.org/unicode/onlinedat/countries.htm

  Struts的国际化是基于properties的message/key对应来实现的,笔者曾写过一个程序,所有Jsp页面上没有任何Text文本串,全部都用的是<bean:message>去Properties文件里面读,这个时候其实只要指定不同的语言区域读不同的Properties文件就实现了国际化。需要注意的是不同语言的字符写进Properties文件的时候需要转化成Unicode码,JDK已经带有转换的功能。JDK的bin目录中有native2ascii这个命令,可以完成对*.txt和*.properties的Unicode码转换。

【编辑推荐】

  1. 新手入门:学习Java的一点经验心得
  2. 61条Java面向对象设计的经验原则
  3. 经验分享:我的JavaEE学习道路
  4. Java对象类型转换的四个经验
  5. 高手支招 Java经验分享(一)
责任编辑:韩亚珊 来源: CSDN
相关推荐

2011-03-31 16:44:43

Java

2011-03-31 16:49:40

Java

2011-03-31 13:32:13

Java

2011-03-31 14:49:35

2011-03-31 13:56:24

Java

2011-03-31 14:07:27

Java

2011-03-31 16:26:28

Java

2011-03-31 13:52:22

Java

2011-04-07 13:18:00

管理软件项目项目

2009-10-29 16:57:05

Oracle传输表空间

2018-06-19 08:12:55

2010-07-21 14:05:31

2014-05-28 10:55:11

Windows XP安全补丁

2017-02-14 09:28:08

GNOME Shell桌面Linux

2010-08-18 14:19:01

无线路由器

2016-02-01 10:38:12

DevOps隐藏技能

2009-09-28 10:52:00

CCNA考试经验CCNA

2011-07-15 17:35:19

JavaScript

2009-12-07 11:11:46

PHP显示图片

2009-10-15 10:59:00

CCNA经验分享CCNA
点赞
收藏

51CTO技术栈公众号