Spring-@ControllerAdvice intercepts exceptions and handles them uniformly

In spring 3.2, @ ControllerAdvice annotation is added,

It can be used to define @ ExceptionHandler, @ InitBinder, @ ModelAttribute and apply to all @ RequestMapping.

Reference resources: @Controlleradvise documentation

1, Introduction

Create mycontrolleradvise and add the @ controlleradvise annotation.

import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;

/**
 * controller Enhancer
 * @author sam
 * @since 2017/7/17
 */
@ControllerAdvice
public class MyControllerAdvice {
    /**
     * Apply to all @ RequestMapping annotation methods and initialize the data binder before execution
     * @param binder
     */
    @InitBinder
    public void initBinder(WebDataBinder binder) {}

    /**
     * Bind the value to the Model so that the global @ RequestMapping can get the value
     * @param model
     */
    @ModelAttribute
    public void addAttributes(Model model) {
        model.addAttribute("author", "Magical Sam");
    }

    /**
     * Global exception capture processing
     * @param ex
     * @return
     */
    @ResponseBody
    @ExceptionHandler(value = Exception.class)
    public Map errorHandler(Exception ex) {
        Map map = new HashMap();
        map.put("code", 100);
        map.put("msg", ex.getMessage());
        return map;
    }
}

After starting the application, the methods annotated by @ ExceptionHandler, @ InitBinder, @ ModelAttribute will all act on the methods annotated by @ RequestMapping.

@ModelAttribute: the value set on the Model can be obtained through ModelMap for all methods annotated by @ RequestMapping

As follows:

@RequestMapping("/home")
public String home(ModelMap modelMap) {
    System.out.println(modelMap.get("author"));
}

//Or through@ModelAttribute Obtain

@RequestMapping("/home")
public String home(@ModelAttribute("author") String author) {
    System.out.println(author);
}

@The exception handler intercepts the exception. We can use this annotation to implement custom exception handling.

Where, the value configured by @ ExceptionHandler specifies the type of exception to be intercepted, which intercepts Exception.class.

2, Custom exception handling (Global exception handling)

By default, spring boot will map to / error for exception handling, but the prompt is not very friendly. Please customize exception handling below to provide a friendly display.

1. Write a custom exception class:

public class MyException extends RuntimeException {
    public MyException(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }
    private String code;
    private String msg;
    // getter & setter
}

Note: spring only rolls back transactions for RuntimeException exceptions.

2. Write global exception handling class

import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;

/**
 * controller Enhancer
 * @author sam
 * @since 2017/7/17
 */
@ControllerAdvice
public class MyControllerAdvice {
    /**
     * Global exception capture processing
     * @param ex
     * @return
     */
    @ResponseBody
    @ExceptionHandler(value = Exception.class)
    public Map errorHandler(Exception ex) {
        Map map = new HashMap();
        map.put("code", 100);
        map.put("msg", ex.getMessage());
        return map;
    }
    
    /**
     * Interception catch custom exception MyException.class
     * @param ex
     * @return
     */
    @ResponseBody
    @ExceptionHandler(value = MyException.class)
    public Map myErrorHandler(MyException ex) {
        Map map = new HashMap();
        map.put("code", ex.getCode());
        map.put("msg", ex.getMsg());
        return map;
    }
}

3. Exception is thrown in the controller for testing.

@RequestMapping("/home")
public String home() throws Exception {
    // throw new Exception("Sam error");
    throw new MyException("101", "Sam error");
}

Start the application, visit: http://localhost:8080/home, display the following json content normally, which proves that the custom exception has been successfully intercepted.

{"msg":"Sam error","code":"101"}

*If you do not need to return json data, but want to render a page template and return it to the browser, you can do this in mycontrolleradvise:

@ExceptionHandler(value = MyException.class)
public ModelAndView myErrorHandler(MyException ex) {
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.setViewName("error");
    modelAndView.addObject("code", ex.getCode());
    modelAndView.addObject("msg", ex.getMsg());
    return modelAndView;
}

In the templates directory, add error.ftl (freemarker is used here) to render:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Error page</title>
</head>
<body>
    <h1>${code}</h1>
    <h1>${msg}</h1>
</body>
</html>

Restart the application. http://localhost:8080/home displays the content of the error page.

Add: if all exception handling returns json, @ restcontrolleradvise can be used instead of @ controlleradvise, so that @ ResponseBody does not need to be added to the method.

 

Reprint link: https://my.oschina.net/langwanghuangshifu/blog/2246890

Tags: Java Spring JSON FreeMarker

Posted on Sun, 22 Dec 2019 05:45:57 -0500 by kyoru