赞
踩
在 SpringBoot 中,@ControllerAdvice 通常结合 @ExceptionHandler 注解处理全局异常,全局异常处理详见第 13 章;通过@ControllerAdvice,我们可以将控制器的全局配置放置在同一个位置,注解了@Controller 的类的方法可使用 @ExceptionHandler、@InitBinder、@ModelAttribute 注解到方法上,这对所有注解了@RequestMapping 的控制器内的方法有效
该注解应用位置包括下面几种:
(1) 应用在方法上
(2) 应用在方法的参数上
(3) 应用在方法上,并且方法也使用了@RequestMapping
2.1 应用在方法上
被 @ModelAttribute 注解的方法会在 Controller 每个方法执行之前都执行,因此对于一个 Controller中包含多个URL的时候,要谨慎使用
@Controller
@RequestMapping("/modelattributeTest")
public class ModelAttributeTestController1 {
// 下面的代码也可以放在添加了 @ControllerAdvice 的类中, 那样就会作用于所有的 Controller
@ModelAttribute
public void myModel(@RequestParam(required = false) String abc, Model model) {
model.addAttribute("attributeName", abc);
}
@RequestMapping(value = "/test1")
public String test1() {
return "modelattributetest/test1";
}
}
在请求 /modelattributeTest/test1?abc=aaa 后,会先执行 myModel 方法,然后接着执行 test1 方法,参数 abc 的值被放入 Model 中后,接着被带到 test1 方法中;当返回视图 modelattributetest/test1 时,Model 会被带到页面上,当然在使用 @RequestParam 的时候可以使用 required 来指定参数是否是必须的;如果把 myModel 和 test1 合二为一后的方法也可以,这是我们最常用的方法
@RequestMapping(value = "/test2")
public String test1(@RequestParam(required = false) String abc, Model model) {
model.addAttribute("attributeName", abc);
return "modelattributetest/test1";
}
此外,使用 @ModelAttribute 注解带有返回值的方法如下
// 方法一 @ModelAttribute public String myModel(@RequestParam(required = false) String abc) { return abc; } // 方法二 @ModelAttribute public Student myModel(@RequestParam(required = false) String abc) { Student stu = new Student(abc); return stu; } // 方法三 @ModelAttribute public int myModel(@RequestParam(required = false) int number) { return number; }
这种情况,返回值对象会被默认放到隐含的 Model 中,在 Model 中的 key 为返回值类型(首字母小写),value 为返回的值;那么对应上面三个方法和下面这三个写法等价
model.addAttribute("string", abc);
model.addAttribute("student", stu);
model.addAttribute("int", number);
自定义 key,只需要给 @ModelAttribute 添加 value 属性即可,如下所示;相当于 model.addAttribute(“num”, number);
@ModelAttribute(value = "num")
public int myModel(@RequestParam(required = false) int number) {
return number;
}
2.2 使用 @ModelAttribute 注解方法的参数
@ModelAttribute(value = "num")
public int myModel(@RequestParam(required = false) int number) {
return number;
}
相当于:model.addAttribute(“attributeName”, abc);
补充,顺便提及一下 @SessionAttributes 的使用:
(1) 如果在类上面使用了 @SessionAttributes(“attributeName”) 注解,而本类中恰巧存在attributeName,则会将 attributeName 放入到 session 作用域
(2) 如果在类上面使用了 @SessionAttributes(“attributeName”) 注解,SpringMVC 会在执行方法之前,自动从 session 中读取 key 为 attributeName 的值,并注入到 Model 中
所以我们在方法的参数中使用 @ModelAttribute(“attributeName”) 就会正常的从 Model 读取这个值,也就相当于获取了 session中的值
(3) 使用了 @SessionAttributes 之后,Spring 无法知道什么时候要清掉 @SessionAttributes 存进去的数据,如果要明确告知,也就是在方法中传入 SessionStatus 对象参数,并调 status.setComplete() 就可以了
注意:@SessionAttributes 需要清除时,使用 SessionStatus.setComplete(); 来清除;注意,它只清除 @SessionAttributes 的 session,不会清除 HttpSession 的数据;可参考:https://blog.csdn.net/hayre/article/details/54666275
2.3 应用在方法上,并且方法也使用了 @RequestMapping 注解
@Controller
@RequestMapping("/modelattributeTest4")
public class ModelAttributeTestController4 {
@RequestMapping(value = "/test1")
@ModelAttribute("name")
public String test1(@RequestParam(required = false) String name) {
return name;
}
}
这种情况下,返回值 String(或者其他对象),就不再是视图了;将是我们上面将到的放入 Model 中的值,此时对应的页面就是 @RequestMapping 的 value 值 test1;等价于
model.addAttribute("name", name);
return "test1";
2.4 全局设置 @ModelAttribute,需要结合 @ControllerAdvice 使用,新建一个类,添加如下代码测试
@ControllerAdvice public class GlobalExceptionHandler { // 全局添加属性值 @ModelAttribute public void newUser(Model model) { System.out.println("... @ModelAttribute 应用到所有@RequestMapping注解方法, 在其执行之前把返回值放入Model..."); model.addAttribute("temp", new User("dufu", "666", new Date())); } // 或者如下这样,这样就相当于 mode.addAttribue("temp", new User("dufu", "666", new Date())) @ModelAttribute("temp") public User newUser() { System.out.println("... @ModelAttribute 应用到所有@RequestMapping注解方法, 在其执行之前把返回值放入Model..."); return new User("dufu", "666", new Date())); } }
所有使用了 @RequestMapping 或者类似的注解(如:@GetMapping)的方法都会被作用到;我们就可以在页面上获取到设置的值
注意:如果要在 Controller 里获取 @ModelAttribute 设置的值,可参考如下代码
@GetMapping("/user")
public User getUser(@ModelAttribue("temp")User user) {
return user;
}
多用作转换器,主要用于对添加了@Controller 的类,@RequestMapping 注解的方法,在方法执行之前执行;主要作用于 GET 请求,常用来校验接收的值,设置不返回的值,或者初始化传递来的值(常用来对前端传递来的日期的转化处理)
示例,结合 @ControllerAdvice 注解将前端传递的 http://xxx?user=ramos:123 这样的字符串转化为 user 对象
@ControllerAdvice
public class GlobalExceptionHandler {
// 全局初始化值
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(User.class, new UserEditor());
System.out.println("... @InitBinder 应用到所有@RequestMapping注解方法,
在其执行之前初始化数据绑定器...");
}
}
上面的代码,我们添加了一个转化器,用于把前端传递过来的字符串转化成对应的 User 对象;那么需要添加一个转化器:UserEditor,注意自定义的转化器需要继承 PropertyEditorSupport
public class UserEditor extends PropertyEditorSupport { @Override public String getAsText() { return super.getAsText(); } @Override public void setAsText(String text) throws IllegalArgumentException { if (!StringUtils.isEmpty(text)) { User user = new User(); String[] items = text.split(":"); user.setUsername(items[0]); user.setPassword(items[1]); user.setCreateDate(new Date()); setValue(user); } else { throw new CommonException("传递的字符串为空"); } } }
Contorller 层调用,注意这里是 Get 请求,接收的值却是 User 对象;@RequestParam 注解不可少
@GetMapping(value="/name}")
@ResponseBody
public User getUserByName(@RequestParam("user") User user) {
System.out.println(user);
return user;
}
前端传递格式:http://localhost:8080/user/name/andy?user=ramos:123,这样就能把字符串转化成 user 对象;相当于一个转换器
除了使用 @ControllerAdvice 来配置全局的 WebDataBinder,还可以使用 RequestMappingHandlerAdapter;如下是一个格式化时间的 dataBinder 的实现
@Bean
public RequestMappingHandlerAdapter webBindingInitializer() {
RequestMappingHandlerAdapter adapter = new RequestMappingHandlerAdapter();
adapter.setWebBindingInitializer(new WebBindingInitializer() {@
Override
public void initBinder(WebDataBinder binder, WebRequest request) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
binder.registerCustomEditor(Date.class, new CustomDateEditor(format, false));
}
});
return adapter;
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。