简体   繁体   English

处理Spring MVC Controller上的异常

[英]Handling exception on Spring MVC Controller

could you guys share some advices on how to design a good implementation for handling exception in Spring MVC? 你们可以分享一些关于如何设计一个好的实现来处理Spring MVC异常的建议吗? Here are some of my thoughts after spending some time online trying to figure out the suitable or better implementation in handling exception. 以下是我在网上花了一些时间试图找出处理异常的合适或更好的实现之后的一些想法。

Here is some background on the project I m working on: 以下是我正在进行的项目的一些背景知识:

  • The MVC framework used is Spring Boot Web. 使用的MVC框架是Spring Boot Web。 Similar to other projects using Spring MVC, I have separated my codes into few layers: controller, services, and model. 与使用Spring MVC的其他项目类似,我将代码分成几层:控制器,服务和模型。
  • In the controller, it is mainly to validate the form inputs from the view(front-end) layer and perform some business logic. 在控制器中,主要是从视图(前端)层验证表单输入并执行一些业务逻辑。 For form validation, I m using using the Spring validation annotation(JSR 303) and it integrates perfectly fine with the controller. 对于表单验证,我使用Spring验证注释(JSR 303)并且它与控制器完美地集成。
  • But, when it comes to the business logic implementation which are distributed across the controller and services layer, I would want to handle some checking which might terminate the execution of the controller/service method block if it fails the check. 但是,当涉及分布在控制器和服务层的业务逻辑实现时,我想要处理一些检查,如果检查失败,可能会终止控制器/服务方法块的执行。
  • So, i think the best would be to use exception for handling this. 所以,我认为最好是使用异常来处理这个问题。
  • There are a few implementation that I found online that share on how to implement a better exception handling framework using Spring existing exception handling mechanism. 我在网上找到的一些实现分享了如何使用Spring现有的异常处理机制实现更好的异常处理框架。 Eg controller advice and controller based exception handler, etc. 例如控制器建议和基于控制器的异常处理程序

So, here is my confusion. 所以,这是我的困惑。 There are two types of exceptions handling mechanism that I have thought of. 我想到了两种类型的异常处理机制。 Both were implemented using @ControllerAdvice, which separates the exception handling in a separate Java class. 两者都是使用@ControllerAdvice实现的,它将单独的Java类中的异常处理分开。

Approach A 方法A.

  • A same exception is reused for a particular method in a mvc controller. 对mvc控制器中的特定方法重用相同的异常。 For example, 例如,

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

  • Then there will be unique AExceptionHandler handling this exception in a separate java file. 然后会有一个独特的AExceptionHandler在一个单独的java文件中处理这个异常。 There could be other method call in methodA() that throws different Exception. 在methodA()中可能有其他方法调用抛出不同的异常。 But, a try catch block would be implemented to wrap the method throwing other type of Exception and re-throw with AException. 但是,将实现一个try catch块来包装该方法抛出其他类型的Exception并使用AException重新抛出。

  • So, it is sort of reusing AException for that methodA. 因此,它有点重用该方法A的AException。 Of cause, there will be some addition attributes for the BaseException class to store the details on return messages(to be displayed on view) and return viewname. 当然,BaseException类会有一些附加属性来存储返回消息的详细信息(在视图中显示)并返回viewname。
  • But, this will cause the controller or service layer to be cluttered with return message or return viewname. 但是,这将导致控制器或服务层混乱,返回消息或返回viewname。

Approach B 方法B.

  • The other uses unique exceptions in controller or service layer. 另一个使用控制器或服务层中的唯一异常。 But, a designated exception handler will be implemented for each exception. 但是,将为每个异常实现指定的异常处理程序。
  • Since the exception is unique, the details(return message and viewname) can be placed at the exception handler, without polluting the controller layer. 由于异常是唯一的,因此可以将详细信息(返回消息和视图名称)放在异常处理程序中,而不会污染控制器层。 They will cleaner in this way. 他们会以这种方式清洁。 But, there will be alot more boilerplate code just for exception handler and many exceptions for different unique cases that I wish to terminate the code execution for a particular method block. 但是,对于异常处理程序将有更多的样板代码,并且我希望终止特定方法块的代码执行的不同唯一情况的许多异常。

So, these are issues I m facing now. 所以,这些是我现在面临的问题。 I hope that I'm moving in the correct direction in terms of handling exception for Spring web. 我希望我在处理Spring Web异常方面朝着正确的方向前进。 Please let me know you thoughts on this. 请让我知道你的想法。 Thanks. 谢谢。

Example: 例:

Lets use the account signup method as example: 让我们使用帐户注册方法作为示例:

//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;
}

So using approach A: 所以使用方法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;
}

Then using approach B: 然后使用方法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;
}

The benefit I mentioned is that the exception handler can be specific as only a certain condition would trigger it. 我提到的好处是异常处理程序可以是特定的,因为只有某个条件会触发它。 So, any long return message that is supposed to be displayed at the html page can be coded in this specific exception handler. 因此,应该在html页面上显示的任何长返回消息都可以在此特定异常处理程序中进行编码。

In my opinion it depends on whether these exceptions you are talking about are checked exceptions or not. 在我看来,这取决于你所讨论的这些例外是否是经过检查的例外情况。 If they are all checked exceptions being thrown in methodA() then I would be inclined to use Approach A and catch these exceptions and return them as your own app specific exception with a single handler in your @ControllerAdvice class. 如果它们都是在methodA()中抛出的所有检查异常,那么我倾向于使用方法A并捕获这些异常并将它们作为您自己的应用程序特定异常返回,并在@ControllerAdvice类中使用单个处理程序。

If however you are wanting to handle error responses for unchecked exceptions that you might expect to occur in your application then I would use approach B. 但是,如果您想要处理应用程序中可能出现的未经检查的异常的错误响应,那么我将使用方法B.

for exception unique field: 对于异常唯一字段:

try{

}
catch(DataIntegrityViolationException e)
{

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM