Spring Boot series (8)@Controller Advice intercepts exceptions and handles them uniformly

Keywords: Java JSON Spring FreeMarker

In spring 3.2, Added @Controller Advice Annotations, Can be used to define @ExceptionHandler,@InitBinder,@ModelAttributeļ¼ŒAnd applied to all @RequestMapping . Reference resources: @ Controller Advice document

I. Introduction

Create MyController Advice and add the @Controller Advice annotation.

package com.sam.demo.controller;

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 to initialize the data binder before execution
     * @param binder
     */
    @InitBinder
    public void initBinder(WebDataBinder binder) {}

    /**
     * Bind the value to Model so that 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 launching the application, the methods annotated by @ExceptionHandler, @InitBinder, @ModelAttribute all work on the methods annotated by @RequestMapping.

@ ModelAttribute: The values set on Model can be obtained through ModelMap for all methods annotated with @RequestMapping, as follows:

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

//Or get it through @ModelAttribute

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

@ ExceptionHandler intercepts exceptions, and we can implement custom exception handling through this annotation. The value of the @ExceptionHandler configuration specifies the type of exception that needs to be intercepted, which intercepts Exception.class.

2. Custom exception handling (global exception handling)

spring boot maps to / error by default for exception handling, but the prompt is not very friendly. Here, we customize exception handling to provide a friendly display.

1. Write custom exception classes:

package com.sam.demo.custom;

/**
 * @author sam
 * @since 2017/7/17
 */
public class MyException extends Exception {

    public MyException(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    private String code;
    private String msg;

    // getter & setter
}

2. Writing global exception handling classes

Create MyControllerAdvice.java as follows:

package com.sam.demo.controller;

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;
    }
    
    /**
     * Intercept and capture 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. Throw an exception 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, access: http://localhost:8080/home The following json content is normally displayed, proving that the custom exception has been successfully intercepted.

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

* If you don't need to return json data and want to render a page template back to the browser, MyController Advice can do this:

@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 (using freemarker here) for rendering:

<!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 Display custom error page content.

Supplementary: If all exception handling returns to json, then @RestController Advice can be used instead of @Controller Advice, so that @ResponseBody does not need to be added in the method.

Copyright Statement: This article is the original article of the blogger. Please indicate the source for reprinting.

Posted by anthylon on Wed, 12 Jun 2019 13:16:51 -0700