struts1是基于当前的一些相关标准的开发技术(servlet,xml…)基础之上,
提供了一个开发框架的开放源码项目。
使用struts1的好处:
1.良好的架构和设计
2.可重用,模块化,扩展性好
3.Open source开源的
4.它提供了丰富的标签库,使页面能更加灵活的使用。

struts1的缺点:
1.它太过于依赖web容器,当配置文件改动一次就要重新启动。
2.它的配置文件太过于复杂。
3.ActionForm无法进行测试.
4.Action测试太过于依赖servlet api,所以在测试的时候要用到模拟对象.


Struts跟Tomcat、Turbine等诸多Apache项目一样,是开源软件,这是它的一大优点。使开发者
能更深入的了解其内部实现机制。 Struts开放源码框架的创建是为了使开发者在构建基于Java
Servlet和JavaServer Pages(JSP)技术的Web应用时更加容易。Struts框架为开放者提供了一个
统一的标准框架,通过使用Struts作为基础,开发者能够更专注于应用程序的商业逻辑。Struts框
架本身是使用Java Servlet和JavaServer Pages技术的一种Model-View-Controller(MVC)实现.
具体来讲,Struts的优点有:

1. 实现MVC模式,结构清晰,使开发者只关注业务逻辑的实现.

MVC即Model-View-Controller的缩写,是一种常用的设计模式。MVC 减弱了业务逻辑
接口和数据接口之间的耦合,以及让视图层更富于变化。Struts 是MVC的一种实现,它
将 Servlet和 JSP 标记(属于 J2EE 规范)用作实现的一部分。Struts继承了MVC的各
项特性,并根据J2EE的特点,做了相应的变化与扩展。

2. 有丰富的tag可以用 ,Struts的标记库(Taglib),如能灵活动用,则能大大提高开发效率。另外,就
目前国内的JSP开发者而言,除了使用JSP自带的常用标记外,很少开发自己的标记,或许Struts是一个很好的起点。

3. 页面导航.页面导航将是今后的一个发展方向,事实上,这样做,使系统的脉络更加清晰。通过一
个配置文件,即可把握整个系统各部分之间的联系,这对于后期的维护有着莫大的好处。尤其是当另
一批开发者接手这个项目时,这种优势体现得更加明显。

4. 提供Exception处理机制 .

5. 数据库链接池管理

6. 支持I18N

缺点:
一、 转到展示层时,需要配置forward,每一次转到展示层,相信大多数都是直接转到jsp,而涉及
到转向,需要配置forward,如果有十个展示层的jsp,需要配置十次struts,而且还不包括有时候目
录、文件变更,需要重新修改forward,注意,每次修改配置之后,要求重新部署整个项目,而tomcate这
样的服务器,还必须重新启动服务器,如果业务变更复杂频繁的系统,这样的操作简单不可想象。现在就
是这样,几十上百个人同时在线使用我们的系统,大家可以想象一下,我的烦恼有多大。

二、 Struts 的Action必需是thread-safe方式,它仅仅允许一个实例去处理所有的请求。所以action用
到的所有的资源都必需统一同步,这个就引起了线程安全的问题。

三、 测试不方便. Struts的每个Action都同Web层耦合在一起,这样它的测试依赖于Web容器,单元测
试也很难实现。不过有一个Junit的扩展工具 Struts TestCase可以实现它的单元测试。

四、 类型的转换. Struts的FormBean把所有的数据都作为String类型,它可以使用工具Commons-Beanutils进行
类型转化。但它的转化都是在Class级别,而且转化的类型是不可配置的。类型转化时的错误信息返回给用户也是非常困难的。

五、 对Servlet的依赖性过强. Struts处理Action时必需要依赖ServletRequest 和ServletResponse,所有
它摆脱不了Servlet容器。

六、 前端表达式语言方面.Struts集成了JSTL,所以它主要使用JSTL的表达式语言来获取数据。可
是JSTL的表达式语言在Collection和索引属性方面处理显得很弱。

七、 对Action执行的控制困难. Struts创建一个Action,如果想控制它的执行顺序将会非常困难。甚
至你要重新去写Servlet来实现你的这个功能需求。

八、 对Action 执行前和后的处理. Struts处理Action的时候是基于class的hierarchies,很难
在action处理前和后进行操作。

九、 对事件支持不够. 在struts中,实际是一个表单Form对应一个Action类(或DispatchAction),换
一句话说:在Struts中实际是一个表单只能对应一个事件,struts这种事件方式称为application
event,application event和component event相比是一种粗粒度的事件。

Struts重要的表单对象ActionForm是一种对象,它代表了一种应用,这个对象中至少包含几个字段,这
些字段是Jsp页面表单中的input字段,因为一个表单对应一个事件,所以,当我们需要将事件粒度细
化到表单中这些字段时,也就是说,一个字段对应一个事件时,单纯使用Struts就不太可能,当然通
过结合JavaScript也是可以转弯实现的。


sturst1初始化
Struts1 = jsp + servlet + tag (MVC Model 2)

