Spring MVC exception handling

Posted by adrianTNT on Thu, 27 Jan 2022 18:58:29 +0100

Spring MVC exception handling

In the development of Spring MVC application, whether operating the underlying database, business layer or control layer, we will inevitably encounter all kinds of predictable and unpredictable exceptions. We need to catch and handle exceptions to ensure that the program is not terminated.

Spring MVC has the following three ways to handle exceptions:

  1. Use the simple exception handler SimpleMappingExceptionResolver provided by Spring MVC.
  2. Implement the exception handling interface HandlerExceptionResolver of Spring and customize your own exception handler.
  3. Use the @ ExceptionHandler annotation to implement exception handling

1. @ExceptionHandler

Local exception handling can only handle exceptions in the specified Controller.

Use the annotation @ ExceptionHandler to specify a method as an Exception handling method. This annotation has only one optional attribute value, which is a class <? > Array, used to specify the Exception class to be handled by the annotated method, that is, the Exception to be matched. The return value of the annotated method can be ModelAndView, String, or void. The method name is optional. The method parameters can be Exception and its subclass objects, HttpServletRequest, HttpServletResponse, etc. The system will automatically assign values to these method parameters. For the usage of Exception handling annotation, you can also directly annotate the Exception handling method in the Controller.

Example 1: the following is implemented using the @ ExceptionHandler annotation. Define a testExceptionHandle method that may have exceptions during processing.

@Controller
@RequestMapping("/test")
public class MyController {

    @RequestMapping(value="/register.do")
    public ModelAndView register(String name,int age) throws StudentException{
        if(!"Zhang San".equals(name)){
            throw new NameException("Incorrect name");
        }
        return new ModelAndView("/WEB-INF/jsp/show.jsp");
    }
    
    //NameException exception handling
    @ExceptionHandler(NameException.class)
    public ModelAndView handleNameException(Exception ex){
        ModelAndView mv = new ModelAndView();
        mv.addObject("ex",ex);
        mv.setViewName("/errors/nameErrors.jsp");
        return mv;
    }
}

However, it is generally not used in this way. Instead, the exception handling method is specifically defined in one Controller, and other controllers can inherit the Controller. However, the disadvantages of this usage are also obvious: Java is "single inheritance and multiple implementations". This Controller inheritance uses this only inheritance opportunity, so that if there are other classes that need to be inherited, they cannot be implemented directly.

@Controller
public class MyExceptionResolver {
    //NameException exception handling
    @RequestHandler(NameException.class)
    public ModelAndView handleNameException(Exception ex){
        ModelAndView mv = new ModelAndView();
        mv.addObject("ex",ex);
        mv.setViewName("/errors/nameErrors.jsp");
        return mv;
    }

    //AgeException exception handling
    @ExceptionHandler(AgeException.class)
    public ModelAndView handleAgeException(Exception ex){
        ModelAndView mv = new ModelAndView();
        mv.addObject("ex",ex);
        mv.setViewName("/errors/ageErrors.jsp");
        return mv;
    }
    
    //Other exception handling
    @ExceptionHandler
    public ModelAndView handleOtherException(Exception ex){
        ModelAndView mv = new ModelAndView();
        mv.addObject("ex",ex);
        mv.setViewName("/errors/defaultErrors.jsp");
        return mv;
    }
    
}

2. Modify the controller

Let the normal Controller inherit the customized exception handling Controller.

@Controller
@RequestMapping("/test")
public class MyController extends MyExceptionResolver{
    
    @RequestMapping(value="/register.do")
    public ModelAndView register(String name,int age) throws StudentException{
        
        if(!"Zhang San".equals(name)){
            throw new NameException("Incorrect name");
        }
        
        if(age>50){
            throw new AgeException("Too old");
        }
        
        return new ModelAndView("/WEB-INF/jsp/show.jsp");
    }
}

The output results of the controller are as follows.

Print error message ===> ArithmeticException:java.lang.ArithmeticException: / by zero

