282010

java 代码

1private final String getClientAddress(HttpServletRequest request) {
2
3 String address = request.getHeader(X-Forwarded-For);
4
5 if (address != null && StringUtil.isIPAddress(address)) {
6
7 return address;
8
9 }

10
11 return request.getRemoteAddr();
12
13}

14

另外原因主要是Squid的使用:

参见:www.blogjava.net/Alpha/archive/2006/07/12/57764.aspx

在很多应用下都可能有需要将用户的真实IP记录下来,这时就要获得用户的真实IP地址,在JSP里,获取客户端的IP地址的方法是:request.getRemoteAddr(), 这种方法在大部分情况下都是有效的。但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实IP地址了。

这段时间在做IP统计的程序设计,由于服务器作了集群,使用了反向代理软件,将http://192.168.1.110:2046/的URL反向代理 为http://www.xxx.com/的URL时,用request.getRemoteAddr()方 法获取的IP地址是:127.0.0.1 或 192.168.1.110, 而并不是客户端的真实IP。这是什么原因呢?

这是反向代理的原因。经过代理以后,由于在客户端和服务之间增加了中间层,因此服务器无法直接拿到客户端的IP,服务器端应用也无法直接通过转发请求的地 址返回给客户端。但是在转发请求的HTTP头信息中,增加了X-FORWARDED-FOR信息。用以跟踪原有的客户端IP地址和原来客户端请求的服务器 地址。当我们访问http://www.xxx.com/index.jsp/时, 其实并不是我们浏览器真正访问到了服务器上的index.jsp文件,而是先由代理服务器去访问http://192.168.1.110:2046/index.jsp, 代理服务器再将访问到的结果返回给我们的浏览器,因为是代理服务器去访问index.jsp的,所以index.jsp中通过request.getRemoteAddr()的 方法获取的IP实际上是代理服务器的地址,并不是客户端的IP地址。

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

282010

