首页 > 其他分享 >@ControllerAdvice 和 @RestControllerAdvice 注解

@ControllerAdvice 和 @RestControllerAdvice 注解

时间:2023-05-06 20:12:17浏览次数:49  
标签:map code ControllerAdvice ex import msg 注解 RestControllerAdvice public

转:Spring Boot 系列(八)@ControllerAdvice 拦截异常并统一处理

在 spring 3.2 中,新增了 @ControllerAdvice 注解,结合 @ExceptionHandler、@InitBinder、@ModelAttribute,可以对所有添加了 @RequestMapping 注解的方法作增强。参考:@ControllerAdvice

一、介绍

创建 MyControllerAdvice,并添加 @ControllerAdvice 注解。

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 增强器
 * @author sam
 * @since 2017/7/17
 */
@ControllerAdvice
public class MyControllerAdvice {

    /**
     * 应用到所有 @RequestMapping 注解方法,在其执行之前初始化数据绑定器
     * @param binder
     */
    @InitBinder
    public void initBinder(WebDataBinder binder) {}

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

    /**
     * 全局异常捕捉处理
     * @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;
    }

}

启动应用后,被 @ExceptionHandler、@InitBinder、@ModelAttribute 注解的方法,都会作用在 被 @RequestMapping 注解的方法上。

对于所有被 @RequestMapping 注解的方法中,都可以通过 ModelMap 获取使用 @ModelAttribute 在 Model 上设置的值,如下:

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

//或者 通过 @ModelAttribute 获取

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

@ExceptionHandler 拦截了异常,我们可以通过该注解实现自定义异常处理。其中,@ExceptionHandler 配置的 value 指定需要拦截的异常类型,上面拦截了 Exception.class 这种异常。

二、自定义异常处理(全局异常处理)

spring boot 默认情况下会映射到 /error 进行异常处理,但是提示并不十分友好,下面自定义异常处理,提供友好展示。

1、编写自定义异常类:

package com.sam.demo.custom;

/**
 * @author sam
 * @since 2017/7/17
 */
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
}

注:spring 对于 RuntimeException 异常才会进行事务回滚。

2、编写全局异常处理类

创建 MyControllerAdvice.java,如下:

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 增强器
 *
 * @author sam
 * @since 2017/7/17
 */
@ControllerAdvice
public class MyControllerAdvice {

    /**
     * 全局异常捕捉处理
     * @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;
    }
    
    /**
     * 拦截捕捉自定义异常 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、controller 中抛出异常进行测试。

@RequestMapping("/home")
public String home() throws Exception {

    // throw new Exception("Sam 错误");
    throw new MyException("101", "Sam 错误");

}

启动应用,访问:http://localhost:8080/home,正常显示以下 json 内容,证明自定义异常已经成功被拦截。

{"msg":"Sam 错误","code":"101"}

* 如果不需要返回 json 数据,而要渲染某个页面模板返回给浏览器,那么 MyControllerAdvice 中可以这么实现:

@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;
}

在 templates 目录下,添加 error.ftl(这里使用 freemarker)进行渲染:

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

重启应用,http://localhost:8080/home 显示自定的错误页面内容。

补充:如果全部异常处理返回 json,那么可以使用 @RestControllerAdvice 代替 @ControllerAdvice,这样在方法上就可以不需要添加 @ResponseBody。

标签:map,code,ControllerAdvice,ex,import,msg,注解,RestControllerAdvice,public
From: https://www.cnblogs.com/Higurashi-kagome/p/17378326.html

相关文章

  • spring3.0 mvc rest 注解之@
    关键字:springmvcrest注解之@@RequestMapping@RequestParam@PathVariable@ModelAttributes@SessionAttributes@CookieValue@RequestHeader都是SpringMVCREST中的注释方法,这几种注释方法的用法如下:1#Controller示例URL示例:POST/users/quer......
  • hibernate二级缓存(包括注解方式)
    二级缓存配置(spring+hibernate)说明:本人不建议使用查询缓存,因为查询缓存要求完全相同的查询sql语句才会起作用,所说的查询缓存是针对第二次查询时sql语句与第一次sql语句完全相同那么就可以从缓存中取数据而不去数据库中取数据了,在不启用查询缓存的情况下......
  • spring-transaction源码分析(2)EnableTransactionManagement注解
    概述(Javadoc)该注解开启spring的注解驱动事务管理功能,通常标注在@Configuration类上面用于开启命令式事务管理或响应式事务管理。@Configuration@EnableTransactionManagementpublicclassAppConfig{@BeanpublicFooRepositoryfooRepository(){//c......
  • swagger3 常用注解
    swagger2OpenAPI3注解位置@Api@Tag(name=“接口类描述”)Controller类上@ApiOperation@Operation(summary=“接口方法描述”)Controller方法上@ApiImplicitParams@ParametersController方法上@ApiImplicitParam@Parameter(description=“参数描......
  • Spring @Scheduled注解的理解
    一个cron表达式有至少6个(也可能7个)有空格分隔的时间元素。按顺序依次为:1.秒(0~59)2.分钟(0~59)3.小时(0~23)4.天(月)(0~31,但是你需要考虑你月的天数)5.月(0~11)6.天(星期)(1~71=SUN或SUN,MON,TUE,WED,THU,FRI,SAT)7.年份(1970-2099)在子表达式(月)里表示每个月的含义,“”在子表达式(天(星期))表示星期......
  • Spring17_注解开发7
    一、Spring原始注解Spring是轻代码而重配置的框架,配置比较繁重,影响开发效率,所以注解开发是一种趋势,注解代替xml配置文件可以简化配置,提高开发效率。Spring原始注解主要是替代<Bean>的配置注入的3个注解用来替代property注入的。注意:使用注解进行开发时,需要在a......
  • @enableFeignClients注解的basePackages属性的作用
    basePackages属性是@EnableFeignClients注解的一个可选属性,它用于指定需要扫描的包路径。通过设置该属性,可以告诉Spring在哪些包下查找用@FeignClient注解标记的接口。basePackages中的包可以指定其他模块的包。在多模块的项目中,如果你想要在一个模块中使用另一个模块的......
  • springboot 切面注解方式 记录日志
    1.定义GateOpLogimportjava.lang.annotation.*;/***操作日志记录*@authorcodefulture*/@Target({ElementType.METHOD,ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic@interfaceGateOpLog{/***说明*/Strin......
  • lombok的@Builder注解
    lombok的@Builder注解:链式构建一个对象Student.builder().sno("001").sname("admin").sage(18).sphone("110").build();......
  • @Import注解原理源码分析
    文章结构@Import注解源码的入口位置@Import注解原理收集@Import注解处理收集的imports@Import注解源码的入口位置源码的入口位置在ConfigurationClassParser#doProcessConfigurationClass方法中,至于为什么是这个位置,先按下不表后续会填坑完善。Spring如何解析配置类先简单看下Spr......