处理类型
- 视图名称
- 当方法返回一个字符串,且该字符串不是ResponseEntity或@ResponseBody注解的返回值时,它通常被视为视图名称。Spring MVC将使用配置的ViewResolver来解析这个视图名称,并生成视图
@Controller public class ViewController { @GetMapping("/viewName") public String viewName() { return "myView"; // 视图解析器将解析为 /WEB-INF/views/myView.jsp } }
- ModelAndView对象
- 当方法返回一个ModelAndView对象时,Spring MVC会使用该对象中的数据来渲染视图
@Controller public class ModelAndViewController { @GetMapping("/modelAndView") public ModelAndView modelAndView() { ModelAndView mav = new ModelAndView(); mav.setViewName("myView"); mav.addObject("message", "Hello, ModelAndView!"); return mav; } }
- Map或Model对象
- 返回的Map或Model对象包含了要传递给视图的属性。Spring MVC会将这些属性添加到模型中,并使用默认或指定的视图名称来渲染视图
@Controller public class ModelController { @GetMapping("/model") public String model(Model model) { model.addAttribute("message", "Hello, Model!"); return "myView"; } }
- 域对象
- 返回的域对象(如DTOs或Entity对象)通常会通过消息转换器(如Jackson)转换为JSON或XML格式的响应体,并标注为@ResponseBody
@RestController public class DomainObjectController { @GetMapping("/domainObject") public User getUser() { User user = new User("John Doe"); return user; // Jackson会自动将其转换为JSON } }
- @ResponseBody注解
- 当方法的返回值被@ResponseBody注解时,Spring MVC会将返回值转换为HTTP响应体。这通常用于RESTful服务
@RestController public class ResponseBodyController { @GetMapping("/responseBody") public @ResponseBody String responseBody() { return "Hello, @ResponseBody!"; } }
- ResponseEntity对象
- 当方法返回一个ResponseEntity对象时,Spring MVC会使用该对象中的HTTP状态码、头部信息和响应体来构建HTTP响应
@RestController public class ResponseEntityController { @GetMapping("/responseEntity") public ResponseEntity<String> responseEntity() { HttpHeaders headers = new HttpHeaders(); headers.add("Custom-Header", "Value"); return new ResponseEntity<>("Hello, ResponseEntity!", headers, HttpStatus.OK); } }
- HttpEntity对象
- 类似于ResponseEntity,但通常用于只包含响应体和头部信息,而不设置状态码
@RestController public class HttpEntityController { @GetMapping("/httpEntity") public HttpEntity<String> httpEntity() { HttpHeaders headers = new HttpHeaders(); headers.add("Custom-Header", "Value"); return new HttpEntity<>("Hello, HttpEntity!", headers); } }
- void或null
- 当方法返回void或null时,Spring MVC不会向客户端发送响应体,但可以设置响应的头部信息
@Controller
public class VoidController {
@GetMapping("/void")
public void voidMethod(HttpServletResponse response) {
response.setStatus(HttpStatus.NO_CONTENT.value());
}
}
- HTTP状态码
- 有时,你可能想要直接返回一个HTTP状态码,而不是数据。这可以通过抛出异常(如ResponseStatusException)来实现
@RestController
public class StatusCodeController {
@GetMapping("/status")
public ResponseEntity<String> status() {
return ResponseEntity.status(HttpStatus.CREATED).body("Resource created successfully");
}
}
- 异常
- 如果Controller方法抛出了异常,Spring MVC会使用异常处理器(@ExceptionHandler)来处理这些异常,并生成相应的响应
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ArithmeticException.class)
public ResponseEntity<String> handleArithmeticException(ArithmeticException ex) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Math error: " + ex.getMessage());
}
}
- 异步处理
- 对于异步处理,你可以返回Callable、DeferredResult或CompletableFuture等类型的对象,Spring MVC会等待异步操作完成后再发送响应
@RestController
public class AsyncController {
@GetMapping("/async")
public CompletableFuture<String> asyncMethod() {
return CompletableFuture.supplyAsync(() -> {
// 模拟长时间运行的任务
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return "Hello, Async!";
});
}
}
- 文件下载
- 如果需要处理文件下载,可以返回Resource对象或使用ResponseEntity与Resource对象一起,来提供文件内容和必要的头部信息
@RestController
public class FileDownloadController {
@GetMapping("/download")
public ResponseEntity<Resource> downloadFile() {
Resource resource = new ClassPathResource("static/files/sample.txt");
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"")
.body(resource);
}
}
源码分析
-
HandlerAdapter接口:
HandlerAdapter接口定义了处理请求的方法,handle方法用于处理请求并返回一个ModelAndView对象。 -
RequestMappingHandlerAdapter类:
RequestMappingHandlerAdapter是HandlerAdapter的一个实现,它负责处理用@RequestMapping注解的方法。
它使用了HandlerMethodReturnValueHandler接口的实现来处理Controller方法的返回值。 -
HandlerMethodReturnValueHandler接口:
这个接口定义了handleReturnValue方法,用于处理Controller方法的返回值。
Spring MVC提供了多种默认的返回值处理器,例如ModelAndViewMethodReturnValueHandler、
ViewMethodReturnValueHandler、ResponseEntityMethodReturnValueHandler等。 -
处理视图名称和ModelAndView对象:
如果方法返回一个String,它通常被视为视图名称,ViewMethodReturnValueHandler会处理这个返回值。
如果方法返回一个ModelAndView对象,ModelAndViewMethodReturnValueHandler会处理这个返回值。 -
处理@ResponseBody和域对象:
当方法返回一个域对象且没有@ResponseBody注解时,Spring MVC会使用ServletModelAttributeMethodProcessor来处理返回值。
如果方法返回的域对象上有@ResponseBody注解,ServletInvocableHandlerMethod会直接将对象写入响应体,通常使用消息转换器(如Jackson)将对象转换为JSON。 -
处理ResponseEntity对象:
ResponseEntityMethodProcessor处理器会处理返回ResponseEntity对象的情况,它允许你完全控制响应的头部、状态码和体。 -
处理void或null:
如果方法返回void或null,EmptyReturnValueHandler处理器会被调用来处理这种情况,通常不会向客户端发送任何响应体。 -
处理异常:
ExceptionMethodReturnValueHandler处理器会处理抛出的异常,它通常会将异常转换为错误页面或JSON响应。 -
异步处理:
对于异步返回类型(如Callable、DeferredResult、CompletableFuture),ServletAsyncHandlerMethodReturnValueHandler处理器会处理这些返回值,并在异步操作完成后发送响应。 -
文件下载:
ResourceMethodReturnValueHandler处理器会处理返回Resource对象的情况,它负责处理文件下载。
在RequestMappingHandlerAdapter的invokeHandlerMethod方法中,会调用extendInterceptors方法来获取返回值处理器链,并根据Controller方法的返回值类型选择合适的处理器来处理返回值。
这些处理器的注册通常发生在RequestMappingHandlerAdapter的初始化过程中,通过afterPropertiesSet方法或通过实现BeanFactoryPostProcessor接口的RequestResponseBodyAdviceAdapterRegistry类来完成。