/**
* 验证普通字串,只要字串中不包含特殊字符即可
*/
function checkTextDataForNORMAL(strValue)
{
// 特殊字符验证格式
var regTextChar = /([*"'<>/])+/ ;
return !regTextChar.test(strValue);
}

/**
* 验证整数,包含正整数和负整数
*/
function checkTextDataForINTEGER(strValue)
{
var regTextInteger = /^(-|+)?(d)*$/;
return regTextInteger.test(strValue);
}

/**
* 检查是否为正整数
*/
function isUnsignedInteger(strInteger)
{
var newPar=/^d+$/
return newPar.test(strInteger);
}

function checkMoney(strValue, strUnit)
{
var testMoney = eval(“/^\d+(\.\d{0,” + (strUnit.length -1) + “})?$/”);
return testMoney.test(strValue);
}

/**
* 验证浮点数
*/
function checkTextDataForFLOAT(strValue)
{
var regTextFloat = /^(-)?(d)*(.)?(d)*$/;
return regTextFloat.test(strValue);
}

/**
* 验证数字
*/
function checkTextDataForNUMBER(strValue)
{
var regTextNumber = /^(d)*$/;
return regTextNumber.test(strValue);
}

/**
* 验证英文字母,不区分大小写
*/
function checkTextDataForENGLISH(strValue)
{
var regTextEnglish = /^[a-zA-Z]*$/;
return regTextEnglish.test(strValue);
}

/**
* 验证大写英文字母
*/
function checkTextDataForENGLISHUCASE(strValue)
{
var regTextEnglishUCase = /^[A-Z]*$/;
return regTextEnglishUCase.test(strValue);
}

/**
* 验证小写英文字母
*/
function checkTextDataForENGLISHLCASE(strValue)
{
var regTextEnglishLCase = /^[a-z]*$/;
return regTextEnglishLCase.test(strValue);
}

/**
* 验证英文字母和数字,不区分大小写
*/
function checkTextDataForENGLISHNUMBER(strValue)
{
var regTextEnglishNumber = /^[a-zA-Z0-9]*$/;
return regTextEnglishNumber.test(strValue);
}

/**
* 验证时间
*/
function checkTextDataForTIME(strValue)
{
var regTextTime = /^(d+):(d{1,2}):(d{1,2})$/;
return regTextTime.test(strValue);
}

/**
* 验证电话号码
*/
function checkTextDataForPHONE(strValue)
{
var regTextPhone = /^((d+))*(d)+(-(d)+)*$/;
return regTextPhone.test(strValue);
}

/**
* 验证EMail
*/
function checkTextDataForEMAIL(strValue)
{
var regTextEmail = /^[w-]+@[w-]+(.(w)+)*(.(w){2,3})$/;
return regTextEmail.test(strValue);
}

/**
* 验证URL
*/
function checkTextDataForURL(strValue)
{
var regTextUrl = /^(file|http|https|ftp|mms|telnet|news|wais|mailto)://(.+)$/;
return regTextUrl.test(strValue);
}

/**
* 验证邮政编码
*/
function checkTextDataForPOST(strValue)
{
var regTextPost = /^(d){6}$/;
return regTextPost.test(strValue);
}

282010
  1. package com.geedao.util;
  2. /**
  3. * @author 卢向 东 lxdhdgss@gmail.com 检验输入
  4. */
  5. public class Regex {
  6. /**
  7. * 检查 email输入是否正确
  8. * 正确的书写格 式为 username@domain
  9. * @param value
  10. * @return
  11. */
  12. public boolean checkEmail(String value, int length) {
  13. return value.matches(“\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*”)&&value.length()<=length;
  14. }
  15. /**
  16. * 检查电话输入 是否正确
  17. * 正确格 式 012-87654321、0123-87654321、0123-7654321
  18. * @param value
  19. * @return
  20. */
  21. public boolean checkTel(String value) {
  22. return value.matches(“\d{4}-\d{8}|\d{4}-\d{7}|\d(3)-\d(8)”);
  23. }
  24. /**
  25. * 检查手机输入 是否正确
  26. *
  27. * @param value
  28. * @return
  29. */
  30. public boolean checkMobile(String value) {
  31. return value.matches(“^[1][3,5]+\d{9}”);
  32. }
  33. /**
  34. * 检查中文名输 入是否正确
  35. *
  36. * @param value
  37. * @return
  38. */
  39. public boolean checkChineseName(String value, int length) {
  40. return value.matches(“^[u4e00-u9fa5]+$”)&&value.length()<=length;
  41. }
  42. /**
  43. * 检查HTML 中首尾空行或空格
  44. * @param value
  45. * @return
  46. */
  47. public boolean checkBlank(String value){
  48. return value.matches(“^\s*|\s*$”);
  49. }
  50. /**
  51. * 检查字符串是 否含有HTML标签
  52. * @param value
  53. * @return
  54. */
  55. public boolean checkHtmlTag(String value){
  56. return value.matches(“<(\S*?)[^>]*>.*?</\1>|<.*? />”);
  57. }
  58. /**
  59. * 检查URL是 否合法
  60. * @param value
  61. * @return
  62. */
  63. public boolean checkURL(String value){
  64. return value.matches(“[a-zA-z]+://[^\s]*”);
  65. }
  66. /**
  67. * 检查IP是否 合法
  68. * @param value
  69. * @return
  70. */
  71. public boolean checkIP(String value){
  72. return value.matches(“\d{1,3}+\.\d{1,3}+\.\d{1,3}+\.\d{1,3}”);
  73. }
  74. /**
  75. * 检查ID是否 合法,开头必须是大小写字母,其他位可以有大小写字符、数字、下划线
  76. * @param value
  77. * @return
  78. */
  79. public boolean checkID(String value){
  80. return value.matches(“[a-zA-Z][a-zA-Z0-9_]{4,15}$”);
  81. }
  82. /**
  83. * 检查QQ是否 合法,必须是数字,且首位不能为0,最长15位
  84. * @param value
  85. * @return
  86. */
  87. public boolean checkQQ(String value){
  88. return value.matches(“[1-9][0-9]{4,13}”);
  89. }
  90. /**
  91. * 检查邮编是否 合法
  92. * @param value
  93. * @return
  94. */
  95. public boolean checkPostCode(String value){
  96. return value.matches(“[1-9]\d{5}(?!\d)”);
  97. }
  98. /**
  99. * 检查身份证是 否合法,15位或18位
  100. * @param value
  101. * @return
  102. */
  103. public boolean checkIDCard(String value){
  104. return value.matches(“\d{15}|\d{18}”);
  105. }
  106. /**
  107. * 检查输入是否 超出规定长度
  108. *
  109. * @param length
  110. * @param value
  111. * @return
  112. */
  113. public boolean checkLength(String value, int length) {
  114. return ((value == null || “”.equals(value.trim())) ? 0 : value.length()) <= length;
  115. }
  116. /**
  117. * 检查是否为空 字符串,空:true,不空:false
  118. *
  119. * @param value
  120. * @return
  121. */
  122. public boolean checkNull(String value) {
  123. return value == null || “”.equals(value.trim());
  124. }
  125. }

Struts的HTML标记库

Posted by 冰河 at 18:56 No Responses » 19,461 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>

jsp图片验证码

Posted by 冰河 at 23:16 No Responses » 5,280 Views
232010

代码如下:

image.jsp

<%@ page contentType="image/jpeg" import="java.awt.*,java.awt.image.*,java.util.*,javax.imageio.*" %>
<%!
// 给定范围获得随机颜色
Color getRandColor(int fc,int bc) {
    Random random = new Random();
    if(fc > 255) {
        fc = 255;
    }
    if(bc > 255) {
        bc = 255;
    }
    int r = fc + random.nextInt(bc - fc);
    int g = fc + random.nextInt(bc - fc);
    int b = fc + random.nextInt(bc - fc);
    return new Color(r, g, b);
}
%>
<%
//设置页面不缓存
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);

// 在内存中创建图象
int width = 60, height = 20;
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

// 获取图形上下文
Graphics g = image.getGraphics();

//生成随机类
Random random = new Random();

// 设定背景色
g.setColor(getRandColor(200,250));
g.fillRect(0, 0, width, height);

//设定字体
g.setFont(new Font("Times New Roman", Font.PLAIN, 18));

//画边框
//g.setColor(new Color());
//g.drawRect(0,0,width-1,height-1);

// 随机产生155条干扰线,使图象中的认证码不易被其它程序探测到
g.setColor(getRandColor(160, 200));
for (int i = 0; i < 155; i++) {
    int x = random.nextInt(width);
    int y = random.nextInt(height);
    int xl = random.nextInt(12);
    int yl = random.nextInt(12);
    g.drawLine(x,y,x+xl,y+yl);
}

// 取随机产生的认证码(4位数字)
String sRand = "";
for (int i = 0;i < 4; i++) {
    String rand = String.valueOf(random.nextInt(10));
    sRand += rand;
    // 将认证码显示到图象中
    // 调用函数出来的颜色相同,可能是因为种子太接近,所以只能直接生成
    g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110)));
    g.drawString(rand, 13 * i + 6, 16);
}

