当前位置: 代码迷 >> 综合 >> SpringBoot之实践@ControllerAdvice
  详细解决方案

SpringBoot之实践@ControllerAdvice

热度:24   发布时间:2024-03-08 21:41:19.0

在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可以获取到该值*/@ModelAttributepublic 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(){@Overridepublic void setAsText(String text){setValue(DateUtils.parseDate(text));}});
}

四、 小结

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

 

 

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

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