浅谈Struts2
学过SSH框架很长一段时间了,一直没有很系统的总结一下,这里先简单谈谈Struts2。
为什么要用Struts2?
这里列举一些Servlet的缺点:
1、每写一个servlet在web.xml中都要做相应的配置。如果有多很servlet,会导致web.xml内容过于繁多。
2、这样的结构不利于分组开发。
3、在servlet中,doGet方法和doPost方法有HttpServletRequest和HttpServletResponse参数。这两个参数与容器相关,如果想在servlet中作单元测试,则必须初始化这两个参数。
4、如果一个servlet中有很多个方法,则必须采用传递参数的形式,分解到每一个方法中。
而而而而而而而而而而。。。。先了解一下Struts2是什么。
Struts2是一个遵循MVC的Web层框架。
先看一下基于Web的MVC三层架构:
这是一个MVC三层架构的基本模式,三层架构中的显示层这里是B/S结构的Web应用。而MVC就是Model、View、Controller。
说好的Struts2是一个Web层的MVC框架呢?在Struts2中MVC是什么呢?
Struts2利用过滤器,拦截客户端的请求。客户端发送请求,经过struts2的过滤器,将HttpServletRequest参数和HttpServletResponse参数封装,利用java反射机制将请求分派给映射的Action。根据Action的执行结果,转向其他Action或jsp页面
Struts2 的Action实现了与Servlet API的解耦,使得在Action里面不需要再直接去引用和使用HttpServletRequest与HttpServletResponse等接口。因而使得Action的单元测试更加简单,而且强大的类型转换也使得我们少做了很多重复的工作。
下面看一下Struts2的原理图:
具体过程大致如下:
1、客户端向Servlet容器(例如Tomcat)发送请求
2、这个请求经过一系列的过滤器(Filter)
3、接着FilterDispatcher(现已过时)被调用,FilterDispatcher询问ActionMapper来决定这个请是否需要调用某个Action
4、如果ActionMapper决定需要调用某个Action,FilterDispatcher把请求的处理交给ActionProxy
5、ActionProxy通过Configuration Manager询问框架的配置文件,找到需要调用的Action类
6、ActionProxy创建一个ActionInvocation的实例。
7、ActionInvocation实例使用命名模式来调用,在调用Action的过程前后,涉及到相关拦截器(Intercepter)的调用。(此处采用了AOP,一系列的拦截器即通知,Action的方法为切入点)
8、Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。返回结果通常是(但不总是,也可 能是另外的一个Action链)一个需要被表示的JSP或者FreeMarker的模版。在表示的过程中可以使用Struts2 框架中继承的标签。在这个过程中需要涉及到ActionMapper
在上述过程中所有的对象(Action,Results,Interceptors,等)都是通过ObjectFactory来创建的。
FilterDispatcher是早期struts2的过滤器,2.1.3后使用StrutsPrepareAndExecuteFilter。StrutsPrepareAndExecuteFilter,prepare进行配制的导入;execute表示进行过滤,指doFilter方法,即将request请求,转发给对应的 action去处理。
上面是Struts2的基本原理,下面看一下Struts2使用主要涉及的几个方面:拦截器,验证,类型转换,属性驱动、模型驱动,OGNL。
拦截器
Struts2自带的拦截器有35个之多。例如:输入验证是由名为validation拦截器处理的,如果禁用该拦截器,输入验证将停止工作;文件上传依靠名为fileUpload的拦截器。
Struts2自带的默认拦截器足以满足绝大多数的应用程序的需要,但也可以自定义拦截器。
自定义拦截器
1、编写一个类,实现com.opensymphony.xwork2.interceptor.Interceptor
2、主要实现public String intercept(ActionInvocation invocation) throws Exception{}方法
3、拦截器定义好后,要在配置文件中进行注册:
<interceptors>
<interceptor name=" interceptorName" class="className"/>
</interceptors>
4、配置文件中的动作,通过 <interceptor-ref name=" interceptorName "></interceptor-ref> 使用该拦截器.
注意:一旦动作中使用了自定义的拦截器,那么默认的就不起作用了。一般应该采用如下的做法:
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name=" interceptorName"></interceptor-ref>
多个动作类都要使用的话,可以通过package来进行组合。
验证
有时候对于从客户端传来的数据需要验证,例如登录页面,验证用户名不能为空,密码也不能为空,并且长度不能小于6位数。
验证的方法有分为以下几种:
1、编程方式
动作类中的所有方法进行验证:
步骤:
a、动作类继承ActionSupport
b、覆盖调用public void validate()方法
c、在validate方法中,编写不符合要求的代码判断,并调用父类的addFieldError(String fieldName,String errorMessage)
如果fieldError(存放错误信息的Map)有任何的元素,就是验证不通过,动作方法不会执行。Struts2框架会返回到name=input的result
d、在name=input指定的页面上使用struts2的标签显示错误信息。<s:fielderror/>
动作类中指定的方法进行验证:
编写步骤与上面相同,验证方法书写有要求:
public void validateXxx() Xxx代表的是要验证的动作方法名,其中要把动作方法名的首字母变为大写。
2、基于XML配置文件的方式
①动作类中的所有方法进行验证:
在动作类的包中,建立一个名称为:动作简单类名-validation.xml ,比如要验证的动作类名是UserAction UserAction-validation.xml,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
"-//OpenSymphony Group//XWork Validator 1.0.3//EN"
"http://www.opensymphony.com/xwork/xwork-validator-1.0.3.dtd">
<validators>
<field name="username">
<!-- 内置验证器都是定义好的,在xwork-core.jar com.opensymphony.xwork2.validator.validators包中的default.xml文件中 -->
<field-validator type="requiredstring"><!-- 不能为null或者""字符串,默认会去掉前后的空格 -->
<message>用户名不能为空</message>
</field-validator>
</field>
</validators>
②动作类中指定的方法进行验证:
配置文件的名称书写有一定要求:动作类名-动作名(配置文件中的动作名)-validation.xml 例如UserAction-user_add-validation.xml
3、自定义基于XML的验证器
a、编写一个类,继承FieldValidatorSupport类。
b、在public void validate(Object object)编写你的验证逻辑,不符合要求的就向fieldErrors中放消息
c、一定注册验证器才能使用
在WEB-INF/classes目录下建立一个名称为validators.xml的配置文件,内容如下:
<validators>
<validator name="strongpassword" class="wz.validators.StrongPasswordValidator"/>
</validators>
d、日后就可以像使用Struts2提供的16个验证器方式去使用了。
属性驱动和模型驱动
属性驱动
条件:
1、页面中name的属性和action中的属性必须保持一致。
2、 Action中的属性必须有get和set方法。
3、满足这两个条件就实现了属性驱动。
过程:
1、 当执行所有的拦截器的时候,当前请求的action已经放在了对象栈栈顶。
2、 放在对象栈的对象的特点是其属性能够直接访问。
3、 也就是说当执行ParameterInterceptor拦截器的时候,action的所有的属性在栈顶。
4、 所以只需要给栈顶的action的属性赋值就可以了。
5、 而ParameterInterceptor拦截器正好完成了此功能。
模型驱动
假设在完成网站的某项功能时,在后台需要得到20多个属性。如果用action中的属性获取值,就要在action中会写20个属性以及其set和get方法。这样会导致action中的代码结构不是很好。
模型驱动很好的解决了这个问题。使用javaBean对象来封装请求参数,实现ModelDriven接口并定义模型成员域即可。
例如:
public class ModelDriverAction extends ActionSupport implements ModelDriven<User>{
private User model = new User();
public User getModel() {
return this.model;
} public String execute(){
return "modeldriver";
}
}
当浏览器提交对当前Action的请求时,先经过拦截器。其中有一个拦截器为ModelDrivenInterceptor,从这个源代码可以看出,这个拦截器的作用就是获取实现了ModelDriver接口的action的模型驱动。在这里为user。然后把模型驱动利用push方法压入到对象栈栈顶。这样就能直接通过属性进行回显和赋值了。
到底是用属性驱动和是模型驱动呢?
(1)最好统一整个系统中的Action使用的驱动模型,即要么都是用属性驱动,要么都是用模型驱动。
(2)如果DB中的持久层的对象与表单中的属性都是一一对应的话,那么就使用模型驱动,代码要整洁很多。
(3)如果表单的属性不是一一对应的话,那么就应该使用属性驱动,否则,你的系统就必须提供两个Bean,一个对应表单提交的数据,另一个用与持久层。
类型转换
从属性驱动的角度考虑,中如果属性中要求接受的不是String类型,而是其他类型呢?struts2将做自动的转化。
客户端表单的每一项输入之可能是一个String或一个String数组。在服务器端,必须先把这些String值转换为特定的数据类型,才能进行相应的处理把请求参数映射到动作属性的工作由Parameters拦截器负责,它是defaultStack拦截器栈的一员。所有的请求参数都是String类型,但并非所有的动作属性都是String类型,所以每一种非String类型的动作属性需要对相关的请求参数进行类型转换。有些Struts2可以自动转化,而有些需要我们手动编写转换的代码。
具体方式:
1、编写一个类,继承com.opensymphony.xwork2.conversion.impl.DefaultTypeConverter
2、覆盖掉其中的public Object convertValue(Map<String, Object> context, Object value,Class toType)
context:OGNL表达式的上下文
value:实际的值。用户输入的都是字符串,但他是一个String数组。
toType:目标类型
3、注册类型转换器
3.1局部类型转换器:只对当前的Action有效
具体做法:在动作类相同的包中,建立一个名称是“动作类名-conversion.properties”的配置文件,文件中增加以下内容:要验证的字段=验证器的类全名。例如:birthday=wz.convertor.DateConvertor
3.2全局类型转换器:对所有的Action都有效
具体做法:在WEB-INF/classes目录下,建立一个名称为"xwork-conversion.properties"的配置文件,文件中增加以下内容:目标类型全名=验证器的类全名。例如:java.util.Date=cn.itcast.convertor.DateConvertor
注意:如果转换失败,Struts2框架会寻找name=input的结果页面
OGNL
OGNL表达式是(Object-Graph Navigation Language)是对象图形化导航语言。OGNL是一个开源的项目,struts2中默认使用OGNL表达式语言来显示数据。与serlvet中的el表达式的作用是一样的。
提起OGNL就不得不提ValueStack了。ValueStack是一个接口,在struts2中使用OGNL表达式实际上是使用实现了ValueStack接口的类OgnlValueStack,这个类是OgnlValueStack的基础。ValueStack贯穿整个action的生命周期。每一个action实例都拥有一个ValueStack对象。其中保存了当前action对象和其他相关对象。Struts2把ValueStack对象保存中名为struts.valueStack的request域中。
当struts接受一个请求时,会迅速创建ActionContext,ValueStack,action。然后把action存放进ValueStack,所以action的实例变量可以被OGNL访问
ActionContext.getContext()从ThreadLocal中得到本线程的ActionContext对象
actionContext对象可以获取context、application、session、valueStack等对象。后三者其实是从context中取出的。
ActionContext的成员域context是OgnlContext对象,即ValueStack中的context对象
context对象中存放request、session、application、parameters、attr等map以及ValueStack等对象
context map与valueStack的关系:
1、context中有一个键值对,key=com.opensymphony.xwork2.util.ValueStack.ValueStack,value=valueStack,即valueStack
2、valueStack中成员域包括CompoundRoot root和OgnlCotext context;。没错,就是上面的context。
3、而ActionContext中的成员域context,就是上面的context。
下面是ActionContext中context对象的内容,注意看地址。
暂时就这么多吧。以上
浅谈Struts2的更多相关文章
- 浅谈struts2之chain
转自:http://blog.csdn.net/randomnet/article/details/8656759 前一段时间,有关chain的机制着实困绕了许久.尽管网上有许多关于chain的解说, ...
- 浅谈 Struts2 面试题收藏
Struts2面试题 一.工作原理 一个请求在Struts2框架中的处理大概分为以下几个步骤 1 客户端初始化一个指向Servlet容器(例如Tomcat)的请求 2 这个请求经过一系列的过滤器(Fi ...
- 浅谈Struts2拦截器的原理与实现
拦截器与过滤器 拦截器是对调用的Action起作用,它提供了一种机制可以使开发者定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行.同时也是提供了 ...
- [SSH 2] 以网站主页面浅谈Struts2配置
导读:前面总体的介绍了一下SSH框架,那么作为Struts这一支,具体是怎么配置的呢?本篇博客则主要是以自己做过的实例中的登录一条线,简单介绍一下struts2的配置,如有不妥之处,还请大家多提点提点 ...
- 小学生之浅谈Struts2与struts1的运行机制
Struts1工作原理图: 1.初始化:struts框架的总控制器ActionServlet是一个Servlet,它在web.xml中配置成自动启动的Servlet,在启动时总控制器会读取配置文件(s ...
- 浅谈Struts2(四)
一.Struts2的拦截器(Intercept) 作用:把多个Action中的共有代码,提取至拦截器,从而减少Action中的冗余代码. 1.Action拦截器 a.编写interceptor类 pu ...
- 浅谈Struts2(三)
一.Struts2收集client的参数 核心思路: <form method="post" action="XXXX"> <input ty ...
- 浅谈Struts2(二)
一.struts2的跳转 1.action跳转JSP a.默认为forward <action name="action1" class="com.liquidxu ...
- 浅谈Struts2(一)
一.Struts2引言 1.Struts2框架的概念 解决的MVC开发过程中,控制器(Controller)的通用问题. a.什么是MVC开发 MVC开发是一种编程思想,由设计者人为的把一个项目,划分 ...
随机推荐
- CSS3文本溢出显示省略号
CCS3属性之text-overflow:ellipsis;的用法和注意之处 语法: text-overflow:clip | ellipsis 默认值:clip 适用于:所有元素 clip: 当对象 ...
- jQuery手机端触摸卡片切换效果
效果:http://hovertree.com/code/run/jquery/a1gr3gm9.html 可以用手机查看效果. 代码如下: <!doctype html> <htm ...
- SharePoint 2013 入门教程之入门手册
当我们搭建完环境,创建应用程序和网站集后,就已经正式开启了我们的SharePoint之旅了,进入网站以后,开始基本的使用.设置,了解SharePoint相关特性,下面,来简单了解下SharePoint ...
- Docker 从零开始制作基础镜像[centos]
http://www.oschina.net/news/62897/docker-hub-contains-high-risk-vulnerabilities 这里有个统计,docker官方和个人发布 ...
- C#中的泛型
写在前面:好几个月没更新了,这些天换了份工作,原来的公司出了很多事所以辞职了.这篇文章写的超级好,让我终于明白了困扰在我心里好久的C#泛型的概念,不仅收藏了,还手动转发一下 哈哈哈~ 1.1 C#中的 ...
- 安卓学习----使用okHttp(get方式)---下载图片
一首先下载Jar包 https://github.com/square/okhttp 如果使用android studio只需要加入依赖 compile 'com.squareup.okhttp3:o ...
- Linux Bond 技术学习资料
Bond 技术原理 Bond 就是将多块网卡虚拟成为一块网卡的技术,通过 bond 技术让多块网卡看起来是一个单独的以太网接口设备并具有相同的 IP 地址. Bond 的原理是网卡在混杂 (promi ...
- 聊下git pull --rebase
有一种场景是经常发生的. 大家都基于develop拉出分支进行并行开发,这里的分支可能是多到数十个.然后彼此在进行自己的逻辑编写,时间可能需要几天或者几周.在这期间你可能需要时不时的需要pull下远程 ...
- [Java入门笔记] 面向对象编程基础(三):成员变量和局部变量
在类中,变量根据定义的位置不同,可以分为成员变量和局部变量.
- Tomcat 启动花费很长时间的解决方案
原始解决方案链接 将 $JAVA_PATH/jre/lib/security/java.security 中的 securerandom.source=file:/dev/urandom 替换为 se ...