从struts1到struts2的跳转

来源:互联网 发布:用友nc软件介绍 编辑:程序博客网 时间:2024/04/28 07:42
struts2原理


1.Struts 2的基本流程


   Struts 2框架由3个部分组成:核心控制器FilterDispatcher、业务控制器和用户实现的业务逻辑组件。在这3个部分里,Struts 2框架提供了核心控制器FilterDispatcher,而用户需要实现业务控制器和业务逻辑组件。 
2.核心控制器:FilterDispatcher 
  FilterDispatcher是Struts 2框架的核心控制器,该控制器作为一个Filter运行在Web应用中,它负责拦截所有的用户请求,当用户请求到达时,该Filter会过滤用户请求。如果用户请求以action结尾,该请求将被转入Struts 2框架处理。 


Struts 2框架获得了*.action请求后,将根据*.action请求的前面部分决定调用哪个业务逻辑组件,例如,对于login.action请求,Struts 2调用名为login的Action来处理该请求。 


Struts 2应用中的Action都被定义在struts.xml文件中,在该文件中定义Action时,定义了该Action的name属性和class属性,其中name属性决定了该Action处理哪个用户请求,而class属性决定了该Action的实现类。 


Struts 2用于处理用户请求的Action实例,并不是用户实现的业务控制器,而是Action代理——因为用户实现的业务控制器并没有与Servlet API耦合,显然无法处理用户请求。而Struts 2框架提供了系列拦截器,该系列拦截器负责将HttpServletRequest请求中的请求参数解析出来,传入到Action中,并回调Action 的execute方法来处理用户请求。


  显然,上面的处理过程是典型的AOP(面向切面编程)处理方式。图3.19显示了这种处理模型。 






图3.19  Struts 2的拦截器和Action


从图3.19中可以看出,用户实现的Action类仅仅是Struts 2的Action代理的代理目标。用户实现的业务控制器(Action)则包含了对用户请求的处理。用户的请求数据包含在 HttpServletRequest对象里,而用户的Action类无需访问HttpServletRequest对象。拦截器负责将 HttpServletRequest里的请求数据解析出来,并传给业务逻辑组件Action实例。


3.业务控制器 
  正如从图3.19所看到的,业务控制器组件就是用户实现Action类的实例,Action类里通常包含了一个execute方法,该方法返回一个字符串——该字符串就是一个逻辑视图名,当业务控制器处理完用户请求后,根据处理结果不同,execute方法返回不同字符串   ——每个字符串对应一个视图名。 


程序员开发出系统所需要的业务控制器后,还需要配置Struts 2的Action,即需要配置Action的如下三个部分定义: 


—  Action所处理的URL。 


—  Action组件所对应的实现类。 


—  Action里包含的逻辑视图和物理资源之间的对应关系。 


每个Action都要处理一个用户请求,而用户请求总是包含了指定URL。当Filter Dispatcher拦截到用户请求后,根据请求的URL和Action处理URL之间的对应关系来处理转发。


4.Struts 2的模型组件 
  实际上,模型组件已经超出了MVC框架的覆盖范围。对于Struts 2框架而言,通常没有为模型组件的实现提供太多的帮助。 


文本框: 图3.20 控制器调用模型组件Java EE应用里的模型组件,通常指系统的业务逻辑组件。而隐藏在系统的业务逻辑组件下面的,可能还包含了DAO、领域对象等组件。 


通常,MVC框架里的业务控制器会调用模型组件的方法来处理用户请求。也就是说,业务逻辑控制器不会对用户请求进行任何实际处理,用户请求最终由模型组件负责处理。业务控制器只是中间负责调度的调度器,这也是称Action为控制器的原因。 






图3.20显示了这种处理流程。 


