SpringBoot之实践@ControllerAdvice

在spring 3.2中,新增了@ControllerAdvice 注解,并且配套有三个注解@ExceptionHandler、@InitBinder、@ModelAttribute,以此来对@RequestMapping注解下的方法进行“切面”环绕。参考:@ControllerAdvice 文档

  • 全局异常处理@ExceptionHandler
  • 全局数据绑定@ModelAttribute
  • 全局数据预处理@InitBinder

一、最常用的全局异常处理

1、自定义异常类

package com.demo.demo.exception;

@Data
public class MyException extends RuntimeException {
    
     public MyException(String msg) {
        this.msg = msg;
    }
    
    public MyException(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }
 
    private String code;
    private String msg;
    
}

2、自定义全局异常处理类

package com.demo.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;

/**
 * 如果全部异常处理返回json,那么可以使用 @RestControllerAdvice 代替 @ControllerAdvice ,这样在方法上就可以不需要添加 @ResponseBody
 */
@ControllerAdvice
public class GlobalExceptionHandler {
 
    /**
     * 全局异常捕捉处理
     */
    @ResponseBody
    @ExceptionHandler(value = Exception.class)
    public Map errorHandler(Exception ex) {
        Map map = new HashMap();
        map.put("code", 500);
        map.put("msg", ex.getMessage());
        return map;
    }
    
    /**
     * 拦截捕捉自定义异常 MyException.class
     */
    @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;
    }
 
     /**
     * 捕捉到异常后,不是返回json而是返回某个渲染的页面
     */
    @ExceptionHandler(value = MyException2.class)
    public ModelAndView myErrorHandler(MyException2 ex) {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("error");
        modelAndView.addObject("code", ex.getCode());
        modelAndView.addObject("msg", ex.getMsg());
        return modelAndView;
    }
}

3、Controller拦截类

@RequestMapping("/getException")
public String getException() throws Exception {
    throw new MyException("500", "自定义异常错误");
//最后返回前端以下json信息
//{"msg":"自定义异常错误","code":"500"}
}

 二、全局数据绑定

1、自定义全局数据绑定类

package com.demo.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;


@ControllerAdvice
public class GlobalController {
 
    /**
     * 把值绑定到Model中,使全局@RequestMapping可以获取到该值
     */
    @ModelAttribute
    public void addAttributes(Model model) {
        model.addAttribute("author", "Magical Sam");
    }

    @ModelAttribute(value = "message")
    public String globalModelAttribute() {
        System.out.println("global model attribute.");
        return "this is from model attribute";
    }
     
}

2、在@RequestMapping下获取定义的值

@RequestMapping("/getValue")
public String getValue(ModelMap modelMap,) {
    System.out.println(modelMap.get("author"));//Magical Sam
}

@RequestMapping("/getValue2")
public String getValue2(@ModelAttribute("message") String message/**感觉像是给一个全局方法返回值取的别名*/) {
    System.out.println(message);//global model attribute.this is from model attribute
}

 

三、全局数据预处理

解决两个实体类有相同属性名,从前端接收两个相同属性会拼接接收的问题

1、有相同属性的实体类

 

2、预处理类

package com.junya.areyouok;

import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.InitBinder;

@ControllerAdvice
public class GlobalData {

    @InitBinder("book")
    public void initA(WebDataBinder binder){
        binder.setFieldDefaultPrefix("book.");
    }

    @InitBinder("author")
    public void initB(WebDataBinder binder){
        binder.setFieldDefaultPrefix("author.");
    }
}

3、controller接收类

package com.junya.areyouok.controller;

import com.junya.areyouok.entity.Author;
import com.junya.areyouok.entity.Book;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

@Controller
public class BookController {

    @PostMapping("/addBook")
    public void addBook(@ModelAttribute("book") Book book, @ModelAttribute("author") Author author) {
        System.out.println(book);
        System.out.println(author);
    }
}

4、从前端传入数据格式

处理前端传入的日期格式字符串到后台解析为Date格式

/**
 * 将前台传递过来的日期格式的字符串,自动转化为Date类型
 */
@InitBinder
public void initBinder(WebDataBinder binder)
{
    //binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));
    // Date 类型转换
    binder.registerCustomEditor(Date.class, new PropertyEditorSupport()
    {
        @Override
        public void setAsText(String text)
        {
            setValue(DateUtils.parseDate(text));
        }
    });
}

四、 小结

       本文首先讲解了@ControllerAdvice注解的作用,然后结合@ControllerAdvice讲解了能够与其结合的三个注解的使用方式。关于这三种使用方式,需要说明的是,这三种注解如果应用于@ControllerAdvice注解所标注的类中,那么它们表示会对@ControllerAdvice所指定的范围内的接口都有效;如果单纯的将这三种注解应用于某个Controller中,那么它们将只会对该Controller中所有的接口有效,并且此时是不需要在该Controller上标注@ControllerAdvice的。

 

 

最后,本文借鉴了一些其他前辈的文章,如果有侵权,请联系我删除哦。

欢迎大家留言交流、共同进步!

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页