[an error occurred while processing this directive] IT • archiv :: Print

IT • archiv


[an error occurred while processing this directive]

[an error occurred while processing this directive]

Проверка ввода данных на Java с использованием схем XML. Часть 4

[an error occurred while processing this directive](none) [an error occurred while processing this directive](none)[an error occurred while processing this directive] ::
[an error occurred while processing this directive](none)
[an error occurred while processing this directive]([an error occurred while processing this directive] Бретт МакЛафлин [an error occurred while processing this directive])

[an error occurred while processing this directive](none)

Создание представления ограничений, заданных схемой, на Java и проверка данных Java на соответствие этим ограничениям.

Data Validation
PDF versionPDF версия
Обзор
Схемы XML могут обеспечить лучший способ проверки правильности ввода данных в приложениях Java, чем простое использование конструкций if-then-else. В последней, 4 статье серии продолжается построение среды проверки правильности ввода данных и заполняются оставшиеся в предыдущей статье пробелы. Читатель узнает, как выполнять разбор схем XML, строить на Java представление ограничений, заданных схемами и применять эти ограничения к данные приложения. (3500 слов)

Проверка. Это слово настолько навязло на зубах, что у меня часто начинаются кошмары от длительного сидения за столом и топтания клавиатуры с помощью которой я ввожу сотни скучных строк кода JavaScript для проверки моих форм HTML. Затем в памяти всплывает еще более надоевшие попытки объединить скрипты со строками кода сервлета, который обрабатывает заданные ограничения и часто полностью покрывает мраком его истинную цель. Если только Вы не новичок в Java, Вам понятна моя боль.

Цель этой серии статей, сопровождаемой кодом, заключается в поиске решения если не полного прекращения, то хотя бы ограничения мучений и рутины, часов разглядывания окна или стены кабинета с желанием играть в хоккей или слушать оркестр Дейва Мэтьюса. Автор насыщен реакцией читателей и рад столь широкой аудитории. Перед началом нового обсуждения, вспомним, с чего все начиналось.

Первая технология

Надо сказать, мы прошли большой путь. Автор испытывает определенные опасения в развитии статьи на часть 4. Возможно, это "комплекс трилогий", ведь кроме Звездных Войн мы не знаем удачных примеров продолжения.

В части 1 мы рассмотрели концепцию общей для программ с вводом данных пользователем проблемы проверки данных. Мы обсудили различные недостатки подходов к решению на основе файлов свойств Java и проверки в коде. Наконец, было высказано предположение, что схема XML может обеспечить простой способ полного представления ограничений на данные и дали предварительный набросок среды для проверки, которая является целью настоящей серии. В части 2 рассматривались возможности использования простых классов Java для представления ограничений на данные, определенные схемой XML. Таким образом была положена основа построению наборов экземпляров Constraint и их сравнения с данными Java (Strings, ints, Dates, и т.д.). В части 3 среда была написана, разработан класс SchemaParser для разбора схем XML и построены ограничения. В результате мы продемонстрировали класс Validator, который мог принимать имя ограничения на данные и возвращать решение, соответствуют эти данные ограничениям или нет. Автор настоятельно рекомендует ознакомиться с содержимым первые три статьи прежде, чем двигаться дальше.

Мы уже получили достаточно хороший набор классов, который помогает проверять данные в приложениях, в частности, в сервлетах. Однако, в среде отсутствуют некоторые детали; хотя правильность данных устанавливается, нет средств сообщения о виде проблемы в случае неправильного ввода данных. Этот вопрос будет целью данной статьи.

Улучшения обработки ошибок

