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,内容如下:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE validators PUBLIC
 3     "-//OpenSymphony Group//XWork Validator 1.0.3//EN"
 4     "http://www.opensymphony.com/xwork/xwork-validator-1.0.3.dtd">
 5 <validators>
 6     <field name="username">
 7         <!-- 内置验证器都是定义好的,在xwork-core.jar com.opensymphony.xwork2.validator.validators包中的default.xml文件中 -->
 8         <field-validator type="requiredstring"><!-- 不能为null或者""字符串,默认会去掉前后的空格 -->
 9         <message>用户名不能为空</message>
10         </field-validator>
11     </field>
12 </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接口并定义模型成员域即可。

例如:

 1 public class ModelDriverAction extends ActionSupport implements ModelDriven<User>{
 2     private User model = new User();
 3     public User getModel() {
 4         return this.model;
 5     }
 6
 7     public String execute(){
 8         return "modeldriver";
 9     }
10 }

  当浏览器提交对当前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的成员域contextOgnlContext对象,即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对象的内容,注意看地址。

时间: 2024-12-09 18:05:13

Struts2的相关文章

解决myeclipse中struts2 bug问题包的替换问题

因为struts2的bug问题,手工替换还是比较麻烦,但即便是最新的myeclipse2014也没有替换最新的struts2包,研究了一天,终于找到了解决办法.以下就解决方法与大家分享一下. 1.在perferences中找到 Myeclipse->Project Libraries,右边找到 struts2.1 Libraries,点击 Enable advanced configiguration,去掉以下文件前面的对勾,然后点击 Add custom Jars 2.在弹出的对话框中选择 A

【Struts2】SSH如何返回JSON数据

  在开发中我们经常遇到客户端和后台数据的交互,使用比较多的就是json格式了.在这里以简单的Demo总结两种ssh返回Json格式的数据 项目目录如下 主要是看 上图选择的部分 WebRoot里面就是平常的配置 第一种方法是使用com.google.gson.Gson 将对象转化为Json字符串  (gson-1.6.jar) 主要的代码如下 1 package com.javen.tool; 2 3 import java.io.IOException; 4 import java.io.P

struts2 版本所导致的 Filter 不同

过了好久又重新接触Struts2,使用maven直接获取的struts2-core-2.5.1的包,从网上直接copy了一段web.xml中的Filter,结果报错,struts2.3.x  以后用以下配置: 1 <filter> 2 <filter-name>struts2</filter-name> 3 <filter-class> 4 org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExe

Struts2学习第三课 访问Web资源

1.什么是WEB资源? HttpServletRequest,HttpSession,ServletContext等原生的Servlet API. 2.为什么访问WEB资源? B/S的应用的Controller中必然需要访问WEB资源,例如,向域对象中读写属性,读写Cookie,获取realPath等等. 3.如何访问? 在Action中,可以通过一下方式访问web的HttpSession,HttpServletRequest,HttpServletResponse等资源 与Servlet AP

struts2+hibernate+spring简单整合且java.sql.SQLException: No suitable driver 问题解决

最近上j2ee的课,老师要求整合struts2+hibernate+spring,我自己其实早早地有准备弄的,现在都第9个项目了,无奈自己的思路和头绪把自己带坑了,当然也是经验问题,其实只是用myeclipse进行整合的,本来也没那么多问题,看视频吧居然好多要手打,我不喜欢看不下去放弃了,教程把就是一堆坑,最最让人不解的是明明有一个冲突是需要解决的,但我看到的教程居然都没有提到,还有一个错误居然好多人都好像自动忽略一样,能解决我问题的都是要漫长的找,所以我一定一定要把这个过程记录下来,给第一次搞

SSH Struts2+hiberante+Spring整合

使用SSH框架编写学生信息: 一.新建Java工程: (1)建立好Java各层级之间的结构:业务处理层dao,数据模型层domain,页面请求处理层(Struts2 MVC层)action,service层. (2)建立好各层的实现类及接口; (3)建立一个source folder文件夹,用来存放一些配置问价. (4)改变字节码生成的位置,改为WEB-INF下面的classes文件夹下. Java工程层级结构如下图: 二.hibernate整合到Spring容器中 步骤: 1.编写domain

Struts2 中的值栈的理解

通过对struts2的一段时间的接触,将自己对OGNL的核心值栈说说,值栈:简单的说,就是存放action的堆栈,当我们提交一个请求道服务器端 action时,就有个堆栈,如果action在服务器端进行跳转,所有action共用一个堆栈,当需要保存在action中的数据时,首先从栈顶开始 搜索,若找到相同的属性名(与要获得的数据的属性名相同)时,即将值取出,但这种情况可能出现找到的值不是我们想要的值,那么解决此问题需要用TOP语法 和N语法来进行解决. 当在客服端进行跳转时,当有请求提交到服务器

struts2和hibernate整合的小Demo

jar包下载地址 创建一个web项目. 导入jar包 配置web.xml <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="

配置struts2+spring,springmvc

Struts2+Spring整合 一.spring负责注入,struts2负责它自己的工作.这样不是很符合spring作为ioc容器的全部功能,不推荐. 二.spring负责全部bean和struts2的action的生成.作为ioc容易的最大共用. 所需要jar包 配置web.xml <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/

Struts2基本使用(二)--配置文件简述

配置文件简述 引入Struts2框架之后项目中多了一个struts.xml,以及web.xml也多了一些代码 web.xml只要的功能就是拦截用户的请求其多出的代码如下: <filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class&