提示  在图3.20中看到Action调用业务逻辑组件的方法。当控制器需要获得业务逻辑组件实例时,通常并不会直接获取业务逻辑组件实例,而是通过工厂模式来获得业务逻辑组件的实例;或者利用其他IoC容器(如Spring容器)来管理业务逻辑组件的实例。 
5.Struts 2的视图组件 
  Struts 2已经改变了Struts 1只能使用JSP作为视图技术的现状,Struts 2允许使用其他的模板技术,如FreeMarker、Velocity作为视图技术。 


当Struts 2的控制器返回逻辑视图名时,逻辑视图并未与任何的视图技术关联,仅仅是返回一个字符串,该字符串作为逻辑视图名。 


当我们在struts.xml文件中配置 Action时,不仅需要指定Action的name属性和class属性,还要为Action元素指定系列result子元素,每个result子元素定义一个逻辑视图和物理视图之间的映射。前面所介绍的应用都使用了JSP技术作为视图,故配置result子元素时没有指定type属性,默认使用JSP 作为视图资源。 


如果需要在Struts 2中使用其他视图技术,则可以在配置result子元素时,指定相应的type属性即可。例如,如果需要使用FreeMarker,则为result指定值为freemarker的type属性;如果想使用Velocity模板技术作为视图资源,则为result指定值为velocity的type属性…… 
6.Struts 2的运行流程 
  经过上面介绍,我们发现Struts 2框架的运行流程非常类似于WebWork框架的流程。 


提示  在Struts 2的官方站点,我们可以找到如下说法:Essentially,Struts 2.0 is the technical equivalent of WebWork 2.3。Aside from the package and property renaming,it isn't much different than,say,migrating from WebWork 2.1 to 2.2——意思是说:Struts 2.0技术等同于WebWork 2.3框架,除了包和属性被改名外。从WebWork 2.2迁移到Struts 2不会比从WebWork 2.1迁移到WebWork 2.2更复杂。


 


一个请求在Struts 2框架中的处理大概分为以下几个步骤。


   1)客户端提交一个(HttpServletRequest)请求。 


   2)请求被提交到一系列(主要是3层)的过滤器(Filter),如(ActionContextCleanUp、其他过滤器(SiteMesh等)、 FilterDispatcher)。注意:这里是有顺序的,先ActionContext CleanUp,再其他过滤器(Othter Filters、SiteMesh等),最后到FilterDispatcher。


   3)FilterDispatcher是控制器的核心,就是MVC的Struts 2实现中控制层(Controller)的核心。


   4)FilterDispatcher询问ActionMapper是否需要调用某个Action来处理这个(HttpServlet Request)请求,如果ActionMapper决定需要调用某个Action,FilterDispatcher则把请求的处理交给ActionProxy。


   5)ActionProxy通过Configuration Manager(struts.xml)询问框架的配置文件,找到需要调用的Action类。例如,用户注册示例将找到UserReg类。


   6)ActionProxy创建一个ActionInvocation实例,同时ActionInvocation通过代理模式调用Action。但在调用之前,ActionInvocation会根据配置加载Action相关的所有Interceptor(拦截器)。


   7)一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果result。


 


Struts2与Struts1的对比


Action 类: 
• Struts1要求Action类继承一个抽象基类。Struts1的一个普遍问题是使用抽象类编程而不是接口。 
• Struts 2 Action类可以实现一个Action接口,也可实现其他接口,使可选和定制的服务成为可能。Struts2提供一个ActionSupport基类去实现 常用的接口。Action接口不是必须的,任何有execute标识的POJO对象都可以用作Struts2的Action对象。


 


线程模式: 
• Struts1 Action是单例模式并且必须是线程安全的,因为仅有Action的一个实例来处理所有的请求。单例策略限制了Struts1 Action能作的事,并且要在开发时特别小心。Action资源必须是线程安全的或同步的。 
• Struts2 Action对象为每一个请求产生一个实例,因此没有线程安全问题。(实际上,servlet容器给每个请求产生许多可丢弃的对象,并且不会导致性能和垃圾回收问题)


