在一个struts项目中,碰到这么一个问题:

用户的登录页面地址是:

http://localhost:8080/sduprs/user/user_login.jsp

登录后显示的地址为:

http://localhost:8080/sduprs/userLogin.do

更悲剧的是我们在后台使用了frame框架。这样登录后所有的操作地址都显示为上面的那个地址。大师兄不满意,要求修改为实际地址。在网上查了半天资料,发现是url转发问题,具体点就是ActionForward的问题。下面是关于ActionForward的资料:

(1)ActionForward是Struts的核心类之一,其基类仅有4个属性:name / path / redirect / classname。在基于Struts的Web应用程序开发过程中,Action操作完毕后程序会通过Struts的配置文件struts- config.xml链接到指定的ActionForward,传到Struts的核心类ActionServlet,ActionServlet使用 ActionForward提供的路径,将控制传递给下一个步骤。ActionForward控制接下来程序的走向。ActionForward代表一个 应用的URI,它包括路径和参数。
(2)ActionForward的参数除了在struts-config.xml和页面中设置外,还可以通过在Action类中添加参数,或重新在 Action中创建一个ActionForward。
(3)在ActionForward中有一个重要的属性redirect,当redirect=false时,将保存存储在http请求和请求上下文中 的所有内容,仅在同一个应用中可用。当redirect=true时,Web客户端进行一次新的http请求,请求的资源可以在同一个应用中,也可以不 在,原来的请求参数不再保存,原来的请求上下文也被清除,新的http请求仅包含ActionForward的path属性里所包含的参数。如果在同一个 应用中,用户会话的上下文会被维护。
(4)ActionForward分为全局转发和局部转发,Action的Mapping对象的findForward方法首先会检查局部转发列表,查 找失败就会到全局转发列表中查找。书写格式中,我们一般将全局变量定义为String常数,避免误解,使得转发列表结构清晰易读。

实际上,struts有两种定向方式:转发和重定向(redirect)。当我们用了重定向的时候,是把页面完全转向到请求的视图去了。同时,浏览器上边的url也更新了。这样的优点是请求完全转移,缺点是无法用request.setAttribute传递参数值;当我们使用转发的时候,是将本次请求的request传递给了要定向的jsp或者servlet。同时执行被请求的jsp或 servlet,结果显示出来。但是,浏览器上看到的依然是发出请求的url,而不是结果的url,这种方式的优点:可以向被请求的jsp或 servlet传递值request.setAttribute,缺点是url依然是请求的url,不是结果的url,刷新的话,将再次执行该请求。

根据上面的介绍我发现使用redirect必须谨慎。仔细排查了下处理登录页面的action,发现只是向session写入了user变量,并没有使用request.setAttribute传参。因此就把struts-config.xml里ActionForward的redirect属性设置为了true:

<forward name=”userLoginSuccess” path=”/user/main.jsp” redirect=”true”/>

这样我遇到的问题就解决了。

首先说下Struts中的<html:reset>标签,对应于html中的<input type=”button” />。虽然都是重置按钮,但是它们的功能是不一样的,更确切的说是效果是不一样的。html中的重置按钮很简单,就是将form中的文本框、选择框中的内容清空,当然你也可以自己定义点击事件。

Struts中的<html:reset>标签是将form中的元素重置为当前值。什么是当前值?这里就要用到面向对象的思想了。每个jsp中的form是对应于后台的一个form类(应该是该类的一个对象),这在Struts的配置文件中已经写明了。如果用对象的观点去理解当前值,就很容易了。比如User类的对象myuser有name属性,当前赋值是“张三”,你想把它修改成“李四”,输入“李四“之后你点击了reset而不是submit,那么jsp表单中对应显示会变成”张三“。form被重置为当前值,而不是默认值,即类实例化为对象时的值,说白了就是代码中的默认值。所以具体用那个重置按钮应该根据实际情况决定。

再说下Struts中的<html:>标签捕获问题。一般我们使用Struts的html标签时只有property和value属性,这里的property属性即对应于普通html中的name属性,可以使用document.getElementsByName()获得。但是这个方法返回的是数组,如果想使用document.getElementById(),就必须给Struts中的<html:>标签天添加styleId属性,例如:

<html:password styleId=”password” property=”password”  />

这样我们就可以使用document.getElementById(“password”)获得这个元素,然后对value进行赋值。

Struts的LOGIC标签库

Posted by 冰河 at 19:37 3 Responses » 24,734 Views
122010

1.  logic:empty

该标签是用来判断是否为空的。如果为空,该标签体中嵌入的内容就会被处理。该标签用于以下情况:

1)当Java对象为null时;

2)当String对象为”"时;

3)当java.util.Collection对象中的isEmpty()返回true时;

4)当java.util.Map对象中的isEmpty()返回true时。
eg.
<logic:empty   name=”userList”>

</logic:empty>
该句等同于:
if   (userList.isEmpty())   {

}

2.  logic:notEmpty
该标签的应用正好和logic:empty标签相反,略。
3. logic:equal
该标签为等于比较符。
eg1. 比较用户的状态属性是否1,若为1,输出”启用”;
<logic:equal   name=”user”   property=”state”   value=”1″>
启用
</logic:equal>
eg2. 如果上例中的value值是动态获得的,例如需要通过bean:write输出,因struts不支持标签嵌套,可采用EL来解决该问题。
<logic:equal   name=”charge”   property=”num”   value=”${business.num}”>
……
</logic:equal>

4. logic:notEqual
该标签意义 与logic:equal相反,使用方法类似,略。
5. logic:forward
该标签用于实现页面导向,查找配置文件的全局forward。
eg. <logic:forward name=”index”/>
6. logic:greaterEqual
为大于等于比较符。
eg. 当某学生的成绩大于等于90时,输出“优秀”:
<logic:greaterEqual name=”student” property=”score” value=”90″>
优 秀
</logic:greaterEqual>
7. logic:greaterThan
此为大于比较符,使用方法同logic:greaterEqual,略;
8. logic:lessEqual
此为小于等于比较符,使用方法同logic:greaterEqual,略;
9. logic:lessThan
此为小于比较符,使用方法同 logic:greaterEqual,略;
10. logic:match
此 标签比较对象是否相等;
eg1. 检查在request范围内的name属性是否包含”amigo”串:
<logic:match name=”name” scope=”request” value=”amigo”>
<bean:write name=”name”/>中有一个“amigo”串。
</logic:match>
eg2. 检查在request范围内的name属性是否已“amigo”作为起始字符串:
<logic:match name=”name” scope=”request” value=”amigo” location=”start”>
<bean:write name=”name”/>以“amigo”作为起始字符串。
</logic:match>
eg3.
<logic:match header=”user-agent” value=”Windows”>
你运行的是Windows系统
</logic:match>
11.  logic:notMatch

