@ModelAttribute从代码看,可以在方法或方法参数上注解。方法为controller类中的方法。可以是不带@RequestMapping方法。
注解在方法上
@ModelAttribute
public Account addAccount(@RequestParam String uid) {
return accountManager.findAccount(uid);
}
@ModelAttribute
public void populateModel(@RequestParam String uid, Model model) {
model.addAttribute(accountManager.findAccount(uid));
// add more ...
}
上面两种写法效果相同,都是将Account暴露到model中,@ModelAttribute 注解的方法只能是@Contrller标注的类或父子类中,每次调用@RequestMapping方法之前都会先调用@ModelAttribute,一般用于获取公共数据,如获取当前用户信息。
注解在方法参数上
public String processSubmit(@ModelAttribute("pet") Pet pet) {
}
如果model中不存在该数据,则会实例化参数,然后添加到model中(省去了手动添加的步骤)。比如示例方法中,如果model中不存在"pet"名称的实例,则会创建一个同名的实例放到model中。model中"pet"来源
- 可能来自于@SessionAttributes
- 可能来自于同Contrller类中的@ModelAttribute方法,如上节addAccount方法
@@RequestMapping(path = "/accounts/update/{uid}", method = RequestMethod.PUT)
public String processSubmit(@ModelAttribute("account") Account account) { }
- 可能来自于URL模板变量
@RequestMapping(path = "/accounts/{uid}", method = RequestMethod.GET)
public String save(@ModelAttribute("uid") String uid) { }
- 可能来自默认构造器实例
注解可配置项
- name:表示在model中的名称,如果不配置默认名称根据参数类型和返回值类型确定
protected final void addReturnValueAsModelAttribute(Method handlerMethod, Class<?> handlerType,
Object returnValue, ExtendedModelMap implicitModel) {
ModelAttribute attr = AnnotationUtils.findAnnotation(handlerMethod, ModelAttribute.class);
String attrName = (attr != null ? attr.value() : "");
if ("".equals(attrName)) {
Class<?> resolvedType = GenericTypeResolver.resolveReturnType(handlerMethod, handlerType);
attrName = Conventions.getVariableNameForReturnType(handlerMethod, resolvedType, returnValue);
}
implicitModel.addAttribute(attrName, returnValue);
}
ControllerAdvice 注解
@ModelAttribute一般解决同一个Controller中共性问题(如果放在一个公共的Contrller父类,也可以解决多Controller间共性问题),@ControllerAdvice主要解决多Contrller中的共性问题,如公共的数据,全局异常处理,全局入参出参转换等。可包含@ExceptionHandler,@InitBinder,@ModelAttribute注解的方法,这些方法默认将对所有Contrller的@RequestMapping方法启用(可通过@ControllerAdvice属性值限制范围)
属性值
basePackages、basePackageClasses、assignableTypes、annotations:限定作用范围,可配置各种类型
//包路径限定
String[] basePackages() default {};
//包路径解析类
Class<?>[] basePackageClasses() default {};
//直接配置Controller类或接口,如{UserController.class,ControllerInterface.class}
Class<?>[] assignableTypes() default {};
//配置指定注解标注的类,如{RestController.class,Controller.class}
Class<? extends Annotation>[] annotations() default {};
InitBinder 注解
初始化数据类型绑定
@Controller
public class MyFormController {
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));
}
// ...
}
@Controller
public class MyFormController {
@InitBinder
public void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
}
//
}
JsonView 注解
jackson包下的实现,可在方法、成员变量、方法参数和注解类上使用。
@PostMapping("/get1")
@JsonView(WithoutPasswordView.class)
public User createUser(){
return new User("eric", "7!jd#h23",23);
}
@PostMapping("/get2")
@JsonView(WithPasswordView.class)
public User createUser(){
return new User("eric", "7!jd#h23",23);
}
public class User {
public interface WithoutPasswordView {};
public interface WithPasswordView extends WithoutPasswordView {};
private String username;
private String password;
private Integer age;
public User() {
}
public User(String username, String password,Integer age) {
this.username = username;
this.password = password;
this.age = age;
}
@JsonView(WithoutPasswordView.class)
public String getUsername() {
return this.username;
}
@JsonView(WithoutPasswordView.class)
public Integer getAge() {
return this.username;
}
@JsonView(WithPasswordView.class)
public String getPassword() {
return this.password;
}
}
请求/get1
返回 {"username":"eric","age":23}
请求/get2
返回 {"username":"eric","age":23,"password":"7!jd#h23"}
实现了根据不同接口需要返回指定数据,也可以在方法入参使用@JsonView(WithPasswordView.class)注解,作用类似