11. Приклад 09 — Перетворення та перевірка цілих чисел
Тепер ми розглянемо серію прикладів щодо перетворення та перевірки параметрів форми. Проблема полягає в наступному. Щоб обробити URL у формі [http://machine:port/.../Action], контролер [FilterDispatcher] створює екземпляр класу, який реалізує запитувану дію, і виконує один із його методів — за замовчуванням метод із назвою execute. Виклик цього методу execute проходить через низку інтерцепторів:
![]() |
Список перехоплювачів визначено у файлі [struts-default.xml] у кореневому каталозі архіву [struts2-core.jar]. Список перехоплювачів, визначений у цьому файлі, є таким:
<interceptor-stack name="defaultStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="debugging"/>
<interceptor-ref name="scopedModelDriven"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="multiselect"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params">
<param name="excludeParams">dojo\..*,^struts\..*</param>
</interceptor-ref>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
</interceptor-stack>
Серед інтерцепторів є один, який відповідає за вставку в дію значень valeuri параметрів parami, що супроводжують запит у формі parami=valeuri. Відомо, що значення valeuri буде вставлено в поле parami дії за допомогою методу setParami, якщо воно існує. В іншому випадку вставлення не відбувається і про помилку не повідомляється.
Рядок parami=valeuri є символьним рядком. До цього моменту введення valeuri здійснювалося в поля parami типу String:
Введення рядка valeuri як значення рядка parami не викликало проблем. Якщо parami не є типом String, то valeuri має бути перетворено з типу parami у тип Ti. У цьому полягає проблема перетворення. Наприклад, ми хочемо, щоб вік був цілим числом, і запишемо в дії:
Крім того, може знадобитися обмежити вік у межах від 1 до 150. Тут виникає проблема перевірки. Параметр parami може бути перетворений у правильний тип, але при цьому не відповідати вимогам. Отже, потрібно пройти два етапи. Якщо повернутися до схеми обробки запиту:
![]() |
Два інтерцептори відповідатимуть відповідно за перетворення та перевірку параметрів. Якщо один із етапів завершиться невдало, запит не пройде далі до дії (червоний контур вище). Форма, з якої були надіслані помилкові параметри, відобразиться знову з повідомленнями про помилки.
Інтерцептори, що відповідають за перетворення та перевірку параметрів, — це інтерцептори conversionError та validation у рядках 19 та 20 списку інтерцепторів, наведеного вище. Зверніть увагу на рядки 20–22: інтерцептор validation не застосовується, якщо викликаний метод є одним із методів input, back, cancel, browse. Ми скористаємося цією властивістю пізніше.
Почнемо з вивчення перетворення та перевірки цілих чисел. Ми приділимо цьому першому прикладу достатньо часу, оскільки перевірка передбачає врахування багатьох елементів. Ознайомившись із ними, ми швидше пройдемо наступні приклади.
11.1. Форма
![]() |
- у [1], форма введення даних
- у [2] — результат перевірки без введення значень
11.2. Проєкт NetBeans
Проект NetBeans виглядає наступним чином:
![]() |
- у [1] — три види додатка
- у [2] — вихідні коди, файли інтернаціоналізованих повідомлень та файли конфігурації Struts.
11.3. Налаштування Struts
Додаток налаштовується за допомогою файлів [struts.xml] та [example.xml].
Файл [struts.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>
<constant name="struts.custom.i18n.resources" value="messages" />
<include file="example/example.xml"/>
<package name="default" namespace="/" extends="struts-default">
<default-action-ref name="index" />
<action name="index">
<result type="redirectAction">
<param name="actionName">Accueil</param>
<param name="namespace">/example</param>
</result>
</action>
</package>
</struts>
У рядках 12–18 дія [/example/Accueil] визначена як дія за замовчуванням, якщо користувач не вказав іншу.
Файл [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="FormInt" class="example.FormInt">
<result name="input">/example/FormInt.JSP</result>
<result name="cancel" type="redirect">/example/Accueil.JSP</result>
<result name="success">/example/ConfirmationFormInt.JSP</result>
</action>
</package>
</struts>
- рядки 8–10: дія [Accueil] викликає відображення подання [Accueil.JSP]
- рядок 11: дія [FormInt] за замовчуванням викликає метод execute класу [example.FormInt]. Ми побачимо, що будуть виконані ще два методи: input та cancel. Ці методи будуть вказані в параметрах запиту.
- рядок 12: ключ input призведе до відображення подання [FormInt.JSP] (рядок 5). Це подання відповідає формі.
- рядок 13: ключ cancel буде повернений методом cancel, пов’язаним із посиланням [Annuler]. Отже, після перенаправлення (type=redirect) буде відображено вигляд [Accueil.JSP].
- Рядок 14: ключ success повертається методом execute дії [FormInt]. Якщо запит доходить до методу execute, це означає, що він успішно пройшов усі перехоплювачі, зокрема ті, що перевіряють правильність параметрів. Метод execute просто повертає ключ success, який відобразить вікно підтвердження [ConfirmationInt.JSP].
11.4. Файли повідомлень
Файл [messages.properties] має такий вигляд:
Accueil.titre=Accueil
Accueil.message=Struts 2 - Conversions et validations
Accueil.FormInt=Saisie de nombres entiers
Form.titre=Conversions et validations
FormInt.message=Struts 2 - Conversion et validation de nombres entiers
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
Окрім цього файлу, у поданнях використовується такий файл [FormInt.properties]:
int1.prompt=1-Nombre entier positif de deux chiffres
int1.error=Tapez un nombre entier positif de deux chiffres
int2.prompt=2-Nombre entier
int2.error=Tapez un nombre entier
int3.prompt=3-Nombre entier >=-1
int3.error=Tapez un nombre entier >=-1
int4.prompt=4-Nombre entier <=10
int4.error=Tapez un nombre entier <=10
int5.prompt=5-Nombre entier dans l''intervalle [1,10]
int5.error=Tapez un nombre entier dans l''intervalle [1,10]
int6.prompt=6-Nombre entier dans l''intervalle [2,20]
int6.error=Tapez un nombre entier dans l''intervalle [2,20]
Файл [FormInt.properties] використовується лише тоді, коли дією, що згенерувала перегляд, є дія [FormInt]. Це спосіб сегментації файлу повідомлень, якщо він занадто великий. Міжнародну локалізацію повідомлень дії «Action» здійснюють у файлі [Action.properties].
11.5. Види та дії
Тепер розглянемо перегляди та дії додатка. Згідно з конфігурацією додатка:
<?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="FormInt" class="example.FormInt">
<result name="input">/example/FormInt.JSP</result>
<result name="cancel" type="redirect">/example/Accueil.JSP</result>
<result name="success">/example/ConfirmationFormInt.JSP</result>
</action>
</package>
</struts>
бачимо, що є три подання [Accueil.JSP, FormInt.JSP, ConfirmationFormInt.JSP] та дві дії [Accueil, FormInt].
11.5.1. Accueil.JSP
Вигляд [Accueil.JSP] має такий вигляд:
![]() |
Його код такий:
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title><s:text name="Accueil.titre"/></title>
<s:head/>
</head>
<body background="<s:url value="/ressources/standard.jpg"/>">
<h2><s:text name="Accueil.message"/></h2>
<ul>
<li>
<s:url id="URL" action="FormInt!input"/>
<s:a href="%{URL}"><s:text name="Accueil.FormInt"/></s:a>
</li>
</ul>
</body>
</html>
Посилання в рядку 14 генерує такий HTML-код:
<a href="<a href="view-source:http://localhost:8084/exemple-09/example/FormInt.action">/exemple-09/example/FormInt!input.action</a>">Saisie de nombres entiers</a>
Отже, це посилання на дію [FormInt], налаштовану в [example.xml] наступним чином:
<action name="FormInt" class="example.FormInt">
<result name="input">/example/FormInt.JSP</result>
<result name="cancel" type="redirect">/example/Accueil.JSP</result>
<result name="success">/example/ConfirmationFormInt.JSP</result>
</action>
Отже, клік на посилання створить екземпляр класу [example.FormInt] і виконає його метод input. Оскільки такого методу не існує, буде виконано метод input батьківського класу ActionSupport. Цей метод нічого не робить, окрім як повертає ключ input. Отже, буде відображено представлення [/example/FormInt.JSP].
Крім того, метод input є одним із методів, які ігноруються перехоплювачем перевірки:
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
Тому перевірка параметрів не відбуватиметься. Це важливо, оскільки тут немає параметрів, а пізніше ми побачимо, що правила перевірки вимагатимуть наявності шести параметрів.
11.5.2. Дія [FormInt]
Дія [FormInt] пов’язана з наступним класом [FormInt]:
package example;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import java.util.Map;
import org.apache.struts2.interceptor.SessionAware;
import org.apache.struts2.interceptor.validation.SkipValidation;
public class FormInt extends ActionSupport implements ModelDriven, SessionAware {
// конструктор без параметрів
public FormInt() {
}
// модель дії
public Object getModel() {
if (session.get("model") == null) {
session.put("model", new FormIntModel());
}
return session.get("model");
}
public String cancel() {
// очищення моделі
((FormIntModel) getModel()).clearModel();
// результат
return "cancel";
}
@SkipValidation
public String clearModel() {
// обнулення моделі
((FormIntModel) getModel()).clearModel();
// результат
return INPUT;
}
// SessionAware
private Map<String, Object> session;
public void setSession(Map<String, Object> session) {
this.session = session;
}
// перевірка
@Override
public void validate() {
// чи введено int6 правильно?
if (getFieldErrors().get("int6") == null) {
int int6 = Integer.parseInt(((FormIntModel) getModel()).getInt6());
if (int6 < 2 || int6 > 20) {
addFieldError("int6", getText("int6.error"));
}
}
}
}
Ми будемо коментувати цей код у міру необхідності. А поки що:
- у рядку 9 клас [FormInt] реалізує два інтерфейси:
- ModelDriven, який має лише один метод, та getModel у рядку 16
- SessionAware, який має лише один метод — setSession у рядку 41
- рядки 16–21: реалізація інтерфейсу ModelDriven. Нагадаємо, що цей інтерфейс дозволяє винести модель подання в зовнішній клас, у даному випадку — у наступний клас [FormIntModel]:
package example;
public class FormIntModel {
// конструктор без параметрів
public FormIntModel() {
}
// поля форми
private String int1;
private Integer int2;
private Integer int3;
private Integer int4;
private Integer int5;
private String int6;
// поле «raz» шаблону
public void clearModel(){
int1=null;
int2=null;
int3=null;
int4=null;
int5=null;
int6=null;
}
// геттери та сеттери
...
}
Модель [FormIntModel] має шість полів, що відповідають шести полям введення даних у подачі [FormInt.JSP]. Саме ці шість полів прийматимуть відправлені значення. Чотири з них мають тип Integer. Тому для них постане проблема перетворення String --> Integer. Метод clearModel дозволяє скинути модель.
Повернемося до методу getModel дії [FormInt]:
// модель дії
public Object getModel() {
if (session.get("model") == null) {
session.put("model", new FormIntModel());
}
return session.get("model");
}
- рядки 3–5: модель шукається в сесії. Якщо її там немає, створюється екземпляр моделі та поміщається в сесію.
- рядок 6: хоча екземпляр дії створюється при кожному новому запиті до дії, її модель залишається в сесії.
Ми бачимо, що клас не визначає метод input, але батьківський клас має такий метод, який повертає ключ input. Виконання цього методу призводить до відображення подання [FormInt.JSP], яке ми зараз демонструємо.
11.5.3. Вигляд [FormInt.JSP]
Вигляд [FormInt.JSP] має такий вигляд:
![]() |
- у [1] — порожня форма
- у [2] — форма після перевірки на наявність помилкових параметрів.
Його код такий:
<%@ 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="FormInt.message"/></h2>
<s:form name="formulaire" action="FormInt">
<s:textfield name="int1" key="int1.prompt"/>
<s:textfield name="int2" key="int2.prompt"/>
<s:textfield name="int3" key="int3.prompt"/>
<s:textfield name="int4" key="int4.prompt"/>
<s:textfield name="int5" key="int5.prompt"/>
<s:textfield name="int6" key="int6.prompt"/>
<s:submit key="Form.submitText" method="execute"/>
</s:form>
<br/>
<s:url id="URL" action="FormInt" method="cancel"/>
<s:a href="%{URL}"><s:text name="Form.cancelText"/></s:a>
<br/>
<s:url id="URL" action="FormInt" method="clearModel"/>
<s:a href="%{URL}"><s:text name="Form.clearModel"/></s:a>
</body>
</html>
- рядки 12–17: шість полів введення, що відповідають шести полям шаблону [FormIntModel] дії [FormInt]. Під час відображення подання саме атрибути value полів введення використовуються для значення, що відображається цими полями. У разі відсутності атрибута value використовується атрибут name.
- рядок 12: поле введення пов’язане (name) з полем int1 дії або її шаблону, якщо дія реалізує інтерфейс ModelDriven. Саме так і є в даному випадку. Це також стосується всіх інших полів.
- рядок 18: кнопка [Valider] відправляє введені дані до дії [FormInt], визначеної в рядку 11. Буде виконано її метод execute.
- рядки 21–22: посилання [Annuler] виконує метод [FormInt.cancel].
- рядки 24–25: посилання [Raz modèle] виконує метод [FormInt.clearModel].
11.5.4. Вигляд [ConfirmationFormInt.JSP]
![]() |
Він відображається, коли всі дані, введені у форму [FormInt.JSP], є правильними.
- У [1] відбуваються записи дійсних значень
- у [2] — сторінка підтвердження
Код подання [ConfirmationInt.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="int1.prompt"/></td>
<td><s:property value="int1"/></td>
</tr>
<tr>
<td><s:text name="int2.prompt"/></td>
<td><s:property value="int2"/></td>
</tr>
<tr>
<td><s:text name="int3.prompt"/></td>
<td><s:property value="int3"/></td>
</tr>
<tr>
<td><s:text name="int4.prompt"/></td>
<td><s:property value="int4"/></td>
</tr>
<tr>
<td><s:text name="int5.prompt"/></td>
<td><s:property value="int5"/></td>
</tr>
<tr>
<td><s:text name="int6.prompt"/></td>
<td><s:property value="int6"/></td>
</tr>
</table>
<br/>
<s:url id="URL" action="FormInt" method="input"/>
<s:a href="%{URL}"><s:text name="Confirmation.lien"/></s:a>
</body>
</html>
Щоб зрозуміти цей код, слід пам’ятати, що подання відображається після інстанціювання класу [FormInt]. Отже, поля цього класу та його моделі [FormIntModel] доступні для подання.
- рядки 16–38: відображаються значення шести полів
- рядки 42–43: посилання на дію [FormInt]. Код, згенерований для цього посилання, такий:
<a href="/exemple-09/example/FormInt!input.action">Formulaire de test</a>
Особливий код URL у посиланні вказує, що метод input дії [FormInt] повинен обробити запит. Нагадаємо конфігурацію дії [FormInt] у [example.xml]:
<action name="FormInt" class="example.FormInt">
<result name="input">/example/FormInt.JSP</result>
<result name="cancel" type="redirect">/example/Accueil.JSP</result>
<result name="success">/example/ConfirmationFormInt.JSP</result>
</action>
Метод input класу [FormInt] буде методом його батьківського класу ActionSupport. Виконання методу input класу [FormInt] відбувається після виконання перехоплювачів
![]() |
Відомо, що виклик методу input ігнорується перехоплювачем перевірки. Отже, перевірка не відбудеться.
Відображається вікно [FormInt.JSP]:
![]() |
У [2] поля введення відновлюють свої значення, введені користувачем. Це може здаватися нормальним, але це не так. Оскільки було викликано дію [FormInt], було створено екземпляр пов’язаного класу [FormInt]. Оскільки цей клас реалізує інтерфейс ModelDriven, було викликано його метод getModel:
// модель дії
public Object getModel() {
if (session.get("model") == null) {
session.put("model", new FormIntModel());
}
return session.get("model");
}
Бачимо, що модель дії отримується із сесії. На попередньому етапі ця модель була оновлена за допомогою відправлених значень. Отже, ми отримуємо ці значення. Якби ми не зберегли модель у сесії, у подання [FormInt.JSP] було б шість порожніх полів.
11.5.5. Дія [FormInt!clearModel]
Дія [Formint!clearModel] запускається при натисканні на посилання [Raz modèle]:
![]() |
- в [1] — форма після введення неправильних даних
- в [2] — форма після кліка на посилання [Raz modèle].
Метод [FormInt.clearModel] виглядає наступним чином:
@SkipValidation
public String clearModel() {
// скидання моделі
((FormIntModel) getModel()).clearModel();
// результат
return INPUT;
}
- рядок 1: перевірка не потрібна. Для позначення цього використовується позначення @SkipValidation. У такому разі перехоплювач перевірки не виконуватиме перевірки.
- рядок 4: виконується метод [FormIntModel].clearModel. Ми вже зустрічали його раніше. Він скидає значення шести полів моделі до null.
- рядок 7: метод повертає ключ input.
Якщо повернутися до конфігурації дії [FormInt]:
<action name="FormInt" class="example.FormInt">
<result name="input">/example/FormInt.JSP</result>
<result name="cancel" type="redirect">/example/Accueil.JSP</result>
<result name="success">/example/ConfirmationFormInt.JSP</result>
</action>
бачимо, що ключ input призведе до відображення подання [FormInt.JSP]. Воно відображає шість полів моделі. Оскільки ці поля знаходяться в null, у поданні відображаються шість порожніх полів [2].
11.5.6. Дія [FormInt!cancel]
Дія [Formint!cancel] запускається при натисканні на посилання [Annuler]:
![]() |
- в [1] — форма після введення неправильних даних
- в [2] — головна сторінка після натискання на посилання [Annuler].
Метод [FormInt.cancel] виглядає так:
public String cancel() {
// очищення моделі
((FormIntModel) getModel()).clearModel();
// результат
return "cancel";
}
- рядок 1: зверніть увагу, що перед методом немає анотації SkipValidation. Адже ми не хочемо виконувати перевірки. Метод cancel входить до числа чотирьох методів input, back, cancel, browse, які ігноруються перехоплювачем перевірки, тому анотація SkipValidation також не потрібна.
- рядок 3: він очищає шаблон
- рядок 5: повертає ключ cancel
Якщо повернутися до конфігурації дії [FormInt]:
<action name="FormInt" class="example.FormInt">
<result name="input">/example/FormInt.JSP</result>
<result name="cancel" type="redirect">/example/Accueil.JSP</result>
<result name="success">/example/ConfirmationFormInt.JSP</result>
</action>
бачимо, що ключ cancel відобразить вигляд [Accueil.JSP] після перенаправлення клієнта. Саме це показує вигляд [2].
11.6. Процес перевірки
Тепер розглянемо перевірку шести полів введення, пов’язаних із наступними шістьма полями моделі:
// поля форми
private String int1;
private Integer int2;
private Integer int3;
private Integer int4;
private Integer int5;
private String int6;
Ця перевірка відбувається щоразу, коли створюється екземпляр класу [FormInt] і виконуваний метод не ігнорується перехоплювачем перевірки. Вона керується:
- файлом [FormInt-validation.xml], якщо він існує в тій самій папці, що й клас [FormInt]
- методом [FormInt.validate], якщо він існує.
![]() |
- у [1]: файл [xwork-validator-1.0.2.dtd], необхідний для процесу перевірки
- у [2]: файл [FormInt-validation.xml] у тій самій папці, що й клас [FormInt]
Файл [FormInt-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-09/example/xwork-validator-1.0.2.dtd">
<validators>
<field name="int1" >
<field-validator type="requiredstring" short-circuit="true">
<message key="int1.error"/>
</field-validator>
<field-validator type="regex" short-circuit="true">
<param name="expression">^\d{2}$</param>
<param name="trim">true</param>
<message key="int1.error"/>
</field-validator>
</field>
<field name="int2" >
...
</field>
...
</validators>
- у [3] — URL з DTD (Document Type Definition) файлу валідації. Доступ до нього має бути забезпечений, інакше файл валідації не використовується.
- [7] замість URL у DTD, що використовується додатком. Ми розмістили файл DTD у папці [example] проекту exemple-09 [1], щоб мати його під рукою навіть у разі відсутності доступу до Інтернету.
- рядки 11–20: визначають умови перевірки параметра int1, пов’язаного з полем int1 у моделі.
Тег із назвою int1 у формі має такий вигляд:
<s:textfield name="int1" key="int1.prompt" />
Поле int1 шаблону оголошується наступним чином:
private String int1;
- рядки 12–14: перевіряють, чи існує параметр int1 (а не null) і чи його довжина не дорівнює нулю. Якщо це не так, до поля введення додається повідомлення про помилку. Він визначений у [FormInt.properties] наступним чином:
int1.error=Tapez un nombre entier positif de deux chiffres
У разі помилки процес перевірки параметра int1 припиняється (short-circuit=true).
- рядки 15–19: правильність параметра int1 перевіряється за допомогою регулярного виразу.
- рядок 16: регулярний вираз, у даному випадку — 2 цифри без будь-яких символів перед та після них.
- рядок 17: перед порівнянням із регулярним виразом з параметра int1 видаляються пробіли на початку та в кінці.
- рядок 18: можливе повідомлення про помилку. Воно таке саме, як і для попереднього валідатора.
Подивимося, що з цього вийде:
![]() |
- в [1] — помилкове значення для поля int1
- у [2] — сторінка, що повертається:
- повідомлення про помилку ключа int1.error присутнє. Воно виділене червоним кольором.
- назва поля з помилкою також виділена червоним кольором.
- Помилкове значення відображається знову. Це слід враховувати, оскільки це не обов’язково є стандартною поведінкою.
Ми бачили, що перевірка форми викликає виконання методу [FormInt].execute, якщо запит проходить усі перехоплювачі, зокрема перехоплювач перевірки:
![]() |
- якщо запит доходить до методу execute дії, то, як ми вже бачили, він повертає контролеру ключ success.
- якщо перехоплювач валідації зупиняє запит через те, що перевірені параметри є недійсними, то до контролера повертається ключ input.
Оскільки дія [FormInt] налаштована наступним чином:
<action name="FormInt" class="example.FormInt">
<result name="input">/example/FormInt.JSP</result>
<result name="cancel" type="redirect">/example/Accueil.JSP</result>
<result name="success">/example/ConfirmationFormInt.JSP</result>
</action>
то при помилці валідації відображається представлення [FormInt.JSP], тобто форма. Теги Struts побудовані таким чином, що відображають можливі повідомлення про помилки, які до них прив’язані. Отже, ми отримаємо вигляд [FormInt.JSP] із повідомленнями про помилки, прив’язаними до різних полів. Саме це показує вигляд [2].
Тепер розглянемо перевірку поля int2, яке в моделі оголошено наступним чином:
private Integer int2;
Перевірка поля int2 у [FormInt-validation.xml] виглядає так:
<field name="int2" >
<field-validator type="required" short-circuit="true">
<message key="int2.error"/>
</field-validator>
<field-validator type="conversion" short-circuit="true">
<message key="int2.error"/>
</field-validator>
</field>
- рядки 2–4: перевіряють, чи існує параметр int2.
- рядки 5–7: перевіряють, чи можливе перетворення String --> Integer
- рядки 3, 6: повідомлення про помилку ключа int2.error має такий вигляд:
int2.error=Tapez un nombre entier
Перевірка полів Integer та int3 моделі в [FormInt-validation.xml] виглядає так:
<field name="int3" >
<field-validator type="required" short-circuit="true">
<message key="int3.error"/>
</field-validator>
<field-validator type="conversion" short-circuit="true">
<message key="int2.error"/>
</field-validator>
<field-validator type="int" short-circuit="true">
<param name="min">-1</param>
<message key="int3.error"/>
</field-validator>
</field>
- рядки 8–11: перевіряють, чи поле int3 є цілим числом >=-1
- рядки 3, 7: повідомлення про помилку ключа int3.error має такий вигляд:
int3.error=Tapez un nombre entier >=-1
Перевірка полів Integer та int4 шаблону в [FormInt-validation.xml] виглядає так:
<field name="int4" >
<field-validator type="required" short-circuit="true">
<message key="int4.error"/>
</field-validator>
<field-validator type="conversion" short-circuit="true">
<message key="int2.error"/>
</field-validator>
<field-validator type="int" short-circuit="true">
<param name="max">10</param>
<message key="int4.error"/>
</field-validator>
</field>
- рядки 8–11: перевіряють, чи є він цілим числом <=10
- рядки 3, 7: повідомлення про помилку ключа int4.error має такий вигляд:
int4.error=Tapez un nombre entier <=10
Перевірка поля Integer int5 моделі в [FormInt-validation.xml] виглядає наступним чином:
<field name="int5" >
<field-validator type="required" short-circuit="true">
<message key="int5.error"/>
</field-validator>
<field-validator type="conversion" short-circuit="true">
<message key="int2.error"/>
</field-validator>
<field-validator type="int" short-circuit="true">
<param name="min">1</param>
<param name="max">10</param>
<message key="int5.error"/>
</field-validator>
</field>
- рядки 5–9: перевіряють, чи є значення цілим числом у діапазоні [1, 10].
- рядки 3, 8: повідомлення про помилку ключа int5.error має такий вигляд:
int5.error=Tapez un nombre entier dans l''intervalle [1,10]
Перевірка полів String та int6 шаблону в [FormInt-validation.xml] виглядає так:
<field name="int6" >
<field-validator type="requiredstring" short-circuit="true">
<message key="int6.error"/>
</field-validator>
<field-validator type="regex" short-circuit="true">
<param name="expression">^\d{1,2}$</param>
<param name="trim">true</param>
<message key="int6.error"/>
</field-validator>
</field>
- рядки 5–9: перевіряють, чи int6 є рядком із 2 цифр.
- рядок 3, 8: повідомлення про помилку ключа int6.error має такий вигляд:
int6.error=Tapez un nombre entier dans l''intervalle [2,20]
Попередня перевірка не перевіряє, чи параметр int6 є цілим числом у діапазоні [2,20]. Ця перевірка виконується в методі [FormInt].validate, який запускається після виконання файлу [FormInt-validation.xml]. Цей метод виглядає так:
// перевірка
@Override
public void validate() {
// чи введено правильне значення int6?
if (getFieldErrors().get("int6") == null) {
int int6 = Integer.parseInt(((FormIntModel) getModel()).getInt6());
if (int6 < 2 || int6 > 20) {
addFieldError("int6", getText("int6.error"));
}
}
}
- рядок 5: перевіряється, чи є помилки, пов’язані з полем int6. Якщо так, то далі не продовжується.
- рядок 6: якщо помилок не було, з моделі отримується поле String int6 і перетворюється на ціле число.
- рядок 7: перевіряємо, чи отримане ціле число знаходиться в діапазоні [2,20].
- рядок 8: якщо це не так, до поля int6 додається повідомлення про помилку. Це повідомлення про помилку шукається у файлі повідомлень за ключем int6.error.
Якщо за підсумками цього процесу перевірки виявлено помилки, виклик методу [FormInt].execute переривається, а ключ input повертається контролеру Struts.
![]() |
11.7. Останні деталі
Ми розглянули кілька способів введення цілих чисел. Не всі вони є рівнозначними. Розглянемо, наприклад, поля введення int5 та int6:
У поданнях [FormInt.JSP] вони оголошені наступним чином:
<s:textfield name="int5" key="int5.prompt"/>
<s:textfield name="int6" key="int6.prompt"/>
Їхній шаблон оголошено в [FormIntModel.java]:
private Integer int5;
private String int6;
Поле int5 має тип Integer, тоді як поле int6 має тип String. Їхні правила перевірки відрізняються:
<field name="int5" >
<field-validator type="required" short-circuit="true">
<message key="int5.error"/>
</field-validator>
<field-validator type="conversion" short-circuit="true">
<message key="int2.error"/>
</field-validator>
<field-validator type="int" short-circuit="true">
<param name="min">1</param>
<param name="max">10</param>
<message key="int5.error"/>
</field-validator>
</field>
<field name="int6" >
<field-validator type="requiredstring" short-circuit="true">
<message key="int6.error"/>
</field-validator>
<field-validator type="regex" short-circuit="true">
<param name="expression">^\d{1,2}$</param>
<param name="trim">true</param>
<message key="int6.error"/>
</field-validator>
</field>
Перевірка поля int6 здійснюється за допомогою методу validate дії [FormInt]:
public void validate() {
// чи введене значення int6 є допустимим?
if (getFieldErrors().get("int6") == null) {
int int6 = Integer.parseInt(((FormIntModel) getModel()).getInt6());
if (int6 < 2 || int6 > 20) {
addFieldError("int6", getText("int6.error"));
}
}
Хоча правила перевірки сформульовані по-різному, обидва вони мають на меті перевірити, чи введене поле є цілим числом, що знаходиться в заданому діапазоні. Однак під час виконання поля int5 та int6 поводяться по-різному, як показано на наступних знімках екрана:
![]() |
- у [1] — одна й та сама неправильна введена інформація для обох полів
- у [2] — повернута сторінка помилок. Обидва поля мають різні повідомлення про помилки.
- у [3] для поля int5 з’являється небажане повідомлення, оскільки воно англійською мовою. Воно пов’язане з невдалим перетворенням String --> Integer. Крім того, у логах Apache є виняток:
Досить дивно, але Struts шукав метод FormIntModel.setInt5(String value), якого не знайшов.
Ключ небажаного повідомлення — xwork.default.invalid.fieldvalue. Щоб перевести його на французьку, достатньо пов’язати з цим ключем французький текст. Тому до файлу [messages.properties] додаємо такий рядок:
...
xwork.default.invalid.fieldvalue=Valeur invalide pour le champ "{0}".
11.8. Conclusion
На цьому завершується розгляд цього першого додатка, призначеного для перевірки параметрів. Пояснити його було досить складно. Тепер ми розглянемо подібні додатки. Тому коментуватимемо лише те, що змінилося.