Servlet 依赖: 
• Struts1 Action 依赖于Servlet API ,因为当一个Action被调用时HttpServletRequest 和 HttpServletResponse 被传递给execute方法。 
• Struts 2 Action不依赖于容器,允许Action脱离容器单独被测试。如果需要,Struts2 Action仍然可以访问初始的request和response。但是,其他的元素减少或者消除了直接访问HttpServetRequest 和 HttpServletResponse的必要性。 


可测性: 
• 测试Struts1 Action的一个主要问题是execute方法暴露了servlet API(这使得测试要依赖于容器)。一个第三方扩展--Struts TestCase--提供了一套Struts1的模拟对象(来进行测试)。 
• Struts 2 Action可以通过初始化、设置属性、调用方法来测试,“依赖注入”支持也使测试更容易。


捕获输入: 
• Struts1 使用ActionForm对象捕获输入。所有的ActionForm必须继承一个基类。因为其他JavaBean不能用作ActionForm,开发者经常创建多余的类捕获输入。动态Bean(DynaBeans)可以作为创建传统ActionForm的选择,但是,开发者可能是在重新描述(创建)已经存在的JavaBean(仍然会导致有冗余的javabean)。 
• Struts 2直接使用Action属性作为输入属性,消除了对第二个输入对象的需求。输入属性可能是有自己(子)属性的rich对象类型。Action属性能够通过web页面上的taglibs访问。Struts2也支持ActionForm模式。rich对象类型,包括业务对象,能够用作输入/输出对象。这种ModelDriven 特性简化了taglib对POJO输入对象的引用。 


表达式语言: 
• Struts1 整合了JSTL,因此使用JSTL EL。这种EL有基本对象图遍历,但是对集合和索引属性的支持很弱。 
• Struts2可以使用JSTL,但是也支持一个更强大和灵活的表达式语言--"Object Graph Notation Language" (OGNL).  


绑定值到页面(view): 
• Struts 1使用标准JSP机制把对象绑定到页面中来访问。 
• Struts 2 使用 "ValueStack"技术,使taglib能够访问值而不需要把你的页面(view)和对象绑定起来。ValueStack策略允许通过一系列名称相同但类型不同的属性重用页面(view)。 
  
类型转换: 
• Struts 1 ActionForm 属性通常都是String类型。Struts1使用Commons-Beanutils进行类型转换。每个类一个转换器,对每一个实例来说是不可配置的。 
• Struts2 使用OGNL进行类型转换。提供基本和常用对象的转换器。 


校验:  
• Struts 1支持在ActionForm的validate方法中手动校验,或者通过Commons Validator的扩展来校验。同一个类可以有不同的校验内容,但不能校验子对象。 
• Struts2支持通过validate方法和XWork校验框架来进行校验。XWork校验框架使用为属性类类型定义的校验和内容校验,来支持chain校验子属性  


Action执行的控制: 
• Struts1支持每一个模块有单独的Request Processors(生命周期),但是模块中的所有Action必须共享相同的生命周期。 
• Struts2支持通过拦截器堆栈(Interceptor Stacks)为每一个Action创建不同的生命周期。堆栈能够根据需要和不同的Action一起使用。


 


Struts2+Spring+Hibernate的开发例子


Web.xml配置


<!-- struts2过滤器 Filter 拦接所以指定action的http请求 -->


    <filter>


       <filter-name>struts2</filter-name>


       <filter-class>


           org.apache.struts2.dispatcher.FilterDispatcher


       </filter-class>


    </filter>


    <filter-mapping>


       <filter-name>struts2</filter-name>


       <url-pattern>*.action</url-pattern>


    </filter-mapping>


    <!-- 如果在jsp页面要用到struts2的标签,则jsp页面也需要被过滤,以生成相应的代码 -->


    <filter-mapping>


       <filter-name>struts2</filter-name>


       <url-pattern>*.jsp</url-pattern>


    </filter-mapping>


 


struts.xml总配置文件


<?xml version="1.0" encoding="UTF-8"?>


<!DOCTYPE struts PUBLIC


"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"