此标签用于比较对象是否不相同,与logic:match意义相反,使用方法类似,略。
12. logic:messagePresent
该标签用于判断ActionMessages/ActionErrors对象是否存在;
eg. 如果存在error信息,将其全部输出:
<logic:messagePresent property=”error”>
<html:messages property=”error” id=”errMsg” >
<bean:write name=”errMsg”/>
</html:messages>
</logic:messagePresent >
13. logic:messagesNotPresent
该标签用于判断ActionMessages/ActionErrors对象是否不存在,使用方法与logic:messagePresent类似,略
14. logic:present
此标签用于判断request对象传递参数是否存在。
eg1. user对象和它的name属性在request中都存在时,输出相应字符串:
<logic:present name=”user” property=”name”>
user对象和该对象的name属性都 存在
</logic:present>
eg2. 若有一个名字为“user”的JavaBean,输出对应字符串:
<logic:present name=”user” >
有一个名字为“user”的JavaBean。
</logic:present>
eg3.
<logic:present header=”user-agent”>
we got a user-agent header.
</logic:present>
15. logic:notPresent
此标签用于判断request对象传递参数是否不存在,意义与了logic:present相反,使用方法类似,略。
16. logic:redirect
该标签用于实现页面转向,可传递参数。
eg1. <logic:redirect href=”http://www.abc.com”/>

17. logic:iterator
用于显示列表为collection的值(List ,ArrayList,HashMap等)。
eg1. 逐一输出用户列表(userlList)中用户的姓名:
<logic:iterate  id=”user” name=”userList”>
<bean:write name=”user” property=”name”/><br>
</logic:iterate>
eg2. 从用户列表中输出从1开始的两个用户的姓名
<logic:iterate  id=”user” name=”userList” indexId=”index”  offset=”1″ length=”2″>
<bean:write name=”index”/>.<bean:write name=”user” property=”name”/><br>
</logic:iterate>
eg3. logic:iterator标签的嵌套举例
<logic:iterate id=”user” indexId=”index” name=”userList”>
<bean:write name=”index”/>. <bean:write name=”user” property=”name”/><br>
<logic:iterate id=”address” name=”user” property=”addressList” length=”3″ offset=”1″>
<bean:write name=”address”/><br>
</logic:iterate>
</logic:iterate>

282010

1,使用Spring 的 ActionSupport 。
2,使用Spring 的 DelegatingRequestProcessor 类。
3,全权委托。

无论用那种方法来整合第一步就是要为struts来装载spring的应用环境。 就是在 struts 中加入一个插件。
struts- config.xml中

<plug-in className=”org.springframework.web.struts.ContextLoaderPlugIn”>
<set-property property=”contextConfigLocation” value=”/WEB-INF/applicationContext.xml“/>
</plug-in>
spring 的配置文件被作为参数配置进来。这样可以省略对web.xml 文件中的配置。确 保你的applicationContext.xml 在WEB-INF目录下面

1,使用Spring的ActionSupport .
Spring 的ActionSupport 继承至 org.apache.struts.action.Action
ActionSupport的子类可以或得 WebApplicationContext类型的全局变量。通过getWebApplicationContext()可以获得这个变量。

这是一个 servlet 的代码:
public class LoginAction extends org.springframework.web.struts.ActionSupport {

public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
LoginForm loginForm = (LoginForm) form;// TODO Auto-generated method stub
//获得 WebApplicationContext 对象
WebApplicationContext ctx = this.getWebApplicationContext();

LoginDao dao = (LoginDao) ctx.getBean(“loginDao”);
User u = new User();

u.setName(loginForm.getName());
u.setPwd(loginForm.getPwd());

if(dao.checkLogin(u)){
return mapping.findForward(“success”);
}else{
return mapping.findForward(“error”);
}

}
}

applicationContext.xml 中的配置
<beans>
<bean id=”loginDao” class=”com.cao.dao.LoginDao”/>
</beans>

这中配置方式同直接在web.xml文件配置差别不大。注意:Action继承自 org.springframework.web.struts.ActionSupport 使得struts和spring耦合在一起。
但实 现了表示层和业务逻辑层的解耦(LoginDao dao = (LoginDao) ctx.getBean(“loginDao”))。
2,使用Spring 的 DelegatingRequestProcessor 类
DelegatingRequestProcessor 继承自 org.apache.struts.action.RequestProcessor 并覆盖了里面的方法。
sturts-config.xml 中 <controller processorClass=”org.springframework.web.struts.DelegatingRequestProcessor”/> 通过 <controller >来替代
org.apache.struts.action.RequestProcessor 的请求处理。

public class LoginAction extends Action {
// 利用spring来注入这个对象。
private LoginDao dao ;

public void setDao(LoginDao dao) {
System.out.println(“执行注入”);
this.dao = dao;
}

public LoginDao getDao() {
return dao;
}

public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
LoginForm loginForm = (LoginForm) form;// TODO Auto-generated method stub
//这样一改这行代码没有必要了。
//WebApplicationContext ctx = this.getWebApplicationContext();
//LoginDao dao = (LoginDao) ctx.getBean(“loginDao”);

User u = new User();

u.setName(loginForm.getName());
u.setPwd(loginForm.getPwd());

//直接用dao来调用spring会将这个对象实例化。
if(dao.checkLogin(u)){
return mapping.findForward(“success”);
}else{
return mapping.findForward(“error”);
}

}
}
这 里的。
LoginAction extends Action 说明 struts 每有和spring 耦合。
看一下
applicationContext.xml 中的配置。
<beans>
<bean id=”loginDao” class=”com.cao.dao.LoginDao”/>

<bean name=”/login” class=”com.cao.struts.action.LoginAction”>
<property name=”dao”>
<ref local=”loginDao”/>
</property>
</bean>
</beans>

这里 name=”/login” 与struts 中的path匹配
class=”com.cao.struts.action.LoginAction” 与struts 中的type匹配

还要为 LoginAction 提供必要的setXXX方法。 获得ApplicationCotext和依赖注入的工作都在DelegatingRequestProcessor中完成。
3,全权委托:
Action 的创建和对象的依赖注入全部由IOC容器来完成。 使用Spring的DelegatingAcionProxy来帮助实现代理的工作
org.springframework.web.struts.DelegatingActiongProxy 继承于org.apache.struts.action.Action .
全权委托的配置方式同 方式 2 类似 (applcationContext.xml文件的配置和 Action类的实现方式相同)。
<struts-config>
<data-sources />
<form-beans >
<form-bean name=”loginForm” type=”com.cao.struts.form.LoginForm” />

</form-beans>

<global-exceptions />
<global-forwards />
<action-mappings >
<!– type指向的是spring 的代理类 –>
<action
attribute=”loginForm”
input=”login.jsp”
name=”loginForm”
path=”/login”
scope=”request”

type=”org.springframework.web.struts.DelegatingActionProxy” >

<forward name=”success” path=”/ok.jsp” />
<forward name=”error” path=”/error.jsp” />
</action>

</action-mappings>
<message-resources parameter=”com.cao.struts.ApplicationResources” />

<plug-in className=”org.springframework.web.struts.ContextLoaderPlugIn”>
<set-property property=”contextConfigLocation” value=”/WEB-INF/applicationContext.xml”/>
</plug-in>

</struts-config>
不同之处
1, <action>中 type指向的是spring 的代理类

2, 去掉struts-config.xml中 <controller >

三种整和方式中我们优先选用 全权委托的方式。
理由:
1,第一种使得过多的耦合了Spring和Action .
2,RequestProcessor 类已经被代理 如果要再实现自己的实现方式(如:编码处理)怕有点麻烦。

