处理Spring MVC Controller

时间:2017-07-07 09:57:22

标签: java spring-mvc exception-handling

你们可以就如何设计一个好的实现来处理Spring MVC中的异常提出一些建议吗?以下是我在网上花了一些时间试图找出处理异常的合适或更好的实现后的一些想法。

以下是我正在进行的项目的背景知识:

  • 使用的MVC框架是Spring Boot Web。与使用Spring MVC的其他项目类似,我将代码分成几层:控制器,服务和模型。
  • 在控制器中,主要是从视图(前端)层验证表单输入并执行一些业务逻辑。对于表单验证,我使用Spring验证注释(JSR 303)并且它与控制器完美地集成。
  • 但是,当涉及分布在控制器和服务层的业务逻辑实现时,我想要处理一些检查,如果检查失败,可能会终止控制器/服务方法块的执行。
  • 所以,我认为最好的办法就是使用异常来处理这个问题。
  • 我在网上找到的一些实现分享了如何使用Spring现有的异常处理机制实现更好的异常处理框架。例如。控制器建议和基于控制器的异常处理程序等

所以,这是我的困惑。我想到了两种类型的异常处理机制。两者都是使用@ControllerAdvice实现的,它将异常处理分离在一个单独的Java类中。

接近A

  • 对mvc控制器中的特定方法重用相同的异常。例如,

    public String methodA()抛出AException {  // bla bla bla }

  • 然后会有一个唯一的AExceptionHandler在一个单独的java文件中处理这个异常。在methodA()中可能有其他方法调用抛出不同的异常。但是,将实现一个try catch块来包装该方法抛出其他类型的Exception并使用AException重新抛出。

  • 因此,它有点重用该方法A的AException。当然,BaseException类会有一些附加属性来存储返回消息的详细信息(在视图中显示)并返回viewname。
  • 但是,这会导致控制器或服务层混乱,返回消息或返回viewname。

方法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页面上显示的长返回消息都可以在这个特定的异常处理程序中编码。

2 个答案:

答案 0 :(得分:0)

在我看来,这取决于你所讨论的这些例外是否是经过检查的例外情况。如果它们都是在methodA()中抛出的所有检查异常,那么我倾向于使用方法A并捕获这些异常并将它们作为您自己的应用程序特定异常返回,并在@ControllerAdvice类中使用单个处理程序。

但是,如果您想要处理应用程序中可能发生的未经检查的异常的错误响应,那么我将使用方法B.

答案 1 :(得分:0)

对于异常唯一字段:

try{

}
catch(DataIntegrityViolationException e)
{

}