@The method priority problem defined by the ExceptionHandler annotation: for example, NullPointerException occurs, but the declared exceptions include RuntimeException and Exception. At this time, the @ ExceptionHandler annotation method with the shallowest inheritance depth will be found according to the nearest inheritance relationship of the Exception, that is, the method marked with RuntimeException.

cover @ExceptionHandler Marked as an exception handling method, no other formal parameters can be set in the method. But you can use ModelAndView Transfer data to the front station.

Using local exception handling, you can only handle exceptions in a Controller. If you need to handle all exceptions uniformly, you can use the following two methods.

2. HandlerExceptionResolver

Spring MVC handles program exceptions through HandlerExceptionResolver, including processor exceptions, data binding exceptions and exceptions that occur during controller execution. HandlerExceptionResolver has only one interface method. The source code is as follows.

public interface HandlerExceptionResolver {
    @Nullable
    ModelAndView resolveException(
            HttpServletRequest request, HttpServletResponse response, 
      @Nullable Object handler, Exception ex);
}

When an exception occurs, Spring MVC will call the resolveException() method, go to the view corresponding to ModelAndView, and return an exception report page to feed back to the user.

Using the SimpleMappingExceptionResolver exception handler defined by spring MVC, you can jump after a specified exception occurs. However, if you want to achieve the purpose of performing some operations when the specified exception is caught, it cannot be completed. At this point, you need to customize the exception handler. To customize the exception handler, you need to implement the HandlerExceptionResolver interface, and this class needs to be registered in the spring MVC configuration file.

public class MyExceptionResolver implements HandlerExceptionResolver{
    
     public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
         
         ModelAndView mv = new ModelAndView();
         //Add exception objects to the data model
         mv.addObject("ex",ex);
         
         //Set default error response page
         mv.setViewName("/errors/defaultErrors.jsp");
         
         //Set NameException response page
         if(ex instanceof NameException){
             mv.setViewName("/errors/nameErrors.jsp");
         }
         
         //Set AgeException response page
         if(ex instanceof AgeException){
             mv.setViewName("/errors/ageErrors.jsp");
         }
         return mv;
     }
}

Example 2: in net biancheng. Create an implementation class MyExceptionHandler of the HandlerExceptionResolver interface in the exception package. The code is as follows.

package net.biancheng.exception;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
public class MyExceptionHandler implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2,
            Exception arg3) {
        Map<String, Object> model = new HashMap<String, Object>();
        // Turn to different pages according to different errors (unified processing), that is, the corresponding relationship between exceptions and views
        if (arg3 instanceof ArithmeticException) {
            return new ModelAndView("error", model);
        }
        return new ModelAndView("error-2", model);
    }
}

In spring MVC servlet Add the following code to the XML file.

<!--trusteeship MyExceptionHandler-->
<bean class="net.biancheng.exception.MyExceptionHandler"/>

Visit again http://localhost:8080/springmvcDemo2/testExceptionHandle?i=0 , page jumps to error.jsp page, and the running results are shown in the figure above.

3. SimpleMappingExceptionResolver

Global exception handling can be implemented using SimpleMappingExceptionResolver. It maps the exception class name to the view name, that is, when an exception occurs, the corresponding view is used to report the exception.

Example 3: in spring MVC servlet Configure the global exception in XML. The code is as follows.

<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <!-- Define the default exception handling page, which is used when the exception type is registered -->
    <property name="defaultErrorView" value="error"></property>
    <!-- Define the variable name used by the exception handling page to obtain exception information. The default name is exception -->
    <property name="exceptionAttribute" value="ex"></property>
    <!-- Define exceptions that need special handling, using class name or full pathname as key,Exception page name as value -->
    <property name="exceptionMappings">
        <props>
            <prop key="ArithmeticException">error</prop>
            <!-- Here you can also continue to expand the handling of different exception types -->
        </props>
    </property>
</bean>

Visit again http://localhost:8080/springmvcDemo2/testExceptionHandle?i=0 , page jumps to error.jsp page, and the running results are shown in the figure above.

Topics: Spring MVC