Ощутимой проблемой в среде оказалось информирование об ошибках. Если вернуться к части 3, в классе Validator мы имели методы приема данных, имени ограничения и решали, удовлетворяют ли данные этим ограничениям. Использовался метод isValid, который возвращал значение типа boolean: true, если данные правильны, false — если нет. Довольно просир, не так ли? Как было упомянуто в части 3, это дает нам ответ, но не полный. Например, нет способа получить информацию о том, с чем именно связана проблемы. Безусловно, пользователь получить точную информацию для исправления ошибок и повторного ввода данных. Представьте себе сложную форму из 20 или 25 полей; пользователь заполняет ее (на что потребуется время), отправляет ее с ошибкой. Пользователь не знает, где допустил ошибку, а программа просто отвечает, "Ошибка проверки ввода данных. Повторите попытку." Это вряд ли обрадует пользователя; скорее, он закроет окно броузера или перейдет на другой сайт. Таков рецепт поражения в бизнесе! Очевидно, необходимы улучшения в этой области. Можно предложить два основных подхода: на основе исключений, когда о проблемах проверки сообщается с помощью исключений, на основе сообщений, когда результаты проверки возвращаются в строках String Java, которые могут содержать сообщение об ошибке проверки.

Подход на основе исключений

Стандартным решением проблемы является использзование механизма обработки исключений в Java. В этом случае метод isValid() должен генерировать исключение при возникновении проблем проверки. Чтобы изобразить ситуацию точнее, рассмотрим ноывй класс InvalidDataException, который представляет собой класс исключения по непрохождении теста на правильность:

package org.enhydra.validation;
 /**
  *
  * Класс InvalidDataException представляет проблему, которая
  * делает данные неправильными по отношению к определенному ограничению.
  *
  */
 public class InvalidDataException extends Exception {

     /**
      *
      * Генерация простого исключения, показывающего,
      * что получены некорректные/неправильные данные.
      *
      */
     public InvalidDataException() {
         super("Invalid Data Supplied.");
     }

     /**
      *
      * Генерация простого исключения, показывающего,
      * что получены некорректные/неправильные данные,
      * со строковым сообщением об этой проблеме.
      *
      * @param message String сообщение о неуспешной проверке
validation.
     */
    public InvalidDataException(String message) {
        super("Invalid Data Supplied: " + message);
    }
}

