我最近继承了使用裸servlet和JSP开发的应用程序(即:没有框架)。我的任务是清理错误处理工作流程。目前,工作流中的每个<form>
都提交给一个servlet,并根据表单提交的结果,servlet执行以下两项操作之一:
我需要重新设计这个系统,以集中处理问题条件的处理方式。到目前为止,我已经考虑了两种可能的解决方案:
Exception
Š
AuthException
。在必要时从此类继承更具体(例如:InvalidUsernameException
,InvalidPasswordException
,AccountDisabledException
等。每当出现问题时,抛出特定于该条件的异常。通过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),我确信有些东西我缺少,或者我的方法不是最理想的。我是在正确的轨道上,还是我需要重新考虑我的策略?
答案 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基础结构。抛出异常不必乱丢服务器日志,如果你将它们冒泡到堆栈中,或者将日志配置为不记录它们,或者不记录堆栈跟踪。
然后,您的错误处理程序可以根据异常类型显示相应的消息/导航/恢复。