"http://struts.apache.org/dtds/struts-2.0.dtd">


<struts>


    <!-- 注意各个子文件的包名称要不一样 name=strutsqs2 --> 


    <!-- 清算账户监控模块 -->


    <include file="/com/forwor/pbms/cleaccrep/struts_clsaccrep.xml" />


</struts>


 


struts.properties的配置


#modify struts2 tag default code generation method 


struts.ui.theme=simple


 


struts_clsaccrep.xml[功能模块struts2配置]


<?xml version="1.0" encoding="UTF-8"?>


<!DOCTYPE struts PUBLIC


"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"


"http://struts.apache.org/dtds/struts-2.0.dtd">


<struts>


    <package name="struts-clsAcc" extends="struts-default">


       <!-- 如果action被Spring托管,则class属性需要填入的是在spring的配置中bean的id,而不是类的位置 -->


       <action name="clsAccMonitor" class="clsAccMonitorAction">


           <!-- 以/开始代表是从系统目录开始寻找资源,否则只以当前访问目录开始寻找资源 -->


           <result name="monitorPage">/WEB-INF/jsp/cleaccrep/clsAccMonitor.jsp


           </result>


           <!-- 错误提示界面 -->


           <result name="error">/WEB-INF/jsp/cleaccrep/error.jsp


           </result>


           <!-- 返回execl报表 -->


           <result name="excel" type="stream">


              <param name="contentType">application/vnd.ms-excel</param>


              <!— action要提供一个返回InputStream流的方法[getInputStream] à


               <param name="inputName">inputStream</param>


              <param name="contentDisposition">attachment;filename="${fileName}"</param>


           </result>


       </action>


    </package>


</struts>


 


applicationContext.xml[spring总配置文件]


<?xml version="1.0" encoding="UTF-8"?>


<beans xmlns="http://www.springframework.org/schema/beans"


    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"


    xmlns:tx="http://www.springframework.org/schema/tx"


    xsi:schemaLocation="


           http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd


           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd


           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">


    <!-- 模块spring资源配置引入-->


    <import resource="hibernate.xml"/> 


    <!-- 清算账户监控模块 -->


    <import resource="/com/forwor/pbms/cleaccrep/applicationContext_clsaccrep.xml" />


 


</beans>


applicationContext_clsaccrep.xml[spring功能模块文件配置]


<?xml version="1.0" encoding="UTF-8"?>


<beans xmlns="http://www.springframework.org/schema/beans"


    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"


    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">


    <!-- service对象配置 -->


    <bean id="clsAccMonitorService"


       class="com.forwor.pbms.cleaccrep.service.impl.ClearAccountService">


       <property name="clearAccountDao" ref="clearAccountDao"></property>


    </bean>


 


    <!-- action对象配置 -->


    <bean id="clsAccMonitorAction" class="com.forwor.pbms.cleaccrep.web.ClearAccountMonitor"


       scope="prototype">


       <property name="clsAccMonitorService" ref="clsAccMonitorService" />


    </bean>


</beans>


Struts2实现Ajax


方式一,纯Struts2实现:


概要:


     如何在struts2的action中返回数据(普通字符串、xml数据岛字符串等)给ajax核心中的XMLHttpRequest对象(即模仿传统jsp页面的ajax交互)</p>


方法:


  public String execute() throws Exception {


       String str = "xxoohuai";


       HttpServletResponse response = ServletActionContext.getResponse();


       response.setContentType("text/html;charset=GBK");//解决中文乱码<br>&nbsp;&nbsp


       PrintStream out = new PrintStream(response.getOutputStream());// 获取out输出对象


       out.println(str);


       return null;// 这里返回的是null</p>


    }


配置struts.xml


<action name="BaseInfo" class="controller.hosp.BaseInfoAction">


        


       </action>


 


 


2010-1-20


struts2 OGNL表达式


1.       OGNL表达式语言
OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,它是一个开源项目。 


 


Struts 2框架使用OGNL作为默认的表达式语言。