Исключение может генерироваться методом isValid() и сопровождаться сообщением, извещающим об ошибке. Метод изменится следующим образом:

    
     /**
      *
      * проверка значения данных (в формате String) на соответствие
      * определенному ограничению и генерирование исключения по ошибке.
      *
      *
      * @param constraintName идентификатор ограничения для проверки
      * @param data String данные для проверки.
     */
    public void checkValidity(String constraintName, String data)
        throws InvalidDataException {

        // проверка по соответствующему ограничению
        Object o = constraints.get(constraintName);

        // если ограничения нет, все правильно
        if (o == null) {
            return;
        }
        Constraint constraint = (Constraint)o;

        // проверка типа данных
        if (!correctDataType(data, constraint.getDataType())) {
            throw new InvalidDataException("Incorrect data type");
        }

        // проверка разрешенных значений
        if (constraint.hasAllowedValues()) {
            List allowedValues = constraint.getAllowedValues();
            if (!allowedValues.contains(data)) {
                throw new InvalidDataException("Disallowed value");
            }
        }

        // проверка диапазона
        try {
            double doubleValue = new Double(data).doubleValue();
            if (constraint.hasMinExclusive()) {
                if (doubleValue <= constraint.getMinExclusive()) {
                    throw new InvalidDataException("Value is not large
enough");
                }
            }
            if (constraint.hasMinInclusive()) {
                if (doubleValue < constraint.getMinInclusive()) {
                    throw new InvalidDataException("Value is not large
enough");
                }
            }
            if (constraint.hasMaxExclusive()) {
                if (doubleValue >= constraint.getMaxExclusive()) {
                    throw new InvalidDataException("Value is not small
enough");
                }
            }
            if (constraint.hasMaxInclusive()) {
                if (doubleValue > constraint.getMaxInclusive()) {
                    throw new InvalidDataException("Value is not large
enough");
                }
            }
        } catch (NumberFormatException e) {
            // If it couldn't be converted to a number, the data type isn't
            // numeric anyway, as it would have already failed,
            // so this can be ignored.
        }

        // если мы здесь, проверка завершена успешно
        // возврат значения не требуется.
    }

Заметим, что мы изменили также и имя метода на checkValidity(), так как он больше не возвращает значение boolean (стиль isXXX() именования методов предполагает возвращение значений true/false в качестве результата). Вместо возрата false при возникновении проблем генерируется InvalidDataException и таким образом вызывающая программа информируется о возникновении проблемы. В этом примере я рассмотрел решение кратко, однако, можно сделать сообщение об ошибке более информативным, добавив проверяемое значение, значение или значения, которым оно должно удевлетворять и другие более подробные детали ошибки.

На деле, можно еще больше детализировать ошибку, создавая отдельные классы исключений, на базе InvalidDataException. Например, рассмотрим такую иерархию исключений:

  • InvalidDataException
    • IncorrectDataTypeException
    • DisallowedValueException
    • ValueTooLowException
    • ValueTooHighValueException
    • и т.д...

Для каждого из них можно написать подходящий конструктор. Например:

public class ValueTooLowException extends InvalidDataException {

     public ValueTooLowException(String value, String minValue) {
         super("The value supplied, " + value + ", was lower than " +
               "the minimum required value, " + minValue);
     }

 }
 

При таком подходе можно просто сообщать об ошиьказ посредством различныхх исключений и обеспечивать вызовы для получения детальной информации о произошедшей проблеме. В действительности, это такой подход, который автору советовали реализовать в большинстве отзывов. Однако, у этого подхода есть один тонкий недостаток. Представим, что клиентский код использует класс Validator:

    
     Validator validator = Validator.getInstance(schemaURL);

     // проверить различные данные, которые были получены ранее
     try {
         validator.checkValidity("shoeSize", shoeSize);
         validator.checkValidity("width", width);
         validator.checkValidity("brand", brand);
         validator.checkValidity("numEyelets", numEyelets);
     } catch (InvalidDataException e) {
         errorMessage = e.getMessage();
     }

     // возвратить клиенту значение errorMessage
 

Казалось бы, все в порядке? Однако, будет возвращена только первая ошибка проверки. Например, предположим, что пользователь ввел размер ботинок "11" (что нормально), ширину "F" (что неправильно), марку "V-Form" (в порядке), а для количества дырочек для шнурков пользователь случайно ввел значение "@2" вместо "22" (чего, кончено, не может быть никогда). Метод checkValidity() возвращает нормальное значение после вызова для размера ботинок, затем генерирует ошибку при вызове для ширины (потому что "F" не есть правильно). Выполнение программы переходит к блоку обработки ошибок, а единственным сообщением об ошибке является "Введенная ширина, F, не соответствует разрешенному диапазону значений: A, B, C, D, или DD. Введите одно из перечисленных." Однако, пользователь остается в неведении, что число дырочек также введено неправильно. Поэтому, исправив ошибку и перенаправив форму, получит еще одно сообщение о неправильном количестве дырочек. Обычно это сильно расстраивает или смущает избалованного американского пользователя, а российского хакера просто начинает доставать. Почему не сообщить обо всех ошибках сразу?

Эта проблема решается изменением предыдущего блока следующим образом:

    
     Validator validator = Validator.getInstance(schemaURL);

     StringBuffer errorBuffer = new StringBuffer();

     // проверить различные данные, которые были получены ранее
     try {
         validator.checkValidity("shoeSize", shoeSize);
     } catch (InvalidDataException e) {
         errorBuffer.append(e.getMessage());
     }
     try {
         validator.checkValidity("width", width);
     } catch (InvalidDataException e) {
         errorBuffer.append(e.getMessage());
     }
     try {
         validator.checkValidity("brand", brand);
     } catch (InvalidDataException e) {
         errorBuffer.append(e.getMessage());
     }
     try {
         validator.checkValidity("numEyelets", numEyelets);
     } catch (InvalidDataException e) {
         errorBuffer.append(e.getMessage());
     }

     // преобразовать буфер в сообщение об ошибке
     String errorMessage = errorBuffer.toString();

     // возвратить клиенту значение errorMessage

К сожалению, изящество кода в первом приближении полностью утеряно! Мы вновь вернулись к ужасному спагетти из части 1, которого старались избежать — все из-за необходимости иметь в распоряжении все сообщения, а не первое появление исключения. Поэтому использование исключений не является универсальным методом, как могло оказаться на первый взгляд. Поэтой причние имеет смысл исследовать второй подход, который позволяет построить чистый код с тем же результатом.

Подход на основе сообщений

Продолжим развивать наши подходы к исключениям и информировании об ошибках. Теперь мы видим, что лучшим решением является не метод checkValidity(), возвращающий ошибку прямо по ее возникновению. Другими словами, нужен метод, возвращающий значение String, которое указывает на проблему. Если проблем нет, возвращается пустая строка, позволяющая просто проверить результат на приавильность.

Следующий код позволяет просто "сложить" все сообщения об ошибках и вернуть из пользователю приложения. Приводим измененный метод checkValidity(), где все на своих местах:

    /**
      *
      * проверка значения данных (в формате String) на соответствие
      * определенному ограничению и генерирование исключения по ошибке.
problem.
      *
      *
      * @param constraintName идентификатор ограничения для проверки
      * @param data String данные для проверки.
     * @return String — сообщение об ошибке, или пустая строка
problems occurred.
     */
    public String checkValidity(String constraintName, String data) {
        StringBuffer errorMessage = new StringBuffer();

        // проверка по соответствующему ограничению
        Object o = constraints.get(constraintName);

        // если ограничения нет, все правильно
        if (o == null) {
            return "";
        }
        Constraint constraint = (Constraint)o;

        // проверка типа данных
        if (!correctDataType(data, constraint.getDataType())) {
            errorMessage.append("The value supplied, ")
                  .append(data)
                  .append(" cannot be converted to the required type, ")
                  .append(constraint.getDataType())
                  .append("\n");
        }

        // проверка разрешенных значений
        if (constraint.hasAllowedValues()) {
            List allowedValues = constraint.getAllowedValues();
            if (!allowedValues.contains(data)) {
               errorMessage.append("The value supplied, ")
                     .append(data)
                     .append(" is not in the allowed set of data types (");
               for (Iterator i = allowedValues.iterator(); i.hasNext(); ){
                    errorMessage.append("'")
                                .append((String)i.next())
                                .append("', ");
               }
               errorMessage.setLength(errorMessage.length()- 2);
               errorMessage.append(")")
                            .append("\n");
            }
        }

        // проверка диапазона
        try {
            double doubleValue = new Double(data).doubleValue();
            if (constraint.hasMinExclusive()) {
                if (doubleValue <= constraint.getMinExclusive()) {
                    errorMessage.append("The value supplied, ")
                                .append(data)
                                .append(" is less than or equal to the
allowed minimum value, ")
                                .append(constraint.getMinExclusive())
                                .append("\n");
                }
            }
            if (constraint.hasMinInclusive()) {
                if (doubleValue < constraint.getMinInclusive()) {
                    errorMessage.append("The value supplied, ")
                                .append(data)
                                .append(" is less than the allowed minimum
value, ")
                                .append(constraint.getMinInclusive())
                                .append("\n");
                }
            }
            if (constraint.hasMaxExclusive()) {
                if (doubleValue >= constraint.getMaxExclusive()) {
                    errorMessage.append("The value supplied, ")
                                .append(data)
                                .append(" is greater than or equal to the
allowed maximum value, ")
                                .append(constraint.getMaxExclusive())
                                .append("\n");
                }
            }
            if (constraint.hasMaxInclusive()) {
                if (doubleValue > constraint.getMaxInclusive()) {
                    errorMessage.append("The value supplied, ")
                          .append(data)
                          .append(" is greater than the allowed minimum
value, ")
                          .append(constraint.getMaxInclusive())
                          .append("\n");
                }
            }
        } catch (NumberFormatException e) {
            // Если значение не преобразовывается в число, тип данных
            // не числовой, все равно проверка закончится неуспехом,
            // можно игнорировать.
        }

        // вернуть все найденные сообщения об ошибках
        return errorMessage.toString();
    }

Другим преимуществом такого подхода является сообщение обо всех участках проверки данных, на которых произошле нарушение ограничений. Например, для данных, не принадлежащих набору разрешенных величин, и в то же время слишком малой величины, будут сообщены обе проблемы (более реальна картина малого значения в неподходящем формате при поддержке шаблонов величин). Польщователю предоставляется полная информация для выполнения необходимых изменений для всех данных одновременно. Это приводит к максимальному удовлетворению.

Соответствующий код клиента не столь прост, как наш код из части 3, но от многочисленной обработки исключений мы также избавились:

    Validator validator = Validator.getInstance(schemaURL);

     StringBuffer errorBuffer = new StringBuffer();

     // проверить данные
     errorBuffer.append (validator.checkValidity("shoeSize", shoeSize))
                .append(validator.checkValidity("width", width))
                .append(validator.checkValidity("brand", brand))
                .append(validator.checkValidity("numEyelets", numEyelets));

     String errorMessage = errorBuffer.toString();
 

Достаточно простое изменение класса Validator привело нас к существенно улучшенной среде., которая теперь точно и полностью сообщает об ошибках клиентам, среде и приложению. Перед завершением рассмотрим пример применения среды в реальном приложении.

Среда в работе

До сих пор мы рассматривали только отдельные фрагменты. В этом разделе мы продемонстрируем работу сервлета, принимающего данные из формы HTML, и остановимся на том, как пользователь извещается о проблемах ввода данных. Мы не будем вдаваться в подробности кода и механизмов работы сервлетов. Это специальная задача может касаться читателя; для изучения этого вопроса смотрите тематика: Java на сервере JavaWorld.

Пример применения: Сервлеты

Рассмотрим простую форму HTML, которая позволяет пользователю ввести информацию о ботинках, которые он хочет увидеть. Конечно, в завершенном сетевом магазине будут присутствовать надлежащая графика и расцветки, но мы остановимся на простом примере. Хотя помимо того, что форма сохраняется как статический документ, она генерируется по запросам GET от BuyShoesServlet. Когда мы будем анализировать отчет об ошибках, мы увидим, почему так происходит. Однако, прежде всего рассмотрим код метода doGet() сервлета BuyShoesServlet.

 import java.io.IOException;
 import java.io.PrintWriter;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;

 public class BuyShoesServlet extends HttpServlet {

     public void doGet(HttpServletRequest req, HttpServletResponse res)
         throws ServletException, IOException {

         res.setContentType("text/html");
         PrintWriter out = res.getWriter();

         // печать формы HTML
         out.println("<HTML>");
         out.println("<HEAD><TITLE>BuyShoes.com — Get All Your ");
         out.println("Shoes Here</TITLE></HEAD>");
         out.println("<BODY>");
         out.println("<H2 ALIGN='center'>Select a Shoe to Look At</H2>");
         out.println("<HR WIDTH='75%' />");
         out.println("<CENTER>");
         out.println("<FORM ACTION='/servlet/BuyShoesServlet' ");
         out.println(" METHOD='POST'>");
         out.println("<TABLE WIDTH='50%' BORDER='2' ");
         out.println(" CELLPADDING='10' CELLSPACING='2'");
         out.println(" BGCOLOR='#CECECE'>");
         out.println("<TR>");
         out.println("<TD WIDTH='50%' ALIGN='right'>Shoe Size:");
         out.println("<INPUT NAME='shoeSize' SIZE='3' /></TD>");
         out.println("<TD WIDTH='50%' ALIGN='left'>Show Width:");
         out.println("<INPUT NAME='width' SIZE='2' /></TD>");
         out.println("</TR>");
         out.println("<TR>");
         out.println("<TD WIDTH='50%' ALIGN='right'>Brand:");
         out.println("<INPUT NAME='brand' SIZE='12' /></TD>");
         out.println("<TD WIDTH='50%' ALIGN='left'>Eyelets on Shoe:");
         out.println("<INPUT NAME='numEyelets' SIZE='2' /></TD>");
         out.println("</TR>");
         out.println("<TR>");
         out.println("<TD WIDTH='100%' COLSPAN='2' ALIGN='center'>");
         out.println("<INPUT NAME='submit' TYPE='submit' ");
         out.println(" value='Find this Shoe' />");
         out.println("</TD>");
         out.println("</TR>");
         out.println("</TABLE>");
         out.println("</FORM>");
         out.println("</CENTER>");
         out.println("</BODY>");
         out.println("</HTML>");

         out.close();
     }

 }

Пример отображает форму HTML и позволяет пользователю ввести значения. Автор понимает, что ни один программист не позволит пользователю вводить всю эту информацию, не используя разного рода элементов выбора и т.п.; но мы здесь пишем не рассказ, а аналитическую статью. Поэтому пусть пользователь вводит информацию. Заметим, что форма реально передает данные самой себе и формирует запрос HTTP POST. Это значит, что в этом же сервлете необходимо реализовать метод doPost(), который будет получать данные, выполнять проверку, а затем передавать данные на другой сервлет (если данные правильны) или сообщать пользователю об ошибке (если данные введены неправильно). Поэтому в методе doPost() ключевым является код, который реализует реакцию на возможные ошибки при проверке.

Обработка ошибок при проверке

В это коде нет ничего потрясающего; просто он использует на деле все, о чем мы говорили в этой серии статей. Добавим, что это можно проследить на способе получения параметра, его проверки и отправки отчета по ошибкам обратно исходному методу doGet() method. В дальнейшем мы разъясним сказанное, а теперь рассмотрим сам код:

    
public void doPost(HttpServletRequest req, HttpServletResponse res)
         throws ServletException, IOException {
         // забрать пользовательский ввод
         String shoeSize = req.getParameter("shoeSize");
         String width = req.getParameter("width");
         String brand = req.getParameter("brand");
         String numEyelets = req.getParameter("numEyelets");

         StringBuffer targetURL = new StringBuffer();
         RequestDispatcher dispatcher;

 
         /** Assign this in your code to your XML schema! */
         URL schemaURL = // запомнить позицию в коде

         // проверить полученное значение
         Validator validator = Validator.getInstance(schemaURL);

         StringBuffer errorBuffer = new StringBuffer();

         // проверить значение
         errorBuffer.append (validator.checkValidity("shoeSize", shoeSize))
                  .append(validator.checkValidity("width", width))
                  .append(validator.checkValidity("brand", brand))
                  .append(validator.checkValidity("numEyelets", numEyelets));

         String errorMessage = errorBuffer.toString();

         // продолжить, если нет ошибок, иначе сообщить об ошибках
         if (errorMessage.equals("")) {
             dispatcher =
              getServletContext().getRequestDispatcher ("PurchaseServlet");
             // отправить по нужному URL
             dispatcher.forward(req, res);
         } else {
             req.setAttribute("shoeSize", shoeSize);
             req.setAttribute("width", width);
             req.setAttribute("brand", brand);
             req.setAttribute("numEyelets", numEyelets);
             req.setAttribute("errorMessage", errorMessage);

             doGet(req, res);
         }
     }

Значения в форме определяются методом req.getParameter(), после чего происходит их проверка. Заметим, что в конкретном коде надо будет назначить переменной schemaURL значение правильного URL необходимой схемы XML. Как только он стал известен, начинается проверка и все сообщения об ошибках записываются в отчет. Если ошибке не обнаружены, запрос перенаправляется в PurchaseServlet (код которого здесь не показан), который будет обрабатывать процесс покупки выбранных ботинок. Если же были ошибки, одному из атрибутов объекта HttpServletRequest присваивается значение сообщения об ошибке. Таким же способом присваиваются значения, заданные пользователем, так что можно отобразить форму вместе с сообщением об ошибках. В результате, выполнение программы переходит снова к методу doGet().

Конечно, сейчас, метод doGet() не работает с этой дополнительно информацией. Его надо изменить, чтобы отобразить в форме все полученные данные и сообщение об ошибках. Рассмотрим следующую модификацию этого метода, которая делает это:

    public void doGet(HttpServletRequest req, HttpServletResponse res)
         throws ServletException, IOException {

         res.setContentType("text/html");
         PrintWriter out = res.getWriter();


         // забрать все значения
         String shoeSize = (String)req.getAttribute("shoeSize");
         if (shoeSize == null) {
             shoeSize = "";
         }
         String width = (String)req.getAttribute("width");
         if (width == null) {
             width = "";
         }
         String brand = (String)req.getAttribute("brand");
         if (brand == null) {
             brand = "";
         }
         String numEyelets = (String)req.getAttribute("numEyelets");
         if (numEyelets == null) {
             numEyelets = "";
         }

         // печать формы HTML
         out.println("<HTML>");
         out.println("<HEAD><TITLE>BuyShoes.com — Get All Your ");
         out.println(" Shoes Here</TITLE></HEAD>");
         out.println("<BODY>");
         out.println("<H2 ALIGN='center'>Select a Shoe to Look At</H2>");
         out.println("<HR WIDTH='75%' />");
         out.println("<CENTER>");
         out.println("<FORM ACTION='/servlet/BuyShoesServlet' ");
         out.println(" METHOD='POST'>");
         out.println("<TABLE WIDTH='50%' BORDER='2' ");
         out.println("CELLPADDING='10' CELLSPACING='2'");
         out.println(" BGCOLOR='#CECECE'>");

 
         // обработка ошибок
         String errorMessage = (String)req.getAttribute("errorMessage");
         if (errorMessage != null) {
             out.println("<TR>");
             out.println("<TD COLSPAN='2' ALIGN='CENTER'>");
             out.println("<B>Errors occurred in your submission:</B><BR />");
             out.println("<FONT COLOR='red'><PRE>");
             out.println(errorMessage);
             out.println("</PRE></FONT>");
             out.println("</TD>");
             out.println("</TR>");
         }

         out.println("<TR>");
         out.println("<TD WIDTH='50%' ALIGN='right'>Shoe Size:");
         out.println("<INPUT NAME='shoeSize' SIZE='3' ");
         out.println("<b>VALUE='" + shoeSize + "'</b> /></TD>");
         out.println("<TD WIDTH='50%' ALIGN='left'>Show Width:");
         out.println("<INPUT NAME='width' SIZE='2' ");
         out.println("<b>VALUE='" + width + "'</b> /></TD>");
         out.println("</TR>");
         out.println("<TR>");
         out.println("<TD WIDTH='50%' ALIGN='right'>Brand:");
         out.println("<INPUT NAME='brand' SIZE='12' ");
         out.println("<b>VALUE='" + brand + "'</b> /></TD>");
         out.println("<TD WIDTH='50%' ALIGN='left'>Eyelets on Shoe:");
         out.println("<INPUT NAME='numEyelets' SIZE='2' ");
         out.println("<b>VALUE='" + numEyelets + "'</b> /></TD>");
         out.println("</TR>");
         out.println("<TR>");
         out.println("<TD WIDTH='100%' COLSPAN='2' ALIGN='center'>");
         out.println("<INPUT NAME='submit' TYPE='submit' ");
         out.println("value='Find this Shoe' />");
         out.println("</TD>");
         out.println("</TR>");
         out.println("</TABLE>");
         out.println("</FORM>");
         out.println("</CENTER>");
         out.println("</BODY>");
         out.println("</HTML>");

         out.close();
     }

Итак, все решено. Новый вариант метода показывает всю введенную информацию, а также отображает красным цветом сообщение о возникающих ошибках. Таким образом, по существу, создается эффект зацикливания до тех пор, пока пользователь не введет правильную информацию. В качестве примера, приведем вид экрана после неправильного ввода:

Вид экрана после неправильного ввода.
Рисунок 1. Вид экрана после неправильного ввода.

Теперь читатель сможет легко изменять эти примеры для использования среды в своих сервлетах и приложениях для Веб.

Отзывы читателей

Автор признателен читателям за груды откликов об этой серии по электронной почте, что показывает интерес к тематике. Автор не ответил всем, поскольку требовалось продолжать серию.

Значительное количество писем было посвящено использованию шаблонов выражений. Эта тема многих интересует, и выражения легко встраиваются в нашу среду. Мы уже отмечали, что для рассмотрения всех вариантов понадобится не одна статья. По этой причине я ограничился примерами ограничений и больше времени уделил концепции. Автор надеется создать с помощью читателей депозитарий открытых кодов, поддерживающих шаблоны, использующих, возможно, библиотеку распознавания регулярных выражений от Apache.

Новые версии

Как было отмечено в части 3, публикации статей часто запаздывают по отношению к имеющемуся в разработке коду. Например, код, который я написал к части 3 может быть, следует немного изменить, чтобы использовать все новые свойства JDOM или следовать смысловому переименованию методов.

В любом случае, автор советует загружать все коды к каждой статье и заменять ими старые коды от предыдущих усилий. Рекомендуем также использовать свежую версию JDOM, желательно из CVS; эта процедура описана на вебсайта JDOM. Поэтому забирайте код статей (см. Ресурсы), берите последнюю версию JDOM, все это компилируйте и проблем не будет.

Заключение

Мы подошли к концу нашего путешествия. Автор уверен, что мы совершим вместе еще не одно, по другим темам, а все сказанное относится только к проверке ввода данных. Мы надеемся, что получили совместное удовольствие от рассмотрения концепций и, возможно, добавили в копилки несколько полезных инструментов!

Код этих статей является полностью открытым, под публичной лицензия Enhydra (EPL), что означает, что его может использовать каждый по своему усмотрению. Кроме того, код будет выложен на FTP сервер Enhydra, и его обсуждение будет продолжено в группе списка рассылки EnhydraEnterprise@enhydra.org, на который можно подписаться на вебсайте Enhdyra. Автор надеется на вклад читателей и взаимную помощь в реализации различных идей, которую уже сумел ощутить благодаря письмам в отношении этой среды. До встречи в Сети!

Об авторе

Бретт МакЛафлин — стратег по Enhydra в Lutris Technologies, специализирующийся на архитектурах распределенных систем. Он является автором Java and XML и работает с такими технологиями как сервлеты Java, технология Enterprise JavaBeans, XML, приложения бизнес-ту-бизнес. Недавно он организовал проект JDOM совместно с Джейсоном Хантером, в котором разработал простой API для работы с XML из приложений Java. МакЛафлин активно участвует в разработке проекта Apache Cocoon и сервера EJBoss EJB, и является сооснователем проекта Apache Turbine.

Ресурсы

Reprinted with permission from the December 2000 edition of JavaWorld magazine. Copyright © ITworld.com, Inc., an IDG Communications company.
View the original article at: http://www.javaworld.com/ jw-12-2000/jw-1208-validation4.html

[an error occurred while processing this directive]
[an error occurred while processing this directive] Перевод на русский © Андрей Ковалев, к.т.н., доцент МИЭТ, 2000
< Вернуться на caйт :: Copyright © 1999 — 2010, IT • archiv.