`

(转)Struts2的参数传递

阅读更多

本篇主要通过实例来讲述Struts2中各种各样的参数传递。这个参数传递的过程主要指数据从View层传递到Control层时Struts2的工作方式。根据前两篇文章的知识,我们知道,Struts2完成参数传递处理工作的基础是OGNL和ValueStack。而在这个过程中,我也把Struts2所要做的工作大致归纳为两个方面: 

1. 对OGNL操作进行封装,完成OGNL表达式所表示的值到Java对象的值传递机制 

2. 在参数传递的过程中,做恰当的类型转化,保证页面上的字符串能够转化成各式各样的Java对象
 

接下来,通过四个不同的角度,来具体讲述Struts2在这两个方面的工作。


  1. 最简单的参数传递
  2. Array、List、Map等容器类型的参数传递
  3. 文件上传
  4. 自定义的类型转化实现

最简单的参数传递 

使用OGNL的最基本的功能,就能完成普通的Java对象的赋值工作。Struts2在内部已经完成了OGNL的基本封装。这些封装包括对OGNL表达式到Java对象的赋值机制,以及对基本的Java类型的类型转化支持。这些基本类型包括String、Number(以及其基本类型int、float、double等)、Boolean(boolean)、数组、Class、Date等类型。 

在这里我想额外强调的是XWork对JDK5.0中的Enum类型和Date类型的支持。 

Enum类型 

枚举类型是JDK5.0引入的新特性。枚举类型也能解决很多实际问题,是J2EE编程中的最佳实践之一。XWork中,有一个专门的EnumTypeConverter负责对Enum类型的数据进行转化。 

Java代码 
  1. public class EnumTypeConverter extends DefaultTypeConverter {   
  2.   
  3.     /**  
  4.      * Converts the given object to a given type. How this is to be done is implemented in toClass. The OGNL context, o 
  5.      * and toClass are given. This method should be able to handle conversion in general without any context or object 
  6.      * specified.  
  7.      *  
  8.      * @param context - OGNL context under which the conversion is being done  
  9.      * @param o       - the object to be converted  
  10.      * @param toClass - the class that contains the code to convert to enumeration  
  11.      * @return Converted value of type declared in toClass or TypeConverter.NoConversionPossible to indicate that the 
  12.      *         conversion was not possible.  
  13.      */  
  14.     public Object convertValue(Map context, Object o, Class toClass) {   
  15.         if (o instanceof String[]) {   
  16.             return convertFromString(((String[]) o)[0], toClass);   
  17.         } else if (o instanceof String) {   
  18.             return convertFromString((String) o, toClass);   
  19.         }   
  20.   
  21.         return super.convertValue(context, o, toClass);   
  22.     }   
  23.   
  24.     /**  
  25.      * Converts one or more String values to the specified class.  
  26.      * @param value - the String values to be converted, such as those submitted from an HTML form 
  27.      * @param toClass - the class to convert to  
  28.      * @return the converted object  
  29.      */  
  30.     public java.lang.Enum convertFromString(String value, Class toClass) {   
  31.         return Enum.valueOf(toClass, value);   
  32.     }   
  33.   
  34. }  


有了这个类,我们就可以比较轻松的对枚举类型进行数据赋值了。 

Java代码 
  1. public enum Gender {   
  2.        
  3.     MALE, FEMALE   
  4.   
  5. }  


Html代码 
  1. <form method="post" action="/struts-example/enum-conversion.action">  
  2.     <input type="text" name="user.name" value="downpour" />  
  3.     <select name="user.gender">  
  4.        <option value="MALE"></option>  
  5.        <option value="FEMALE"></option>  
  6.     </select>  
  7.     <input type="submit" value="submit" />  
  8. </form>  


Java代码 
  1. public class EnumConversionAction extends ActionSupport {   
  2.   
  3.     private static final Log logger = LogFactory.getLog(Policy.class);   
  4.        
  5.     private User user;   
  6.        
  7.     /* (non-Javadoc)  
  8.      * @see com.opensymphony.xwork2.ActionSupport#execute()  
  9.      */  
  10.     @Override  
  11.     public String execute() throws Exception {   
  12.         logger.info("user's gender:" + user.getGender());   
  13.         return super.execute();   
  14.     }   
  15.        
  16.     // setters and getters   
  17. }  


通过上面的代码,就完成了对枚举类型的赋值。不过这里有一点需要特别指出:那就是XWork在XWork-2.1.X的版本之前,枚举类型不被默认支持。如果你需要获得枚举类型的自动赋值,还需要增加一个配置文件xwork-conversion.properties到classpath下: 
Java代码 
  1. java.lang.Enum=com.opensymphony.xwork2.util.EnumTypeConverter  

对于使用新的版本的XWork的朋友,则不需要增加这个配置文件。 

Date类型 

XWork默认是支持Date类型的转化的。不过从源码上来看,貌似我们很难用上它默认的类型转化。 

Java代码 
  1. private Object doConvertToDate(Map context, Object value, Class toType) {   
  2.         Date result = null;   
  3.   
  4.         if (value instanceof String && value != null && ((String) value).length() > 0) {   
  5.             String sa = (String) value;   
  6.             Locale locale = getLocale(context);   
  7.   
  8.             DateFormat df = null;   
  9.             if (java.sql.Time.class == toType) {   
  10.                 df = DateFormat.getTimeInstance(DateFormat.MEDIUM, locale);   
  11.             } else if (java.sql.Timestamp.class == toType) {   
  12.                 Date check = null;   
  13.                 SimpleDateFormat dtfmt = (SimpleDateFormat) DateFormat.getDateTimeInstance(DateFormat.SHORT,   
  14.                         DateFormat.MEDIUM,   
  15.                         locale);   
  16.                 SimpleDateFormat fullfmt = new SimpleDateFormat(dtfmt.toPattern() + MILLISECOND_FORMAT,   
  17.                         locale);   
  18.   
  19.                 SimpleDateFormat dfmt = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT,   
  20.                         locale);   
  21.   
  22.                 SimpleDateFormat[] fmts = {fullfmt, dtfmt, dfmt};   
  23.                 for (int i = 0; i < fmts.length; i++) {   
  24.                     try {   
  25.                         check = fmts[i].parse(sa);   
  26.                         df = fmts[i];   
  27.                         if (check != null) {   
  28.                             break;   
  29.                         }   
  30.                     } catch (ParseException ignore) {   
  31.                     }   
  32.                 }   
  33.             } else if (java.util.Date.class == toType) {   
  34.                 Date check = null;   
  35.                 SimpleDateFormat d1 = (SimpleDateFormat) DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG, locale);   
  36.                 SimpleDateFormat d2 = (SimpleDateFormat) DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM, locale);   
  37.                 SimpleDateFormat d3 = (SimpleDateFormat) DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, locale);   
  38.                 SimpleDateFormat rfc3399 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");   
  39.                 SimpleDateFormat[] dfs = {d1, d2, d3, rfc3399}; //added RFC 3339 date format (XW-473)   
  40.                 for (int i = 0; i < dfs.length; i++) {   
  41.                     try {   
  42.                         check = dfs[i].parse(sa);   
  43.                         df = dfs[i];   
  44.                         if (check != null) {   
  45.                             break;   
  46.                         }   
  47.                     }   
  48.                     catch (ParseException ignore) {   
  49.                     }   
  50.                 }   
  51.             }   
  52.             //final fallback for dates without time   
  53.             if (df == null) {   
  54.                 df = DateFormat.getDateInstance(DateFormat.SHORT, locale);   
  55.             }   
  56.             try {   
  57.                 df.setLenient(false); // let's use strict parsing (XW-341)   
  58.                 result = df.parse(sa);   
  59.                 if (!(Date.class == toType)) {   
  60.                     try {   
  61.                         Constructor constructor = toType.getConstructor(new Class[]{long.class});   
  62.                         return constructor.newInstance(new Object[]{new Long(result.getTime())});   
  63.                     } catch (Exception e) {   
  64.                         throw new XWorkException("Couldn't create class " + toType + " using default (long) constructor", e);   
  65.                     }   
  66.                 }   
  67.             } catch (ParseException e) {   
  68.                 throw new XWorkException("Could not parse date", e);   
  69.             }   
  70.         } else if (Date.class.isAssignableFrom(value.getClass())) {   
  71.             result = (Date) value;   
  72.         }   
  73.         return result;   
  74.     }  


这段代码就是XWork处理将String转成Date类型的过程,从整个过程上来看,我们很难用上这段代码,因为我们在界面上的Date类型的表现形式往往是:'yyyy-MM-dd'或者相关的形式,很明显,上面的流程无法匹配这样的日期类型。 

所以,针对Date,我们往往会自定义一个日期转化的类进行处理,这个在下面会有具体的介绍。

Array、List、Map等容器类型的参数传递 Top

除了简单的基于JavaBean方式的参数传递支持,Struts2还支持对Array、List、Map等容器类型的数据结构做数据赋值。不过历史一路走来,XWork针对容器类型的数据赋值一直有变化,让我们慢慢解读这些变化,从而也来看看编程思路是如何改变的。 

1. 2004年,XWork-1.0.X的年代 

当时XWork所支持的针对容器的数据赋值还比较土。这方面moxie在论坛上有一篇文章专门来讲述:http://www.javaeye.com/topic/8770。 

总的来说,那个年代对于容器的数据赋值,需要依赖于XWork的辅助类。我们可以看到,如果你要对List进行赋值,需要新建一个XWorkList的实现类,并把所需要进行数据赋值的Java类传递到XWorkList的构造函数中。而对Map等对象的赋值,也同理可得。 

这种数据赋值的方式的优缺点都非常明显。优点在于简单,你不需要额外定义任何其他的内容,而是直接使用XWork的辅助类来实现类型转化。缺点在于扩展性很弱,很明显,针对某一个具体的容器,就需要一个XWork的实现类,List有XWorkList对应,Map有XWorkMap对应。甚至在那个时候,还没有Set的支持,因为没有XWorkSet的实现。所以使用这种方式,在扩展性方面需要遭受严重的考验。 

2. 2006年,XWork-2.0.X的年代 

也许是XWork团队看到了扩展性上的问题,所以在XWork和Webwork同时升级以后,采用了新的方式来处理容器赋值。而此时,Javaeye上也涌现出了新的文章,Tin同学对新的方式做了详细的表述:http://www.javaeye.com/topic/17939。 

不过这个新的整合方式似乎并不被大家所看好。 

lllyq 写道
我觉得XWorkList, XWorkMap还是很有用的,挺好的设计,其实没有必要deprecated。


moxie 写道
集合支持不向下兼容。XWorkList已经是@deprecated,用它就错,还不如直接删除掉。在webwork2.2中,它需要为集合另外配置一个conversion.properties文件。真不明白,这样有什么优点?


这种新的整合方式,实际上只是解决了针对容器赋值,不需要依赖XWork的辅助类这样的一个问题,不过其付出的代价,却是多了一个配置文件,这也让人非常郁闷。好好的类型转化,平白无故多出了一个同package下的配置文件,这也无形中增加了编程的复杂度。 

3. 现在,拥抱了泛型和Annotation的年代 

实际上,在XWork发展到XWork-2.0.X之后,也开始注重了对泛型和Annotation的支持。所以,容器类型的转化,我们也可以尝试一下使用JDK的新特性来进行,当然这也是目前最为推荐的做法。 

下面分别给出使用泛型和Annotation的代码示例: 

Html代码 复制代码
  1. <form method="post" action="/struts-example/ognl-collection-conversion.action">  
  2.     <input type="text" name="users[0].name" value="aaa" />  
  3.     <input type="text" name="users[1].name" value="bbb" />  
  4.     <input type="text" name="users2[0].name" value="ccc" />  
  5.     <input type="text" name="users2[1].name" value="ddd" />  
  6.     <input type="text" name="userMap['user1'].name" value="eee" />  
  7.     <input type="text" name="userMap['user2'].name" value="fff" />  
  8.     <input type="text" name="userMap2['user3'].name" value="ggg" />  
  9.     <input type="text" name="userMap2['user4'].name" value="hhh" />  
  10.     <input type="submit" value="submit" />  
  11. </form>  


Java代码 
  1. public class OgnlConversionAction extends ActionSupport {   
  2.   
  3.     private static final long serialVersionUID = 4396125455881691845L;   
  4.   
  5.     private static final Log logger = LogFactory.getLog(Policy.class);   
  6.        
  7.     private List<User> users;   
  8.        
  9.     @Element(value = User.class)   
  10.     private List users2;   
  11.        
  12.     private Map<String, User> userMap;   
  13.        
  14.     @Element(value = User.class)   
  15.     private Map userMap2;   
  16.        
  17.     /* (non-Javadoc)  
  18.      * @see com.opensymphony.xwork2.ActionSupport#execute()  
  19.      */  
  20.     @Override  
  21.     public String execute() throws Exception {   
  22.            
  23.         // -> aaa   
  24.         logger.info("users[0].name : " + users.get(0).getName());   
  25.         // -> bbb   
  26.         logger.info("users[1].name : " + users.get(1).getName());   
  27.         // -> ccc   
  28.         logger.info("users2[0].name : " + ((User)users2.get(0)).getName());   
  29.         // -> ddd   
  30.         logger.info("users2[1].name : " + ((User)users2.get(1)).getName());   
  31.            
  32.         // -> [user1, user2]   
  33.         logger.info("userMap.key : " + userMap.keySet());   
  34.         // -> eee   
  35.         logger.info("userMap.key = " + "user1" + " : " + "userMap.value(user1's name) = " + userMap.get("user1").getName());   
  36.         // -> fff   
  37.         logger.info("userMap.key = " + "user2" + " : " + "userMap.value(user2's name) = " + userMap.get("user2").getName());   
  38.         // -> [user3, user4]   
  39.         logger.info("userMap2.key : " + userMap2.keySet());   
  40.         // -> ggg   
  41.         logger.info("userMap2.key = " + "user3" + " : " + "userMap.value(user3's name) = " + ((User)userMap2.get("user3")).getName());   
  42.         // -> hhh   
  43.         logger.info("userMap2.key = " + "user4" + " : " + "userMap.value(user4's name) = " + ((User)userMap2.get("user4")).getName());   
  44.            
  45.         return super.execute();   
  46.     }   
  47.        
  48.     // setters and getters   
  49. }  


上面的代码中,我们可以看到,如果你使用泛型,那么你无需再使用任何额外的配置文件或者Annotation,XWork会把一切都为你准备好。如果你没有使用泛型,那么你可以使用Annotation来指定你需要进行转化的对象类型。其中,对Map对象使用Annotation时,Element中的value所对应的值,是Map中的value所对应的class。 

由此可见,泛型和Annotation,在一定程度上,还是可以简化我们很多工作的。 

文件上传 Top

文件上传其实也是参数传递的一种,所以从方案上来讲,Struts2同样使用了一个拦截器来处理。而这个拦截器,同样来自于原来的Webwork,基本上没有做什么很大的改变。有关这个拦截器的详细内容,我们也留一个悬念,在后续章节中详细讲解。目前,你只要知晓,这个拦截器能帮助你完成一切文件上传相关的机制。 

早在2005年,Quake Wang就对Webwork的文件上传机制有了详细的讲解:http://www.javaeye.com/topic/10697

在这里我简单小结一下在进行文件上传时的三大要点: 

1. 在配置文件上传时,拦截器的顺序非常关键 

Xml代码 
  1. <interceptor-stack name="uploadStack">     
  2.     <interceptor-ref name="upload"/>                     
  3.     <interceptor-ref name="defaultStack"/>     
  4. </interceptor-stack>  


具体来说,upload的拦截器,必须在params的拦截器之前 

2. 拦截器额外提供了一些额外的文件信息 

Quake Wang 写道
ContentType: 文件的ContentType(可以用在做download的时候) 
FileName: 实际的文件名 
在上面的action例子里, 那么有uploadFilesContentType和uploadFilesFileName这2个属性, 也能够被自动绑定


3. 拦截器提供的文件上传功能,你得到的是一个临时文件 

robbin 写道
在webwork的file upload 拦截器功能中,它提供的File只是一个临时文件,Action执行之后就会被自动删除,因此你必须在Action中自己出来文件的存储问题,或者写到服务器的某个目录,或者保存到数据库中。如果你准备写到服务器的某个目录下面的话,你必须自己面临着处理文件同名的问题


而时代发展到Struts2的年代,对于文件上传的整体机制没有做什么改变。只是Struts2将apache的common-fileupload作为了其默认的文件上传的机制。 

例子归例子,实际情况中,我们还是会遇到一些问题: 

1. 默认实现中,文件和文件信息是分开表述的,对于后台处理来说,不是非常方便 

2. common-fileupload的实现,虽然提供了文件上传的机制,也可以让你得到文件的一些属性信息,但是它无法得到客户端的上传路径 

对于第一个问题,我们可以使用OGNL的特性,将这些文件和文件名等文件信息做封装: 

Java代码 
  1. public class FileComponent implements Serializable {   
  2.   
  3.     private static final long serialVersionUID = 4594003082271182188L;   
  4.   
  5.     private File upload;   
  6.   
  7.     private String fileName;   
  8.        
  9.     /**  
  10.      * The default constructor  
  11.      */  
  12.     public FileComponent() {   
  13.   
  14.     }   
  15.   
  16.     /**  
  17.      * @return Returns the upload.  
  18.      */  
  19.     public File getUpload() {   
  20.         return upload;   
  21.     }   
  22.   
  23.     /**  
  24.      * @return Returns the fileName.  
  25.      */  
  26.     public String getFileName() {   
  27.         return fileName;   
  28.     }   
  29.        
  30.     /**  
  31.      * @param upload  
  32.      *            The upload to set.  
  33.      */  
  34.     public void setUpload(File upload) {   
  35.         this.upload = upload;   
  36.     }   
  37.   
  38.     /**  
  39.      * @param fileName  
  40.      *            The fileName to set.  
  41.      */  
  42.     public void setFileName(String fileName) {   
  43.         this.fileName = fileName;   
  44.     }   
  45.   
  46.     /**  
  47.      * @param fileName  
  48.      *            The fileName to set.  
  49.      */  
  50.     public void setUploadFileName(String uploadFileName) {   
  51.         this.fileName = uploadFileName;   
  52.     }   
  53. }  


在这个类中,我定义了upload表示上传的文件,fileName表示上传文件的文件名。请注意我整个文件中的最后一个方法:setUploadFileName。这个方法将保证FileUploadInterceptor在运行时,能够正确设置上传的文件名。 

Java代码 
  1. /**  
  2.  * @param fileName  
  3.  *            The fileName to set.  
  4.  */  
  5. public void setUploadFileName(String uploadFileName) {   
  6.     this.fileName = uploadFileName;   
  7. }  


这样,在Action中,我们将面对一个个完整的fileComponent对象,其中包括文件的引用、文件名称和其他文件信息。这样就不会因为上传多个文件而手足无措,你只需要使用fileComponent数组,就能轻松对上传的文件进行管理,而避免了在Action中书写许多个文件、文件名等属性了。 

对于第二个问题,目前我也没有找到很好的方法。我所采用的方式与Yulimin是一致的: 

Yulimin 写道
我现在的做法是表单中增加了一个隐藏域,当用户文件选择后,利用JS截取到用户选择的文件名,然后一起提交上去。 
不知道有没有最终的解决方法?

自定义的类型转化实现 Top

Struts2在处理参数传递的过程中,需要完成类型转化,保证页面上的字符串能够转化成各式各样的Java对象。而这一点,其实也是由OGNL完成的。还记得我们在讲述OGNL的基础知识的时候列出来过的一个接口嘛? 

Java代码 
  1.   
  2. /**  
  3.  * Appends the standard naming context for evaluating an OGNL expression  
  4.  * into the context given so that cached maps can be used as a context.  
  5.  *  
  6.  * @param root the root of the object graph  
  7.  * @param context the context to which OGNL context will be added.  
  8.  * @return Context Map with the keys <CODE>root</CODE> and <CODE>context</CODE>  
  9.  *         set appropriately  
  10.  */  
  11. public static Map addDefaultContext( Object root, ClassResolver classResolver, TypeConverter converter, MemberAccess memberAccess, Map context );  


在这个接口中,我们可以在使用OGNL的时候,注册针对某个Class级别的自己实现的TypeConverter,这样,OGNL就会在进行设值计算和取值计算的时候,使用自定义的类型转化方式了。让我们来看看TypeConverter的接口定义: 

Java代码 
  1. /**  
  2.  *  context - OGNL context under which the conversion is being done  
  3.  *  target - target object in which the property is being set  
  4.  *  member - member (Constructor, Method or Field) being set  
  5.  *  propertyName - property name being set  
  6.  *  value - value to be converted  
  7.  *  toType - type to which value is converted   
  8.  */  
  9. public Object convertValue(Map context, Object target, Member member, String propertyName, Object value, Class toType);  


知道了原理,就简单了,我们可以自己实现一个TypeConverter的实现类,并且在Struts2中注册一下使用这个TypeConverter的Java类型的对应关系,我们就可以完成自定义的类型转化了。 

具体的例子,可以参考一下Quake Wang同学在2005年时的一篇文章:http://www.javaeye.com/topic/10507。文章针对的是Webwork2,但是无论是实现方式还是操作步骤,与Struts2是完全相同的。值得提醒的是,这篇文章的回复也非常有价值,在看文章的同时,不要忘记看回复。 

不过针对Quake Wang的例子,我也想做一些补充。它的例子中,主要讲述了Struts2中如何去做java.utils.Date的自动类型转化,也正如后面回复中有人提到: 
wolfsquare 写道
如果我在界面上有两种格式的日期怎么办? 
例如一种短格式: SimpleDateFormat("yyyy-mm-dd"),一种长格式SimpleDateFormat("yyyy-mm-dd hh:MM:ss")

而Quake Wang对此是这样解决的: 
Quake Wang 写道
可以根据你的应用情况,看哪种方式是比较常见的转换规则,那么把这个规则定成Application-wide conversion rules: 
Java代码 
  1. 在classpath root下面写一个xwork-conversion.properties:   
  2. java.util.Date=com.javaeye.core.webwork.converter.DateConverter   

另外的一个转换,可以写成Class-specific conversion rules : 
otherDate=com.javaeye.core.webwork.converter.OtherDateConverter


我在这里提供一个我在实际项目中采用的方式: 

Java代码 
  1. public class DateConverter extends DefaultTypeConverter {   
  2.   
  3.     private static final Log logger = LogFactory.getLog(DateConverter.class);   
  4.   
  5.     private static final String DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";   
  6.   
  7.     private static final String DATE_PATTERN = "yyyy-MM-dd";   
  8.        
  9.     private static final String MONTH_PATTERN = "yyyy-MM";   
  10.   
  11.     /**  
  12.      * Convert value between types  
  13.      */  
  14.     public Object convertValue(Map ognlContext, Object value, Class toType) {   
  15.         Object result = null;   
  16.         if (toType == Date.class) {   
  17.             result = doConvertToDate(value);   
  18.         } else if (toType == String.class) {   
  19.             result = doConvertToString(value);   
  20.         }   
  21.         return result;   
  22.     }   
  23.   
  24.     /**  
  25.      * Convert String to Date  
  26.      *   
  27.      * @param value  
  28.      * @return  
  29.      */  
  30.     private Date doConvertToDate(Object value) {   
  31.         Date result = null;   
  32.   
  33.         if (value instanceof String) {   
  34.   
  35.             // TODO add date converter parse order here   
  36.             result = DateUtils.parseDate((String) value, new String[] { DATE_PATTERN, DATETIME_PATTERN, MONTH_PATTERN });   
  37.   
  38.             // all patterns failed, try a milliseconds constructor   
  39.             if (result == null && StringUtils.isNotEmpty((String)value)) {   
  40.   
  41.                 try {   
  42.                     result = new Date(new Long((String) value).longValue());   
  43.                 } catch (Exception e) {   
  44.                     logger.error("Converting from milliseconds to Date fails!");   
  45.                     e.printStackTrace();   
  46.                 }   
  47.   
  48.             }   
  49.   
  50.         } else if (value instanceof Object[]) {   
  51.             // let's try to convert the first element only   
  52.             Object[] array = (Object[]) value;   
  53.   
  54.             if ((array != null) && (array.length >= 1)) {   
  55.                 value = array[0];   
  56.                 result = doConvertToDate(value);   
  57.             }   
  58.   
  59.         } else if (Date.class.isAssignableFrom(value.getClass())) {   
  60.             result = (Date) value;   
  61.         }   
  62.         return result;   
  63.     }   
  64.   
  65.     /**  
  66.      * Convert Date to String  
  67.      *   
  68.      * @param value  
  69.      * @return  
  70.      */  
  71.     private String doConvertToString(Object value) {   
  72.         SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DATETIME_PATTERN);   
  73.         String result = null;   
  74.         if (value instanceof Date) {   
  75.             result = simpleDateFormat.format(value);   
  76.         }   
  77.         return result;   
  78.     }   
  79. }  


在我采用的方式中,依然采用Application-wide conversion rules,只是在自定义的Converter中,根据不同的日期形式进行逐个匹配,找到第一个匹配的日期类型进行转化。当然,这是一种投机取巧的办法,不过比较实用,适用于项目中不太使用国际化,日期的形式不太复杂的情况。

分享到:
评论

相关推荐

    struts2 向结果传参数

    总的来说,Struts2提供了多种方式来向结果传递参数,这使得它在处理复杂的业务逻辑和页面跳转时具有高度的可定制性。根据项目的具体需求,选择合适的方法可以提高代码的可维护性和效率。在实践中,结合使用不同的...

    Struts2中的参数传递

    ### Struts2中的参数传递 #### 一、概述 在Web开发中,Struts2框架因其灵活、高效的特点被广泛采用。Struts2的核心之一就是它对于参数传递的支持能力,这一点主要依赖于OGNL(Object-Graph Navigation Language)...

    AJAX和struts2传递JSON数组

    在本场景中,我们将探讨如何使用AJAX来传递JSON数组,并在Struts2的Action中接收和处理这些数据。 首先,JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它易于人阅读和编写,同时也易于机器解析...

    struts2支持方法上传递参数

    Struts2作为一款流行的Java Web框架,为开发者提供了丰富的功能,其中包括通过方法上传递参数的能力。这种方法使得在处理用户请求时更加灵活,不需要依赖特定的注解,而是直接通过参数名来获取界面传递的参数信息。...

    struts2 action跳转action传参数

    ### Struts2中Action间的参数传递方法 在Struts2框架中,经常需要实现Action之间的跳转,并在跳转过程中传递必要的参数。这种需求在实际开发中非常常见,尤其是在需要根据用户的不同操作来调用不同的业务逻辑时。...

    struts2 接收参数

    在Struts2中,接收参数是常见的操作,这涉及到用户通过HTTP请求传递的数据如何被框架捕获和处理。这篇博客文章可能深入探讨了Struts2如何在Action类中获取和管理这些参数。 首先,Struts2的核心是DispatcherServlet...

    struts2传递参数及ModelDriven的使用示例

    2. **传递参数**:在Struts2中,可以通过不同的方式传递参数,如表单参数、URL参数、Action上下文参数等。例如,在`main.jsp`中可以使用表单元素将数据提交到服务器,然后在Action类中通过`@ActionParams`注解或者...

    Struts2中Action接收参数的方法

    2. 在 JSP 页面中,使用表单或其他方式将参数传递给 Action。 3. 在 Action 中,使用设定的属性接收参数,例如 `userName`。 例如,在 Action 中定义了 `userName` 属性,可以在 JSP 页面中使用 `user1!add?...

    struts2 使用action属性接收中文参数(post提交)

    在处理用户请求时,Struts2允许开发者通过Action类来接收和处理参数,包括中文参数。当我们需要通过POST方法提交包含中文字符的数据时,可能会遇到编码问题,因为HTTP请求默认使用的是ASCII编码,而中文字符需要UTF-...

    struts1.x 和 struts2.x向Action里填充jsp参数原理

    本篇文章将深入探讨Struts1.x和Struts2.x在向Action中填充JSP参数的原理。 Struts1.x的工作原理: Struts1的核心是ActionServlet,它是一个实现了Servlet接口的控制器。当用户发起HTTP请求时,请求会被Dispatcher...

    Struts2接口文档

    “Struts2.3.1.2_API.chm”文档包含了Struts2框架的详细API,其中涵盖了各个主要类和接口的解释、方法签名、参数说明以及返回值类型。开发者可以通过查阅此文档,快速查找特定功能的实现方式,例如ActionSupport类,...

    留言板留言板struts2留言板struts2

    5. **OGNL(Object-Graph Navigation Language)**:Struts2使用OGNL作为默认表达式语言,用于在Action和视图之间传递数据。通过OGNL,可以在JSP页面中直接访问Action中的属性,或者在Action中动态设置模型数据。 6. ...

    struts2中action接收参数的方式

    本篇文章将深入探讨Struts2中Action接收参数的多种方式,以及相关源码解析。 首先,最常见的接收参数方式是通过方法签名直接接收。例如,如果在JSP页面上有这样一个表单: ```jsp 提交" /&gt; ``` 对应的Action...

    转:struts1与struts2的区别

    - **Struts1**: Struts1的Action类依赖于servlet API,这意味着在执行Action方法时,必须传递`HttpServletRequest`和`HttpServletResponse`参数。这种方式增加了测试的难度,因为测试过程中往往需要模拟这些servlet ...

    Struts2 的接受参数的几种方式

    ### Struts2 接受参数的几种方式 #### 第一种方式:直接在 Action 中设置变量 这种方式是最直接的参数接收方式。当从前端传递参数到后端时,我们需要确保 Action 类中有与这些参数名称相匹配的变量。例如,如果...

    Struts2+Jquery+Ajax

    7. 请求与响应的处理,包括参数传递和数据封装 8. 实例演示:使用Struts2+Jquery+Ajax实现动态加载数据或表单验证 "struts2 jar"文件包含了Struts2框架的核心库,可能包括struts2-core、struts2-convention、struts...

    struts2 学习重点笔记

    ### Struts2 学习重点知识点总结 #### 一、Struts2 概念与架构 **1.1 Struts2 简介** - **定义**:Struts2 是 Apache 组织提供的一个基于 MVC 架构模式的开源 Web 应用框架。 - **核心**:Struts2 的核心其实是 ...

    Struts2学习笔记(5)-参数传递方法

    在Struts2框架中,参数传递是连接前端页面与后台Action类的重要环节,使得用户交互的数据能够被正确处理。在本文中,我们将深入探讨几种在Struts2中进行参数传递的方法。 1. **Action中直接参数法** 这是最基本的...

    Struts2全部jar包

    5. **OGNL(Object-Graph Navigation Language)**:Struts2使用OGNL作为默认表达式语言,用于在Action和视图之间传递数据,支持对象属性的直接访问和动态表达式。 6. **插件体系**:Struts2支持丰富的插件,如...

    Struts2的视频学习代码

    4. **OGNL(Object-Graph Navigation Language)**:OGNL是Struts2中的默认表达式语言,用于在视图和模型之间传递数据。它允许开发者在JSP或其他视图层中直接访问Action对象的属性,或者设置模型数据。例如,`${user...

Global site tag (gtag.js) - Google Analytics