相对EL表达式,它提供了平时我们需要的一些功能,如:
支持对象方法调用,如xxx.sayHello(); 
支持类静态方法调用和值访问,表达式的格式为@[类全名(包括包路径)]@[方法名 | 值名],例如:@java.lang.String@format('foo %s', 'bar')或@cn.itcast.Constant@APP_NAME; 
操作集合对象。


支持赋值操作和表达式串联,例如:


price=100, discount=0.8, calculatePrice(),这个表达式会返回80;


访问OGNL上下文(OGNL context)和ActionContext;


 


Ognl 有一个上下文(Context)概念,说白了上下文就是一个MAP结构,它实现了java.utils.Map接口,在Struts2中上下文(Context)的实现为ActionContext,下面是上下文(Context)的结构示意图




2.访问上下文(Context)中的对象需要使用#符号标注命名空间,如#application、#session


另外OGNL会设定一个根对象(root对象),在Struts2中根对象就是ValueStack(值栈) 。如果要访问根对象(即ValueStack)中对象的属性,则可以省略#命名空间,直接访问该对象的属性即可。


在struts2中,根对象ValueStack的实现类为OgnlValueStack,该对象不是我们想像的只存放单个值,而是存放一组对象。在OgnlValueStack类里有一个List类型的root变量,就是使用他存放一组对象
   |--request   
   |--application   
context ------|--OgnlValueStack root变量[action, OgnlUtil, ... ]   
   |--session   
   |--attr   
   |--parameters


在root变量中处于第一位的对象叫栈顶对象。通常我们在OGNL表达式里直接写上属性的名称即可访问root变量里对象的属性,搜索顺序是从栈顶对象开始寻找,如果栈顶对象不存在该属性,就会从第二个对象寻找,如果没有找到就从第三个对象寻找,依次往下访问,直到找到为止。 
大家注意: Struts2中,OGNL表达式需要配合Struts标签才可以使用。如:<s:property value="name"/>


3.由于ValueStack(值栈)是Struts 2中OGNL的根对象,如果用户需要访问值栈中的对象,在JSP页面可以直接通过下面的EL表达式访问ValueStack(值栈)中对象的属性:
${foo} //获得值栈中某个对象的foo属性


如果访问其他Context中的对象,由于他们不是根对象,所以在访问时,需要添加#前缀。
application对象:用于访问ServletContext,例如#application.userName或者#application['userName'],相当于调用ServletContext的getAttribute("username")。


session对象:用来访问HttpSession,例如#session.userName或者#session['userName'],相当于调用session.getAttribute("userName")。


request对象:用来访问HttpServletRequest属性(attribute)的Map,例如#request.userName或者#request['userName'],相当于调用request.getAttribute("userName")。


parameters对象:用于访问HTTP的请求参数,例如#parameters.userName或者#parameters['userName'],相当于调用request.getParameter("username")。


attr对象:用于按page->request->session->application顺序访问其属性。


4.为何使用EL表达式能够访问valueStack中对象的属性


原因是Struts2对HttpServletRequest作了进一步的封装。简略代码如下:


public class StrutsRequestWrapper extends HttpServletRequestWrapper {
       public StrutsRequestWrapper(HttpServletRequest req) {
           super(req);
       }
       public Object getAttribute(String s) {
        ......
        ActionContext ctx = ActionContext.getContext();
        Object attribute = super.getAttribute(s);//先从request范围获取属性值
        if (ctx != null) {
            if (attribute == null) {//如果从request范围没有找到属性值,即从ValueStack中查找对象的属性值
               ......
               ValueStack stack = ctx.getValueStack();
               attribute = stack.findValue(s);
               ......
            }
        }
        return attribute;
    }
}


5.采用OGNL表达式创建List/Map集合对象


如果需要一个集合元素的时候(例如List对象或者Map对象),可以使用OGNL中同集合相关的表达式。
使用如下代码直接生成一个List对象:
<s:set name="list" value="{'zhangming','xiaoi','liming'}" />
<s:iterator value="#list" id="n">
<s:property value="n"/><br>
</s:iterator>