总结一下:
整合工作中的步骤:
1,修改struts-config.xml
2, 配置applicationContext.xml
3, 为Action添加get/set方法 来获得依赖注入的功能

异常代码:

org.hibernate.exception.GenericJDBCException: could not insert: [com.huama.equma.entity.DicPackage]
java.sql.DataTruncation: Data truncation
java.sql.SQLException: 将截断字符串或二进制数据org.hibernate.exception.GenericJDBCException: could not insert: [com.yp.Person]
at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:103)
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:91)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2272)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2665)
at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:60)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:167)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
at com.yp.db.PersistenceService.save(PersistenceService.java:191)
at com.yp.action.PersonAction.personAdd(PersonAction.java:216)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.apache.struts.actions.DispatchAction.dispatchMethod(DispatchAction.java:274)
at org.apache.struts.actions.DispatchAction.execute(DispatchAction.java:194)
at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:419)
at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:224)
at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1194)
at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:432)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at com.yp.db.Filter.doFilter(PersistenceFilter.java:46)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at com.yp.util.Filter.doFilter(EncodingFilter.java:45)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:845)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
at java.lang.Thread.run(Thread.java:595)
Caused by: java.sql.DataTruncation: Data truncation
at net.sourceforge.jtds.jdbc.SQLDiagnostic.addDiagnostic(SQLDiagnostic.java:378)
at net.sourceforge.jtds.jdbc.TdsCore.tdsErrorToken(TdsCore.java:2778)
at net.sourceforge.jtds.jdbc.TdsCore.nextToken(TdsCore.java:2214)
at net.sourceforge.jtds.jdbc.TdsCore.getMoreResults(TdsCore.java:597)
at net.sourceforge.jtds.jdbc.JtdsStatement.processResults(JtdsStatement.java:465)
at net.sourceforge.jtds.jdbc.JtdsStatement.executeSQL(JtdsStatement.java:427)
at net.sourceforge.jtds.jdbc.JtdsPreparedStatement.executeUpdate(JtdsPreparedStatement.java:397)
at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(NewProxyPreparedStatement.java:105)
at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:23)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2252)
… 45 more

出错分析:在jdbc插入数据时,当数据库表中某列设置的长度小于要插入的字符的实际长度时就会抛出此异常。

如:数据表中某列char [4],长度为4,插入:”string”时,字符”string”长度超过4,抛出异常。据超过了字段的限制导致截断

解决方法:在.hbm配置文件中把String长度设置大一些,默认是255

Struts的HTML标记库

