Spring MVC Controller 方法的返回类型非常灵活,可以根据不同的需求返回多种类型的值。Spring MVC 会根据返回值的类型和相关的注解来决定如何处理响应。
以下是一些常见的 Controller 方法返回类型:
-
String
:- 最常见的类型之一,用于返回逻辑视图名 (Logical View Name)。 Spring MVC 会使用配置的
ViewResolver
根据这个逻辑视图名找到对应的物理视图(例如 JSP 文件、Thymeleaf 模板等),并渲染响应。 - 特殊用法: 如果返回的
String
以"redirect:"
开头,Spring MVC 会执行一个客户端重定向到指定的 URL。 - 特殊用法: 如果返回的
String
以"forward:"
开头,Spring MVC 会执行一个服务器端转发到指定的 URL 或另一个 Controller 方法。
java@GetMapping("/show") public String showPage() { return "myPage"; // 返回逻辑视图名 "myPage" } @PostMapping("/save") public String saveData() { // ... save data ... return "redirect:/success"; // 重定向到 /success } @GetMapping("/process") public String processRequest() { // ... process ... return "forward:/internal/handler"; // 转发到 /internal/handler }
- 最常见的类型之一,用于返回逻辑视图名 (Logical View Name)。 Spring MVC 会使用配置的
-
void
:- 当 Controller 方法返回
void
时,意味着该方法直接处理了响应(例如通过 Servlet API 获取HttpServletResponse
并写入数据),或者 Spring MVC 会根据请求的 URL 自动推断视图名(这种方式较少使用,且依赖于特定的配置)。 - 更常见的是结合
@ResponseBody
使用void
,表示不需要返回响应体,或者响应体已经在方法内部通过其他方式写入(例如流式写入)。
java@PostMapping("/noContent") @ResponseBody // 表示不需要视图,但也没有响应体 public void doNothing() { // 完成一些操作,但不需要返回数据或视图 } // 或者直接操作 response @GetMapping("/directWrite") public void writeResponse(HttpServletResponse response) throws IOException { response.setContentType("text/plain"); response.getWriter().write("Directly written!"); }
- 当 Controller 方法返回
-
Object
(any POJO or collection) with@ResponseBody
:- 当方法返回一个普通的 Java 对象(POJO)、集合或基本数据类型,并且方法或类上使用了
@ResponseBody
注解时,Spring MVC 会跳过视图解析阶段。 - 它会使用配置的
HttpMessageConverter
将返回的对象序列化成特定的格式(如 JSON、XML)写入到 HTTP 响应体中。这种方式是构建 RESTful API 的主要方式。 @RestController
注解本质上是@Controller
和@ResponseBody
的组合,用在类级别时,该类下所有方法默认都会将返回值序列化为响应体。
java@GetMapping("/api/user") @ResponseBody public User getUser() { // ... retrieve user ... return new User("Alice", 30); // 返回 User 对象,会被序列化为 JSON/XML 等 } @RestController // 整个类的方法默认都带 @ResponseBody @RequestMapping("/api") public class UserRestController { @GetMapping("/list") public List<User> getAllUsers() { // ... retrieve list ... return Arrays.asList(new User("Alice", 30), new User("Bob", 25)); } }
- 当方法返回一个普通的 Java 对象(POJO)、集合或基本数据类型,并且方法或类上使用了
-
ResponseEntity<?>
:- 这是 Spring MVC 提供的用于完全控制 HTTP 响应的类型。它允许设置响应的状态码 (Status Code)、HTTP 头 (Headers) 和响应体 (Body)。
- 适合构建 RESTful API,可以方便的返回 200 OK, 201 Created, 404 Not Found 等不同的状态码,并包含响应体。
java@GetMapping("/api/users/{id}") public ResponseEntity<User> getUserById(@PathVariable Long id) { User user = findUser(id); if (user != null) { return ResponseEntity.ok(user); // 返回 200 OK 和用户对象 } else { return ResponseEntity.notFound().build(); // 返回 404 Not Found } } @PostMapping("/api/users") public ResponseEntity<User> createUser(@RequestBody User newUser) { User savedUser = saveUser(newUser); return ResponseEntity.status(HttpStatus.CREATED).body(savedUser); // 返回 201 Created 和创建的用户对象 }
-
ModelAndView
:- Spring MVC 早期常用的类型,它将模型数据 (Model Data) 和视图名 (View Name) 封装在一起返回。
- 虽然功能强大,但相对于返回
String
和@ResponseBody
+Object
而言,代码略显繁琐,但在某些场景下(例如需要在返回视图的同时设置特定的模型数据)仍然有用。
java@GetMapping("/details") public ModelAndView showDetails(@RequestParam Long id) { User user = findUser(id); ModelAndView mav = new ModelAndView("userDetails"); // 设置视图名 mav.addObject("user", user); // 添加模型数据 return mav; }
-
View
:- 可以直接返回一个
View
接口的实现类实例,而不是逻辑视图名。这允许你编程方式地选择或创建一个视图。
java@GetMapping("/customView") public View customView() { return new MyCustomView(); // 返回一个自定义的 View 实现 }
- 可以直接返回一个
-
异步支持的类型:
- Spring MVC 提供了对异步请求处理的支持,可以在 Controller 方法中返回代表未来结果的对象,从而释放容器线程。
Callable<?>
: 将耗时操作封装在Callable
中,Spring 会在一个单独的线程中执行它。DeferredResult<?>
: 允许在一个完全独立的线程或服务中返回结果,然后通过DeferredResult.setResult()
来完成请求。ListenableFuture<?>
(Spring 4.x+),CompletionStage<?>
/CompletableFuture<?>
(Spring 5.x+): 支持与异步框架(如 CompletableFuture)集成。
java@GetMapping("/async/callable") public Callable<String> asyncCallable() { return () -> { Thread.sleep(2000); // 模拟耗时操作 return "asyncResult"; // 返回逻辑视图名 }; } @GetMapping("/async/deferred") public DeferredResult<ResponseEntity<?>> asyncDeferred() { DeferredResult<ResponseEntity<?>> deferredResult = new DeferredResult<>(); // 在另一个线程或事件中处理并设置结果 // someExternalService.process(data -> deferredResult.setResult(ResponseEntity.ok(data))); return deferredResult; }
-
资源相关类型:
- 用于直接返回文件或流资源。
Resource
/InputStreamResource
/ByteArrayResource
: 用于文件下载或提供静态资源。StreamingResponseBody
: 用于需要流式写入响应体,特别是当响应体非常大或需要动态生成时。
java@GetMapping("/download") public ResponseEntity<Resource> downloadFile() throws IOException { Path file = Paths.get("path/to/your/file.txt"); Resource resource = new UrlResource(file.toUri()); return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"") .body(resource); } @GetMapping("/stream") public StreamingResponseBody streamData() { return outputStream -> { for (int i = 0; i < 1000; i++) { outputStream.write(("Data line " + i + "\n").getBytes()); outputStream.flush(); Thread.sleep(10); } }; }
总结:
- 返回 HTML 页面: 使用
String
返回视图名,或ModelAndView
。 - 返回 JSON/XML 数据 (REST API): 使用
@ResponseBody
+Object
,或ResponseEntity<?>
。推荐ResponseEntity<?>
因为它能控制响应状态和头部。 - 重定向: 使用
String
(前缀"redirect:"
)。 - 服务器端转发: 使用
String
(前缀"forward:"
)。 - 需要完全控制响应 (状态码、头部、体): 使用
ResponseEntity<?>
。 - 异步处理请求: 使用
Callable<?>
,DeferredResult<?>
,CompletableFuture<?>
等。 - 直接返回文件或流: 使用
Resource
相关类型或StreamingResponseBody
。 - 不需要返回任何内容 (with @ResponseBody): 使用
void
。
Spring MVC 通过 HandlerMethodReturnValueHandler 机制来处理这些不同的返回类型,为每种类型找到合适的处理器来生成最终的 HTTP 响应。