生成一个Map对象:
<s:set name="foobar" value="#{'foo1':'bar1', 'foo2':'bar2'}" />
<s:iterator value="#foobar" >
<s:property value="key"/>=<s:property value="value"/><br>
</s:iterator>


Set标签用于将某个值放入指定范围。
scope:指定变量被放置的范围,该属性可以接受application、session、request、 page或action。如果没有设置该属性,则默认放置在OGNL Context中。
value:赋给变量的值.如果没有设置该属性,则将ValueStack栈顶的值赋给变量。




6.采用OGNL表达式判断对象是否存在于集合中
对于集合类型,OGNL表达式可以使用in和not in两个元素符号。其中,in表达式用来判断某个元素是否在指定的集合对象中;not in判断某个元素是否不在指定的集合对象中,如下所示。
in表达式:
<s:if test="'foo' in {'foo','bar'}">
   在
</s:if>
<s:else>
   不在
</s:else>


not in表达式:
<s:if test="'foo' not in {'foo','bar'}">
   不在
</s:if>
<s:else>
   在
</s:else>


7.OGNL表达式的投影功能
除了in和not in之外,OGNL还允许使用某个规则获得集合对象的子集,常用的有以下3个相关操作符。
?:获得所有符合逻辑的元素。
^:获得符合逻辑的第一个元素。
$:获得符合逻辑的最后一个元素。
例如代码:
<s:iterator value="books.{?#this.price > 35}">
      <s:property value="title" /> - $<s:property value="price" /><br>
</s:iterator>
在上面代码中,直接在集合后紧跟.{}运算符表明用于取出该集合的子集,{}内的表达式用于获取符合条件的元素,this指的是为了从大集合books筛选数据到小集合,需要对大集合books进行迭代,this代表当前迭代的元素。本例的表达式用于获取集合中价格大于35的书集合。
public class BookAction extends ActionSupport {
private List<Book> books;
....
@Override
     public String execute() {
          books = new LinkedList<Book>();
          books.add(new Book("A735619678", "spring", 67));
books.add(new Book("B435555322", "ejb3.0",15));
}
}


8.property标签
property标签用于输出指定值:
<s:set name="name" value="'kk'" />
<s:property value="#name"/>
default:可选属性,如果需要输出的属性值为null,则显示该属性指定的值
escape:可选属性,指定是否格式化HTML代码。
value:可选属性,指定需要输出的属性值,如果没有指定该属性,则默认输出ValueStack栈顶的值。
id:可选属性,指定该元素的标识




9. iterator标签
iterator标签用于对集合进行迭代,这里的集合包含List、Set和数组。
<s:set name="list" value="{'zhangming','xiaoi','liming'}" />
<s:iterator value="#list" status="st">
<font color=<s:if test="#st.odd">red</s:if><s:else>blue</s:else>>
<s:property /></font><br>
</s:iterator> 
value:可选属性,指定被迭代的集合,如果没有设置该属性,则使用ValueStack栈顶的集合。
id:可选属性,指定集合里元素的id。
status:可选属性,该属性指定迭代时的IteratorStatus实例。该实例包含如下几个方法:
int getCount(),返回当前迭代了几个元素。
int getIndex(),返回当前迭代元素的索引。
boolean isEven(),返回当前被迭代元素的索引是否是偶数
boolean isOdd(),返回当前被迭代元素的索引是否是奇数
boolean isFirst(),返回当前被迭代元素是否是第一个元素。
boolean isLast(),返回当前被迭代元素是否是最后一个元素。


10.if/elseif/else标签
<s:set name="age" value="21" />
<s:if test="#age==23">
23
</s:if>
<s:elseif test="#age==21">
21
</s:elseif>
<s:else>
都不等
</s:else>


10.url标签