Struts主要有三个核心的类,分别是ActionServlet,ModuleConfig,RequestProcessor。
ActionServlet就是控制器,
ModuleConfig封装着Struts应用程序的配置信息,
RequestProcessor负责处理每一个HTTP请求。

Struts的核心类就是org.apache.struts.action.ActionServlet,它继承于 javax.servlet.http.HttpServlet,当我
们配置Struts时就要在web.xml文件中配置这个Servlet类。当 ActionServlet初始化时,就调用init()方法。

1.启动
加载多个配置文件 ctrl+shift+T(jar) ctrl+shift+R(源文件resource) ctrl+O(快速查询方法)
*init()
initInternal()读取资源文件(国际化) 初始化Struts框架内在的消息资源,如与系统日志相关的日志、警告和错误消息。
MessageResources类的getMessageResources()方法
在getMessageResources()方法中,通过工厂类调配资源文件

initOther() 由于从form传输过来的都是String类型的值,所以我们要把它们转换成相应的类型。
在这里我们可以学到几个技巧:
技巧一:判断是否是一个Array 类的方法 isArray()
技巧二:判断type是否是 List的一个父类或者父接口,或者与List为同一个类
要注意如果List是另一个 primitive的TYPE类,那么type必须也是这个类才会
返回true,否则都是 false。注意long.TYPE与Long.class是不同的

查找在web.xml中config参数和convertnull参数的配置
config默认配置路径为WEB-INF/struts-config.xml (struts1配置文件)

ActionServlet.initOther()—〉其他初始化
读取web.xml中的config,debug,convertNull的内容。
此方法主要是读取struts-config配置文件和参数convertNull。
convertNull如果convertNull为真时
初始化一个ConvertUtils对象; 由于ConvertUtils.deregister()的初始化,所
有的Converter都是有初始值的,所以这里Struts自己把这些初始值设置为null,即
转换出错的时候返回null,而不是初始值。使用ConvertUtils类的原因是由于从form
传输过来的都是String类型的值,所以我们要把它们转换成相应的类型。目前没有找
到更多有关ConvertUtils的更多信息,如有了解的朋友,可以的话请帮助提供相关信息.多谢!
这里的”convertNull”是在Struts 1.0里提供的,有的文章中,在这里写的是”debug”而在
目前,我所使用的web.xml文件里也只有设定。
简单地说就是:如果convertNull为true,在转化从form传输过来的都是String类型的值的时
候,如果出现类型错误就设置为null。



initServlet()
这个方法主要是通过digester类解析web.xml,对String servletMapping 属性进行初始化。对于
digester说明如下:这是一个基于DOM的SAX实现的类,它是事件触发的,根据xml文件的结 构,
每次读到一个节点元素就会触发一个事件。 它可以直接把xml文件解析为一个java对象。

这是一个比较少见的方法。首先通过this.servletName = getServletConfig().
getServletName()获取servlet的名称,然后根据
if (servletName.equals(this.servletName)) {
this.servletMapping = urlPattern;
}
来判断当前读到的servlet名称是否是我们运行的servlet的名称,如果是,就把url- pattern作为
我们的servletMapping。


从web.xml中加载ActionServlet的初始化参数如servlet-name,加载DTD文件并把
其放入HashMap缓存,读取并解析web.xml的内容,

另外会将当前的ActionServlet放入到创建的Digester对象的栈中。

initChain()
读取web.xml中命令链文件初始值chainConfig
如果没有,则用默认的"org/apache/struts/chain/chain-config.xml"

将当前ActionServlet加入到上下文ServletContext()中

获取ModuleConfig实例,
这个方法使用由initOther()方法获取的config值为要解析的xml路径,用来初始化 ModuleConfig。

Struts中的MessageResource、PlugIn、数据源等,
都是通过ModuleConfig来实现的;

调用initModuleMessageResources(moduleConfig),用户资源文件的初始化;

调用initModulePlugIns(moduleConfig),用户插件的初始化;

调用initModuleFormBeans(moduleConfig);
initModuleForwards(moduleConfig);
initModuleExceptionConfigs(moduleConfig);
initModuleActions(moduleConfig),
把struts配置文件中的其他配置存储到servletContext中;

调用moduleConfig.freeze(),固定组件配置;

通过while循环,解析以"config/"开头的其他struts配置文件,遍历web.xml中
servletConfig配置的initParameterNames,如发现以"config/" 开始的parameter,
则根据此值初始化其它的ModuleConfig;

调用initModulePrefixes(this.getServletContext()) 初始化其他模块并存储

到此,ActionServlet初始化工作就算完成

附:org.apache.commons的通用组件
commons-digester 解析XML 是XML文件与对象之间的转化器
commons-chain 组织复杂流程的处理,是个责任链模式


一次请求的流程
1.以.do结尾的URL被ActionServlet拦截,执行service方法
2.根据请求传递的方法GET/POST选择执行doGet()或doPost()方法
3.在doGet()/doPost()方法中,调用process()方法

