SpringBoot中@ControllerAdvice结合@InitBinder、@ModelAttribute、@ExceptionHandler的使用

简介

@ControllerAdvice 就是 @Controller 的增强版。主要用来处理全局数据,一般搭配 @InitBinder@ModelAttribute@ExceptionHandler 使用。在@ControllerAdvice注解类的内部使用以上三个注解的方法会应用到所有的@RequestMapping注解的方法。

注:

  • 如果这三个注解直接在@Controller类中使用,则只对当前控制器生效
  • 如果@ControllerAdvice中不需要返回view,也可以使用@RestControllerAdvice,即@RestControllerAdvice = @ControllerAdvice + @ResponseBody

下面将分别介绍:

一、@InitBinder

作用:对HTTP请求参数进行预处理,再绑定到对应的接口。这里我们就可以对参数做一些额外的处理,比如时间格式的转换等。(注意:这里对@RequestBody注解的参数无效,需要自行实现)

在Spring MVC的web项目中,相信小伙伴们经常会遇到一些前端给后端传值比较棘手的问题:
比如后端Controller如何接收Date日期类型的参数,业界比较通用的做法是用时间戳或者用字符串或者使用@DateTimeFormat注解,但是这还需要我们自己做后续的处理转换,或者每一个日期类型的参数都需要加注解处理,用起来麻烦而且不够优雅,这里看我们的@InitBinder是怎么处理的:

import org.apache.commons.lang3.time.DateUtils;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.InitBinder;

import java.beans.PropertyEditorSupport;
import java.text.ParseException;
import java.util.Date;

@ControllerAdvice
public class GlobalHandler {

    private static String[] patterns = {
            "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
            "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
            "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"
    };

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(Date.class, new PropertyEditorSupport() {
            @Override
            public void setAsText(String text) {
                Date date = null;
                try {
                    if (text != null) {
                        date = DateUtils.parseDate(text, patterns);
                    }
                } catch (ParseException e) {
                }
                setValue(date);
            }
        });
    }
}

这样当前后端再需要传日期类型的参数时,后端可以直接使用Date进行接收了。

使用时:
在这里插入图片描述

二、@ModelAttribute

作用:绑定数据

这个注解大家应该很熟悉了,可以在进入接口前绑定一些数据

import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ModelAttribute;

import java.util.HashMap;

@ControllerAdvice
public class GlobalHandler {

    @ModelAttribute
    public void addAttributes(Model model) {
        model.addAttribute("msg", "Hello World");

        HashMap<String, Object> map = new HashMap<>();
        map.put("name", "张三");
        map.put("age", 20);
        model.addAttribute("info", map);
    }
}

使用时:
在这里插入图片描述

三、@ExceptionHandler

作用:统一异常处理

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ExceptionHandler;

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

@ControllerAdvice
public class GlobalHandler {

    private static final Logger LOGGER = LoggerFactory.getLogger(GlobalHandler.class);

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Map<String, Object> handleException(Exception e) {
        LOGGER.error(e.getMessage(), e);

        HashMap<String, Object> map = new HashMap<>(3);
        map.put("code", 500);
        map.put("msg", "服务器内部错误");
        return map;
    }
}

使用时:
在这里插入图片描述
这样,对于RequestMapping标记的方法,只要抛出了Exception异常,便会被此方法拦截,从而返回我们封装标准的响应格式或者view,这里我只处理了Exception异常,还可以指定其他自定义的业务异常等等。

当定义了多个异常处理器的时候,比如@ExceptionHandler(Exception.class)@ExceptionHandler(ParseException.class),如果程序中抛出了异常,那么它将尝试查找为处理异常而注册的最“特定”的异常处理程序。如果没有这样的处理程序,它将尝试检查异常的超类,如果它也没有找到,它会更高级别等等等等,从最具体到一般。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章