14. Приклад 11 — Перетворення та перевірка дат
У новій програмі передбачено введення дат:
![]() |
- у [1], форму введення
- у [2], відповідь, що повертається
Додаток працює аналогічно до функції введення цілих чисел, тому ми прокоментуємо лише ті моменти, які відрізняються.
14.1. Проєкт NetBeans
Проект NetBeans виглядає так:
![]() |
- у [1] — екрани додатка
- [Accueil.JSP]: головна сторінка
- [FormDate.JSP]: форма введення даних
- [ConfirmationFormDate.JSP]: сторінка підтвердження
- у [2], файл повідомлень [messages.properties] та головний файл конфігурації Struts
- у [3]:
- [FormDate.java]: дія, яка відображає та обробляє форму
- [FormDate-validation.xml]: правила перевірки дії [FormDate]. Цей файл делегує ці перевірки моделі.
- [FormDateModel]: модель дії [FormDate]
- [ FormDateModel-validation.xml]: правила перевірки моделі
- [FormDateModel.properties]: файл повідомлень моделі
- [example.xml]: файл додаткової конфігурації Struts
14.2. Конфігурація проєкту
Проєкт налаштовується переважно за допомогою такого файлу [example.xml]:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="example" namespace="/example" extends="struts-default">
<action name="Accueil">
<result name="success">/example/Accueil.JSP</result>
</action>
<action name="FormDate" class="example.FormDate">
<result name="input">/example/FormDate.JSP</result>
<result name="cancel" type="redirect">/example/Accueil.JSP</result>
<result name="success">/example/ConfirmationFormDate.JSP</result>
</action>
</package>
</struts>
Він аналогічний тому, що розглядався для введення цілих чисел.
14.3. Файли повідомлень
Файл [messages.properties] має такий вигляд:
Accueil.titre=Accueil
Accueil.message=Struts 2 - Conversions et validations
Accueil.FormDate=Saisie de dates
Form.titre=Conversions et validations
FormDate.message=Struts 2 - Conversion et validation de dates
FormDate.conseil=Tapez les dates au format JJ/MM/AAAA comme dans 12/10/2008
Form.submitText=Valider
Form.cancelText=Annuler
Form.clearModel=Raz mod\u00e8le
Confirmation.titre=Confirmation
Confirmation.message=Confirmation des valeurs saisies
Confirmation.champ=champ
Confirmation.valeur=valeur
Confirmation.lien=Formulaire de test
xwork.default.invalid.fieldvalue=Valeur invalide pour le champ "{0}".
Файл [FormDateModel.properties] має такий вигляд:
date.format={0,date,dd/MM/yyyy}
date1.prompt=1-Tapez une date au format JJ/MM/AAAA
date1.error=Date erron\u00E9e
date2.prompt=2-Tapez une date au format JJ/MM/AAAA
date2.error=Date erron\u00E9e
date3.prompt=3-Tapez une date >=18/05/2000
date3.error=Date erron\u00E9e
date4.prompt=4-Tapez une date <=20/06/2001
date4.error=Date erron\u00E9e
date5.prompt=5-Tapez une date dans l''intervalle [18/05/2000,20/06/2001]
date5.error=Date errron\u00E9e
date6.prompt=6-Tapez une date dans l''intervalle [18/05/2000,20/06/2001]
date6.error=Date errron\u00E9e
Рядок 1 відіграє важливу роль. Ми повернемося до нього пізніше.
14.4. Форма введення даних
Вигляд [FormDate.JSP] такий:
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title><s:text name="Form.titre"/></title>
<s:head/>
</head>
<body background="<s:url value="/ressources/standard.jpg"/>">
<h2><s:text name="FormDate.message"/></h2>
<h4><s:text name="FormDate.conseil"/></h4>
<s:form name="formulaire" action="FormDate">
<s:textfield name="date1" key="date1.prompt"/>
<s:textfield name="date2" key="date2.prompt" value="%{#parameters['date2']!=null ? #parameters['date2'] : date2==null ? '' :getText('date.format',{date2})}"/>
<s:textfield name="date3" key="date3.prompt" value="%{#parameters['date3']!=null ? #parameters['date3'] : date3==null ? '' :getText('date.format',{date3})}"/>
<s:textfield name="date4" key="date4.prompt" value="%{#parameters['date4']!=null ? #parameters['date4'] : date4==null ? '' :getText('date.format',{date4})}"/>
<s:textfield name="date5" key="date5.prompt" value="%{#parameters['date5']!=null ? #parameters['date5'] : date5==null ? '' :getText('date.format',{date5})}"/>
<s:textfield name="date6" key="date6.prompt"/>
<s:submit key="Form.submitText" method="execute"/>
</s:form>
<br/>
<s:url id="URL" action="FormDate" method="cancel"/>
<s:a href="%{URL}"><s:text name="Form.cancelText"/></s:a>
<br/>
<s:url id="URL" action="FormDate" method="clearModel"/>
<s:a href="%{URL}"><s:text name="Form.clearModel"/></s:a>
</body>
</html>
Рядки з 13 по 18 — це шість полів для введення дат. Поля від date2 до date5 мають складний атрибут value, такий самий, як і для введення дійсних чисел. Оскільки виникли ті самі труднощі, їх було вирішено таким самим чином.
14.5. Вікно підтвердження
Екран підтвердження [ConfirmationFormDate.JSP] виглядає наступним чином:
![]() |
Його код такий:
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title><s:text name="Confirmation.titre"/></title>
<s:head/>
</head>
<body background="<s:url value="/ressources/standard.jpg"/>">
<h2><s:text name="Confirmation.message"/></h2>
<table border="1">
<tr>
<th><s:text name="Confirmation.champ"/></th>
<th><s:text name="Confirmation.valeur"/></th>
</tr>
<tr>
<td><s:text name="date1.prompt"/></td>
<td><s:text name="date1"/></td>
</tr>
<tr>
<td><s:text name="date2.prompt"/></td>
<td>
<s:text name="date.format">
<s:param value="date2"/>
</s:text>
</td>
</tr>
<tr>
<td><s:text name="date3.prompt"/></td>
<td>
<s:text name="date.format">
<s:param value="date3"/>
</s:text>
</td>
</tr>
<tr>
<td><s:text name="date4.prompt"/></td>
<td>
<s:text name="date.format">
<s:param value="date4"/>
</s:text>
</td>
</tr>
<tr>
<td><s:text name="date5.prompt"/></td>
<td>
<s:text name="date.format">
<s:param value="date5"/>
</s:text>
</td>
</tr>
<tr>
<td><s:text name="date6.prompt"/></td>
<td><s:text name="date6"/></td>
</tr>
</table>
<br/>
<s:url id="URL" action="FormDate!input"/>
<s:a href="%{URL}"><s:text name="Confirmation.lien"/></s:a>
</body>
</html>
Вигляд [ConfirmationFormDate.JSP] просто відображає шаблон [FormDateModel]. У рядках 47–49 показано відображення дати. Ми хочемо, щоб це відображення враховувало формат дати. Для цього використовуємо тег <s:text>, який ми до цього використовували для інтернаціоналізації додатка.
Тут використовується ключ повідомлення date.format. Цей ключ міститься у файлі [FormDateModel.properties]:
date.format={0,date,dd/MM/yyyy}
Значення, пов’язане з цим ключем, тут є не повідомленням, а форматом відображення:
- 0 — це параметр, що позначає значення, яке потрібно відобразити. У даному випадку це буде поле date5 шаблону.
- date позначає дату. Раніше для числа використовувався формат number.
- dd/MM/yyyy — це формат дати. У даному випадку нам потрібна форма jj/mm/aaaa. Відповідний формат Java — dd/MM/yyyy (d: день, M: місяць, y: рік)
Тег
<s:text name="date.format">
<s:param value="date5"/>
</s:text>
виводить повідомлення {0, date, dd/MM/yyyy}, де параметр date5 (рядок 2) замінить параметр 0 у форматі. Таким чином, шаблон date5 відображатиметься у форматі дд/мм/рррр.
14.6. Шаблон [FormDateModel]
Поля від date1 до date6 з форми [FormDate.JSP] вставляються в наступний шаблон [FormDateModel]:
package example;
import java.util.Date;
public class FormDateModel {
// конструктор без параметрів
public FormDateModel() {
}
// поля
private String date1;
private Date date2 = new Date();
private Date date3 = new Date();
private Date date4;
private Date date5;
private String date6;
// розмітка шаблону
public void clearModel() {
date1 = null;
date2 = null;
date3 = null;
date4 = null;
date5 = null;
date6 = null;
}
// гетери та сеттери
...
}
- поля date1 та date6 мають тип String
- інші поля мають тип Date
14.7. Перевірка моделі
Перевірка моделі контролюється двома файлами: [FormDate-validation.xml] та [FormDateModel-validation.xml].
Файл [FormDate-validation.xml] делегує перевірки файлу [FormDateModel-validation.xml]:
<!--
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//
EN" "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
-->
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//
EN" "http://localhost:8084/приклад-10/example/xwork-validator-1.0.2.dtd">
<validators>
<field name="model" >
<field-validator type="visitor">
<param name="appendPrefix">false</param>
<message/>
</field-validator>
</field>
</validators>
Ми вже зустрічали цей файл.
Файл [FormDateModel-validation.xml] містить такі правила перевірки:
<!--
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//
EN" "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
-->
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//
EN" "http://localhost:8084/exemple-11/example/xwork-validator-1.0.2.dtd">
<validators>
<field name="date1" >
<field-validator type="requiredstring" short-circuit="true">
<message key="date1.error"/>
</field-validator>
<field-validator type="regex" short-circuit="true">
<param name="expression">^\d{2}/\d{2}/\d{4}$</param>
<param name="trim">true</param>
<message key="date1.error"/>
</field-validator>
</field>
<field name="date2" >
<field-validator type="required" short-circuit="true">
<message key="date2.error"/>
</field-validator>
<field-validator type="conversion" short-circuit="true">
<message key="date2.error"/>
</field-validator>
</field>
<field name="date3" >
<field-validator type="required" short-circuit="true">
<message key="date2.error"/>
</field-validator>
<field-validator type="conversion" short-circuit="true">
<message key="date3.error"/>
</field-validator>
<field-validator type="date" short-circuit="true">
<param name="min">18/05/2000</param>
<message key="date3.error"/>
</field-validator>
</field>
<field name="date4" >
<field-validator type="required" short-circuit="true">
<message key="date2.error"/>
</field-validator>
<field-validator type="conversion" short-circuit="true">
<message key="date4.error"/>
</field-validator>
<field-validator type="date" short-circuit="true">
<param name="max">20/06/2001</param>
<message key="date4.error"/>
</field-validator>
</field>
<field name="date5" >
<field-validator type="required" short-circuit="true">
<message key="date2.error"/>
</field-validator>
<field-validator type="conversion" short-circuit="true">
<message key="date5.error"/>
</field-validator>
<field-validator type="date" short-circuit="true">
<param name="min">18/05/2000</param>
<param name="max">20/06/2001</param>
<message key="date5.error"/>
</field-validator>
</field>
<field name="date6" >
<field-validator type="requiredstring" short-circuit="true">
<message key="date6.error"/>
</field-validator>
<field-validator type="regex" short-circuit="true">
<param name="expression">^\d{2}/\d{2}/\d{4}$</param>
<param name="trim">true</param>
<message key="date6.error"/>
</field-validator>
</field>
</validators>
- правило в рядках 11–20 перевіряє, чи поле введення date1 відповідає шаблону регулярного виразу, що представляє дату у форматі дд/мм/рррр. Слід зауважити, що перевіряється лише відповідність рядка формату дати, але не перевіряється, чи є ця дата дійсною. Так, 29/02/2011 має вигляд дати, але не є дійсною датою.
- Правило в рядках 22–29 перевіряє, чи поле введення date2 є дійсною датою.
- Правило в рядках 31–42 перевіряє, чи поле введення date3 є дійсною датою >=18/05/2000
- правило для рядків 44–55 перевіряє, чи поле введення date4 містить дійсну дату <=20/06/2001.
- правило для рядків 57–69 перевіряє, чи поле введення date5 містить дійсну дату <=20/06/2001 та >=18/05/2000.
- Правило для рядків 71–80 перевіряє, чи поле date6 має формат дати дд/мм/рррр.
Після обробки файлу [FormDateModel-validation.xml] модулем перевірки останній запускає метод validate дії [FormDate], якщо такий існує. Ми розглянемо його разом з усією дією.
14.8. Дія [FormDate]
Дія [FormDate] виглядає наступним чином:
package example;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import org.apache.struts2.interceptor.SessionAware;
import org.apache.struts2.interceptor.validation.SkipValidation;
public class FormDate extends ActionSupport implements ModelDriven, SessionAware {
// конструктор без параметрів
public FormDate() {
}
// модель дії
public Object getModel() {
if (session.get("model") == null) {
session.put("model", new FormDateModel());
}
return session.get("model");
}
@SkipValidation
public String clearModel() {
// очищення моделі
((FormDateModel) getModel()).clearModel();
// результат
return INPUT;
}
public String cancel() {
// очищення моделі
((FormDateModel) getModel()).clearModel();
// результат
return "cancel";
}
// SessionAware
Map<String, Object> session;
public void setSession(Map<String, Object> session) {
this.session = session;
}
// перевірка
@Override
public void validate() {
// форматування дат
SimpleDateFormat formateurDate = new SimpleDateFormat("dd/MM/yyyy");
formateurDate.setLenient(false);
// чи введено дійсну дату1?
if (getFieldErrors().get("date1") == null) {
// перевірка дійсності дати
try {
formateurDate.parse(((FormDateModel) getModel()).getDate1());
} catch (Exception e) {
addFieldError("date1", getText("date1.error"));
}
}
// Чи введено правильну дату 6?
if (getFieldErrors().get("date6") == null) {
Date d = null;
try {
// перевірка дійсності дати
d = formateurDate.parse(((FormDateModel) getModel()).getDate6());
// перевірка меж
if (d.after(formateurDate.parse("20/06/2001")) || d.before(formateurDate.parse("18/05/2000"))) {
addFieldError("date6", getText("date6.error"));
return;
}
} catch (Exception e) {
addFieldError("date6", getText("date6.error"));
return;
}
}
}
}
Акція [FormDate] побудована за тим самим зразком, що й акція [FormInt]. Ми прокоментуємо лише метод validate. Нагадаємо, що метод validate виконується після обробки файлу перевірки [FormDateModel-validation.xml] і перед виконанням методу execute.
- Метод validate завершує перевірку дат, виконану методами date1 та date6. Файл перевірки [FormDateModel-validation.xml] перевірив, чи введені рядки мають вигляд дати. Тепер перевіряється, чи дійсно це дійсні дати. Також нагадуємо, що date1 та date6 були єдиними двома полями шаблону, що мали тип String.
- рядок 50: створюється формат дати дд/мм/рррр, щоб перевірити, чи рядки цього типу дійсно є дійсними датами.
- рядок 51: setLenient(false) дозволяє уникнути ситуації, коли недійсна дата 32/01/2012 інтерпретується як дійсна дата 01/02/2012.
- рядок 53: date1 перевіряється лише в тому випадку, якщо попередні перевірки не виявили помилок у цьому полі.
- рядок 56: перевіряється, чи date1 є дійсною датою у форматі дд/мм/рррр.
- рядок 58: якщо це не так, до поля date1 додається повідомлення про помилку.
- рядок 62: date6 вважається дійсним лише в тому випадку, якщо це поле пройшло попередні перевірки.
- рядок 66: перевіряється, чи date6 є дійсною датою
- рядок 68: якщо date6 <18/05/2000 або date6>20/06/2001, то date6 є некоректним.
14.9. Останні деталі
Попередня форма містить недоліки, як показано в наступному прикладі:
![]() |
- у [1] введено недійсну дату
- у [2] вона була прийнята. Враховувалися лише перші символи дд/мм/рррр.
Поля від date2 до date5, пов’язані з шаблонами типу Date, мають цю проблему. Знову ж таки, можливо, я щось пропустив у документації. Поля date1 та date6, пов’язані з шаблонами типу String, не мають цієї проблеми.



