Русский English Тэги View Sergey Zolotaryov's profile on LinkedIn Вход
Одно сообщение на поле в Spring MVC
Постоянная ссылка 11-04-2008 anydoby java

У нас в проекте возникла забавная проблемка. У поля формы тип java.util.Date. Сначала я его сделал строковым, валидировал регулярным выражением и потом каждый раз при доставании создавал объект даты. Сами понимаете, дело мутное и неприятное, особенно если таких полей много. Выход нашелся довольно простой - написал я свой PropertyEditor для дат, и прикрепил его к форме


package com.anydoby.web;


import java.beans.PropertyEditorSupport;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;

/**
 * Supports transformation of dates to strings and vice versa using the specified date format. If
 * string representation could not be parsed correctly, returns null date.
 * 
 * @author SergeyZ
 * 
 */
public class DateEditor extends PropertyEditorSupport {

  private final String datePattern;
  private final Pattern textValidator;


  public DateEditor(String datePattern, Pattern textValidator) {
    this.datePattern = datePattern;
    this.textValidator = textValidator;
  }


  @Override
  public String getAsText() {
    SimpleDateFormat format = new SimpleDateFormat(datePattern);
    Object value = getValue();
    if (value == null) {
      return null;
    }
    String string = format.format(value);
    return string;
  }


  @Override
  public void setAsText(String text) throws IllegalArgumentException {
    if (StringUtils.isBlank(text)) {
      setValue(null);
    } else {
      if (!textValidator.matcher(text).matches()) {
        throw new IllegalArgumentException("Invalid pattern");
      }

      SimpleDateFormat format = new SimpleDateFormat(datePattern);
      format.setLenient(false);

      try {
        Date parse = format.parse(text);
        setValue(parse);
      } catch (ParseException e) {
        throw new IllegalArgumentException(e);
      }
    }
  }

}


    Pattern datePattern = Pattern.compile("\\d{1,2}/\\d{1,2}/\\d{4}");
    DateEditor dateEditor = new DateEditor("dd/MM/yyyy", datePattern);
    binder.registerCustomEditor(java.util.Date.class, dateEditor);

Все работает замечательно - Spring конвертирует параметр в дату и присваивает в нужное место. Вот только одна проблема - если дату ввести в неправильном формате, то появляется два сообщения об ошибке - первая от байндера, а вторая от валидатора формы, о том, что поле пустое. Заказчику это не понравится. Начали думать и ничего лучшего не нашли как просто не показывать более одного сообщения на поле. Для этого пришлось написать простенький тэг:


package com.anydoby.util;


import javax.servlet.jsp.JspException;

import org.apache.commons.lang.StringUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.servlet.support.BindStatus;
import org.springframework.web.servlet.tags.form.ErrorsTag;
import org.springframework.web.servlet.tags.form.TagWriter;

/**
 * This extension to spring tags will show only first error of every field it displays.
 * @author SergeyZ
 * 
 */
public class FirstErrorTag extends ErrorsTag {

  private static final long serialVersionUID = 716823632508216981L;


  @Override
  protected void renderDefaultContent(TagWriter tagWriter) throws JspException {
    tagWriter.startTag(getElement());
    writeDefaultAttributes(tagWriter);
    String delimiter = ObjectUtils.getDisplayString(evaluate("delimiter", getDelimiter()));
    BindStatus status = getBindStatus();
    String path = status.getPath();
    if (StringUtils.isBlank(path)) {
      String[] errorMessages = status.getErrorMessages();
      for (int i = 0; i < errorMessages.length; i++) {
        String errorMessage = errorMessages[i];
        if (i > 0) {
          tagWriter.appendValue(delimiter);
        }
        tagWriter.appendValue(getDisplayString(errorMessage));
      }
      tagWriter.endTag();
    } else {
      String[] errorMessages = status.getErrorMessages();
      if (errorMessages.length > 0) {
        tagWriter.appendValue(getDisplayString(errorMessages[0]));
      }
      tagWriter.endTag();
    }
  }

}

и taglib.tld


<!DOCTYPE taglib PUBLIC
   "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
   "http://java.sun.com/j2ee/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
    <tlib-version>1.0</tlib-version>
    <jsp-version>2.0</jsp-version>
    <short-name>a</short-name>
    <uri>http://anydoby.com/tags</uri>
    <tag>
        <name>errors</name>
        <tag-class>com.anydoby.util.FirstErrorTag</tag-class>
        <body-content>JSP</body-content>
        <description>Renders field errors in an HTML 'span' tag.</description>
        <variable>
            <name-given>messages</name-given>
            <variable-class>java.util.List</variable-class>
        </variable>
        <attribute>
            <name>path</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
            <description>Path to errors object for data binding</description>
        </attribute>
        <attribute>
            <name>id</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
            <description>HTML Standard Attribute</description>
        </attribute>
        <attribute>
            <name>htmlEscape</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
            <description>Enable/disable HTML escaping of rendered values.</description>
        </attribute>
        <attribute>
            <name>delimiter</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
            <description>Delimiter for displaying multiple error messages. Defaults to the br tag.</description>
        </attribute>
        <attribute>
            <name>cssClass</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
            <description>Equivalent to "class" - HTML Optional Attribute</description>
        </attribute>
        <attribute>
            <name>cssStyle</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
            <description>Equivalent to "style" - HTML Optional Attribute</description>
        </attribute>
        <attribute>
            <name>lang</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
            <description>HTML Standard Attribute</description>
        </attribute>
        <attribute>
            <name>title</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
            <description>HTML Standard Attribute</description>
        </attribute>
        <attribute>
            <name>dir</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
            <description>HTML Standard Attribute</description>
        </attribute>
        <attribute>
            <name>tabindex</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
            <description>HTML Standard Attribute</description>
        </attribute>
        <attribute>
            <name>onclick</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
            <description>HTML Event Attribute</description>
        </attribute>
        <attribute>
            <name>ondblclick</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
            <description>HTML Event Attribute</description>
        </attribute>
        <attribute>
            <name>onmousedown</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
            <description>HTML Event Attribute</description>
        </attribute>
        <attribute>
            <name>onmouseup</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
            <description>HTML Event Attribute</description>
        </attribute>
        <attribute>
            <name>onmouseover</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
            <description>HTML Event Attribute</description>
        </attribute>
        <attribute>
            <name>onmousemove</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
            <description>HTML Event Attribute</description>
        </attribute>
        <attribute>
            <name>onmouseout</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
            <description>HTML Event Attribute</description>
        </attribute>
        <attribute>
            <name>onkeypress</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
            <description>HTML Event Attribute</description>
        </attribute>
        <attribute>
            <name>onkeyup</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
            <description>HTML Event Attribute</description>
        </attribute>
        <attribute>
            <name>onkeydown</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
            <description>HTML Event Attribute</description>
        </attribute>
        <attribute>
            <name>element</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
            <description>Specifies the HTML element that is used to render the enclosing errors.</description>
        </attribute>
    </tag>
</taglib>

Добавить комментарий

Предыдущая статья Дубликаты в Hibernate Следующая статья Подлые даты в Mysql