Struts2标签详解及具体实例解析

来源:互联网 发布:网络劫持广告怎么解决 编辑:程序博客网 时间:2024/06/03 23:06

 

struts2标签详解

 

A:
<s:a xhref=""></s:a>-----超链接,类似于html里的<a></a>
<s:action name=""></s:action>-----执行一个view里面的一个action
<s:actionerror/>-----如果action的errors有值那么显示出来
<s:actionmessage/>-----如果action的message有值那么显示出来
<s:append></s:append>-----添加一个值到list,类似于list.add();
<s:autocompleter></s:autocompleter>-----自动完成<s:combobox>标签的内容,这个是ajax

B:
<s:bean name=""></s:bean>-----类似于struts1.x中的,JavaBean的值

C:
<s:checkbox></s:checkbox>-----复选框
<s:checkboxlist list=""></s:checkboxlist>-----多选框
<s:combobox list=""></s:combobox>-----下拉框
<s:component></s:component>-----图像符号

D:
<s:date/>-----获取日期格式
<s:datetimepicker></s:datetimepicker>-----日期输入框
<s:debug></s:debug>-----显示错误信息
<s:div></s:div>-----表示一个块,类似于html的<div></div>
<s:doubleselect list="" doubleName="" doubleList=""></s:doubleselect>-----双下拉框

E:
<s:if test="#name=’hujianqiang’">asdfasdf</s:if>
<s:elseif test=""></s:elseif>
<s:else></s:else>-----这3个标签一起使用,表示条件判断

F:
<s:fielderror></s:fielderror>-----显示文件错误信息
<s:file></s:file>-----文件上传
<s:form action=""></s:form>-----获取相应form的值

G:
<s:generator separator=""val=""></s:generator>----和<s:iterator>标签一起使用

H:
<s:head/>-----在<head></head>里使用,表示头文件结束
<s:hidden></s:hidden>-----隐藏值

I:
<s:i18n name=""></s:i18n>-----加载资源包到值堆栈
<s:include value=""></s:include>-----包含一个输出,servlet或jsp页面
<s:inputtransferselectlist=""></s:inputtransferselect>-----获取form的一个输入
<s:iterator></s:iterator>-----用于遍历集合

L:
<s:label></s:label>-----只读的标签

M:
<s:merge></s:merge>-----合并遍历集合出来的值

O:
<s:optgroup></s:optgroup>-----获取标签组
<s:optiontransferselect doubleList="" list=""doubleName=""></s:optiontransferselect>-----左右选择框

P:
<s:param></s:param>-----为其他标签提供参数
<s:password></s:password>-----密码输入框
<s:property/>-----得到'value'的属性
<s:push value=""></s:push>-----value的值push到栈中,从而使property标签的能够获取value的属性

R:
<s:radio list=""></s:radio>-----单选按钮
<s:reset></s:reset>-----重置按钮

S:
<s:select list=""></s:select>-----单选框
<s:set name=""></s:set>-----赋予变量一个特定范围内的值
<s:sort comparator=""></s:sort>-----通过属性给list分类
<s:submit></s:submit>-----提交按钮
<s:subset></s:subset>-----为遍历集合输出子集

T:
<s:tabbedPanel id=""></s:tabbedPanel>-----表格框
<s:table></s:table>-----表格
<s:text name=""></s:text>-----I18n文本信息
<s:textarea></s:textarea>-----文本域输入框
<s:textfield></s:textfield>-----文本输入框
<s:token></s:token>-----拦截器
<s:tree></s:tree>-----树
<s:treenode label=""></s:treenode>-----树的结构

U:
<s:updownselect list=""></s:updownselect>-----多选择框
<s:url></s:url>-----创建url

optiontransferselect标签属性

 

名字

数据类型

默 认 值

说明

addAllToLeftLabel

String

 

“全部添加到左边”按钮的行标

addAllToLeftOnclick

String

 

按下“全部添加到左边”按钮时将被调用的Javascript函数

addAllToRightLabel

String

 

“全部添加到右边”按钮的行标

addAllToRightOnclick

String

 

按下“全部添加到右边”按钮时将被调用的Javascript函数

addToLeftLabel

String

 

“添加到左边”按钮的行标

addToLeftOnclick

String

 

按下“添加到左边”按钮时将被调用的Javascript函数

addToRightLabel

String

 

“添加到右边”按钮的行标

addToRightOnclick

String

 

按下“添加到右边”按钮时

将被调用的Javascript函数

allowAddAllToLeft

boolean

true

是否激活“全部添加到左边”按钮

allowAddAllToRight

boolean

true

是否激活“全部添加到右边”按钮

allowAddToLeft

boolean

true

是否激活“添加到左边”按钮

allowAddToRight

boolean

true

是否激活“添加到右边”按钮

allowSelectAll

boolean

true

是否激活“全选”按钮

allowUpDownOnLeft

boolean

true

是否激活左侧select元素的“上下移动选项”按钮

allowUpDownOnRight

boolean

true

是否激活右侧select元素的“上下移动选项”按钮

buttonCssClass

String

 

按钮的CSS

buttonCssStyle

String

 

按钮的CSS样式

doubleCssClass

String

 

第二个选项列表的CSS

doubleCssStyle

String

 

第二个选项列表的CSS样式

doubleDisabled

boolean

false

是否禁用第二个选项列表

doubleEmptyOption

boolean

false

是否要在第二个选项列表里插入

一个空白选项

doubleHeaderKey

String

 

第二个选项列表的标题的键

doubleHeaderValue

String

 

第二个选项列表的标题的键

doubleId

String

 

第二个选项列表的标识符

doubleList*

String

 

用来充当第二个选项列表的选

项来源的可遍历对象

doubleListKey

String

 

为第二个选项列表提供选项值的对象属性

doubleListValue

String

 

为第二个选项列表提供选项行标的对象属性

doubleMultiple

boolean

false

是否允许用户在第二个选项列表里进行“多选多”选择

doubleName*

String

 

第二个组件的名字

doubleSize

integer

 

第二个选项列表的尺寸属性

emptyOption

boolean

false

是否要在第一个选项列表里插入一个空白选项

formName

String

 

包含这个组件的表单的名字

headerKey

String

 

第一个选项列表里的标题的键

headerValue

String

 

第一个选项列表里的标题的值

leftDownLabel

String

 

左侧“下移”按钮上的文本

leftTitle

String

 

左侧select元素的名称

leftUpLabel

String

 

左侧“上移”按钮上的文本

list*

String

 

用来充当第一个选项列表的选项来源的可遍历对象

listKey

String

 

为第一个选项列表提供选项值的对象属性

listValue

String

 

为第一个选项列表提供选项行标的对象属性

multiple

boolean

 

是否允许用户在第一个选项列表里进行“多选多”选择

rightDownLabel

String

 

右侧“下移”按钮上的文本

rightTitle

String

 

右侧select元素的名称

rightUpLabel

String

 

右侧“上移”按钮上的文本

selectAllLabel

String

 

“全选”按钮上的文本

selectAllOnclick

String

 

按下“全选”按钮时将被调用的Javascript函数

size

integer

 

在第一个select元素里需要显示的选项的个数

updownOnLeftOnclick

String

 

按下左侧的“上移/下移”按钮时将被调用的Javascript函数

updownOnRightOnclick

String

 

按下右侧的“上移/下移”按钮时将被调用的Javascript函数

 

 

 

 

 

 

 

Struts2常用的Ajax标签

Struts2为了简化Ajax过程,提供了一些常用的Ajax标签,对于一些更复杂的Ajax通信过程,我们可以使用JSON插件来实现。

1div标签

div标签在页面上生成一个div元素,但这个div元素的内容不是静态内容,而是从服务器获取的内容。必须为该div标签指定一个href属性,这个href属性必须是一个action,该action负责生成该div元素的内容。还可以指定该div标签生成的div元素以固定的频率来更新自身的内容,可以指定如下两个属性:

updateFreq:指定更新div的时间间隔,单位是ms,如果不指定,则只在页面加载时更新该div的内容。

delay:指定更新div内容的时间延迟,单位是ms,如果没有指定updateFreq属性,则该属性没有意义。

如果服务器包含了JavaScript代码,且希望在本页面内执行服务器响应的JavaScript代码,则可以为该div标签标签指定executeScripts="true"

例子的页面代码如下:

 

<%@ page contentType="text/html;charset=GBK" language="java" %>
<%
@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
    
<title>远程Div</title>
    
<s:head theme="ajax"/>
</head>
<body>
<s:url id="rd" value="/random.action" />
仅一次获取服务器内容的Div<br>
<s:div id="div1"
        theme
="ajax"
        cssStyle
="border: 1px solid black;background-color:#dddddd;
    width:300px;height:40px;padding-top:8px;padding-left:20px"

        href
="%{rd}">
初始化文本
</s:div>
动态更新内容的Div,每隔1s刷新一次(通过指定updateFreq="1000")<br>
使用indicator(通过指定indicator="indicator")<br>
<s:div id="div2"
        theme
="ajax"
        cssStyle
="border: 1px solid black;background-color:#dddddd;
    width:300px;height:40px;padding-top:8px;padding-left:20px"

        href
="%{rd}"
        updateFreq
="1000"
        indicator
="indicator">
初始化文本
</s:div>
<img id="indicator" src="${pageContext.request.contextPath}/images/indicator.gif" alt="Loading" style="display:none"/><br>
3s
之后才开始更新(通过指定delay="3000")<br>
指定与服务器交互出错的提示(通过指定errorText属性)<br>
指定与服务器交互过程中的提示(通过指定loadText属性)<br>
<s:div id="div3"
        theme
="ajax"
        cssStyle
="border: 1px solid black;background-color:#dddddd;
    width:300px;height:40px;padding-top:8px;padding-left:20px"

        href
="%{rd}"                     //使用变量来指定URL
        updateFreq
="1000"
   delay
="3000"
   errorText
="加载服务器数据出错"
   loadingText
="正在加载服务器内容">
初始化文本
</s:div>
指定显示系统出错提示(通过指定showErrorTransportText="true")<br>
<s:div id="div4"
        theme
="ajax"
        cssStyle
="border: 1px solid black;background-color:#dddddd;
    width:300px;height:40px;padding-top:8px;padding-left:20px"

        href
="/AjaxNoUrl.jsp"
        updateFreq
="1000"
   showErrorTransportText