Posted by 冰河 at 18:56 No Responses » 19,457 Views
282010
<html:html>
<html:html>标记可以说是Struts所 有标记中最简单的了。它简单的在页面开始处和结尾处产生一个的标记。在 Struts1.1以前的 版本中,该标记有一个locale属性。如下所示:
<html:html locale=”true”>
该 属性的作用是读取用户session中的locale属 性并显示出来。比如用户使用的是zh-CN,那么,生成的页面代码将如下所示:
<html locale=”zh-CN”>
不过,从Struts1.2开始,该属性被lang所取代。原 因是locale属性当其值为true时, 会读取session中的locale信 息。但是当HttpSession不存在时,它会强制创建一个新的session并将HTTP请求中的locale信息放入session中去。这种方式 时显并不合理,因此,从Struts1.2开始,locale属 性被lang属性所取代
<html:html lang=”true”>
当 使用lang属性后,若没有session对 象时,就根据Http请求中的locale信 息来输出相应的语言信息。
<html:base>
<html:base>用于在网页的head部 分生成一个base标记。它的用法很简单,只需在head部 分加入如下标记就可以了
<html:base/>
当经过Web容器编译后,会生成如下的一段标记。
<base href=”http://localhost:8080/taglib1/html-base.jsp”>
这也就是本网页的实际的URL地 址。请记住,base标记将不会被显式的显示在网页上,只有通过查看生成的 html源代码才可以看得见。其实,base标记的含义 不仅是生成本网页的URL,它更重要的功能是为该页面内的所有其它链接提供相对的位置。例如,在本 网页使用了<html:base>标记后,生成了如上的URL地址。倘若此时需要指定一张图片,只须使用相对的位置链接就可以了。假设在 taglib1的根目录下有一个image目录,里面 有一张叫image.gif的图片,则引用的代码如下所示:
<img src=”image/image.gif”>
这 张图片的实际URL就是:
http://localhost:8080/taglib1/image/image.gif
<html:link>
<html:link>标记是用来生成HTML中 的<a>标记的,它带有多种参数,可以和Struts框 架结合生成多种不 同形式的链接。
1.外部完整URL链接
<html:link>标 记最简单的用法就是直接链到一个外部的完整URL链接,比如用户需要创建一个到新浪网的链接。可以 使用 href属性,代码如下:
<html:link href=”http://www.sina.com.cn”>
新浪网
</html:link>
以上代码经编译后会生成如下html代 码:
<a href=”http://www.sina.com.cn”>新浪网</a>
2.相对URL链接
当需要从同一个应用中的某个网页链接到另一个网页时,可以使用page属性,代码如下:
<html:link page=”/index.jsp”>
首页
</html:link>
当 需要向所链接的页面传输某些参数时,可以将参数直接加在请求的尾部就可以了。例如,下面的代码示例将向测试页面传递一个字符串参数和一个整型参 数:
<html:link page=”/test.do?testString=a+new+string&testInt=10000″>
测试页面
</html:link>
由它生成的页面html代 码如下所示:
<a href=”/taglib1/test.do?testString=a+new+string&testInt=10000″>
试页面
</a>
下面的链接是一个测试,它向测试页面传递两个参数,一个是testString,它的值为”a new string”, 另一个是testInt,它的值为10000。
3.全局转发URL链接
在Struts的struts-config.xml文 件中定义了<global-forward>全局转发变量,可以通 过<html:link> 来链接到这种全局转发的URL链 接,使用forward属性,示例代码如下所示:
<html:link forward=”index”>
回到主页
</html:link>
生 成的页面html代码如下所示:
<a href=”/taglib1/index.jsp”>
回到主页
</a>
4.带有页面变量的URL链接
在创建链接时常常需要访问一些页面的变量,将它们的值作为参数传递给将 要链到的网页。<html:link>标记也提供了这样的功能。
如果仅需传递单个参数,可以使用paramID与paramName这两个属性。以下为代码示例
<%
String test1 = “testABC”;
request.setAttribute(“stringtest”,test1);
%>
<html:link page=”/test.do” paramId=”testString” paramName=”stringtest”>
试页面
</html:link>
在 这段程序中,首先定义一个变量为test1它的值为testABC。 然后将它存入request对象中,命名为stringtest。 接着,使 用<html:link>标记的paramName属 性指定欲从内建对象中读取值的变量名,此处也就是stringtest。然后,使用 paramId属性指定传值的目标参数,此处为testString。 点击下面的链接可以通过测试页面查看运行效果:
如果需要传递 的参数有多个,则可使用<html:link>标记的name属性来实现,name属性的值是一个 java.util.HashMap类型的对象名称,它的每一个”键/值”对就代表一对的”参数名/参数值”, 以下为代码示例:
<%
HashMap para_map = new HashMap();
para_map.put(“testString”,”testABC”);
para_map.put(“testInt”,new Integer(10000));
request.setAttribute(“map1″,para_map);
%>
<html:link page=”/test.do” name=”map1″>
测试页面</html:link>
在 上面的代码中,首先在页面上声明一个HashMap类型的变量para_map用来存储将要传递的参数,接着,向 para_map中 存入两个对象。然后再将该对象存入页面的request对象中。使用<html:link>标记的name属性 来将参数带 入目标页面中。实际生成的html代码如下所示:
<a href=”/taglib1/test.do?testString=testABC&testInt=10000″>测试页面< /a>
<html:rewrite>
<html:rewrite>标记是用来输出链接中的URI的。 所谓URI就是指一个完整URL地址去掉协 议,主机地址和端口号以后的 部分。它的众多属性都和<html:link>一样,只 是它输出的仅是一个URI字符串,而非链接。示例代码如下:
<html:rewrite page=”/test.do?testString=testABC”/>
它 生成的html如下:
/struts/test.do?testString=testABC
可以看出,它输出的内容只是实际URL中除去协议,主机地址和端口号以后的部分。实际的URL应 为:
http://localhost:8080/taglib1/test.do?testString=testABC
它也可以使用paramId和paramName等属性,如下面的例 子:
<%
String str = “testABC”;
request.setAttribute(“test1″,str);
%>
<html:rewrite page=”/test.do” paramId=”testString” paramName=”test1″ />
实际生成的html代码如下所示:
/struts/test.do?testString=testABC
下面的例子将演示当有多个参数要传递时<html:rewrite>生成的URI样 式。它与<html:link> 一样,都使用name属 性来传递多个参数。
<%
HashMap para_map = new HashMap();
para_map.put(“testString”,”testABC”);
para_map.put(“testInt”,new Integer(10000));
request.setAttribute(“map1″,para_map);
%>
<html:rewrite page=”/test.do” name=”map1″/>
实 际生成的html代码如下所示:
/struts/test.do?testString=testABC&testInt=10000
这里有一点需要注意的,当从网页源代码上看 生成的多参数链接时,在多个参数间连接符并不是简单的& 而是一个&amp;,在html代码中它就代表&。
<html:img>
<html:img>标记是用来显示图片的,它的用法很简单,如下所示:
<html:img page=”/a.jpg”/>
此处值得注意的一点是,在page属 性后图片的路径并没有因为设定了<html:base>而使用了相对路径,而是依然使 用了绝对路 径。如果使用非Struts的<img src=”a.jpg”>标记则可以正确显示图片。
<html:form>
<html:form>标记生成页面表单,这个由Struts标 记生成的表单和普通的HTML表单略有不同。普通的表单用法如下所示:
<form method=”post” action=”/loginServlet”>
<input type=”text” name=”username”>
<input type=”text” name=”username”>
</form>
可以看到,在普通的form标 记后的action属性的值是一个Servlet(当 然也可以是一个JSP文件),而使用 了<html:form> 标记后,代码则变成了下面的样子:
<html:form action=”/test.do”>
其 中action属性后跟的是一个在struts-config.xml文 件中定义的Action,而这个Action也 必定要对应一个 ActionForm才能完成其应有的功能。所以,对每个<html:form>标记来说,都该对应一个ActionForm。 而这个 ActionForm中的属性值也将和网页上的<html:form>表 单中的各个表单项相对应。这些表单相将会是类似 于<html:text>的一些表单 元素。下面有一段示例代码:
<html:form action=”/test.do”>
输入字 符串testString:<html:text property=”testString”/>
提 交:<html:submit property=”submit”/>
</html:form>
这 段代码将在页面上显示一个文本框和一个提交按钮,当用户在文本框中输入一个字符串后并点击按钮,将会触发test这 个Action。在初始化这个 JSP页面 时,JSP引擎在初始化<html:form>标 记时将会初始化test这个Action所 对应的ActionForm,当用户提 交表单时,表单项中的testString刚好对应ActionForm中的 这一项(只需名称相同)。
此处值得注意的一点是,在<html:form>表 单中的各个表单项一定要在ActionForm可以找到一个对应的项,这样才能在提 交的时候进行赋值,否则,Struts将会报一个错,显示无法找到某表单项在ActionForm的对应get方法
<html:text>
<html:text>标记比较简单,是用来在页面上生成一个文本框,该标记通常被用在一个<html:form>中。以 下是一段示例代码:
<html:form action=”/test.do”>
输入字 符串testString:<html:text property=”testString”/>
输入整数 testInt:<html:text property=”testInt”/>
<html:submit property=”submit” value=”submit”/>
</html:form>
通常,<html:text property=”testString”/>语句将生成以下的html代 码:
<input type=”text” name=”testString”>
可以看到,<html:text>标记的property属 性指定了文本框的名称,如果它位于<html:form>表单 内部,那么, property的值若刚好与ActionForm中 的一项对应时,该文本框内的值就将被赋给该ActionForm中的该项。以test这个 Action所对应的ActionForm为例,它其中就有这么一段代码刚好与上面的<html:text>相 对应:
private String testString = null;
public void setTestString(String testString){
this.testString = testString;
}
public String getTestString(){
return testString;
}
从 上面的代码可以看出用户在提交表单后,Struts会自动将property=”testString”的<html:text>文 本框的值赋给 ActionForm中的testString字段。
<html:password>
<html:password>用来在页面上产生一个密码框。所谓密码框其实就是一个文本框,只 不过对它的任何输入都将显示为”*”。 它的用法和<html:text>差 不多,property属性用来表示它的名称。
<html:form action=”/test.do”>
<html:password property=”testString”/>
<html:submit property=”submit” value=”查看测试页面”/>
</html:form>
上面的代码中将一个<html:password>标 记放在一个表单中,这也是必须的,否则Struts框架会报错。以下是上面代码的 运行效果,无论用户输入什么,都只会显示”*”。点击提交钮后,会在测试页面看到用户输入的内容。
<html:textarea>标 记和&html:textarea基本相同,只不过它会产生一个更大的文本输入域。同样 的, 它也需要存在于一个<html:form>表单中,下面是示例代码:
<html:form action=”/test.do”>
<html:textarea property=”testString” rows=”8″/>
<html:submit property=”submit” value=”查看 测试页面”/>
</html:form>
<html:hidden>
<html:hidden>标记用于在网页上生成一个隐藏的字段。众所周知,网页上总有一些信息不 希望被用户看到,但在提交的时候却需 要传递到服务器上以帮助业务逻辑进行处理。在传统的html中, 隐藏字段是用下面的方式表示的:
<input type=”hidden” name=”testString” value=”hiddenString”>
<html:hidden>标 记不需要被限定在一个表单的内部来使用,以下的例子还是将它放在一个表单的内部。当用户点击 “查 看测试页面”的按钮时,会看到测试页面中testString被 赋与了”hiddenString”的值。
在<html:hidden>标记中有一个write属 性,可以决定在页面上是否显示出这个隐藏的值,如下面的代码:
<html:hidden property=”testString” value=”hiddenString” write=”true”/>
运行效果如下所示,虽然只有短短的一个字符串,但可以看出标记还是把testString的value打印出来了。
hiddenString
<html:submit>
<html:submit>标记生成一个提交按钮,用于提交表单。它的用法很简单,如下所示:
<html:submit property=”submit” value=”提 交“/>
它 会生成如下的html代码
<input type=”submit” name=”submit” value=”提交“>
另 外,<html:submit>标记还可以写成如下的形式,它也将生成同样的html代码。
<html:submit> 提交</html:submit>
<html:reset>
<html:reset>标记生成一个复位按钮,用于复位表单内的各项元素。代码如下:
<html:form action=”/test.do”>
<html:text property=”testString”/>
<html:submit property=”submit” value=”Submit”/>
<html:reset property=”reset” value=”reset”/>
</html:form>

