【发布时间】:2017-12-11 13:59:29
【问题描述】:
你们能否分享一些关于如何设计一个好的实现来处理 Spring MVC 中的异常的建议?以下是我在网上花了一些时间试图找出处理异常的合适或更好的实现后的一些想法。
以下是我正在从事的项目的一些背景:
- 使用的 MVC 框架是 Spring Boot Web。与使用 Spring MVC 的其他项目类似,我将代码分为几层:控制器、服务和模型。
- 在控制器中,主要是验证来自视图(前端)层的表单输入并执行一些业务逻辑。对于表单验证,我使用的是 Spring 验证注释 (JSR 303),它与控制器完美集成。
- 但是,当涉及到分布在控制器和服务层的业务逻辑实现时,我想处理一些检查,如果检查失败,可能会终止控制器/服务方法块的执行。李>
- 所以,我认为最好使用异常来处理这个问题。
- 我在网上找到了一些实现,分享了如何使用 Spring 现有的异常处理机制来实现更好的异常处理框架。例如。控制器建议和基于控制器的异常处理程序等。
所以,这是我的困惑。我想到了两种类型的异常处理机制。两者都是使用 @ControllerAdvice 实现的,它将异常处理分隔在一个单独的 Java 类中。
方法 A
-
在 mvc 控制器中为特定方法重用相同的异常。例如,
公共字符串方法 A() 抛出 AException{ // 呜呜呜 }
然后会有唯一的 AExceptionHandler 在单独的 java 文件中处理这个异常。在 methodA() 中可能有其他方法调用会引发不同的异常。但是,将实现一个 try catch 块来包装抛出其他类型异常的方法并用 AException 重新抛出。
- 因此,对于该方法A,它有点重用AException。当然,BaseException 类还有一些附加属性来存储返回消息(显示在视图上)和返回视图名称的详细信息。
- 但是,这会导致控制器或服务层被返回消息或返回视图名弄乱。
方法 B
- 另一个在控制器或服务层使用独特的异常。但是,将为每个异常实现一个指定的异常处理程序。
- 由于异常是唯一的,细节(返回消息和视图名称)可以放在异常处理程序中,而不会污染控制器层。他们会以这种方式清洁。但是,将有更多的样板代码仅用于异常处理程序和许多针对不同独特情况的异常,我希望终止特定方法块的代码执行。
所以,这些是我现在面临的问题。我希望我在处理 Spring web 异常方面朝着正确的方向前进。请让我知道你对此的想法。谢谢。
示例:
我们以账户注册方式为例:
//In the controller class
public String accountSignUp(@Valid AccountSignUpForm form){
if(bindingResult.hasErrors()){
return "signupview";
}
accountSignUpSvc.validateEmail(form.getEmail);
accountSignUpSvc.createAccount(form);
}
// In the accountSignUpSvc class;
public interface AccountSignUpSvc {
// Check if email has been used for sign up.
void validateEmail(String email) throws DuplicateAccountException;
// Create the account based on the form.
void createAccount(AccountSignUpForm form) throws AccountCreationException;
}
所以使用方法A:
//In the controller class
public String accountSignUp(@Valid AccountSignUpForm form){
if(bindingResult.hasErrors()){
return "signupview";
}
try{
accountSignUpSvc.validateEmail(form.getEmail);
} catch ( DuplicateAccountException e){
// Rethrow with a controller method specific exception
throw new AccountSignUpException("Returned error message"," Internal error message.",e);
}
// Then implement the similar try catch block for the accountSignUpSvc.createAccount method
}
@ControllerAdvice
public class AccountSignUpExceptionHandler{
@ExceptionHandler(AccountSignUpException.class)
public ModelAndView handleAccountSignUpException(HttpServletRequest request, AccountSignUpException ex){
log.error(ex.getInternalError);
ModelAndView mav = new ModelAndView("signup");
mav.addObject("returnError", ex.getReturnError());
return mav;
}
然后使用方法B:
//In the controller class
public String accountSignUp(@Valid AccountSignUpForm form){
if(bindingResult.hasErrors()){
return "signupview";
}
accountSignUpSvc.validateEmail(form.getEmail);
// Then implement the similar try catch block for the accountSignUpSvc.createAccount method
}
@ControllerAdvice
public class AccountSignUpExceptionHandler{
@ExceptionHandler(DuplicateAccountException.class)
public ModelAndView handleDuplicateAccountException(HttpServletRequest request, DuplicateAccountException ex){
log.error("Error due to error");
ModelAndView mav = new ModelAndView("signup");
mav.addObject("returnError", "Return error message: a long error message.");
return mav;
}
我提到的好处是异常处理程序可以是特定的,因为只有特定的条件才会触发它。因此,任何应该在 html 页面上显示的长返回消息都可以在这个特定的异常处理程序中进行编码。
【问题讨论】:
标签: java spring-mvc exception-handling