我最近继承了一个使用裸 servlet 和 JSP(即:无框架)开发的应用程序。我的任务是清理错误处理工作流程。目前,每个<form>
在工作流中提交给 servlet,并根据表单提交的结果,servlet 执行以下两件事之一:
- 如果一切正常,Servlet 将转发或重定向到工作流程中的下一页。
- 如果出现问题,例如用户名或密码无效,servlet 会转发到特定于问题情况的页面。例如,有AccountDisabled.jsp、AccountExpired.jsp、AuthenticationFailed.jsp、SecurityQuestionIn Correct.jsp等页面。
我需要重新设计这个系统,以集中处理问题情况的方式。到目前为止,我已经考虑了两种可能的解决方案:
-
Exception
s- 创建一个特定于我的需求的异常类,例如
AuthException
。必要时从此类继承以更加具体(例如:InvalidUsernameException
、InvalidPasswordException
、AccountDisabledException
等)。每当出现问题情况时,就抛出特定于该情况的异常。通过 web.xml 捕获所有异常,并使用<error-page>
将它们路由到适当的页面。标签。
- 创建一个特定于我的需求的异常类,例如
-
enum
s- 采用错误代码方法,
enum
跟踪错误代码和描述。可以从成品的资源包中读取描述。
- 采用错误代码方法,
我更倾向于 enum
方法,因为身份验证失败并不是真正的“异常(exception)情况”,而且我认为向服务器日志添加困惑没有任何好处。另外,我只是用另一种令人头痛的维护问题来代替。我不需要维护单独的 JSP,而是拥有单独的 Exception
类。
我计划在专门为此目的编写的 servlet 中实现“错误”处理。我还将消除所有单独的错误页面,而不是设置 error
request 属性,其中包含要显示给用户并转发回引荐来源网址的错误消息。每个目标 servlet(登录、更改密码、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),我确信我遗漏了一些东西,或者我的方法不是最佳的。我是否走在正确的道路上,或者我是否需要重新考虑我的策略?
最佳答案
(网络)应用程序中的异常/错误处理是一个敏感话题。有些人可能会选择抛出硬异常并在单个位置捕获它们,其他人可能会选择传递错误消息的集合。
我自己更喜欢抛出异常。这样更加清晰简洁,并且具有更好的可重用性、可维护性和可测试性。设计Validator
与 validate()
的接口(interface)抛出 ValidatorException
的方法。相应地实现所需的 validator 。收集 validator 并在 try/catch block 中一一运行它们,并在那里收集异常。例如
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 框架的工作原理。
关于java - Servlet/JSP 流程控制 : Enums, 异常,还是其他原因?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2547486/