="true"
   loadingText
="正在加载服务器内容">
初始化文本
</s:div>
执行服务器脚本(通过指定executeScripts="true")
<s:url id="test" value="/Test3.action" />
<s:div id="div5"
        theme
="ajax"
        cssStyle
="border: 1px solid black;background-color:#dddddd;
    width:300px;height:40px;padding-top:8px;padding-left:20px"

        href
="%{test}"
        updateFreq
="9000"
   executeScripts
="true"
   loadingText
="正在加载服务器内容">
初始化文本
</s:div>
</body>
</html>


random.action
的处理ActionJSP页面内容如下:

public class RandomAction implements Action {
    
private String data;

    
public String getRdmStr() {
        String result = String.valueOf(Math.round(Math.random() * 10000));
        
return data != null && !data.equals("") ? data + result : result;
    }


    
public void setData(String data) {
        
this.data = data;
    }


    
public String getData() {
        
return this.data;
    }


    
public String execute() {
        
return SUCCESS;
    }

}

 

<%@ page contentType="text/html;charset=GBK" language="java" %>
<%
@ taglib prefix="s" uri="/struts-tags" %>
<%

    request.setAttribute("decorator", "none");
    response.setHeader("Cache-Control","no-cache"); //HTTP 1.1
    response.setHeader("Pragma","no-cache"); //HTTP 1.0
    response.setDateHeader ("Expires", 0); //prevents caching at the proxy server
System.out.println("----------"
);
%>


服务器返回的随机数字是<s:property value="rdmStr"/>

第二个Action是直接的JSP页面,页面包含JavaScript代码,页面内容如下:

 

<%@ page contentType="text/html;charset=GBK" language="java" %>
<%

    request.setAttribute("decorator", "none");
    response.setHeader("Cache-Control","no-cache"); //HTTP 1.1
    response.setHeader("Pragma","no-cache"); //HTTP 1.0
    response.setDateHeader ("Expires", 0); //prevents caching at the proxy server
%>

<script language="JavaScript" type="text/javascript">
    alert('Spring2.0宝典');
</script>
轻量级J2EE企业应用实战
<script language="JavaScript" type="text/javascript">
    alert('基于J2EEAjax宝典!');
</script>

 

如果我们不需要该div调用远程Java方法,而是定期执行某个JavaScript函数,则可以为该div标签指定一个handler属性,该属性的值为该JavaScript函数。如下例子JSP页面代码:

 

<%@ page contentType="text/html;charset=GBK" language="java" %>
<%
@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
    
<title>远程Div</title>
    