<s:url action="helloworld_add" namespace="/test"><s:param name="personid" value="23"/></s:url>
生成类似如下路径:
/struts/test/helloworld_add.action?personid=23
红色部分为内容路径。


当标签的属性值作为字符串类型处理时, “%”符号的用途是计算OGNL表达式的值。
<s:set name="myurl" value="'http://www.foshanshop.net'"/>
   <s:url value="#myurl" /><br>
   <s:url value="%{#myurl}" />
输出结果:
#myurl
http://www.foshanshop.net




11.表单标签_checkboxlist复选框


如果集合为list
<s:checkboxlist name="list" list="{'Java','.Net','RoR','PHP'}" value="{'Java','.Net'}"/>
生成如下html代码:
<input type="checkbox" name="list" value="Java" checked="checked"/><label>Java</label>
<input type="checkbox" name="list" value=".Net" checked="checked"/><label>.Net</label>
<input type="checkbox" name="list" value="RoR"/><label>RoR</label>
<input type="checkbox" name="list" value="PHP"/><label>PHP</label>


如果集合为MAP
<s:checkboxlist name="map" list="#{1:'瑜珈用品',2:'户外用品',3:'球类',4:'自行车'}" listKey="key" listValue="value" value="{1,2,3}"/>
生成如下html代码:
<input type="checkbox" name="map" value="1" checked="checked"/><label>瑜珈用品</label>
<input type="checkbox" name="map" value="2" checked="checked"/><label>户外用品</label>
<input type="checkbox" name="map" value="3" checked="checked"/><label>球类</label>
<input type="checkbox" name="map" value="4"/><label>自行车</label>




12. 表单标签_checkboxlist复选框
如果集合里存放的是javabean
<%
Person person1 = new Person(1,"第一个");
Person person2 = new Person(2,"第二个");
List<Person> list = new ArrayList<Person>();
list.add(person1);
list.add(person2);
request.setAttribute("persons",list);
%>
<s:checkboxlist name="beans" list="#request.persons" listKey="personid" listValue="name"/>
Personid和name为Person的属性


生成如下html代码:
<input type="checkbox" name=“beans" value="1"/><label>第一个</label>
<input type="checkbox" name=“beans" value="2"/><label>第二个</label>


13.表单标签_radio单选框
该标签的使用和checkboxlist复选框相同。
如果集合里存放的是javabean(personid和name为Person的属性)
< s:radio name="beans" list="#request.persons" listKey="personid" listValue="name"/>
生成如下html代码:
<input type="radio" name="beans" id="beans1" value="1"/><label>第一个</label>
<input type="radio" name="beans" id="beans2" value="2"/><label>第二个</label>
如果集合为MAP
<s:radio name="map" list="#{1:'瑜珈用品',2:'户外用品',3:'球类',4:'自行车'}" listKey="key" listValue="value“ value="1"/>
生成如下html代码:
<input type="radio" name="map" id="map1" value="1"/><label for="map1">瑜珈用品</label>
<input type="radio" name="map" id="map2" value="2"/><label for="map2">户外用品</label>
<input type="radio" name="map" id="map3" value="3"/><label for="map3">球类</label>
<input type="radio" name="map" id="map4" value="4"/><label for="map4">自行车</label>
如果集合为list
<s:radio name="list" list="{'Java','.Net'}" value="'Java'"/>
生成如下html代码:
<input type="radio" name="list" checked="checked" value="Java"/><label>Java</label>
<input type="radio" name="list" value=".Net"/><label>.Net</label>


14.表单标签_select下拉选择框
<s:select name="list" list="{'Java','.Net'}" value="'Java'"/>
<select name="list" id="list">
    <option value="Java" selected="selected">Java</option>
    <option value=".Net">.Net</option>
</select>
<s:select name="beans" list="#request.persons" listKey="personid" listValue="name"/>
<select name="beans" id="beans">
    <option value="1">第一个</option>
    <option value="2">第二个</option>
