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 方法。
@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
,表示不需要返回響應體,或者響應體已經在方法內部通過其他方式寫入(例如流式寫入)。
@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
的組合,用在類級別時,該類下所有方法默認都會將返回值序列化為響應體。
@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 等不同的狀態碼,并包含響應體。
@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
而言,代碼略顯繁瑣,但在某些場景下(例如需要在返回視圖的同時設置特定的模型數據)仍然有用。
@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
接口的實現類實例,而不是邏輯視圖名。這允許你編程方式地選擇或創建一個視圖。
@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)集成。
@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
: 用于需要流式寫入響應體,特別是當響應體非常大或需要動態生成時。
@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 響應。