在struts1.3.8之前
是在process()方法中获得RequestProcessor的实例
5.RequestProcess的实例调用process()方法,处理请求
6.在RequestProcess类中,创建和验证Form都是在一个方法里面写的,由此我们可以看出它的耦合度非常高。

首先通过processMultipart()处理请求。
若传送方法为get,不做处理,直接返回到process()方法
若传送方法为post,做简单处理后返回process()方法
其次通过processPath()方法获取path
若path为null,返回上一层调用
path不为null,接着进行其它处理
包括对Locale,Content,NoCache,Preprocess,CachedMessages,Mapping,
Roles,ActionForm,Populate,Validate,Forward,Include的处理。

然后创建Action实例,并执行Action返回ActionForward,最后处理
ActionForward。


正是由于耦合度非常高,所以就出现了责任链模式,用责任链模式来代替了RequestProcess类。这样的话
在处理的过程中,采用责任链模式分别由对应的Command类进行处理,
并随时可能由于异常等原因返回。
在这里我学到了责任链模式对外扩展是开放,对内修改是封闭的。
对外扩展是开放的:如果我们需要加一个新的功能,或者客户需要,我们只要配置一个Command就可以了,而
不用修改源代码。
对内修改是封闭的:比如说要加一个权限,不需要修改它的源代码。或者说改的程度最小。


7.一次请求到此结束,会根据ActionForward执行下一个流程 或 直接转往JSP生成
HTML发送到浏览器。

通过源码我们可以看出struts1的好处和缺点。

使用struts1的好处:
1.良好的架构和设计
2.可重用,模块化,扩展性好
3.Open source开源的
4.它提供了丰富的标签库,使页面能更加灵活的使用。

struts1的缺点:
1.它太过于依赖web容器,当配置文件改动一次就要重新启动。
2.它的配置文件太过于复杂。
3.ActionForm无法进行测试.
4.Action测试太过于依赖servlet api,所以在测试的时候要用到模拟对象.





它的一些常识:
1.它的默认配置名:struts-config.xml.
2.Action类中最重要的方法: execute().
3.它的验证方式有两种:在服务器端验证(在FormBean里面重写Validate方法),在客户
端验证(通过配置文件来进行验证)。
4.在服务器启动时会执行init()来进行初始化一些信息。
5.它的乱码问题可以通过过滤器来解决。
6.struts1所需要用到的jar包可能会和tomcat中的jsp-api.jar,servlet-api.jar包冲突,最好
的解决方案是将这两个jar包放到
重新建的一个包中去,然后再引用这个包中的jar。
7.在使用validate框架时from类一定要继承ValidatorFrom这个类。
Struts Validator框架采用两个基于XML的配置文件来配置验证规则。
这两个文件为validator-rules.xml和validation.xml。

struts的标签库的标签主要分为几类:
1.html标签库 这个标签库的大部分标签和HTML中的标签一一对应的。
html标签库的目的是将jsp页面和Action通过ActionForm连接起来。
2.bean标签库 这个标签库主要用来向客户端输出文本信息(比如说国际化的一些信息等)。
3.logic标签库 为了避免在JSP页面中直接使用Java代码进行逻辑判断和循环操作.
4.nested标签库 这个标签库中的标签有来显示form或对象中的“nested”属性
5.tiles标签库:这个标签库的标签允许我们为视图层建立布局。

struts的自定义标签使用过程:
1.先写一个标签类这个类继承了SimpleTagSupport这个类,实现doTag()方法。
2.然后再写一个以.tld为后缀的标签库配置文件里面进行配置一些属性包括(标签类、URI等一些东西)
如果有属性里面还需要添加attribute这个属性。
3.在页面上通过<%@taglib uri="" prefix="" %>导入标签库 使用的时候注意前缀和在.tld中配置的标签名及属性

struts1中DynaValidatorForm的使用 

 <form-beans> 

 <form-bean name="LoginForm" type="org.apache.struts.validator.DynaValidatorForm"> 

 <form-property name="userName" type="java.lang.String" /> 

 <form-property name="password" type="java.lang.String" /> 

 </form-bean> 

 </form-beans>


如果在Action类中使用它,可以这样子:DynaValidatorForm loginForm=(DynaValidatorForm)form;

客户端数据验证与服务端数据验证的区别:
Struts中客户端验证跟服务器端验证有区别.客户端验证直接写一个action文件便可实现,
而服务器端验证必须通过客户端程序去调用服务器端相应的 WebServices,实现业务逻辑.
它们的本质区别是,就是客户端数据校验是在客户端上进行的,而服务器端校验是在服务器上进行的,
在速度上客户端要快很多,但也有缺陷,就是当有黑客攻击的时候,他完全可以绕过客户端直接和服务器交互。
我看到过有人介绍这方面的知识时说,一个有经验的黑客至少能有100种以上的方法绕过客户端之间访问服务器,
而且服务器如果是用JDBC写的话,还要防止sql的注入。不然很容易让黑客攻击。
1、如果注册的时候输入了密码它还显示在页面的话,就用redisplay在输入框不显示它。
2、如果试用框架验证继承ValidatorForm的话,不需要验证的类就可以在action配置里面加个Validator属性="false";