</select>
<s:select name="map" list="#{1:'瑜珈用品',2:'户外用品',3:'球类',4:'自行车'}" listKey="key" listValue="value" value="1"/>
<select name="map" id="map">
    <option value="1" selected="selected">瑜珈用品</option>
    <option value="2">户外用品</option>
    <option value="3">球类</option>
    <option value="4">自行车</option>
</select>


 


使用OGNL表达式


OGNL要结合struts标签来使用。由于比较灵活,也容易把人给弄晕,尤其是“%”、“#”、“$”这三个符号的使用。由于$广泛应用于EL中,这里重点写%和#符号的用法。


1、“#”符号有三种用途:


(1)、访问非根对象(struts中值栈为根对象)如OGNL上下文和Action上下文,#相当于ActionContext.getContext();下表有几个ActionContext中有用的属性:


名称
作用
例子


parameters
包含当前HTTP请求参数的Map
#parameters.id[0]作用相当于request.getParameter("id") 


request
包含当前HttpServletRequest的属性(attribute)的Map
#request.userName相当于request.getAttribute("userName") 


session
包含当前HttpSession的属性(attribute)的Map
#session.userName相当于session.getAttribute("userName") 


application
包含当前应用的ServletContext的属性(attribute)的Map
#application.userName相当于application.getAttribute("userName") 


注:attr 用于按request > session > application顺序访问其属性(attribute),#attr.userName相当于按顺序在以上三个范围(scope)内读取userName属性,直到找到为止。用于过滤和投影(projecting)集合,如books.{?#this.price<100};构造Map,如#{'foo1':'bar1', 'foo2':'bar2'}。


(2)、用于过滤和投影(projecting)集合,如: books.{?#this.price>35} 


books.{?#this.price>35}


(3)、构造Map,如: #{'foo1':'bar1', 'foo2':'bar2'} 


#{'foo1':'bar1', 'foo2':'bar2'}这种方式常用在给radio或select、checkbox等标签赋值上。如果要在页面中取一个map的值可以这样写:


<s:property value="#myMap['foo1']"/> 


<s:property value="#myMap['foo1']"/>


2、“%”符号的用途是在标签的属性值被理解为字符串类型时,告诉执行环境%{}里的是OGNL表达式。


这是一开始最让我不能理解的符号,原因是一些相关资源在表述时不太准备,经过一翻痛苦的探索,终于明白了它的用途。实际上就是让被理解为字符串的表达式,被真正当成ognl来执行。很有点类似javascript里面的eval()功能,例如 :


var oDiv = eval("document.all.div"+index) 


var oDiv = eval("document.all.div"+index)


当index变量为1时,语句就会被当作var oDiv = document.all.div1 var oDiv = document.all.div1来执行。%{}就是起这个作用。举例:


<s:set name="myMap" value="#{'key1':'value1','key2':'value2'}"/>  


<s:property value="#myMap['key1']"/>  


<s:url value="#myMap['key1']" />


<s:set name="myMap" value="#{'key1':'value1','key2':'value2'}"/>


<s:property value="#myMap['key1']"/>


<s:url value="#myMap['key1']"/>


上面的代码第2行会在页面上输出“value1”,而第3行则会输出"#myMap['key1']"这么一个字符串。 如果将第3行改写成这样:


<s:url value="%{#myMap['key1']}"/> 


<s:url value="%{#myMap['key1']}"/>


则输出为“value1”。


这说明struts2里不同的标签对ognl的表达式的理解是不一样的。如果当有的标签“看不懂”类似“#myMap['key1']”的语句时,就要用%{}来把这括进去,“翻译”一下了。


3、“$”有两种用途


(1)、在国际化资源文件中,引用OGNL表达式。


(2)、在Struts 2配置文件中,引用OGNL表达式:


<action name="saveUser" class="userAction" method="save">


<result type="redirect">listUser.action?msg=${msg}</result>


</action>


<action name="saveUser" class="userAction" method="save">   


<result type="redirect">listUser.action?msg=${msg}</result>


</action>