Управление потоком сервлетов / JSP: перечисления, исключения или что-то еще? - PullRequest
2 голосов
/ 30 марта 2010

Я недавно унаследовал приложение, разработанное с использованием пустых сервлетов и JSP (т.е. без фреймворков). Мне было поручено очистить рабочий процесс обработки ошибок. В настоящее время каждый <form> в рабочем процессе отправляется сервлету, и в зависимости от результата отправки формы сервлет выполняет одну из двух операций:

  1. Если все в порядке, сервлет либо перенаправляет, либо перенаправляет на следующую страницу в рабочем процессе.
  2. В случае возникновения проблемы, например, из-за неверного имени пользователя или пароля, сервлет переходит на страницу, относящуюся к условию проблемы. Например, есть такие страницы, как AccountDisabled.jsp, AccountExpired.jsp, AuthenticationFailed.jsp, SecurityQuestionIncorrect.jsp и т. Д.

Мне нужно перепроектировать эту систему, чтобы централизованно решать проблемы. Пока что я рассмотрел два возможных решения:

  • Exception s
    • Создайте класс исключений, соответствующий моим потребностям, например AuthException. Наследуйте от этого класса, чтобы быть более точным, когда это необходимо (например: InvalidUsernameException, InvalidPasswordException, AccountDisabledException и т. Д.). Всякий раз, когда возникает проблема, генерируйте исключение, специфичное для этого условия. Перехватывайте все исключения через web.xml и направляйте их на соответствующие страницы с тегом <error-page>.
  • enum s
    • Принять подход с кодом ошибки, с enum отслеживанием кода ошибки и описания. Описания можно прочитать из комплекта ресурсов в готовом продукте.

Я больше склоняюсь к подходу enum, поскольку сбой аутентификации на самом деле не является «исключительным условием», и я не вижу никакой выгоды в добавлении беспорядка в журналы сервера. Плюс, я просто заменил бы одну головную боль обслуживания другой. Вместо поддержки отдельных JSP у меня были бы отдельные Exception классы.

Я планирую реализовать обработку «ошибок» в сервлете, который я пишу специально для этой цели. Я также собираюсь исключить все отдельные страницы ошибок, вместо этого установив атрибут запроса error с сообщением об ошибке для отображения пользователю и переадресацией обратно на реферер. Каждый целевой сервлет (Logon, ChangePassword, AnswerProfileQuestions и т. Д.) Будет добавлять код ошибки в запрос и перенаправлять на мой новый сервлет в случае возникновения проблемы. Мой новый сервлет будет выглядеть примерно так:

public enum Error {
    INVALID_PASSWORD(5000, "You have entered an invalid password."),
    ACCOUNT_DISABLED(5002, "Your account has been disabled."),
    SESSION_EXPIRED(5003, "Your session has expired. Please log in again."),
    INVALID_SECURITY_QUESTION(5004, "You have answered a security question incorrectly.");

    private final int code;
    private final String description;

    Error(int code, String description) {
        this.code = code;
        this.description = description;
    }

    public int getCode() {
        return code;
    }

    public String getDescription() {
        return description;
    }
};

protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    String sendTo = "UnknownError.jsp";
    String message = "An unknown error has occurred.";

    int errorCode = Integer.parseInt((String)request.getAttribute("errorCode"), 10);

    Error errors[] = Error.values();
    Error error = null;

    for (int i = 0; error == null && i < errors.length; i++) {
        if (errors[i].getCode() == errorCode) {
            error = errors[i];
        }
    }

    if (error != null) {
        sendTo = request.getHeader("referer");
        message = error.getDescription();
    }

    request.setAttribute("error", message);

    request.getRequestDispatcher(sendTo).forward(request, response);
}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    doGet(request, response);
}

Будучи довольно неопытным с Java EE (это мое первое настоящее знакомство с JSP и сервлетами), я уверен, что что-то мне не хватает, или мой подход неоптимален. Я на правильном пути или мне нужно пересмотреть свою стратегию?

Ответы [ 2 ]

2 голосов
/ 31 марта 2010

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

Я сам предпочитаю бросать исключения. Это более четко и кратко, а также лучше использовать повторно, поддерживать и тестировать. Разработайте интерфейс Validator с помощью метода validate(), который создает ValidatorException. Реализуйте желаемые валидаторы соответственно. Соберите валидаторы и запустите их один за другим в блоке try / catch и соберите там исключения. Э.Г.

Map<String, String> messages = new HashMap<String, String>();
for (Validator validator : validators) {
    try {
        validator.validate(value);
    } catch (ValidatorException e) { 
        messages.add(fieldname, e.getMessage());
    }
}

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

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

Для неустранимых ошибок, таких как неработающая база данных или ошибка в коде (ошибки времени выполнения, внутренние ошибки сервера и т. Д.), Я бы просто позволил исключению пройти через все слои, чтобы вы могли «поймать» его с помощью общая и настраиваемая страница ошибок, которую вы можете определить как <error-page> в web.xml. Вы можете определить отдельную страницу ошибки для каждого типа Exception и / или кода состояния HTTP.

Это, кстати, и то, как работает средний MVC-фреймворк.

1 голос
/ 30 марта 2010

Если вы используете исключения, вы можете использовать инфраструктуру ErrorHandling по умолчанию. Выдача исключений не должна засорять журнал вашего сервера, если вы заполняете их стеком или настраиваете свой журнал, чтобы либо не регистрировать их, либо не отслеживать трассировки стека.

Ваш обработчик ошибок может затем отобразить соответствующее сообщение / навигацию / возобновление на основе типа исключения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...