<html:cancel>
<html:cancel> 标记将在网页上生成一个取 消按钮,用户可以通过点击它触发一个取消事件。这个取消事件通常是在用户已经点击了提交按钮后,又临时想取消这次提交 时生成的。因此,取消按钮并不只是简单的页面效果,而要深入后台,其实也就是调用一个Action来对用户的提交进行处理,做一些清除的工作。<html:cancel>按钮要使用 在一个表单内部,可以用以下两种方式来使用该标记:
<html:cancel>Cancel</html:cancel>

<html:cancel property=”org.apache.struts.taglib.html.CANCEL” value=”Cancel”/><br>

上面的代码生成的 html代码如 下所示:
<input type=”submit” name=”org.apache.struts.taglib.html.CANCEL” value=”Cancel” onclick=”bCancel=true;”>
可以看到,在生成的 html标记最后有一个onclick=”bCancel=true;”, 这个onclick动作是在用户点击取消按钮时发生的,其实也就是运行一个 javascript脚本,它给一个名为bCancel的变量赋值为true。为什么要这样呢?先看看以下代码,这是一 段在用户点击cancel后执行的程序,其实它就是位于和提交表单后所执行的相同的Action内。 因为cancel动作和submit动作在 生成html代码后的类型都是一样的,都“submit”。这一点从上面的介绍中可以看到。
……
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception{
…..
if (isCancelled(request)){
return mapping.findForward(“cancelled”);
}
……
}
这其中有一个 isCancelled(),该函数的作用就是从request对象中取出bCancel变量,并且判断其是否为真,若为真则转发到相应的Action处理,则不为真,则说明是普通的提交动作,继续下面的代 码。这个isCancelled()方法被定义在Action 类中,其代码如下:
protected boolean isCancelled(HttpServletRequest request) {
return (request.getAttribute(Globals.CANCEL_KEY) != null);
}
这个 Globals.CANCEL_KEY的值就是cancel按钮的name属性,也就 是 org.apache.struts.taglib.html.CANCEL
<html:checkbox>
<html:checkbox> 生成网页上的选择框,它必须存在于一个表单范围内,因此也就说明在ActionForm必须使用一个字段来接收从表单传过来的值。一般情况下,在 ActionForm中都使用布尔型变量来表示一个checkbox,这是因为它要么没被选中,要么就是被选中。以下是一段示例代码:
<html:form action=”/test.do”>
checkbox1:<html:checkbox property=”checkbox1″/>
checkbox2:<html:checkbox property=”checkbox2″/>
<html:submit property=”submit” value=”
测试“/> </html:form>
这样一段代码生成的html如下所示:
<form name=”testbean2″ method=”post” action=”/taglib1/test.do”>
checkbox1:<input type=”checkbox” name=”checkbox1″ value=”on”>
checkbox2:<input type=”checkbox” name=”checkbox2″ value=”on”>
<input type=”submit” name=”submit” value=”
测试“>
</form>
可以看到,checkboxvalueon,这一点需要特别注意。当某 个checkbox被选中时,使用checked属性 来表示,代码如下:
<input type=”checkbox” name=”checkbox1″ value=”on” checked=”checked”>
另外,有一点需要特别注意。为了让checkbox能够正确的显示,应当在ActionFormreset()方法中对其进行复 位。也就是在 ActionFormreset()方法中加入如下代码:
public void reset(ActionMapping mapping, HttpServletRequest request){
this.checkbox1 = false;
this.checkbox2 = false;
}
如果不checkbox进行复位,那么一个checkbox一旦被选中,就会永远处于被选中的状态。发生这种情况的原因是,在html中浏览器不会向Web务器发送一个类似于某某选择框没有被选中这样的信息,因此,当一个checkbox被选中后,即便下一次用户将它的勾去掉,Web服务器端也将 认为它是被选中的。
运行效果如下所示:
checkbox1:

checkbox2:

<html:multibox>
<html:multibox> 标签生成网页上的复选框,其实它的功能和<html:checkbox>一样,所不同的是,在此复选框所在的ActionForm中使用一个数组来表示该复选框。先看看以下网页代码:
<html:form action=”/test.do”> <html:multibox property=”testStringArray” value=”China”/>中国
<html:multibox property=”testStringArray” value=”USA”/>
美国
<html:multibox property=”testStringArray” value=”England”/>
英国
<html:multibox property=”testStringArray” value=”Germany”/>
德国
<html:multibox property=”testStringArray” value=”France”/>
法国
</html:form>
当用户选中其 中的几项并点击提交后,ActionForm中 的testStringArray数组就会被赋上相应的值。这里有一点值得注意,例如用户选择了中国英国两项,ActionFormtestStringArray的 值就会是{“中国“,”英国“}

中国

美国

英国

德国

法国
<html:radio>
<html:radio> 标记生成一个单选框,示例代码如下:
<html:form action=”/test.do”>
<html:radio property=”testRadio” value=”testvalue1″/>
</html:form>
它有一个value性,用来指定当选中该单选框时ActionForm中对应的属性 的值。下面是另一种单选框的用法:
<html:form action=”/test.do”>
<html:radio property=”testRadio” value=”value1″>Choice1
<html:radio property=”testRadio” value=”value2″>Choice2
<html:radio property=”testRadio” value=”value3″>Choice3
</html:form>
在上面的代码 中,单选框一共有三个,这三个单选框组成一个单选框组,只能选取其中一个。无论选中哪一个,它的值在提交表单后都 将赋给ActionForm中相对应的属性,如果三个单选框一个都没有选 中,那么该属性的值将为一个空串。
运行效果如下所示:

Choice1

Choice2

Choice3
<html:select>
<html:select> 用来在网页上产生选择列表。通常它与<html:option>等选项标记连用。示例代码如下:
<html:select property=”testString” size=”1″>
<html:option value=”value1″>Show Value1</html:option>
<html:option value=”value2″>Show Value2</html:option>
<html:option value=”value3″>Show Value3</html:option>
<:html:submit property=”submit” value=”
提交“/> </html:select>
中,property表示该选择列表与ActionForm中对应的属性名。当用户点击提交后,会在测试页面看到用户所选中的选项的值。以下是代码的运行效果:

