Servlet / JSP流控制:枚举,异常还是其他?

时间:2010-03-30 18:09:21

标签: java jsp exception-handling enums

我最近继承了使用裸servlet和JSP开发的应用程序(即:没有框架)。我的任务是清理错误处理工作流程。目前,工作流中的每个<form>都提交给一个servlet,并根据表单提交的结果,servlet执行以下两项操作之一:

  1. 如果一切正常,servlet会转发或重定向到工作流程中的下一页。
  2. 如果出现问题,例如用户名或密码无效,则servlet会转发到特定于问题状况的页面。例如,有一些页面,如AccountDisabled.jsp,AccountExpired.jsp,AuthenticationFailed.jsp,SecurityQuestionIncorrect.jsp等。
  3. 我需要重新设计这个系统,以集中处理问题条件的处理方式。到目前为止,我已经考虑了两种可能的解决方案:

    • ExceptionŠ
      • 创建一个特定于我需要的异常类,例如AuthException。在必要时从此类继承更具体(例如:InvalidUsernameExceptionInvalidPasswordExceptionAccountDisabledException等。每当出现问题时,抛出特定于该条件的异常。通过web.xml捕获所有异常,并使用<error-page>标记将它们路由到相应的页面。
    • enumŠ
      • 采用错误代码方法,enum跟踪错误代码和描述。可以从成品中的资源包中读取描述。

    我更倾向于enum方法,因为身份验证失败并非真正的“例外情况”,我认为在添加服务器日志的混乱方面没有任何好处。另外,我只是将一个维护头痛替换为另一个。我没有单独的JSP来维护,而是有单独的Exception类。

    我正计划在我专门为此目的编写的servlet中实现“错误”处理。我还将消除所有单独的错误页面,而是设置一个error请求属性,并显示错误消息以显示给用户并转发回引用者。每个目标servlet(Logon,ChangePassword,AnswerProfileQuestions等)都会向请求添加错误代码,并在出现问题时重定向到我的新servlet。我的新servlet看起来像这样:

    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和servlet),我确信有些东西我缺少,或者我的方法不是最理想的。我是在正确的轨道上,还是我需要重新考虑我的策略?

2 个答案:

答案 0 :(得分:2)

(web)应用程序中的异常/错误处理是一个敏感主题。有些人可能选择抛出硬异常并将其捕获到一个地方,其他人可能会选择传递一组错误消息。

我自己更喜欢抛出异常。这更加清晰简洁,可重复使用,可维护和可测试。使用Validator方法设计validate()接口,该方法会引发ValidatorException。相应地实现所需的验证器。收集验证器并在try / catch块中逐个运行它们并在那里收集异常。 E.g。

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中,或者更优选地存储在外部资源文件中,例如,属性文件。这样,它更易于维护,也更容易为您的webapp添加多种语言。

对于不可恢复的错误,例如死数据库或代码中的错误(运行时错误,内部服务器错误等),我只是让异常遍历所有层,以便您可以“捕获”它您可以在<error-page>中定义为web.xml的通用和自定义错误页面。您可以为每种类型的Exception和/或HTTP状态代码定义单独的错误页面。

这也是平均MVC框架如何运作的方式。

答案 1 :(得分:1)

如果使用“例外”,则可以重用默认的ErrorHandling基础结构。抛出异常不必乱丢服务器日志,如果你将它们冒泡到堆栈中,或者将日志配置为不记录它们,或者不记录堆栈跟踪。

然后,您的错误处理程序可以根据异常类型显示相应的消息/导航/恢复。