// 将认证码存入SESSION
session.setAttribute("captcha", sRand);

// 图象生效
g.dispose();

// 输出图象到页面
ImageIO.write(image, "JPEG", response.getOutputStream());

out.clear();
out = pageContext.pushBody();

%>
一定不要漏掉红色部分,否则会报出错误:
getOutputStream() has already been called for this response

在需要使用验证码的地方加入:
<img src="include/image.jsp">
152010

原理就是修改模板,根据邮箱调用gravatar头像。

1.找到content/templates/(你正在使用的模板名字)/module.php

2.打开,找到:

//blog:博客评论列表

再往下看,找到:

<p><?php echo $value['content']; ?>

3. 在

<p><?php echo $value['content']; ?>

的 上面加上

<img alt="gravatar" src="http://www.gravatar.com/avatar/<?php echo md5($value['mail']); ?>?s=48" width="48″ height="48″ style="float:right"/>

4. 保存,上传

5.大功告成!

原文链接:http://bbs.emlog.net/viewthread.php?tid=3794

152010

这个功能很不错,转过来和所有使用emlog的童靴分享。

众所周知EMlog验证码一旦加载了却无法再次只刷新验证码,这样很不爽,偶尔看不清楚却导致必须将整个页面刷新一次才能获取新的验证码,这样严重 影响用户的心情,一个小小的验证码确实能看出EMlog在人性化的一方面还需要改进。实际上一两行代码就可以使博客系统更加人性化,我们何乐而不为呢?废 话不多说,下面结合EMlog讲讲如何点击验证码实现自动刷新验证码的功能。

