Grails可以自动把params里面的参数绑定到domain class。有些时候为了能够绑定自定义的日期格式,例如"yyyy-MM-dd",需要register一个自己的CustomDateEditor。
有时候还有需求要绑定多种格式的日期,例如"yyyy/MM/dd"、"yyyy-MM-dd HH:mm:ss"等等,这时候就需要一个支持多种日期格式的CustomDateEditor,解决方法如下:
1. 新建一个MultipleDateEditor.groovy
package com.myapp
import java.beans.PropertyEditorSupport;
import java.text.ParseException;
import java.util.Date;
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.commons.lang.time.DateUtils;
import org.springframework.util.StringUtils;
/**
* Property editor for java.util.Date, supporting multiple custom input formats
* and custom output formats. This class utilizes DateUtils and
* DateFormatUtils of Apache Commons Lang, and has been tested for version 2.4
* but may work with older versions.
*
* It should be noted that the date input formats should be inserted into the
* array based on the length of the string, longest to shortest.
*
* This is not meant to be used as system PropertyEditor but rather as
* locale-specific date editor within custom controller code, parsing
* user-entered number strings into Date properties of beans and rendering
* them in the UI form.
*
* In web MVC code, this editor will typically be registered with
* binder.registerCustomEditor calls in a custom initBinder method.
*
* @author jpreston
* @see java.beans.PropertyEditorSupport
* @see java.util.Date
* @see org.apache.commons.lang.time.DateUtils
* @see org.apache.commons.lang.time.DateFormatUtils
*/
public class MultipleDateEditor extends PropertyEditorSupport {
/**
* The date format used to format a Date into a String
*/
public final static String DEFAULT_OUTPUT_FORMAT = "dd/mm/yyyy";
/**
* The date formats used to parse a String into a Date
*/
public final static String[] DEFAULT_INPUT_FORMATS = [
"dd/mm/yyyy hh:mm:ss",
"dd-mm-yyyy hh:mm:ss",
"dd/mm/yy hh:mm:ss",
"dd-mm-yy hh:mm:ss",
"dd/mm/yyyy",
"dd-mm-yyyy",
"dd/mm/yy",
"dd-mm-yy"
];
/** The format used to convert a Date into a String */
private String outputFormat;
/** An array of date formats used to convert a String into a Date */
private String[] inputFormats;
/** Allow empty strings to be parsed instead of treated as null */
private boolean allowEmpty;
/**
* Create a new MultipleDateEditor instance using the default values
*/
public MultipleDateEditor() {
outputFormat = MultipleDateEditor.DEFAULT_OUTPUT_FORMAT;
inputFormats = MultipleDateEditor.DEFAULT_INPUT_FORMATS;
allowEmpty = false;
}
/**
* Create a new MultipleDateEditor instance using the given date
* input and output formats.
*
* The "allowEmpty" parameter states if an empty String should be allowed for
* parsing, i.e. get interpreted as null value. Otherwise, an
* IllegalArgumentException gets thrown in that case.
*
* @param outputFormat The format used to convert a Date into a String
* @param inputFormats An array of date formats used to convert a String into a Date
*/
public MultipleDateEditor(String outputFormat, String[] inputFormats) {
this.outputFormat = outputFormat;
this.inputFormats = inputFormats;
allowEmpty = false;
}
/**
* Create a new MultipleDateEditor instance using the given date
* input and output formats.
*
* The "allowEmpty" parameter states if an empty String should be allowed for
* parsing, i.e. get interpreted as null value. Otherwise, an
* IllegalArgumentException gets thrown in that case.
*
* @param outputFormat The format used to convert a Date into a String
* @param inputFormats An array of date formats used to convert a String into a Date
* @param allowEmpty Allow empty strings to be parsed instead of treated as null
*/
public MultipleDateEditor(String outputFormat, String[] inputFormats,
boolean allowEmpty) {
this.outputFormat = outputFormat;
this.inputFormats = inputFormats;
this.allowEmpty = allowEmpty;
}
/**
* Format the Date as String, using the specified outputFormat.
*
* If allowEmpty is true (default is false), and the Date is null, an empty
* String will be returned; otherwise it is possible that a NPE or other
* parsing exception will occur.
*
* @return The string value of the Date
*/
@Override
public String getAsText() {
if (allowEmpty && getValue() == null) {
return "";
}
return DateFormatUtils.format((Date) getValue(), outputFormat);
}
/**
* Parse the Date from the given text, using the first matching date format
* specified in the inputFormats array.
*
* If no matching input format is found, an IllegalArgumentException is thrown.
*
* If allowEmpty is true (default is false), and the String is null, the Date
* will be interpreted as null; otherwise an IllegalArgumentException is thrown.
*
* @param text the text to convert into a java.util.Date
* @throws IllegalArgumentException thrown if no matching format is found
*/
@Override
public void setAsText(String text) throws IllegalArgumentException {
try {
if (StringUtils.hasText(text)) {
setValue(DateUtils.parseDate(text, inputFormats));
} else {
if (allowEmpty) {
setValue(null);
} else {
throw new IllegalArgumentException(
"The text specified for parsing is null");
}
}
} catch (ParseException ex) {
throw new IllegalArgumentException("Could not parse text ["
+ text + "] into any available date input formats", ex);
}
}
/**
* If allowEmpty is true (default is false), and the Date is null, an empty
* String will be returned; otherwise it is possible that a NPE or other
* parsing exception will occur.
*
* If allowEmpty is true (default is false), and the String is null, the Date
* will be interpreted as null; otherwise an IllegalArgumentException is thrown.
*
* @return whether empty strings are allowed
*/
public boolean isAllowEmpty() {
return allowEmpty;
}
/**
* If allowEmpty is true (default is false), and the Date is null, an empty
* String will be returned; otherwise it is possible that a NPE or other
* parsing exception will occur.
*
* If allowEmpty is true (default is false), and the String is null, the Date
* will be interpreted as null; otherwise an IllegalArgumentException is thrown.
*
* @param allowEmpty whether empty strings should be allowed
*/
public void setAllowEmpty(boolean allowEmpty) {
this.allowEmpty = allowEmpty;
}
/**
* Get the date formats used to parse a String into a Date
*
* @return The date formats used to parse a String into a Date
*/
public String[] getInputFormats() {
return inputFormats;
}
/**
* Set the date formats used to parse a String into a Date. It should be
* noted that the date formats should be inserted into the array based
* on the length of the format, longest to shortest.
*
*
* @param inputFormats The date formats used to parse a String into a Date
*/
public void setInputFormats(String[] inputFormats) {
this.inputFormats = inputFormats;
}
/**
* Get the format used to convert a Date into a String
*
* @return The format used to convert a Date into a String
*/
public String getOutputFormat() {
return outputFormat;
}
/**
* Set the format used to convert a Date into a String
*
* @param outputFormat The format used to convert a Date into a String
*/
public void setOutputFormat(String outputFormat) {
this.outputFormat = outputFormat;
}
}
2. 新建MultipleDateEditorRegistrar.groovy
package com.myapp
import org.springframework.beans.PropertyEditorRegistrar
import org.springframework.beans.PropertyEditorRegistry
/**
* binding date properties with customer format
* "yyyy-MM-dd HH:mm:ss"
* "yyyy-MM-dd HH:mm"
* "yyyy-MM-dd"
*/
public class MultipleDateEditorRegistrar implements PropertyEditorRegistrar {
public void registerCustomEditors(PropertyEditorRegistry registry) {
registry.registerCustomEditor(Date.class,
new MultipleDateEditor("yyyy-MM-dd HH:mm:ss",
["yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM-dd"] as String[], true));
}
}
3. 注册到spring beans
beans = {
customPropertyEditorRegistrar(com.nazuche.MultipleDateEditorRegistrar)
}
Reference:
http://forum.springsource.org/showthread.php?78118-Multiple-Date-Formats-in-a-Form