spring boot中@ControllerAdvice的用法,全局异常处理,全局数据绑定,全局数据预处理

1: @ControllerAdvice理解

@ControllerAdvice是spring 3.2提供的新注解,他是一个controller增强器,加了@ControllerAdvice的类为那些声明了(@ExceptionHandler、@InitBinder 或 @ModelAttribute注解修饰的)方法的类而提供的专业化的@Component , 以供多个 Controller类所共享。说白了,就是aop思想的一种实现,你告诉我需要拦截规则,我帮你把他们拦下来,具体你想做更细致的拦截筛选和拦截之后的处理,你自己通过@ExceptionHandler、@InitBinder 或 @ModelAttribute这三个注解以及被其注解的方法来自定义。可以对controller中使用到@RequestMapping注解的方法做逻辑处理,用法可分为以下三种:

  • 全局异常处理:@ExceptionHandler注解标注的方法:用于捕获Controller中抛出的不同类型的异常,从而达到异常全局处理的目的
  • 全局数据绑定:@InitBinder注解标注的方法:用于请求中注册自定义参数的解析,从而达到自定义请求参数格式的目的;
  • 全局数据预处理:@ModelAttribute注解标注的方法:表示此方法会在执行目标Controller方法之前执行

注意:这三个注解都可以在普通的Controller类上使用,ControllerAdvice只是作用范围可以自定义(默认全部)

@ControllerAdvice作用范围

ControllerAdvice 提供了多种指定Advice规则的定义方式,默认什么都不写,则是Advice所有Controller,当然你也可以通过下列的方式指定规则
1:指定包

匹配com.example.springbootshiro.controller包及其子包下的所有Controller
@ControllerAdvice(basePackages="com.example.springbootshiro.controller")
当然也可以用数组的形式指定,如:
@ControllerAdvice(basePackages={"com.example.springbootshiro.controller", "com.example.other.controller"}),

2:指点注解

//比如我自定了一个 @CustomAnnotation 注解,我想匹配所有被这个注解修饰的 Controller, 可以这么写:
@ControllerAdvice(annotations={CustomAnnotation.class})

2:@ExceptionHandler全局异常处理

@ControllerAdvice
public class MyGlobalExceptionHandler {
    @ExceptionHandler(Exception.class)
    public ModelAndView grobalExceptionHandler(Exception e) {
        ModelAndView mv = new ModelAndView();
        mv.addObject("message", e.getMessage());
        mv.setViewName("myerror");
        return mv;
    }

    @ExceptionHandler(CustomException.class)
    public ModelAndView customException(Exception e) {
        ModelAndView mv = new ModelAndView();
        mv.addObject("message", e.getMessage());
        mv.setViewName("myerror");
        return mv;
    }    

	@ExceptionHandler(MaxUploadSizeExceededException.class)
    public void myexcept(MaxUploadSizeExceededException e, HttpServletResponse response){
         response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = null;
        try {
            writer = response.getWriter();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        writer.write("文件太大,请重新选择");
        writer.flush();
        writer.close();

    }
 
}

@ExceptionHandler(Exception.class)表示捕捉没有在代码中try catch的异常
@ExceptionHandler(CustomException.class)表示只捕捉自定义的异常,SurvetException是我自定义的继承Exception的类,如果执行了@ExceptionHandler(CustomException.class)中的代码就不再执行@ExceptionHandler(Exception.class)中的代码

3:预设全局数据 @ModelAttribute

有一些初始数据的操作,我们可以将一些公共的数据定义在添加了@ControllerAdvice类中,这样所有的Controller接口, 都能访问到这些数据,如下:
示例1:

//定义全局数据
@ControllerAdvice
public class MyGlobalExceptionHandler {
    //标记该方法的返回数据是一个全局数据,默认key是返回的变量名(下面方法即为 map),value是方法返回值
    //可以通过 @ModelAttribute 注解的 name 属性去重新指定 key(下面方法即为 place)。
     @ModelAttribute(name = "place")
    public Map<String,Object> mydata() {
        HashMap<String, Object> map = new HashMap<>();
        map.put("city", "广州");
        map.put("province", "广东");
        return map;
    }
}
-----------------------------------------------------------------------------------

//在controller使用全局变量
@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello(Model model) {
        // 获取数据
        Map<String, Object> map = model.asMap();
        System.out.println(map);
        return "Welcome to here";
    }
}
// {place={city=广州, province=广东}

示例2:

	//​ 使用@ModelAttribute可以在controller请求前存入数据
	// 1.无返回值方法,放入Model,自定义 key ,value
    @ModelAttribute()
    public void presetParam(Model model) {
        model.addAttribute("globalAttr", "我是全局参数");
    }

    // 2.不有指定name,返回值方法,返回值是map,int等,key就是map,int等,,value是返回值
    @ModelAttribute()
    public Map<String, String> presetParam2() {
        Map<String, String> map1 = new HashMap<String, String>();
        map1.put("key1", "value1");
        return map1;
    }

    // 3.指定name,返回值方法,key就是name,value是返回值
    @ModelAttribute(name = "map2")
    public Map<String, String> presetParam3() {
        Map<String, String> map = new HashMap<String, String>();
        map.put("key2", "value2");
        return map;
    }

	// 4.可以接受请求参数
    @ModelAttribute()
    public void presetParam4(@RequestParam("name") String name,Model model) {
        model.addAttribute("name", name);
    }

-----------------------------------------------------------------------------------

	 //1.使用Model取出
    @GetMapping("model")
    public String methodOne(Model model) {
        Map<String, Object> modelMap = model.asMap();
        System.out.println(modelMap.get("name").toString()); // 传入name的值    
        return modelMap.get("globalAttr").toString();
    }

    //2.使用ModelMap取出
    @GetMapping("modelMap")
    public String methodThree(ModelMap modelMap) {
        return modelMap.get("map").toString();
    }

    //3.@ModelAttribute()指定key,直接取出
    @GetMapping("modelAttribute")
    public String methodTwo(@ModelAttribute("map2") Map map2) {
        return map2.toString();
    }
	


4:请求参数预处理 @InitBinder

1:考虑我有两个实体类,Book 和 Author,分别定义如下:

@Data
public class Book {
    private String name;
    private Long price; 
}
@Data
public class Author {
    private String name;
   private Integer age;
}

2:访问接口添加操作就会有问题,因为两个实体类都有一个 name 属性,从前端传递时 ,无法区分

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

3:此时,通过 @ControllerAdvice 的全局数据预处理可以解决这个问题,@ModelAttribute给接口中的变量取别名

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

4:进行请求数据预处理,在 @ControllerAdvice 标记的类中添加如下代码:

public class InitController {
@InitBinder("b")
public void b(WebDataBinder binder) {
    binder.setFieldDefaultPrefix("b.");
}
@InitBinder("a")
public void a(WebDataBinder binder) {
    binder.setFieldDefaultPrefix("a.");
}
}

@InitBinder(“b”) 注解表示该方法用来处理和Book和相关的参数,在方法中,给参数添加一个 b 前缀,即请求参数要有b前缀。请求发送时,通过给不同对象的参数添加不同的前缀,可以实现参数的区分.url=http://localhost:8080/book?a.name=张三&a.age=18&b.name=三国演义&b.price=88

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值