核心代码是在img标签中加入:onclick=”this.src=this.src+’?'”,他的作用就是当点击图片的时候加载验证码。为了 使在鼠标点击验证码图片时有手型链接效果,可以在img标签中加入style=”cursor : pointer;”,同时还可以加入alt和title属性。

就EMlog而言,需要修改的验证码有登陆验证、评论验证及碎语验证(手机版除外),所涉及到的文件有:

1.修改/lib/function.login.php

function loginPage()
{
global $login_code;
$login_code == ‘y’ ?
$ckcode = “<span>验证码</span>
<div class=”val”><input name=”imgcode” id=”imgcode” type=”text” />
<img style=”cursor : pointer;” alt=”未显示?请点击刷新” title=”看不清楚?请点击刷新” onclick=”this.src=this.src+’?'” src=”../lib/checkcode.php” align=”absmiddle”></div>” :
$ckcode = ”;
require_once(getViews(‘login’));
cleanPage();
exit;
}

2.修改/index.php

//comments
$cheackimg = $comment_code == ‘y’ ? “<img style=”cursor : pointer;” alt=”未显示?请点击刷新” title=”看不清楚?请点击刷新” onclick=”this.src=this.src+’?'” src=”".BLOG_URL.”lib/checkcode.php” align=”absmiddle” /><input name=”imgcode”  type=”text” class=”input” size=”5″>” : ”;
$ckname = isset($_COOKIE['commentposter']) ? htmlspecialchars(stripslashes($_COOKIE['commentposter'])) : ”;
$ckmail = isset($_COOKIE['postermail']) ? $_COOKIE['postermail'] : ”;
$ckurl = isset($_COOKIE['posterurl']) ? $_COOKIE['posterurl'] : ”;
$comments = $emComment->getComments(0, $logid, ‘n’);

3.修改/t/index.php(我的是3.4版,好像没有这个)

4.修改其他用到验证码的地方。比如我添加的友链插件/content/plugins/linklink_show.php

$log_content=$log_content.(verification==’yes’?'<img src=”./lib/checkcode.php” align=”absmiddle” style=”cursor : pointer;” alt=”未显示?请点击刷新” title=”看不清楚?请点击刷新” onclick=”this.src=this.src+’?'” /><input name=”imgcode”  type=”text” class=”input” size=”5″>’:”).’&nbsp<input type=”submit” name=”" value=”申请链接”  /><input type=”reset” name=”" value=”重新填写”  /></form>’;//验证码

这里要注意单引号、双引号和转义符的使用。

原理是将上述三文件中验证码img标签中加入:style=”cursor : pointer;” alt=”未显示?请点击刷新” title=”看不清楚?请点击刷新” onclick=”this.src=this.src+’?'”,即可实现点击验证码刷新功能。

经测试在firefox,ie6,chrome下均未发现异常。大家可以点击刷新本博的验证码试试。

参考链接:http://huikon.cn/post-189.html

© 2009 - 2024 冰河的博客