<html:select> 有一个size属性,它表示同时显示的选项的数目,如上例中的size1,则只同时显示一个选项。还有 一个multiple属性,当其为true时,该选择列表就允许多选。用户可以通过鼠标的拖动,或是按住Ctrl键进行多选。
以下是 multiple=”true”size=”8″例子
multiple性为true时,在ActionForm中 对应的属性应是一个数组类型以便同时向其赋上用户选中的多个值。
<html:option>
<html:option> 标记是<html:select>标记的选项,每个<html:option>将在选择框中代表一个选项。有如下代码所示:
<html:select property=”testString” size=”1″>
<html:option value=”value1″>Show Value1</html:option>
<html:option value=”value2″>Show Value2</html:option>
<html:option value=”value3″>Show Value3</html:option>
</html:select>
一个选项有两部分重要的内容。第一就是它所显示 给用户的内容,这可以通过以下方式来指定:
<html:option value=”value1″>Show Value1</html:option>
可以看出,使 用两<html:option>间的部分来表示用户所见到的内容。当然,也可以使用<html:option> 所带的keybundle等属性用来指定所在资源文件中的内容,以此来表示用户所见到的内容。其中,bundlekey属性的用法请参看配置文件相关章节。
另一个重要 的内容就是它所传递给ActionForm的 值。这是由标记的value属性指定的。如上面的例子中,value的值分别为 value1,value2value3,当用户选中某个标记时,JSP页面就会将该标记所对应的value传给ActionForm中相应的属性。
以下是运行 效果:

<html:options>
<html:options> 标记用来表示一组选择项,也就是相当于一组的<html:option>标记。在一个 <html:select>标记中可以包含多个<html:options>标记。以下是一段代码示例:
<%
ArrayList list = new ArrayList();
list.add(new org.apache.struts.util.LabelValueBean(“Show value1″,”value1″));
list.add(new org.apache.struts.util.LabelValueBean(“Show value2″,”value2″));
list.add(new org.apache.struts.util.LabelValueBean(“Show value3″,”value3″));
list.add(new org.apache.struts.util.LabelValueBean(“Show value4″,”value4″));
pageContext.setAttribute(“valuelist”,list);
%>
<html:form action=”/test.do”>
<html:select property=”testString”>
<html:options collection=”valueslist” property=”value” labelProperty=”label”/>
</html:select>
</html:form>
这是一<html:options>标记的应用方式。首先,页面创建一个ArrayList型的对象list,以此作为 存放所有选项的容器。接下来,将四个org.apache.struts.util.LabelValueBean类型的对象放入list中,在初始 化这四个 LabelValueBean对象时,对每个对象 的构造函数传入两个字符型参数。第一个参数将赋给LabelValueBean对象 中的label变量,这个变量的值将成为页面选项中用户所见到的部 分;第二个参数将赋给LabelValueBean对象中的value变量,该变量的值就是用户在选择页面中这个选项后传递给后台ActionForm的值,也就是<html:option>标记中value属性的 值。
在四个对象都存入 list对象后,程序把list对象放入pageContext中。这样做的目的是为了让<html:options>标记来引用它。<html:options>标记有一个collection属 性,它可以在页面上下文pageContext中指定一个实现了List 接口的对象,然后将该对象列表中所有存储的对象遍历,取出每一个对象相应的属性值,用来作为页面选项(也就是每一个option)value label。如在本例中,collection属性首先指定了从pageContext中取出valuelist对象,由于valuelist对象中存储的是一个 org.apache.struts.util.LabelValueBean类 型的对象列表,所以,<:html:options>标记会将每个对象取出,用 org.apache.struts.util.LabelValueBean对象中的value属性值赋 给标记的property属性,再用对象中的 label属性值赋给标记的 labelProperty属性。这样就将存储在valuelist中的对象和页面 上的每一个选项建立起了一一对应的关系,<:html:options> 的功能也就实现了。
以下是代码实际运行效果:

