SpringMVC常用注解(三)

一、@Controller 、@RestController 和 @ControllerAdvice

1. @Controller

@Controller 用于标记在一个类上,使用它标记的类就是一个SpringMVC Controller 对象。分发处理器将会扫描使用了该注解的类的方法,并检测该方法是否使用了@RequestMapping 注解。
使用@Controller 注解,在对应的方法上,视图解析器可以解析return 的jsp,html页面,并且跳转到相应页面;
若返回json等内容到页面,则需要加@ResponseBody注解。

2. @RestController

@RestController注解相当于@ResponseBody + @Controller合在一起的作用。

返回json数据不需要在方法前面加@ResponseBody注解了,但使用@RestController这个注解,就不能返回jsp,html页面,视图解析器无法解析jsp,html页面,返回的内容就是return 里的内容。

若使用@RestController,又想返回页面,则需要使用ModelAndView:

public ModelAndView login(){
        ModelAndView mv = new ModelAndView("index");
        return mv;
   }

3. @ControllerAdvice

@ControllerAdvice,是Spring3.2后提供的新注解,从名字上可以看出大体意思是控制器增强。

ControllerAdvice拆分开来就是Controller Advice,关于Advice,其是用于封装一个切面所有属性的,包括切入点和需要织入的切面逻辑。这里ContrllerAdvice也可以这么理解,其抽象级别应该是用于对Controller进行“切面”环绕的,而具体的业务织入方式则是通过结合其他的注解来实现的(@ControllerAdvice并不是使用AOP的方式来织入业务逻辑的,而是Spring内置对其各个逻辑的织入方式进行了内置支持)。@ControllerAdvice是在类上声明的注解,其用法主要有三点:

(1) 全局异常处理,结合方法型注解@ExceptionHandler,用于捕获Controller中抛出的指定类型的异常,从而达到不同类型的异常区别处理的目的

@ControllerAdvice(basePackages = "mvc")
public class SpringControllerAdvice {
  @ExceptionHandler(RuntimeException.class)
  public ModelAndView runtimeException(RuntimeException e) {
    e.printStackTrace();
    return new ModelAndView("error");
  }
}

在该接口中抛出了RuntimeException,那么理论上,这里的异常捕获器就会捕获该异常,然后返回默认的error视图。以下是UserController的代码:

@RequestMapping(value = "/detail", method = RequestMethod.GET)
public ModelAndView detail(@RequestParam("id") long id) {
    ModelAndView view = new ModelAndView("user");
    User user = userService.detail(id);
    view.addObject("user", user);
    throw new RuntimeException("mock user detail exception.");
}

在UserController中抛出的异常能够被SpringControllerAdvice捕获。

这里需要注意的是,统一处理异常的controller需要放在和普通controller同级的包下,或者在ComponentScan的包下。在处理异常的时候可以使用System.out的方式,也可以使用logger.info,或者可以入到数据库中。

(2) 全局数据绑定,结合方法型注解@InitBinder,用于request中自定义参数解析方式进行注册,从而达到自定义指定格式参数的目的;

对于@InitBinder,该注解的主要作用是绑定一些自定义的参数。一般情况下我们使用的参数通过@RequestParam,@RequestBody或者@ModelAttribute等注解就可以进行绑定了,但对于一些特殊类型参数,比如Date,它们的绑定Spring是没有提供直接的支持的,我们只能为其声明一个转换器,将request中字符串类型的参数通过转换器转换为Date类型的参数,从而供给@RequestMapping标注的方法使用。

@ControllerAdvice(basePackages = "mvc")
public class SpringControllerAdvice {
  @InitBinder
  public void globalInitBinder(WebDataBinder binder) {
    binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));
  }
}

@InitBinder标注的方法注册的Formatter在每次request请求进行参数转换时都会调用,用于判断指定的参数是否为其可以转换的参数。以下是UserController的代码:

@RequestMapping(value = "/detail", method = RequestMethod.GET)
public ModelAndView detail(@RequestParam("id") long id, Date date) {
    System.out.println(date);
    ModelAndView view = new ModelAndView("user");
    User user = userService.detail(id);
    view.addObject("user", user);
    return view;
}

(3) 全局数据预处理,结合方法型注解@ModelAttribute,表示其标注的方法将会在目标Controller方法执行之前执行。

使用@ModelAttribute,如果声明在方法上,并且结合@ControllerAdvice,该方法将会在@ControllerAdvice所指定的范围内的所有接口方法执行之前执行,并且@ModelAttribute标注的方法的返回值还可以供给后续会调用的接口方法使用。

@ControllerAdvice(basePackages = "mvc")
public class SpringControllerAdvice {
  @ModelAttribute(value = "message")
  public String globalModelAttribute() {
    System.out.println("global model attribute.");
    return "this is from model attribute";
  }
}

这里需要注意的是,该方法提供了一个String类型的返回值,而@ModelAttribute中指定了该属性名称为message,这样在Controller层就可以接收该参数了,如下是UserController(普通的@Controller):

@RequestMapping(value = "/detail", method = RequestMethod.GET)
public ModelAndView detail(@RequestParam("id") long id, 
       @ModelAttribute("message") String message) {
    System.out.println(message);
    ModelAndView view = new ModelAndView("user");
    User user = userService.detail(id);
    view.addObject("user", user);
    return view;
}

@ModelAttribute标注的方法的执行是在所有拦截器的preHandle()方法执行之后才会执行。

4. @ControllerAdvice和@RestControllerAdvice的区别

//@ControllerAdvice和@RestControllerAdvice都可以指向控制器的一个子集
// 指向所有带有注解@RestController的控制器
@ControllerAdvice(annotations = RestController.class)
public class AnnotationAdvice {}
// 指向所有指定包中的控制器
@ControllerAdvice("org.example.controllers")
public class BasePackageAdvice {}
// 指向所有带有指定签名的控制器
@ControllerAdvice(assignableTypes = {ControllerInterface.class, AbstractController.class})
public class AssignableTypesAdvice {}

@ControllerAdvice和@RestControllerAdvice的区别 类似于 @RestController 与 @Controller的区别。

二、@RequestBody 和 @ResponseBody

1. @RequestBody

@RequestBody是作用在形参列表上,用于将前台发送过来固定格式的数据【xml 格式或者 json等】封装为对应的 JavaBean 对象,封装时使用到的一个对象是系统默认配置的 HttpMessageConverter进行解析,然后封装到形参上。

public Object login(@RequestBody User loginUuser, HttpSession session)

2. 

猜你喜欢

转载自www.cnblogs.com/myitnews/p/11567719.html