<s:head theme="ajax"/>
</head>
<script type="text/javascript">
function handler(widget, node) {
   alert('
本地JavaScript函数处理动态Div');
   node.innerHTML = Math.random() > 0.4 ? "Spring2.0
宝典" : "轻量级J2EE企业应用实战";
}

</script>
<body>
<s:url id="rd" value="/random.action" />
直接使用本页面的JS函数,不再调用远程服务器<br>
<s:div id="div1"
        theme
="ajax"
        cssStyle
="border: 1px solid black;background-color:#dddddd;
    width:300px;height:40px;padding-top:8px;padding-left:20px"

        href
="%{rd}"       //此时的href属性无效
   updateFreq
="2000"
  handler
="handler">
初始化文本
</s:div>
</body>
</html>

 

此外,div标签还可将一个表单里包含的表单域转换成对应的请求参数,并且把这些请求参数发送给远程服务器。为了让一个div标签发送表单里包含的表单域,可以为该div标签指定如下属性:

fromId:该属性的属性值为一个表单元素的ID,表明该div标签会把该表单里的表单域作为参数来发送。

为了通过在JavaScript代码中手动控制div标签启动自动更新,关闭自动更新,则可以为该div标签指定如下两个属性:

startTimerListenTopics:该属性设置一个监听的事件主题,当有Struts2组件向该主题发布事件时,该div标签的计时器被启动。

stopTimerListenTopics:该属性设置一个监听的事件主题,当有Struts2组件向该主题发布事件时,该div标签的计时器被关闭。

例子的JSP页面代码如下:

 

<%@ page contentType="text/html;charset=GBK" language="java" %>
<%
@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
    
<title>远程Div</title>
    
<s:head theme="ajax"/>
</head>
<script>
var controller = {
   refresh : 
function() {alert("手动刷新");},
   start : 
function() {alert("启动自动刷新");},
   stop : 
function() {alert("停止自动刷新");}
};

//controllerrefresh方法注册成/refresh主题的发布者
dojo.event.topic.registerPublisher("/refresh", controller, "refresh");
//controllerstart方法注册成/startTimer主题的发布者
dojo.event.topic.registerPublisher("/startTimer", controller, "start");
//controllerstop方法注册成/stopTimer主题的发布者
dojo.event.topic.registerPublisher("/stopTimer", controller, "stop");
//after主题指定一个事件处理函数
    dojo.event.topic.subscribe("/after", function(data, type, e){
   alert('
与服务器交互过程中现在的过程类型是:' + type);
   
//data : text returned
   //type : "before", "load" or "error"
   //e    : request object
    });
</script>
<body>
<form id="form">
<s:textfield name="data" label="输入框"/>
</form>

<input type="button" value="手动刷新" onclick="controller.refresh()">
<input type="button" value="停止计时器" onclick="controller.stop()">
<input type="button" value="启动计时器" onclick="controller.start()">
<br>
<s:url id="rd" value="/random.action"/>
使用pub-sub机制(通过指定listenTopics等属性)<br>
发送表单请求参数(通过指定formId="form")<br>
<s:div id="div1"
        theme
="ajax"
        cssStyle
="border: 1px solid black;background-color:#dddddd;
    width:300px;height:40px;padding-top:8px;padding-left:20px"

        href
="%{rd}"
   loadingText
="正在加载服务器内容"
  listenTopics
="/refresh"            //加载服务器响应
   startTimerListenTopics
="/startTimer"     //当有startTimer事件发布时启动计数器
   stopTimerListenTopics
="/stopTimer"     //当有stopTimer事件发布是停止计数器
   updateFreq
="9000"
  autoStart
="true"                         //加载此页面时自动启动计数器
  formId
="form"        //指定表单的ID
  notifyTopics
="/after">        //指定主题名为after,其它的事件都会发布到此主题下
初始化文本
</s:div>
</body>
</html>

2asubmit标签

asubmit标签的作用几乎完全一样,除了外在的表现不一样(a标签生成一个超链接,submit标签生成一个提交按钮)。它们都是用于向服务器发送异步请求,并将服务器响应加载在指定的HTML元素中,

href:指定单击这两个标签生成的超链接,按钮时发送请求的URL

targets:该属性指定HTML元素的ID,该属性设置服务器响应来加载到该属性指定的几个HTML元素上。

executeScripts:设置是否执行远程的JavaScript代码。

handler:指定使用本页面的JavaScript函数作为按钮,超链接的单击事件处理函数,如果指定了此属性,则href属性无效。

此外,这两个标签也支持notifyTopics属性,把load事件发布到指定主题。

loadingText:当服务器响应还未成功装载时,targets属性指定的HTML标签显示的内容。

errorText:当与服务器交互之间存在错误时,targets属性指定的HTML标签显示的内容。

form:设置将form属性指定的表单的表单域作为请求参数发送到服务器。

下面是a标签的例子JSP页面代码:

<%@ page contentType="text/html;charset=GBK" language="java" %>
<%
@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
    
<title>远程链结</title>
<s:head theme="ajax"/>
</head>
<script type="text/javascript">
function before() {alert("before request");}
function after() {alert("after request");}
function handler(widget, node) 
{
   alert('
本地自定义函数');
   dojo.byId(widget.targetsArray[0]).innerHTML = "Spring2.0
宝典";
}

    dojo.event.topic.subscribe("/after", function(data, type, e){
      alert('
正处于Dojo的异步交互过程中,类型是:'+type);
      
//data : text returned
      //type : "before", "load" or "error"
      //e    : request object
   });
</script>
<body>
<div id="t1" style="background-color:#bbbbbb;width:360px;height:80px">Div 1</div>
<br/>
<div id="t2" style="background-color:#bbbbbb;width:360px;height:80px">Div 2</div>
<br/>
<s:url id="ajaxTest" value="/AjaxTest.action" />
<s:url id="test3" value="/Test3.action" />
<br/>
同时修改Div1Div2的内容<br/>
且将事件发布到/after主题(指定notifyTopics属性)<br/>
<s:a    id="link1"   
   theme
="ajax"
        href
="%{ajaxTest}"
        indicator
="indicator"
   targets
="t1,t2" notifyTopics="/after" >修改Div1Div2内容</s:a>
<img id="indicator" src="${pageContext.request.contextPath}/images/indicator.gif" alt="Loading" style="display:none"/>
<br/>
指定服务期返回失败时的错误提示(指定errorText属性)<br/>
因为系统中AjaxNoUrl.jsp页面不存在,肯定出错!<br/>
<s:a id="link2"
        theme
="ajax"
        href
="/AjaxNoUrl.jsp"
   errorText
="系统服务器返回信息出错"
   targets
="t1">修改'Div 1'内容,使用自定义出错提示</s:a>
<br/>
指定系统加载中的提示信息(指定loadingText属性)<br/>
<s:a    id="link3"
        theme
="ajax"
        href
="%{ajaxTest}"
   loadingText
="系统正在加载中"
   targets
="t1">修改'Div 1'内容,使用自定义加载信息</s:a>
<br/>
执行远程JavaScript代码(指定executeScriptstrue属性)<br/>
<s:a    id="link4"
        theme
="ajax"
        href
="%{test3}"
   executeScripts
="true"
   targets
="t2">接执行远程JavaScript</s:a>
<br/>
通过使用自定义JavaScript函数来实现Ajax交互(指定handle属性)<br/>
<s:a    id="link5"
        theme
="ajax"
        href
="%{ajaxTest}"
   handler
="handler"
   targets
="t2">使用自定义的处理函数</s:a>
<form id="form">
<input type=textbox name="data">
</form>
提交表单请求(通过指定formId属性)
<s:a    id="link6"
        theme
="ajax"
        href
="%{ajaxTest}"
   targets
="t2"
   formId
="form">Div 2 会显示在上面文本框中输入的内容</s:a>
</body>
</html>

ActionJSP页面代码如下:

public class AjaxTestAction implements Action, Serializable
{
    
private static int counter = 0;
    
private String data;
    
public long getServerTime()
{
        
return System.currentTimeMillis();
    }

    
public int getCount()
{
        
return ++counter;
    }

    
public String getData()
{
        
return "服务器提示:" + data;
    }

    
public void setData(String data)
{
        
this.data = data;
    }

    
public String execute() throws Exception 
{
        
return SUCCESS;
    }

}

JSP页面:

<%@ page contentType="text/html;charset=GBK" language="java" %>
<%
@ taglib prefix="s" uri="/struts-tags" %>
<%

    request.setAttribute("decorator", "none");
    response.setHeader("Cache-Control","no-cache"); //HTTP 1.1
    response.setHeader("Pragma","no-cache"); //HTTP 1.0
    response.setDateHeader ("Expires", 0); //prevents caching at the proxy server
%>

服务器计数器<s:property value="count"/><br>
当前时间是:<s:property value="serverTime"/><br>
服务器返回的提示是:<s:property value="data"/>
JSP
页面2

<%@ page contentType="text/html;charset=GBK" language="java" %>
<%

    request.setAttribute("decorator", "none");
    response.setHeader("Cache-Control","no-cache"); //HTTP 1.1
    response.setHeader("Pragma","no-cache"); //HTTP 1.0
    response.setDateHeader ("Expires", 0); //prevents caching at the proxy server
%>

<script language="JavaScript" type="text/javascript">
    alert('Spring2.0宝典');
</script>
轻量级J2EE企业应用实战
<script language="JavaScript" type="text/javascript">
    alert('基于J2EEAjax宝典!');
</script>

下面是使用submit标签的例子代码:

<%@ page contentType="text/html;charset=GBK" language="java" %>
<%
@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
    
<title>远程按钮</title>
<s:head theme="ajax" debug="true"/>
</head>

<script type="text/javascript">
    dojo.event.topic.subscribe("/after", function(data, type, e){
      alert('
正处于Dojo的异步交互过程中,类型是:'+type);
      
//data : text returned
      //type : "before", "load" or "error"
      //e    : request object
   });
</script>
<body>
<div id="t1" style="background-color:#bbbbbb;width:360px;height:80px">将被改变的结果</div>
<s:url id="ajaxTest" value="/AjaxTest.action" />
简单的提交按钮,使用indicator<br>
<img id="indicator" src="${pageContext.request.contextPath}/images/indicator.gif" alt="Loading" style="display:none"/>
<!-- targets属性设置用于装载被改变的HTML元素 -->
<s:submit type="submit" theme="ajax" value="提交" targets="t1" href="%{ajaxTest}" align="left" indicator="indicator"/>
<br/>
简单的提交按钮,使用pub-sub事件模型(设置notifyTopics=/after属性)<br>
<s:submit type="submit" theme="ajax" value="提交" targets="t1" href="%{ajaxTest}" align="left" notifyTopics="/after"/>
<br/>
图片按钮(通过指定type="image"<br>
<s:submit type="image" theme="ajax" label="Alt Text" targets="t1"
src
="${pageContext.request.contextPath}/images/struts-power.gif" href="%{ajaxTest}" align="left" />
<br/>
异步方式提交表单:(在下面输入的文本将在上面显示)
<s:form id="form" action="AjaxTest">
<input type="text" name="data"/>
<s:submit type="button" theme="ajax" label="发送" targets="t1" id="ajaxbtn"/> //会发送from中的参数
</s:form>
</body>
</html>

实际上,使用submit标签有两种用法,一是指定formID属性,二是在form标签内部使用submit标签。

3autocompleter标签

autocompleter标签会生成一个带下拉按钮的单行文本输入框,当用户单击按钮时,将看到一系列的选项,单击某个选项时可以将该选项填入单行文本框.
选择框的选项会在页面加载时自动加载,而且随着用户在单行广西框中输入时改变,当用户输入字符串时,列表框的选项总是和单行文本框中内容以某种方式匹配.此时,用户也可以通过上,箭头来选择合适的选项,并将指定选项填入单行文本框.
如果我们设置autocompleter标签的autoComplete=true(默认是false),该标签将会在单行文本框中生成输入提示.如果希望强制用户只能输入列表中的列表,则可以设置forceValidOption=true(默认是false).
该标签有如下几个属性:
autoComplete:
设置是否在单行文本输入框中显示提示输入
forceValidOption:
设置单行文本框内是否只接受下拉列表列表
delay:
指定显示列表框之前的延迟时间
href:
指定异步生成列表项的URL
searchType:
设置列表项与单行文本框的字符串的匹配模式,可以接受3个值:startstring(显示以文本框中字符串开头的选项,这是默认值);startword(显示以文本框中单词开头的选项);substring(显示包含文本框中字符串的选项).
dropdownHeight:
设置列表框的高度,默认是120
dropdownWidth:
设置列表框的宽度,默认与单行文本框的宽度相同.
formId:
指定发送哪个表单里的表单域的请求参数
value:
theme使用simple,指定该标签的默认值
list:
指定用于迭代生成选项的集合
loadOnTextChange:
设置当用户在单行文本框内输入时,是否重新加载列表.
loadMinimumCount:
loadOnTextChange属性设置为true,该属性设置输入多少字符后,才会触发重新加载列表.
showDownArrow:
是否显示箭头,默认是显示.
因为autocompleter标签要求服务器响应可以被解析成列表,autocompleter是使用JSON格式来解析服务器响应的,因此,要求服务器响应必须是如下格式:
[

["Spring2.0宝典"],
["
轻量级J2EE企业实战"],
["
基于J2EEAjax宝典"]
]

上面的服务器响应将被解析成两个选项,第一个是显示文本的display Text1,对应的值是value1;第二是显示文本的display Text2,对应的值是value2.
下面是使用autocompleter的例子JSP页面代码:

<%@ page contentType="text/html;charset=GBK" language="java" %>
<%
@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
    
<title>自动完成</title>
<s:head theme="ajax" debug="true"/>
</head>
<body>
<s:url id="books" value="/books.action"/>
服务器(/books.action)总是返回一个简单的JSON list<br>
不使用自动完成(autoComplete="false")<br>
使用indicator<br>
字符串匹配模式是子串匹配(searchType="substring")<br>
<s:autocompleter name="book" theme="ajax" indicator="indicator1" href="%{books}" 
cssStyle
="width: 200px;" 
autoComplete
="false" 
searchType
="substring"/>
<img id="indicator1" src="${pageContext.request.contextPath}/images/indicator.gif" alt="Loading" style="display:none"/>
<br/>
用户输入时重新加载下拉列表项(loadOnTextChange="true")<br>
3个字符后才触发重新加载下拉列表(loadMinimumCout="3")<br>
不出现下拉箭头 (showDownArrow="false")<br>
<s:autocompleter theme="ajax" indicator="indicator" href="%{books}" cssStyle="width: 200px;" autoComplete="false" loadOnTextChange="true" loadMinimumCount="3" showDownArrow="false"/>
<img id="indicator" src="${pageContext.request.contextPath}/images/indicator.gif" alt="Loading" style="display:none"/>
<br/>
设置在文本框中提示自动完成(autoComplete="true")<br>
<s:autocompleter theme="ajax" href="%{books}" cssStyle="width: 200px;" autoComplete="true" />
<br/>
使用本页面的集合来自动完成
<br/>
<s:autocompleter theme="simple" list="{'Spring2.0宝典','轻量级J2EE企业实战','基于J2EEAjax宝典'}" cssStyle="width: 240px;"/>
<br/>
校验用户输入,强制只能输入下拉列表项(forceValidOption="true")
<br/>
<s:autocompleter theme="ajax" href="%{books}" cssStyle="width: 200px;" forceValidOption="true"/>
<br/>
设置dropdown的高度是180px (dropdownHeight="180")
<br/>
<s:autocompleter theme="ajax" href="%{books}" cssStyle="width: 200px;" dropdownHeight="180"/>
<br/>
禁用combobox功能 (disabled="true")
<br/>
<s:autocompleter theme="ajax" href="%{books}" cssStyle="width: 200px;" disabled="true"/>
</body>
</html>

此页面请求的action直接返回一个文件,文件内容为:(国际化后的数据内容)

[
["Spring2.0\u5b9d\u5178"],
["\u8f7b\u91cf\u7ea7J2EE\u4f01\u4e1a\u5b9e\u6218"],
["\u57fa\u4e8eJ2EE\u7684Ajax\u5b9d\u5178"]
]
此外还可以使用autocompleter标签进行异步提交表单,异步提交同样有两种方式:1,为autocompleter标签指定formId属性,该属性指向需要异步提交的表单ID2,将autocompleter标签放在form标签使用。

下面代码是实现两个autocompleter标签的关联,第二个autocompleter的选项内容将根据第一个autocompleter标签的请求参数来重新加载选项。因此将第一个autocompleter的事件注册成某个事件主题的发布者,将第二个autocompleter的事件注册成该事件的订阅者。例子JSP页面代码如下:

<%@ page contentType="text/html;charset=GBK" language="java" %>
<%
@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
    
<title>自动完成</title>
<s:head theme="ajax" debug="true"/>
</head>
将两个关联起来
<br/>
<form id="selectForm">
请选择您喜欢的作者:<br>
<s:autocompleter theme="simple" name="author" 
list
="{'','Rod Johnson' , 'David Flanagan'}" 
value
="" notifyTopics="/book"
forceValidOption
="true"
id
="sel"/>
</form>
请选择您喜欢的图书:<br>
<s:url id="getBook" value="/getBook.action"/>
<s:autocompleter theme="ajax" href="${getBook}" cssStyle="width: 240px;"
autoComplete
="false" formId="selectForm" listenTopics="/book" forceValidOption="true" id="ops"/>
</body>
</html>

Action代码如下:

public class GetBookAction extends ActionSupport {
    
private String author;
    
private List<String> books = new ArrayList<String>();

    
public String getAuthor() {
        
return author;
    }


    
public void setAuthor(String author) {
        
this.author = author;
    }


    
public List<String> getBooks() {
        
return books;
    }


    
public String execute() throws Exception {
        System.out.println(author);
        
if (author.equals("")) // 这里是用""unicode码来作比较,因为Dojo采用了unicode码来处理
        // 所有的非西欧字符,Struts2是建立在Dojo基础上的。
            books.clear();
            books.add("Spring2.0
宝典");
            books.add("
轻量级J2EE企业应用实战");
            books.add("
基于J2EEAjax宝典");
        } 
else if (author.equals("Rod Johnson")) {
            books.clear();
            books.add("Expert One-on-One J2EE Design and Development");
        } 
else if (author.equals("David Flanagan")) {
            books.clear();
            books.add("JavaScript
权威指南");
        }

        
return SUCCESS;
    }

}

Action返回的数据页面代码如下:

<%@ page contentType="text/html;charset=GBK" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
[
<s:iterator value="books">

["<s:property/>"],
</s:iterator>

]

 

 

 

 

 

struts2中非表单标签的使用

     非表单标签主要用于在页面生成一些非表单的可视化元素,例如Tab页面,输出HTML页面的树形结构等。当然,非表单标签也包含在页面显示Action里封装的信息。非表单标签主要有如下几个: 
     a
:生成一个超级连接(link)
     actionerror
:如果Action实例的getActionErrors()方法返回不为null,则该标签负责输出该方法返回的系列错误。
     actionmessage
:如果Action实例的getActionMessages()方法返回不为null,则该标签负责输出该方法返回的系列消息。
     component
:使用此标签可以生成一个自定义组件。
     div
:此标签负责生成一个div片段。
     fielderror
:如果Action实例存在表单域的类型转换错误、校验错误,该标签负责输出这些错误提示。
     tabbedPanel
:生成HTML页面的Tab页。
     tree
:生成一个树形结构。
     treenode
:生成树形结构的节点。
下面,使用上面列出的一些十分常用的非表单标签。

     1. actionerror
actionmessage标签 
    
这两个标签用法完全一样,作用也几乎完全一样,都是负责输出Action实例里封装的信息,区别是actionerror标签负责输出Action实例的getActionError()方法的返回值,而actionmessage标签负责输出Action实例的getActionMessage()方法的返回值。对于这两个标签而言,几乎没有自己的专有属性,故使用起来非常简单。下面是本示例应用中的Action类,这个Action类仅仅添加了两条ActionErrorActionMessage,并没有做过多处理,代码:

public class DemoAction extends ActionSupport {

    
public String execute() {
        
        
// 添加两条Error信息
        addActionError("第一条错误消息!");
        addActionError("
第二条错误消息!");
        
        
// 添加两条普通信息
        addActionMessage("第一条普通消息!");
        addActionMessage("
第二条普通消息!");
        
        
return SUCCESS;
    }
}


上面的Actionexecute方法仅仅在添加了四条消息后,直接返回success字符串,success字符串对应的JSP页面中使用<s:actionerrror/><s:actionmessage/>来输出ActionErrorActionMessage信息。下面是该JSP页面中使用这两个标签的示例代码:

<!-- 输出getActionError()方法返回值 --> 
<s:actionerror/> 
<!-- 输出getActionMessage()方法返回值 --> 
<s:actionmessage /> 


在另一个页面中使用<s:action .../>标签来调用上面的Action,调用Action的标签代码片段如下:
<s:action name="demo" executeResult="true"/>
从上面的<s:action .../>标签中可以看出,上面代码将demoAction的处理结果包含到本页面中来。

     2. component
标签
     component
标签用于使用自己的自定义组件,这是一个非常灵活的用法,如果经常需要使用某个效果片段,就可以考虑将这个效果片段定义成一个自定义组件,然后在页面中使用component标签来使用该自定义组件。因为使用自定义组件还是基于主题、模板管理的,因此在使用component标签时,常常需要指定如下三个属性:
 
theme:自定义组件所使用的主题,如果不指定该属性,默认使用xhtml主题。q
qtemplateDir:指定自定义组件的主题目录,如果不指定,默认使用系统的主题目录,即template目录。
qtemplate:指定自定义组件所使用的模板。
除此之外,还可以在cmponent标签内使用param子标签,子标签表示向该标签模板中传入额外的参数。如果希望在模板中取得该参数,总是采用如下形式:$parameters.paramname,或者$parameters['paramname']
提示:自定义的模板文件可以采用FreeMarkerJSPVelocity三种技术来书写。
看下面的JSP页面,该页面多次使用了<s:component .../>标签来使用自定义组件,下面是该页面使用<s:component .../>标签的代码片段:

使用自定义主题,自定义主题目录<br>  
Web应用根路径下加载模板,使用ftl模板。 
<s:component 
        
theme="customTheme" 
        templateDir
="customTemplateDir" 
        template
="ftlCustomTemplate"> 
<s:param name="list" value="{'Spring2.0宝典' , '轻量级J2EE企业应用实战' , '基于J2EEAjax宝典'}" /> 
</s:component> 
<hr/>    
使用自定义主题,自定义主题目录<br> 
Web应用根路径下加载模板,使用JSP模板。 
<s:component 
        
theme="customTheme" 
        templateDir
="customTemplateDir" 
        template
="jspCustomTemplate.jsp"> 
<s:param name="list" value="{'Spring2.0宝典' , '轻量级J2EE企业应用实战' , '基于J2EEAjax宝典'}" /> 
</s:component> 
<hr/> 
使用默认主题(xhtml),默认主题目录(template)<br> 
Web应用中加载模板,使用JSP模板。 
<s:component template="mytemplate.jsp"> 
<s:param name="list" value="{'Spring2.0宝典' , '轻量级J2EE企业应用实战' , '基于J2EEAjax宝典'}" /> 
</s:component> 
<hr/>  
使用自定义主题,自定义主题目录<br> 
/WEB-INF/classes路径下加载模板,使用ftl模板。 
<s:component 
theme="myTheme" 
templateDir
="myTemplateDir" 
template
="myAnotherTemplate"> 
<s:param name="list" value="{'Spring2.0宝典' , '轻量级J2EE企业应用实战' , '基于J2EEAjax宝典'}" /> 
</s:component> 


在上面页面中使用了2FreeMarker模板,这两个FreeMarker模板都使用了FreeMarker标签。除此之外,本页面中还使用了两个JSP模板,这两个JSP页面只是加载的位置不同,两个模板的代码是相同的,下面是JSP模板的代码:

<!-- 设置页面编码 --> 
<%
@ page contentType="text/html; charset=GBK" language="java"%> 
<%
@taglib prefix="s" uri="/struts-tags" %> 
<div style="background-color:#eeeeee;"> 
<b>JSP自定义模板<br> 
请选择您喜欢的图书<br></b> 
<!-- 使用select标签迭代输出list参数所穿过来的集合 --> 
<s:select list="parameters.list"/> 
</div> 


3. tree
treenode初步
这里仅仅介绍treetreenode标签的初步用法,我们可以通过treetreenode在页面中生成一个树形结构。其中tree生成一个树形结构,treenode生成一个树节点。
对于treetreenode标签,都可指定一个label属性,该属性指定了树、或者树节点的标题。看如下代码:

<!-- 使用s:tree生成树 --> 
<s:tree label="计算机图书" id="book" theme="ajax" 
showRootGrid
="true" showGrid="true" treeSelectedTopic="treeSelected"> 
<!-- 每个treenode生成一个树节点 --> 
    
<s:treenode theme="ajax" label="李刚" id="yeeku"> 
<!-- treenode生成下一级的子节点 --> 
        
<s:treenode theme="ajax" label="Spring2.0宝典" id="spring"/> 
        
<s:treenode theme="ajax" label="轻量级J2EE企业应用实战" id="lightweight"/> 
        
<s:treenode theme="ajax" label="基于J2EEAjax宝典" id="ajax"/> 
    
</s:treenode> 
    
<s:treenode theme="ajax" label="David" id="David"> 
        
<s:treenode theme="ajax" label="JavaScript: The Definitive Guide" id="javascript"/> 
    
</s:treenode> 
    
<s:treenode theme="ajax" label="Johnson" id="Johnson"> 
        
<s:treenode theme="ajax" label="Expert One-on-One J2EE Design and Development" id="j2ee"/> 
    
</s:treenode> 
</s:tree> 


从上面代码中可以看出,所有的treenode标签必须放在tree标签内部,或者放在treenode标签的内部。当放在tree标签的内部时,该节点是该树的根节点,当放在treenode标签的内部时,它是该节点的子节点。

 

Strus2的表单标签的使用

Struts2为大家提供了不少常用的很酷的表单标志,简化了我们程序员的工作。不过,由于这些都是新标志,大家可能在使用上还存在不少疑问。本文将就朋友们的回复、留言或Email上的问题,分别对这些酷标志进行讲述。

表单标志使用小技巧

Struts 2的表单标志在输出(renderHTML时,使用了模板的概念,增加了复杂性(因为它不像Struts 1.x的表单标志,它通常都是一个标志对应HTML的一个元素),因此大家在使用时,需要一些技巧:

  1. Struts 2的UI标志的表单标志默认是以表格布局,按钮是右对齐的。如果你不喜欢此风格,你可以简单地将<s:form />标志的“theme”属性设为“simple”,然后用以往的做法自已布局表单元素(注意:此法有利有弊,弊就是当你将“theme”属性设为“simple”时,表单标志以最简单方式输出HTML,所以你可能失去一些默认输出提供的便利,如:友好的错误信息的显示,或客户端的表单验证等)。当然更好的做法是通过CSS或自定义主题(theme)然后应用到整个应用程序,这样可以获得一致的页面风格,加强用户体验(我会在以后的文章对此进行讲解);
  2. 当你在页面上加入某些标志(如:<s:doubleselect />等)时,应该通过action来访问页面,而不是通过*.jsp的URL直接访问。

下面我将分别对这些标志进行讲述:

1<s:checkboxlist />

大家对<s:checkboxlist />的最大的疑问可能是:如何在默认情况下,选中某些checkbox

答案其实很简单,只需要将其“value”属性设为你的要选中的值,如以代码所示:

<%@page language="java" contentType="text/html; charset=utf-8"pageEncoding="utf-8"%>
<%@taglib prefix="s" uri="/struts-tags"%>

<!DOCTYPE html PUBLIC"-//W3C//DTDXHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
   
<title>Struts 2 Cool Tags -&lt;s:checkboxlist/&gt;</title>
   
<s:head />
</head>
<body>    
   
<h2>&lt;s:checkboxlist/&gt;</h2>
   
<s:form action="Store">
       
<s:checkboxlistname="skills1" 
                       label
="Skills 1" 
                       list
="{ 'Java', '.Net', 'RoR', 'PHP' }" 
                       value
="{ 'Java', '.Net' }"/>
       
<s:checkboxlistname="skills2" 
                       label
="Skills 2" 
                       list
="#{ 1:'Java', 2: '.Net', 3: 'RoR', 4:'PHP' }" 
                       listKey
="key" 
                       listValue
="value" 
                       value
="{ 1, 2, 3 }"/>
   
</s:form>
</body>
</html>

清单1 WebContent/checkboxlist.jsp

分布运行应用程序,在浏览器中键入:http://localhost:8080/Struts2_CoolTags/checkboxlist.jsp,出现如下图所示页面:


清单2 checkboxlist.jsp页面

2<s:doubleselect />

大家看Struts 2showcase的例子,<s:doubleselect/>的用法如下所示:

    <s:doubleselect
           
tooltip="Choose Your State"
            label
="State"
            name
="region" list="{'North', 'South'}"
            value
="'South'"
            doubleValue
="'Florida'"
            doubleList
="top== 'North' ? {'Oregon', 'Washington'}: {'Texas', 'Florida'}" 
            doubleName
="state"
            headerKey
="-1"
            headerValue
="----------Please Select ----------"
            emptyOption
="true"/>

清单3 Showcase<s:doubleselect />

很多朋友问:上面的‘list’属性只有两个值,如果我有三个或更多的值,‘doublelist’属性应该如何设定呢?

我建议的做法是先定义一个Map类型的对象,键为“list”的集合,值则为“doubleList”的集合,然后“doubleList”OGNL写成“#myMap[top]”,如以下代码所示:

<%@page language="java" contentType="text/html; charset=utf-8"pageEncoding="utf-8"%>
<%@taglib prefix="s" uri="/struts-tags"%>

<!DOCTYPE html PUBLIC"-//W3C//DTDXHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
   
<title>Struts 2 Cool Tags -&lt;s:doubeselect/&gt;</title>
   
<s:head />
</head>
<body>    
   
<h2>&lt;s:doubleselect/&gt;</h2>
   
<s:form action="Store">
       
<s:setname="foobar" 
               value
="#{'Java': {'Spring', 'Hibernate', 'Struts 2'}, '.Net': {'Linq',' ASP.NET 2.0'}, 'Database': {'Oracle', 'SQL Server', 'DB2', 'MySQL'}}"/>
       
<s:doubleselectlist="#foobar.keySet()"
                         doubleName
="technology" 
                         doubleList
="#foobar[top]" 
                         label
="Technology"/>
   
</s:form>
</body>
</html>

清单4 WebContent/doubleselect.jsp

分布运行应用程序,在浏览器中键入:http://localhost:8080/Struts2_CoolTags/doubleselect.action,出现如下图所示页面:


清单5 doubleselect.jsp页面

3<s: token />

这个标志可能大家不常用,不过本人认为它还是挺有用的。在使用Struts1.x时,因为跳转通常是用Forward(而不是Redirect)实现的,所以当用户完成请求后,按“F5”刷新页面时,就会重新提交上次的请求,这样经常会出错。要解决这个问题,<s:token />可以帮你忙。

实现原理

在页面加载时,<s: token />产生一个GUIDGloballyUnique Identifier,全局唯一标识符)值的隐藏输入框如:

<inputtype="hidden" name="struts.token.name" value="struts.token"/>
<input type="hidden" name="struts.token" value="BXPNNDG6BB11ZXHPI4E106CZ5K7VNMHR"/>

清单6 <s:token />HTML输出

同时,将GUID放到会话(session)中;在执行action之前,“token”拦截器将会话token与请求token比较,如果两者相同,则将会话中的token删除并往下执行,否则向actionErrors加入错误信息。如此一来,如果用户通过某种手段提交了两次相同的请求,两个token就会不同。

具体实现

首先看一下Action的代码:

package tutorial;

import com.opensymphony.xwork2.ActionSupport;

publicclass CoolTagActionextends ActionSupport{    
   
privatestaticfinallong serialVersionUID = 6820659617470261780L;
   
   
private String message;
       
   
public String getMessage(){
       
return message;
   }

   
publicvoid setMessage(String message){
       
this.message = message;
   }
   
   @Override
   
public String execute(){
      System.out.println("Executing action, your message is " +message);
       
return SUCCESS;
   }    
}

清单7 src/tutorial/CoolTagAction.java

以上代码一目了然,再看看JSP的写法:

%@ page language="java" contentType="text/html;charset=utf-8" pageEncoding="utf-8" %>
<%@taglib prefix="s" uri="/struts-tags"%>

<!DOCTYPE html PUBLIC"-//W3C//DTDXHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
   
<title>Struts 2 Cool Tags -&lt;s:token/ &gt;</title>
   
<s:head />
</head>
<body>    
   
<h2>&lt;s:token/&gt;</h2>
   
<s:actionerror/>
   
<s:form action="Token">
       
<s:textfieldname="message" label="Message"/>
       
<s:token/>
       
<s:submit/>
   
</s:form>
</body>
</html>

清单8 WebContent/token.jsp

JSP也很简单,就是加入<s:token/>标志。接下来是Actoin配置的XML片段:

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

<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd"
>

<struts>
   
<package name="Struts2_COOL_TAGS_DEMO" extends="struts-default">
       
<actionname="Token" class="tutorial.CoolTagAction">
           
<interceptor-refname="defaultStack"/>
           
<interceptor-refname="token"/>
           
<resultname="invalid.token">/token.jsp</result>                       
           
<result>/token.jsp</result>
       
</action>
       
<actionname="*">
           
<result>/{1}.jsp</result>
       
</action>
   
</package>
</struts>

清单9 src/struts.xml

以上XML片段值注意的是加入了“token”拦截器和“invalid.token”结果,因为“token”拦截器在会话token与请求token不一致时,将会直接返回“invalid.token”结果。

发布运行应用程序,在浏览器中键入:http://localhost:8080/Struts2_CoolTags/token.jsp,出现如下图所示页面:


清单10 正常显示的token.jsp页面

随便填点东西并提交页面,一切正常返回以上页面,然后按“F5”刷新页面,在弹出的对话框中点击“Retry”,出现如下图所示页面:


清单11 重复提交出错显示

4<s:datetimepicker /><s:optiontransferselect/><s:updownselect />

这几个标志的使用相对简单,所以我想小举一例即可,以下是JSP的代码:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
   
<title>Struts 2 Cool Tags - Others</title>
   
<s:head />
</head>
<body>    
   
<h2>Others</h2>
   
<s:form action="Store">
       
<s:datetimepickername="birthday" label="Birthday"/>
       
<s:updownselect
           
label = "Favourite Countries"
            list
="#{'england':'England','america':'America', 'germany':'Germany'}"
            name
="prioritisedFavouriteCountries"
            headerKey
="-1"
            headerValue
="---Please Order Them Accordingly ---"
            emptyOption
="true"/>
       
<s:optiontransferselect           
           
label="Favourite Cartoons Characters"
            name
="leftSideCartoonCharacters" 
            leftTitle
="LeftTitle"
            rightTitle
="RightTitle"
            list
="{'Popeye','He-Man', 'Spiderman'}" 
            multiple
="true"
            headerKey
="headerKey"
            headerValue
="---Please Select ---"
            emptyOption
="true"
            doubleList
="{'Superman','Mickey Mouse', 'Donald Duck'}" 
            doubleName
="rightSideCartoonCharacters"
            doubleHeaderKey
="doubleHeaderKey"
            doubleHeaderValue
="--- Please Select ---" 
            doubleEmptyOption
="true"
            doubleMultiple
="true"/>
   
</s:form>
</body>
</html>

清单12 WebContent\others.jsp页面

发布运行应用程序,在浏览器中键入:http://localhost:8080/Struts2_CoolTags/others.jsp,出现如下图所示页面:


清单13 其它表单标志页面

总结

Struts 2在标志上的确比Struts1.x丰富了许多,同时模板机制也给程序员带来不少方便(如果你不太喜欢个性化的风格)。另外,Struts 2还有一些AJAX(如<s: autocompleter />等)的标志和非表单的UI标志(如<s: tree />等),我会在以后的文章中讲述其使用。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Struts2在OGNL基础上的增强

        1、值栈(ValueStack)
Struts2OGNL上下文设置为Struts2中的ActionContext(内部使用的仍然是OgnlContext),并将值栈设为OGNL的根对象。
    我们知道,OGNL上下文中的根对象可以直接访问,不需要使用任何特殊的标记,而引用上下文中的其他对象则需要使用“#”来标记。由于值栈是上下文中的根对象,因此可以直接访问。那么对于值栈中的对象该如何访问呢?Struts2提供了一个特殊的OGNLPropertyAccessor,它可以自动查找栈内的所有对象(从栈顶到栈底),直接找到一个具有你所查找的属性的对象。也就是说,对于值栈中的任何对象都可以直接访问,而不需要使用“#”
    假设值栈中有两个对象:studentemployee,两个对象都有name属性,student有学号属性number,而employee有薪水属性salaryemployee先入栈,student后入栈,位于栈顶,那么对于表达式name,访问的就是studentname属性,因为student对象位于栈顶;表达式salary,访问的就是employeesalary属性。正如你所见,访问值栈中的对象属性或方法,无须指明对象,也不用“#”,就好像值栈中的对象都是OGNL上下文中的根对象一样。这就是Struts2OGNL基础上做出的改进。
  2、[N]语法
    如上所述,如果想要访问employeename属性,应该如何写表达式呢?我们可以使用[N].xxx(N是从0开始的整数)这样的语法来指定从哪一个位置开始向下查找对象的属性,表达式[1].name访问的就是employee对象的name属性。
    在使用[N].xxx语法时,要注意位置序号的含义,它并不是表示获取栈中索引为N的对象,而是截取从位置N开始的部分栈。
  3、top关键字
top用于获取栈顶的对象,结合[N].xxx语法,我们就可以获取栈中任意位置的对象。
    如:[0].top,[1].top
  4、访问静态成员
    除了使用标准的OGNL表达式访问静态字段和静态方法外,Struts2还允许你不指定完整的类名,而是通过“vs”前缀来调用保存在栈中的静态字段和静态方法。
@vs@FOO_PROPERTY
@vs@someMethod()
@vs1@someMethod()
vs表示ValueStack,如果只有vs,那么将使用栈顶对象的类;如果在vs后面跟上一个数字,那么将使用栈中指定位置处的对象类。
  5、值栈中的Action实例
Struts2框架总是把Action实例放在栈顶。因为Action在值栈中,而值栈又是OGNL中的根,所以引用Action的属性可以省略“#”标记,这也是为什么我们在结果页面中可以直接访问Action的属性的原因。
  6、Struts2中的命名对象
Struts2还提供了一些命名对象,这些对象没有保存在值栈中,而是保存在ActionContext中,因此访问这些对象需要使用“#”标记。这些命名对象都是Map类型。
parameters
    用于访问请求参数。如:#parameters['id']#parameters.id,相当于调用了HttpServletRequest对象的getParameter()方法。
    注意,parameters本质上是一个使用HttpServletRequest对象中的请求参数构造的Map对象,一量对象被创建(在调用Action实例之前就已经创建好了),它和HttpServletRequest对象就没有了任何关系。
request
    用于访问请求属性。如:#request['user']#request.user,相当于调用了HttpServletRequest对象的getAttribute()方法。
session
    用于访问session属性。如:#session['user']#session.user,相当于调用了HttpSession对象的getAttribute()方法。
application
    用于访问application属性。如:#application['user']#application.user,相当于调用了ServletContextgetAttribute()方法。
attr
    如果PageContext可用,则访问PageContext,否则依次搜索requestsessionapplication对象。

 

 

 

 

struts2标签详解

要在jsp中使用Struts2的标志,先要指明标志的引入。通过jsp的代码的顶部加入以下的代码:

<%@taglibprefix="s"uri="/struts-tags"%>

If elseif  else

描述:

执行基本的条件流转。

参数:

名称

必需

默认

类型

描述

备注

test

 

boolean

决定标志里的内容是否显示的表达式

else标志没有这个参数

id

 

Object/String

用来标识元素的id。在UI和表单中为HTMLid属性

 

例子:

<s:setname="age"value="61"/>

<s:iftest="${age > 60}">

    老年人

</s:if>

<s:elseiftest="${age> 35}">

    中年人

</s:elseif>

<s:elseiftest="${age> 15}"id="wawa">

    青年人

</s:elseif>

<s:else>

    少年

</s:else>

<s:setname="name"value="<%="'"+ request.getParameter("name")+"'"%>"/>

<%

 System.out.println(request.getParameter("name"));

 %>

<s:iftest="#name=='zhaosoft'">

  zhaosoft here

</s:if>

<s:elseiftest="#name=='zxl'">

  zxl here

</s:elseif>

<s:else>

  other is here

</s:else>

Iterator(迭代)

描述:用于遍历集合(java.util.Collection)或枚举值(java.util.iterator)

参数

名称

必需

默认

类型

描述

status

 

String

如果设置此参数,一个IteratorStatus的实例将会压入每一个遍历的堆栈

value

 

Object/String

要遍历的可枚举的(iteratable)数据源,或者将放入的新列表(List)的对想

id

 

Object/String

用来标识元素的id。在ui和表单中为HTMLid属性

I18n(国际化操作)

描述:

加载资源包到值堆栈。它可以允许text标志访问任何资源包的信息。而不只当前的action相关联的资源包。

名称

必需

默认

类型

描述

name

 

Object/String

资源包的类路径(com.xxxx.resources.AppMsg)

id

 

Object/String

用来标识元素的id。在ui和表单中为HTMLid属性

Include

描述:包含一个servlet的输出(servletjsp的页面)

名称

必需

默认

类型

描述

value

 

String

要包含的jsp页面或servlet

id

 

Object/String

用来标识元素的id。在ui和表单中为HTMLid属性

param

描述:属性是可选的,如果提供,会调用Component的方法,addParameter(String,Object),如果不提供,则外层嵌套标签必须实现UnnamedParametric接口。

Value的提供有两种方式,通过value属性或者标签中间的text,不同之处:

<s:paramname="name">zhaosoft</s:param>

参数会以String的格式放入statck

<s:paramname="name" value="zhaosoft"/>

该值会以java.lang.Object的格式放入statck

名称

必需

默认

类型

描述

name

 

String

参数名

value

 

String

value表达式

id

 

Object/String

用来标识元素的id。在ui和表单中为HTMLid属性

set

描述:set标签赋予变量一个特定范围内的值。当希望给一个变量赋一个复杂的表达式,每次访问该变量而不是复杂的表达式时用到。其在两种情况下非常有用:复杂的表达式很耗时(性能提升)或者很难理解(代码的可读性提高)

参数:

名称

必需

默认

类型

描述

name

 

String

变量名字

scope

 

String

变量作用域,可以为application,session,request,page,action

value

 

Object/String

将会赋给变量的值

id

 

Object/String

用来标识元素的id。在ui和表单中为HTMLid属性

Text

描述:支持国际化信息的标签。国际化信息必须放在一个和当前action同名的resource bundle中,如果没有找到相应message,tagbody将被当作默认的message,如果没有tag bodymessagename会被作为默认message.

名称

必需

默认

类型

描述

name

 

String

资源属性的名字

id

 

Object/String

用来标识元素的id。在ui和表单中为HTMLid属性

url

描述:该标签用于创建url,可以通过”param”标签提供request参数。

includeParams的值是allgetparam标签中定义的参数将有优先权,也就是说其会覆盖其他同名参数的值。

UI标志

单行文本框

Textfield标签输出一个HTML单行文本输入控件,等价于HTML代码<inputtype=”text”>

名称

必需

默认

类型

描述

maxlength

Integer

文本输入控件可以输入字符的最大长度

readonly

false

Boolean

当该属性为true时,不能输入

size

Integer

指定可视尺寸

id

 

Object/String

用来标识元素的id。在ui和表单中为HTMLid属性

例子:

<s:formaction="register" method="post">

  <s:textfield name="username" label="用户名"></s:textfield>

</s:form>

文本框区

Textarea标签输出一个HTML多行文本输入控件,等价于HTML代码:<textarea/>

名称

必需

默认

类型

描述

cols

Integer

列数

rows

Integer

行数

readonly

false

Boolean

当该属性为true时,不能输入

wrap

false

Boolean

指定多行文本输入控件是否应该换行

id

 

Object/String

用来标识元素的id。在ui和表单中为HTMLid属性

例子:

<s:textareaname="personal"cols="10"rows="5"label="个人简历"></s:textarea>

下拉列表

s:select标签输出一个下拉列表框,相当于HTML代码中的<select/>

名称

必需

默认

类型

描述

list

Cellection Map Enumeration Iterator array

要迭代的集合,使用集合中的元素来设置各个选项,如果list的属性为MapMapkey成为选项的valueMapvalue会成为选项的内容

listKey

String

指定集合对象中的哪个属性作为选项的value

listValue

String

指定集合对象中的哪个属性作为选项的内容

headerKey

String

设置当用户选择了header选项时,提交的的value,如果使用该属性,不能为该属性设置空值

headerValue

String

显示在页面中header选项内容

emptyOption

false

Boolean

是否在header选项后面添加一个空选项

multiple

false

Boolean

是否多选

size

Integer

显示的选项个数

例子:

%@ pagecontentType="text/html;charset=GBK"%>

<%@ taglibprefix="s"uri="/struts-tags"%>

<h3>使用namelist属性list属性的值是一个列表</h3>

<s:form>

   <s:selectlabel="最高学历"name="education"list="{'高中','大学','硕士','博士'}"/>

</s:form>

<h3>使用namelist属性list属性的值是一个Map</h3>

<s:form>

   <s:selectlabel="最高学历"name="education"list="#{1:'高中',2:'大学',3:'硕士',4:'博士'}"/>

</s:form>

<h3>使用headerKeyheaderValue属性设置header选项</h3>

<s:form>

   <s:selectlabel="最高学历"name="education"list="{'高中','大学','硕士','博士'}"

       headerKey="-1"headerValue="请选择您的学历"/>

</s:form>

<h3>使用emptyOption属性在header选项后添加一个空的选项</h3>

<s:form>

   <s:selectlabel="最高学历"name="education"list="{'高中','大学','硕士','博士'}"

       headerKey="-1"headerValue="请选择您的学历"

       emptyOption="true"/>

</s:form>

<h3>使用multiple属性设置多选</h3>

<s:form>

   <s:selectlabel="最高学历"name="education"list="{'高中','大学','硕士','博士'}"

       headerKey="-1"headerValue="请选择您的学历"

       emptyOption="true"

       multiple="true"/>

</s:form>

<h3>使用size属性设置下拉框可显示的选项个数</h3>

<s:form>

   <s:selectlabel="最高学历"name="education"list="{'高中','大学','硕士','博士'}"

       headerKey="-1"headerValue="请选择您的学历"

       emptyOption="true"

       multiple="true"size="8"/>

</s:form>

<h3>使用listKeylistValue属性利用Action实例的属性property来设置选项的值和选项的内容</h3>

<s:form>

   <s:selectlabel="最高学历"name="education"list="educations"

       listKey="id"listValue="name"/>

</s:form

doubleselect标签

doubleselect标签输出关联的两个HTML列表框产生联动效果。

名称

必需

默认

类型

描述

list

Cellection Map Enumeration Iterator array

要迭代的集合,使用集合中的元素来设置各个选项,如果list的属性为MapMapkey成为选项的valueMapvalue会成为选项的内容

listKey

String

指定集合对象中的哪个属性作为选项的value,该选项只对第一个列表框起作用

listValue

String

指定集合对象中的哪个属性作为选项的内容,该选项只对第一个列表框起作用

headerKey

String

设置当用户选择了header选项时,提交的的value,如果使用该属性,不能为该属性设置空值

headerValue

String

显示在页面中header选项内容

emptyOption

false

Boolean

 

multiple

false

Boolean

是否多选

size

Integer

显示的选项个数,该选项只对第一个列表框起作用

doubleId

String

指定第二个列表框的ID

doubleList

Cellection Map Enumeration Iterator array

要迭代的集合

doubleListKey

String

指定集合对象中的哪个属性作为选项的value,该选项只对第二个列表框起作用

doubleListValue

String

指定集合对象中的哪个属性作为选项的内容,该选项只对第二个列表框起作用

doubleSize

Integer

选项个数

doubleName

String

指定第二个列表框的name映射

doubleValue

Object

第二个列表框的初始选种项

实例:

<s:formname="test">

    <s:doubleselectlabel="请选择所在省市"

      name="province"list="{'四川省','山东省'}"doubleName="city"

      doubleList="top == '四川省' ? {'成都市', '绵阳市'} : {'济南市', '青岛市'}"/>

</s:form>

<s:formaction="doubleselectTag">

    <s:doubleselect

           label="请选择所在省市"

           name="province"

           list="provinces"

           listKey="id"

           listValue="name"

           doubleList="cities"

           doubleListKey="id"

           doubleListValue="name"

           doubleName="city"

           headerKey="-1"

           headerValue="----------请选择 ----------"

           emptyOption="true"/>

</s:form>

复选框

名称

必需

默认

类型

描述

fieldValue

true

String

指定在复选框选中时,实际提交的值

复选框组,对应Action中的集合

名称

必需

默认

类型

描述

list

Cellection Map Enumeration Iterator array

要迭代的集合,使用集合中的元素来设置各个选项,如果list的属性为MapMapkey成为选项的valueMapvalue会成为选项的内容

listKey

String

指定集合对象中的哪个属性作为选项的value

listValue

String

指定集合对象中的哪个属性作为选项的内容

例子:checkboxlistTag.jsp

<%@ pagecontentType="text/html;charset=GBK"%>

<%@ taglibprefix="s"uri="/struts-tags"%>

<s:form>

    <s:checkboxlistname="interest"list="{'足球','篮球','排球','游泳'}"label="兴趣爱好"/>

</s:form>

单击复选框

文件选择组建

file标签输出一个HTML文件选择框。

名称

必需

默认

类型

描述

accept

input

String

HTML accept属性,指出接受文件的MIME类型

按钮

Submit标签输出一个按钮,submit标签和form标签使用可以提供异步表单提交功能。Submit标签可以输出以下三种类型的提交按钮:

Input等价于 HTML代码<inputtype=”submit”>

Image等价于 HTML代码<inputtype="image">

Button<buttontype="submit"></button>

名称

必需

默认

类型

描述

type

input

String

要使用的提交按钮的类型,有效值:input button image

src

String

image类型的提交按钮设置图片地址。该属性对inputbutton类型的提交按钮无效

action

String

指定处理提交请求的action

method

String

指定处理提交请求的action的方法

实例

实例1.<s:submittype="image"method="login"src="images/login.jpg"></s:submit>

页面输出:

<input type="image" alt="Submit" src="images/login.jpg" id="user__login" name="method:login" value="Submit"/>

实例2.<s:submittype="button"action="selectTag"method="login"label="登陆"></s:submit>

页面输出:

<button type="submit" id="user_selectTag_login" name="action:selectTag!login" value="Submit">登陆</button>

Struts2预定义的前缀:

1method  method:login

使用method前缀,来取代action默认的execute()方法的执行。

<s:formaction="user">

   <s:textfieldname="user.username"label="用户名"></s:textfield>

   <s:textfieldname="user.password"label="密码"></s:textfield>

   <s:submitvalue="登陆"name="method:login"></s:submit>

   <s:submitvalue="注册"name="method:register"></s:submit>

</s:form>

注意:1input类型的按钮,不能用label设置按钮上的文本,只能用value

2action前缀

使用action前缀,取代form标签指定的action,导向到另一个action进行处理。

<s:formaction="login">

   <s:textfieldname="user.username"label="用户名"></s:textfield>

   <s:textfieldname="user.password"label="密码"></s:textfield>

   <s:submitvalue="登陆"></s:submit>

   <s:submitvalue="注册"name="action:register"></s:submit>

</s:form>

2redirect前缀

使用redirect前缀请求重定向到其他的url,甚至可以是web英语程序外部的url

<s:formaction="login">

   <s:textfieldname="user.username"label="用户名"></s:textfield>

   <s:textfieldname="user.password"label="密码"></s:textfield>

   <s:submitvalue="登陆"></s:submit>

   <s:submitvalue="搜索"name="redirect:www.google.com"></s:submit>

</s:form>

2redirect-action前缀

使用redirect-action前缀请求重定向到其他的action.

<s:formaction="login">

   <s:textfieldname="user.username"label="用户名"></s:textfield>

   <s:textfieldname="user.password"label="密码"></s:textfield>

   <s:submitvalue="登陆"></s:submit>

   <s:submitvalue="搜索"name="redirect-action:register"></s:submit>

</s:form>

reset标签

reset标签输出一个重置按钮

名称

必需

默认

类型

描述

type

input

String

要使用的重置按钮的内容,inputbutton

<s:resetvalue="重置"></s:reset>

<s:resettype="button"label="重置"></s:reset>

updownselect标签

updownselect标签创建一个带有上下移动的按钮的列表框,可以通过上下移动按钮来调整列表框的选项的位置。

名称

必需

默认

类型

描述

list

Cellection Map Enumeration Iterator array

要迭代的集合,使用集合中的元素来设置各个选项,如果list的属性为MapMapkey成为选项的valueMapvalue会成为选项的内容

listKey

String

指定集合对象中的哪个属性作为选项的value

listValue

String

指定集合对象中的哪个属性作为选项的内容

headerKey

String

设置当用户选择了header选项时,提交的的value,如果使用该属性,不能为该属性设置空值

headerValue

String

显示在页面中header选项内容

emptyOption

false

Boolean

是否在header选项后面添加一个空选项

multiple

false

Boolean

是否多选

size

Integer

显示的选项个数

moveUplabel

 

String

设置向上移动按钮上的文本

moveDownLabel

 

String

设置向下移动按钮上的文本

selectAllLabel

 

String

设置向全部选择按钮上的文本

allowMoveUp

Boolean

设置是否使用向上移动按钮

allowMoveDown

Boolean

设置是否使用向下移动按钮

allowSelectAll

Boolean

设置是否使用全部选择按钮

实例:

<s:form>

<!-- 使用简单集合来生成可上下移动选项的下拉选择框 -->

<s:updownselectname="a"label="请选择您喜欢的图书"labelposition="top"

    moveUpLabel="向上移动"

    list="{'Spring2.0宝典' , '轻量级J2EE企业应用实战' , 'JavaScript: The Definitive Guide'}"/>

   

   

<!-- 使用简单Map对象来生成可上下移动选项的下拉选择框

    且使用emptyOption="true"增加一个空选项-->

<s:updownselectname="b"label="请选择您想选择出版日期"labelposition="top"

    moveDownLabel="向下移动"

    list="#{'Spring2.0宝典':'200610' , '轻量级J2EE企业应用实战':'20074' , '基于J2EEAjax宝典':'20076'}"

    listKey="key"

    emptyOption="true"

    listValue="value"/>

   

<s:beanname="com.zhaosoft.ui.formtag.BookService"id="bs"/>

<!-- 使用集合里放多个JavaBean实例来可上下移动选项的生成下拉选择框-->

<s:updownselectname="c"label="请选择您喜欢的图书的作者"labelposition="top"

    selectAllLabel="全部选择"multiple="true"

    list="#bs.books"

    listKey="author"

    listValue="name"/>

</s:form>

package com.zhaosoft.ui.formtag;

publicclass BookService

{

    public Book[] getBooks()

    {

      returnnew Book[]

      {

          newBook("Spring2.0宝典","zhaosoft"),

          newBook("轻量级J2EE企业应用实战","zhaosoft"),

          newBook("基于J2EEAjax宝典","zhaosoft")

      };

    }

}

optiontransferselect标签

optiontransferselect标签创建一个选项转移列表组建,它由两个<select>标签以及它们之间的用于将选项在两个<select>之间相互移动的按钮组成。表单提交时,将提交两个列表框中选中的选项。

名称

必需

默认

类型

描述

list

Cellection Map Enumeration Iterator array

要迭代的集合,使用集合中的元素来设置各个选项,如果list的属性为MapMapkey成为选项的valueMapvalue会成为选项的内容,该选项只对第一个列表框起作用

listKey

String

指定集合对象中的哪个属性作为选项的value,该选项只对第一个列表框起作用

listValue

String

指定集合对象中的哪个属性作为选项的内容,该选项只对第一个列表框起作用

headerKey

String

设置当用户选择了header选项时,提交的的value,如果使用该属性,不能为该属性设置空值

headerValue

String

显示在页面中header选项内容

multiple

false

Boolean

是否多选

size

Integer

显示的选项个数,该选项只对第一个列表框起作用

doubleId

String

指定第二个列表框的ID

doubleList

Cellection Map Enumeration Iterator array

要迭代的集合,使用集合中的元素来设置各个选项,如果doubleList的属性为MapMapkey成为选项的valueMapvalue会成为选项的内容,该选项只对第二个列表框起作用

doubleListKey

String

指定集合对象中的哪个属性作为选项的value,该选项只对第二个列表框起作用

doubleListValue

String

指定集合对象中的哪个属性作为选项的内容,该选项只对第二个列表框起作用

doubleHeaderKey

String

设置当用户选择了header选项时,提交的的value,如果使用该属性,不能为该属性设置空值

doubleHeaderVale

String

显示在页面中header选项内容

doubleEmptyOption

String

是否在第二列表框的header后面添加一个空选项

doubleMultiple

true

Boolean

是否多选

doubleSize

Integer

选项个数

doubleName

String

指定第二个列表框的name映射

doubleValue

Object

第二个列表框的初始选种项

leftTitle

String

左边列表框的标题

rightTitle

<-

String

右边列表框的标题

addToLeftLable

 

String

 

addToRightLable

 

 

 

 

addAllToLeftLable

 

 

 

 

addAllToRightLable

 

 

 

 

leftUpLabel

 

 

 

 

leftDownLabel

 

 

 

 

rightUpLabel

 

 

 

 

rightDownLabel

 

 

 

 

allowAddToLeft

 

 

 

 

allowAddToright

 

 

 

 

allowAddAllToLeft

 

 

 

 

allowAddAllToRight

 

 

 

 

allowSelectAll

Boolean

设置是否使用全部选择按钮

allowUpdownOnLeft

 

 

 

 

allowUpDownOnRight

 

 

 

 

例子:

<s:head/>

<s:form>

    <s:optiontransferselect

    label="最喜爱的图书"

       name="javaBook"

       list="{'Java Web开发详解》', 'Struts 2深入详解》', 'Java快速入门》'}"

       doubleName="cBook"

       doubleList="{'VC++深入详解》', 'C++ Primer', 'C++程序设计语言》'}"/>

</s:form>

---------------------------

<s:form>

    <s:optiontransferselect

    label="最喜爱的图书"

       name="book1"

       leftTitle="Java图书"

       rightTitle="C/C++图书"

       list="{'Java Web开发详解》', 'Struts 2深入详解》', 'Java快速入门》'}"

       headerKey="-1"

       headerValue="---请选择 ---"

       emptyOption="true"

       doubleName="book2"

       doubleList="{'VC++深入详解》', 'C++ Primer', 'C++程序设计语言》'}"

       doubleHeaderKey="-1"

       doubleHeaderValue="---请选择 ---"

       doubleEmptyOption="true"

       addToLeftLabel="向左移动"

       addToRightLabel="向右移动"

       addAllToLeftLabel="全部左移"

       addAllToRightLabel="全部右移"

       selectAllLabel="全部选择"

       leftUpLabel="向上移动"

       leftDownLabel="向下移动"

       rightUpLabel="向上移动"

       rightDownLabel="向下移动"/>

</s:form>

 

 

 

 

 

 

 

Struts2中的OGNL

本人是一个ELExpression Language,以下译为表达式语言)的支持者。因为我对<% %>写法极为反感,忘记了在那本书上看到的一句话——“使用标志(Tag)的一个目的就是避免在JSP页面中出现过多的<%%>的语句,使页面与后台代码分离。

表达式语言主要有以下几大好处:

  1. 避免(MyType) request.getAttribute()myBean.getMyProperty()之类的语句,使页面更简洁;
  2. 支持运算符(如+-*/),比普通的标志具有更高的自由度和更强的功能;
  3. 简单明了地表达代码逻辑,使用代码更可读与便于维护。

Struts 2中的表达式语言

Struts 2支持以下几种表达式语言:

  1. OGNL(Object-Graph Navigation Language),可以方便地操作对象属性的开源表达式语言;
  2. JSTL(JSP Standard Tag Library),JSP 2.0集成的标准的表达式语言;
  3. Groovy,基于Java平台的动态语言,它具有时下比较流行的动态语言(如Python、Ruby和Smarttalk等)的一些起特性;
  4. Velocity,严格来说不是表达式语言,它是一种基于Java的模板匹配引擎,具说其性能要比JSP好。

Struts 2默认的表达式语言是OGNL,原因是它相对其它表达式语言具有下面几大优势:

  1. 支持对象方法调用,如xxx.doSomeSpecial()
  2. 支持类静态的方法调用和值访问,表达式的格式为@[类全名(包括包路径)]@[方法名 |  值名],例如:@java.lang.String@format('foo %s', 'bar')@tutorial.MyConstant@APP_NAME
  3. 支持赋值操作和表达式串联,如price=100, discount=0.8, calculatePrice(),这个表达式会返回80;
  4. 访问OGNL上下文(OGNL context)和ActionContext;
  5. 操作集合对象。

OGNL的用法

OGNL是通常要结合Struts2的标志一起使用,如<s:property value="xx" />等。大家经常遇到的问题是#%$这三个符号的使用。下面我想通过例子讲述这个问题:

首先新建名为Struts2_OGNLWeb工程,配置开发环境。之前很多朋友在使用Struts 2的过程中都遇到乱码问题。当然乱码问题由来已久,而且涉及多方面的知识,所以并非三言两语可以说明白,而且互联网上也已经有很多这方便的文章,大家可以Google一下。不过,如果你在开发的过程,多注意一下,避免乱码问题也不难。乱码多数是由于编码与解码所使用的方式不同造成的,所以我建议大家将编码方式都设为“utf-8”,如<%@  page language="java"contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>。另外,在配置web.xml时使用ActionContextCleanUp过滤器(Filter),如下面代码所示:

<?xml version="1.0"encoding="UTF-8"?>
<web-app id="WebApp_9"version="2.4"
    xmlns
="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation
="http://java.sun.com/xml/ns/j2eehttp://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

   
<display-name>Struts 2 OGNL</display-name>
    
   
<filter>
       
<filter-name>struts-cleanup</filter-name>
       
<filter-class>
           org.apache.struts2.dispatcher.ActionContextCleanUp
       
</filter-class>
   
</filter>
    
   
<filter-mapping>
       
<filter-name>struts-cleanup</filter-name>
       
<url-pattern>/*</url-pattern>
   
</filter-mapping>
    
   
<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>/*</url-pattern>
   
</filter-mapping>

   
<welcome-file-list>
       
<welcome-file>index.html</welcome-file>
   
</welcome-file-list>

</web-app>

清单1 WebContent/WEB-INF/web.xml

“#”主要有三种用途:

  1. 访问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属性,直到找到为止

  1. 用于过滤和投影(projecting)集合,如books.{?#this.price<100}
  2. 构造Map,如#{'foo1':'bar1', 'foo2':'bar2'}

下面让我们它们的具体写法,首先是Action类代码:

package tutorial.action;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;

import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.interceptor.SessionAware;
import org.apache.struts2.util.ServletContextAware;

import tutorial.model.Book;

import com.opensymphony.xwork2.ActionSupport;

publicclass OgnlActionextends ActionSupportimplements ServletRequestAware, SessionAware, ServletContextAware  {
   
privatestaticfinallong serialVersionUID = 1L;
   
   
private HttpServletRequest request;
   
private Map<String, String> session;
   
private ServletContext application;
   
private List<Book> books;
           
   
publicvoid setServletRequest(HttpServletRequest request){
       
this.request = request;    
   }

  @SuppressWarnings("unchecked")
   
publicvoid setSession(Map session){
       
this.session = session;       
   }

   
publicvoid setServletContext(ServletContext application){
       
this.application = application;
   }
   
   
public List<Book> getBooks(){
       
return books;
   }

   @Override
   
public String execute(){
      request.setAttribute("userName", "Max From request");
      session.put("userName", "Max From session");
      application.setAttribute("userName", "Max Fromapplication");
       
       books =
new LinkedList<Book>();
       books.add(
new Book("978-0735619678","Code Complete, Second Edition", 32.99));
       books.add(
new Book("978-0596007867","The Art of Project Management", 35.96));
       books.add(
new Book("978-0201633610","Design Patterns: Elements of Reusable Object-Oriented Software",43.19));
       books.add(
new Book("978-0596527341","Information Architecture for the World Wide Web: Designing Large-ScaleWeb Sites", 25.19));
       books.add(
new Book("978-0735605350","Software Estimation: Demystifying the Black Art", 25.19));
       
       
return SUCCESS;
   }
}

清单2 src/tutorial/action/OgnlAction.java

以上代码分别在requestsessionapplication的范围内添加“userName”属性,然后再在JSP页面使用OGNL将其取回。我还创建了Book对象的列表用于演示用于过滤和投影(projecting)集合的功能,至于Book的代码大家可以在我前一文章《Struts 2中实现CRUD》看到。

下面是Ognl.jsp的代码,内容如下:

<%@page language="java" contentType="text/html; charset=utf-8"pageEncoding="utf-8"%>
<%@taglib prefix="s" uri="/struts-tags"%>

<!DOCTYPE html PUBLIC"-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
   
<title>Struts OGNL Demo</title>
</head>
<body>    
   
<h3>访问OGNL上下文和Action上下文</h3>
   
<p>parameters:<s:property value="#parameters.userName"/></p>
   
<p>request.userName:<s:property value="#request.userName"/></p>
   
<p>session.userName:<s:property value="#session.userName"/></p>
   
<p>application.userName:<s:property value="#application.userName"/></p>
   
<p>attr.userName:<s:property value="#attr.userName"/></p>
   
<hr />
   
<h3>用于过滤和投影(projecting)集合</h3>
   
<p>Books more than $35</p>
   
<ul>
       
<s:iteratorvalue="books.{?#this.price> 35}">
           
<li><s:propertyvalue="title"/> - $<s:propertyvalue="price"/></li>
       
</s:iterator>
   
</ul>
   
<p>The price of "Code Complete, SecondEdition" is:<s:propertyvalue="books.{?#this.title=='CodeComplete, Second Edition'}.{price}[0]"/></p>
   
<hr />
   
<h3>构造Map</h3>
   
<s:set name="foobar" value="#{'foo1':'bar1','foo2':'bar2'}"/>
   
<p>The value of key "foo1" is<s:property value="#foobar['foo1']"/></p>
</body>
</html>

清单3 WebContent/Ognl.jsp

以上代码值得注意的是<s:property value="books.{?#this.title=='Code Complete,Second Edition'}.{price}[0]"/>,因为books.{?#this.title=='Code Complete, Second Edition'}.{price}返回的值是集合类型,所以要用“[索引]”来访问其值。

最后是Struts 2的配置文件struts.xml,内容如下:

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

<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd"
>

<struts>
   
<constant name="struts.devMode" value="true"/>
   
<package name="Struts2_OGNL_DEMO" extends="struts-default">
       
<actionname="Ognl" class="tutorial.action.OgnlAction">
           
<result>/Ognl.jsp</result>
       
</action>        
   
</package>
</struts>

清单4 src/struts.xml

发布运行应用程序,结果如下所示:


清单5 示例运行结果1

“%”符号的用途是在标志的属性为字符串类型时,计算OGNL表达式的值。例如在Ognl.jsp中加入以下代码:

<hr/>
   
<h3>%的用途</h3>
   
<p><s:urlvalue="#foobar['foo1']"/></p>
   
<p><s:urlvalue="%{#foobar['foo1']}"/></p>

清单6演示%用途的代码片段

刷新页面,结果如下所示:

清单7示例运行结果2

“$”有两个主要的用途

  1. 用于在国际化资源文件中,引用OGNL表达式,例子请参考《在Struts 2.0中国际化(i18n)您的应用程序》
  2. 在Struts 2配置文件中,引用OGNL表达式,如

<actionname="AddPhoto" class="addPhoto">
           
<interceptor-refname="fileUploadStack"/>           
           
<resulttype="redirect">ListPhotos.action?albumId=${albumId}</result>
       
</action>

清单8演示$用途的代码片段

总结

OGNL是一种功能很大的表达式语言,熟悉它可以使我们的开发变得更快捷。

 

 

原创粉丝点击