<html:optionsCollection>
<html:optionsCollection> 标记用来表示一组选择项,与<html:options>所不同的是,它不从pageContext中取出对象,而是从与表单相关联的 ActionForm中取出同 名的数组,并将该数组中的各个对象当作选项表示出来。先看以下ActionForm中 的代码片断:
private TestPageBean [] pagebean = new TestPageBean[4];
public TestBean2 ()
{
super();
for (int i=0;i<4;i++){
pagebean[i]=new TestPageBean(“name” + i,”value” + i);
}
}
ActionForm中,定义一个叫做pagebean的 数组对象,它的类型是TestPageBean,这个Bean只有两个属性,value label。接下来,在ActionForm调 用构造函数进行初始化时将这个pagebean数组对象进行初始化,存入四个TestPageBean类型的对象。这四个对象的valuelabel分别从value1value4以及name1name4。以下是TestPageBean的代码:
public class TestPageBean {

private String name = “”;
private String value = “”;
public TestPageBean(String n, String v){
name = n;
value = v;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getValue() {
return value;
}

public void setValue(String value) {
this.value = value;
}
}

以下<html:optionsCollection>的使用方法:
<html:form action=”/test.do”>
<html:select property=”testString” size=”1″>
<html:optionsCollection property=”pagebean” label=”name” value=”value”/>
</html:select>
<html:submit property=”submit” value=”submit” />
</html:form>
可以从代码中看到,<html:optionsCollection>标记使用property属 性来指定ActionForm的数组属性,用label性来指定数组元素对象中用于代表选项页面显示的值,而用value属性来指定数组元素对象中用于代表选项被选中后传入ActionForm 的值。
以下是以上代码的运行效果,若用户选择了name1则可在测试页面上看到与其对应的value1

<html:file>
<html:file> 标签用于上传文件。上传文件指的是从客户端将文件上传到服务器上,这一过程和通过表单提交请求到服务器端并 没有本质上的不同。在这一过程中有以下两点需要注意:
1. 文件存储于客户端的机器上,因此在服务器端不能使用获得文件路径的方式来获取文件对象。
2. 由于使用GET方式提交表单时,可提交的串长度受到限制,所 以,在上传文件时必须使用POST方式。
文件上传是一 项从页面开始的工作,下面首先看一下页面上的代码:
<html:form action=”/upload.do” enctype=”multipart/form-data”>
<html:file property=”file” />
<html:submit property=”submit” value=”submit”/>
</html:form>

您上传的文件是:<bean:write name=”upload” property=”filename”/>
它的大小为:<bean:write name=”upload” property=”size”/>

上面的代码中使用<html:file>标记来进行文件的上传。前面已经说过,上传过程实际上和通过表单提交请求到服务器没有不同,因此,该标记 也必须存在于一个表单中。这个表单所进行的操作是/upload.do。通过查找struts-config.xml可以知道,该表单类型应为 org.apache.struts.webapp.exercise.UploadBean,以下是它的代码:
public class UploadBean extends ActionForm{

private FormFile file = null;
private String filename = “”;
private String size = “”;

public UploadBean(){
}

public FormFile getFile() {
return file;
}

public void setFile(FormFile file) {
this.file = file;
}

public String getFilename() {
return filename;
}

public void setFilename(String filename) {
this.filename = filename;
}

public String getSize() {
return size;
}

public void setSize(String size) {
this.size = size;
}
}

在上面的代码中,定义了一个FormFile类型的对象file。这个FormFile类是Struts提供的 专门用于文件上传的类。在这个ActionForm 中,FormFile类的对象file的名称与网 页上<html:file>标记的property属 性相对应,这一点非常重要!
用户点击上传按钮后执行的是upload的操作,这个操作与后台的UploadAction关联。以下是UploadAction的代码:
public class UploadAction extends Action {

public ActionForward execute(ActionMapping mapping,ActionForm form,HttpServletRequest request,HttpServletResponse response) throws Exception {

UploadBean filebean = (UploadBean) form;

FormFile file = filebean.getFile();
if (file == null){
return mapping.findForward(“input”);
}

String filename = file.getFileName();
filebean.setFilename(filename);
String size = Integer.toString(file.getFileSize()) + “bytes”;
filebean.setSize(size);

InputStream is = file.getInputStream();
String store_path = servlet.getServletContext().getRealPath(“/fileupload”);
System.out.println(store_path);
OutputStream os = new FileOutputStream(store_path + “/” + filename);

int bytes = 0;
byte [] buffer = new byte[8192];
while ((bytes = is.read(buffer,0,8192))!=-1){
os.write(buffer,0,bytes);
}

os.close();
is.close();
file.destroy();

return mapping.findForward(“input”);
}
}

上面的代码首 先从表单 ActionForm中获取FormFile对象,然后创建输入流读取文件内容,再创建一个输出流,将上传的文件保存到工程目录下的fileupload 目录中。最后关闭输出流和输入流,并将与客户端的文件连接断开。整个过程非常清楚,简单。其中,有两句代 码分别将文件名和文件大小保存到 UploadBean中去,这是为了在JSP页面上可以显示出文件名和文件大小。在上面的页面代码中可以看到这样两句:
您上传的文件是:<bean:write name=”upload” property=”filename”/>
它的大小为:<bean:write name=”upload” property=”size”/>
这里使用了 Struts Bean标记库的标签来显示与页面相关的ActionForm的变量值。
以下是程序的运行效果,用户可以在/tablig/fileupload目录下看到上传的文件。

<html:errors>
Struts 1.1中该标签的使用方法
<html:errors> 标签用来在网页上输出错误消息。以下是一段实际运行效果,当用户选中下面的选 择框后并提交表单时,页面上就会显示错误消息,而当用户不选中直接点击时,会出现不同的错误消息。
选择框:

这里使用到的代码如下所示:
<html:form action=”/testerr.do”>
择框:<html:checkbox property=”checkbox1″/>
<html:submit/>
</html:form>
<html:errors bundle=”error”/>
错误信息是通 过什么方式添加的呢,<html:errors>标记又是通过什么方式将错误信息显示出来的呢?在前面的章节中曾提到过ActionForm中的 validate()方法,它的作用是检验用户的输入,当用户的输入不符合某种条件时,就返回一个 ActionErrors对象,倘若返回的对象不为空,Struts框架就会将请求发回页面。此时,倘若页面上有相应的显示错误的标记,就会将在 validate()方法中所添加的错误显示出来。
另外,除了在 ActionFormvalidate()方法中可以添加ActionErrors外,在Action中也可 以添加。通过查看struts- config.xml文件可以知 道,与这个表单相关联的ActionFormAction分别是ErrBeanErrAction。以下先看看 ErrBean的 代码:
public class ErrBean extends ActionForm{

private boolean checkbox1;
public boolean isCheckbox1() {
return checkbox1;
}

public void setCheckbox1(boolean checkbox1) {
this.checkbox1 = checkbox1;
}

public void reset(ActionMapping mapping, HttpServletRequest request){
this.setCheckbox1(false);
}

public ActionErrors validate(ActionMapping mapping, HttpServletRequest request){
ActionErrors errors = new ActionErrors();
if (checkbox1){
errors.add(ActionMessages.GLOBAL_MESSAGE,new ActionError(“html.errors.error1″));
errors.add(“checkbox1″,new ActionError(“html.errors.error2″));
}
return errors;
}
}

<html:checkbox> 标记一节已经说过,用于在ActionForm中表示一个选择框的类型通常使用boolean型。此处在ErrBean中就声明了一个boolean型的变量checkbox1用于表示页面上的选择框。当用户在页面上点击了该选择框时,选择框的值被设置为true。然后用户点击提交按钮,此时,Struts框架从struts-config.xml文件中得知这个提交的ActionFormvalidate属性为true,因此需要 调用 ErrBeanvalidate()方法进行验证。
ErrBean validate()方法中,首先初始化一个ActionErrors对象,然后判断checkbox1是 否被选中。若选中,则向 ActionErrors 对象中添加两个ActionError。添加ActionError时采用的是ActionErrorsadd()方法。该方法有两个参数,第一个参数是所添加ActionError key,然后是ActionError的值。这样做的原因是因为在ActionErrors内部保存了一个HashMap,以 此来将所有的 ActionError保存。其中,添加第一个ActionError的代码如下:
errors.add(ActionMessages.GLOBAL_MESSAGE,new ActionError(“html.errors.error1″));
这里的 ActionMessages.GLOBAL_MESSAGE的值“org.apache.struts.action.GLOBAL_MESSAGE”,它是一个常量,表示全局消息。对于每一个key来说,都可以存入多个ActionError。这是因为ActionErrors的内置的HashMap中并不是仅仅存入一个简单的ActionError 对象,而是存入一个List对象,再将多个ActionError对象存入该List中。ActionError的构造函数中的参数是资源文件中的key 值,将来在页面上就将显 示该key值对应的value。下面是 添加第二个ActionError的代码:
errors.add(“checkbox1″,new ActionError(“html.errors.error2″));
这个 ActionErrorkey值为checkbox1,它表示和特定的表单元素相关的错误信息。在页面中的<html:errors>标签中使用 property属性来指定。
通过上面的代码可以看到,用户在提交表单时由ActionForm产生了错误信息,然后转交回页面。此时,就该由页面上的<html:errors> 来显示相应的错误信息了。这时,考虑另一种情形,如果页面上用户输入的信息并 无错误,通过了ActionFormvalidate()方法的检查,但在 Action中 经由业务逻辑处理后,返回了一些错误信息。此时,仍然需要将ActionErrors对象存储进request对象中。但Action中并 validate方法了,该怎么办呢?Action类的saveErrors()方法解决了这一困难。看看 下面ErrActionexecute()法的代码:
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {

ActionErrors errors = new ActionErrors();
errors.add(ActionMessages.GLOBAL_MESSAGE,new ActionError(“html.errors.error3″));
saveErrors(request,errors);
return mapping.findForward(“input”);
}

Action类中提供了一个saveErrors()方法,可以将ActionErrors对象存入request中。通过这个方法<html:errors> 标签可以在request中找到它并将其显示在网页上。
前面已经看到了页面上显示的代码,下面就来讲解 一下<html:errors>标记的具体用法。
<html;errors> 标记可以放在网页上的任何位置,它有以下三个比较重要的属性:
name属性:它指定了存放在requestsession属性中的错误对象的值。我们知道,在requestsession中,对象的存储一般都以键/值对的方式来进行。ActionErrors对象在requestsession中的key默认为Globals.ERROR_KEY
property性:用于指定与ActionError对应的key值,如前面例 中的checkbox1
bundle属性:用于指定资源文件,即显示ActionErrors信息时去哪个资源文件中读取相应的消息文本。例如在taglib1中,struts- config.xml 文件中有这样一句代码:
<message-resources parameter=”message” key=”error”/>
则在页面<html:errors>标签中使用下面的方式来引用这个资源文件
<html:errors bundle=”error”/>
以下是几个代码示例:
<html:errors bundle=”error”/>
上面的代码表示显示所有的错误信息。
<html:errors property=”org.apache.struts.action.GLOBAL_MESSAGE” bundle=”error”/>
上面的代码 表示显示所有的全局消息,也就是在向ActionErrors中添加ActionError对象时,选用 ActionMessages.GLOBAL_MESSAGE 做为该ActionErrorkey的对象。
Struts 1.2中该标签的使用方法
到目前为止,所有有<html:errors>标签的讨论都是基于Struts 1.1的核心。但在2005Apache正式推出Struts 1.2后, 有许多东西已经被改变。其中很重要的一个改动就是与<html:errors>标记相关的改动,主要就是已经不再推荐使用 ActionError类和ActionErrors类,因此,如果要将现有的 使用到与<html:errors>标记相关的 代码从 Struts 1.1下移至Struts 1.2下,需要作以下改动。
1. 将代码中使用到ActionError类的地方换为ActionMessage类。
2. 将除了在ActionFormvalidate()方法以外使用到ActionErrors类的地方都替换为ActionMessages
这样做的主 要原因是,ActionErrorActionMessage的子类,而ActionErrorsActionMessages的 子类。开发者认为一个错误消息也是消息的一种,并没有必要专门将其分开存放。只需要使用Globals.MESSAGE_KEY,Globals.ERROR_KEY来进行区分就分。
例如,在 ErrAction中,若要使其支持Struts1.2, 则可将代码改为如下形式:
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {

ActionMessages messages = new ActionMessages();
messages.add(ActionMessages.GLOBAL_MESSAGE,new ActionMessage(“html.errors.error3″));
saveErrors(request,messages);
return mapping.findForward(“input”);
}

242010

最近在做一个推荐系统的项目,原来是设计前台一个表单对应后台一个form和action。无奈前台表单太多,只能把表单合并处理(在vo里都是对应同一个类,只是处理不同的逻辑)。这样就在前台表单里加了2个参数type和method。type用来区分form里的validate,然后利用method使用DispatchAction类。

采用 DispathAction
* 如果覆写DispathAction中的execute方法,必须显示的用super调用execute方法
* parameter参数值不能是execute或perform
* 了解<action>标签中的parameter的含义
* 了解DispathAction中的unspecified方法的含义

DispatchAction 的定义:
public abstract class DispatchAction extends Action
这是一个抽象的Action,它会根据request 中的parameter来执行相应的方法。通个这个Action类可以将不同的Action集中到一个Action文件中来。

Struts-config.xml:

<action path=”/saveSubscription” type=”org.apache.struts.actions.DispatchAction” name=”subscriptionForm” scope=”request” input=”/subscription.jsp” parameter=”method”/>

在Action中要有相应的方法:

Public class demoAction extends DispatchAction{

public ActionForward delete(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception

public ActionForward insert(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception

public ActionForward update(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception

}

你就可以通过这样的方法来访问你的程序:

http://localhost:8080/myapp/saveSubscription.do?method=update

如果parameter中参数为空,则执行Action中unspecified方法
DispatchAction就是在struts-config中用parameter参数 配置一个表单字段名,这个字段的值就是最终替代execute被调用的方法. 例如parameter=”method”而request.getParameter(“method”)=”save”,其中”save”就是 MethodName。struts的请求将根据parameter被分发到”save”或者”edit”或者什么。但是有一点,save()或者 edit()等方法的声明和execute必须一模一样。

DispatchAction的父类是 Action ,它的作用就在于将多个功能相似的业务逻辑放在同一个 Action 中实现,各个业务逻辑通过传入不同的参数来决定执行哪个操作方法

通常在 Action 中我们都是通过 execute 方法来处理业务逻辑及页面转向,一个 Action 只能完成一种业务逻辑处理 , 当然我们也可以在页面插入一个隐藏的变量,然后在 Action execute 方法中通过判断这个隐藏变量的值来决定调用哪个方法,也可以达到同 一个 Action 来处理多种业务逻辑

DispatchAction 是如何实现的?

比如对一个用户对象来说,存在增加,删除,修改的操作,首先创建一 个继承 DispatchAction UserAction 类,

然后将 addUser,delUser,updateUser 这些方法写在这个类里面,代码如下:

package com.why.struts.action;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionForm;

import org.apache.struts.action.ActionForward;

import org.apache.struts.action.ActionMapping;

import org.apache.struts.actions.DispatchAction;

import com.why.Constant;

import com.why.struts.form.AddUserForm;

import com.why.struts.form.LoginForm;

public class UserAction extends DispatchAction

{

public ActionForward addUser (ActionMapping mapping,ActionForm form,

HttpServletRequest request,HttpServletResponse response) throws Exception

{

// 增加用户业务的逻辑

return mapping.findForward(Constant. FORWARD_ADD );

}

public ActionForward delUser(ActionMapping mapping,ActionForm form,

HttpServletRequest request,HttpServletResponse response) throws Exception

{

// 删除用户业务的逻辑

return mapping.findForward(Constant. FORWARD_SUCCESS );

}

public ActionForward updateUser(ActionMapping mapping,ActionForm form,

HttpServletRequest request,HttpServletResponse response) throws Exception

{

// 更新用户业务的逻辑

return mapping.findForward(Constant. FORWARD_SUCCESS );

}

}

如何实现这些不同方法的调用呢 ? 那就是要在 struts-config.xml 文件中更改 action-mapping 的配置,如下:

< action-mappings >

< action

attribute = “addUserForm”

input = “/addUser.jsp”

name = “addUserForm”

parameter=”method”

path = “/addUser”

scope = “request”

type=”com.why.struts.action.UserAction” >

</ action >

< action

attribute = “delUserForm”

input = “/delUser.jsp”

name = “delUserForm”

parameter=”method”

path = “/delUser”

scope = “request”

type=”com.why.struts.action.UserAction” />

< action

attribute = “updateUserForm”

input = “/updateUser.jsp”

name = “updateUserForm”

parameter=”method”

path = “/updateUser”

scope = “request”

type=”com.why.struts.action.UserAction” />

</ action-mappings >

可以看到每个 <action  /> 中都增加了 parameter=” “ 项,这个值可以随便命名,如上面命名为 metho d ,用来接收页面传来的参数

如下为页面的提交, 注意:对应 <action  /> 中的 parameter , 对应 UserAction 类中的方法名

AddUser.jsp

<html:link href=”addUser.do?method=addUser“>Add User</html:link>

DelUser.jsp

<html:link href=”delUser.do?method=delUser“>Add User</html:link>

UpdateUser.jsp

<html:link href=”updateUser.do?method=updateUser“>Add User</html:link>

© 2009 - 2024 冰河的博客