Discover 17 Spring Boot Return Types: From @ResponseBody to Flux & Mono
This article explains how Spring Boot controllers can return up to 17 different response types—including @ResponseBody, HttpEntity, ResponseEntity, HttpHeaders, ErrorResponse, ProblemDetail, String views, ModelAndView, @ModelAttribute, DeferredResult, Callable, CompletableFuture, ResponseBodyEmitter, SseEmitter, StreamingResponseBody, Flux and Mono—providing code examples, usage notes, and sample output images for each.
In Spring Boot development, using @RestController or @Controller together with @RequestMapping lets developers define controller methods that can return a wide variety of response types, from JSON data to view pages.
1. Introduction
The article lists 17 possible return value types for Spring MVC controller methods and demonstrates each with code snippets and example output.
2.1 @ResponseBody
Annotating a method with @ResponseBody causes Spring MVC to serialize the returned object via HttpMessageConverter into the response body.
<span>@GetMapping("/{id}")</span>
<span>@ResponseBody</span>
<span>public Account query(@PathVariable Long id) {</span>
<span> return new Account(id, "Spring全家桶实战案例源码");</span>
<span>}</span>When placed at the class level, it has the same effect as @RestController.
2.2 HttpEntity
Returning HttpEntity lets you set both response headers and body manually.
<span>@GetMapping("/httpentity")</span>
<span>public HttpEntity<Account> httpentity() {</span>
<span> Account data = new Account(1L, "Pack");</span>
<span> HttpHeaders headers = new HttpHeaders();</span>
<span> headers.add("Content-Type", "application/xml");</span>
<span> return new HttpEntity<Account>(data, headers);</span>
<span>}</span>2.3 ResponseEntity
ResponseEntityextends HttpEntity and is typically used to customize status code, headers and body for responses.
<span>@GetMapping("/responseentity")</span>
<span>public ResponseEntity<Account> responseentity() {</span>
<span> Account data = new Account(1L, "Pack/Spring全家桶实战案例源码");</span>
<span> return ResponseEntity.ok()</span>
<span> .header("Content-Type", "application/xml")</span>
<span> .body(data);</span>
<span>}</span>2.4 HttpHeaders
Returning HttpHeaders alone sends only header information without a body.
<span>@GetMapping("/httpheaders")</span>
<span>public HttpHeaders httpheaders() {</span>
<span> HttpHeaders headers = new HttpHeaders();</span>
<span> headers.add("x-token", UUID.randomUUID().toString().replace("-", ""));</span>
<span> return headers;</span>
<span>}</span>2.5 ErrorResponse
Used to render RFC 9457 compliant error responses.
<span>@GetMapping("/errorresponse")</span>
<span>public ErrorResponse errorresponse() {</span>
<span> URI uri = MvcUriComponentsBuilder.fromMethodName(ReturnValueController.class, "errorresponse").build().toUri();</span>
<span> return ErrorResponse.builder(new RuntimeException("接口发生异常"), HttpStatusCode.valueOf(500), "错误的参数信息")
<span> .title("API错误")
<span> .instance(uri)
<span> .build();</span>
<span>}</span>2.6 ProblemDetail
Another way to produce RFC 9457 error bodies.
<span>@GetMapping("/problemdetail")</span>
<span>public ProblemDetail problemdetail() {</span>
<span> ProblemDetail detail = ProblemDetail.forStatus(500);</span>
<span> detail.setDetail("请求接口的参数不正确");</span>
<span> detail.setInstance(URI.create("http://localhost:8888/api/query"));</span>
<span> detail.setTitle("API错误");</span>
<span> return detail;</span>
<span>}</span>2.7 String (View Name)
Returning a String from a controller method indicates the name of a view (e.g., an HTML or JSP page).
<span>@Controller</span>
<span>@RequestMapping("/view")</span>
<span>public class ViewController {</span>
<span> @GetMapping("home")</span>
<span> public String index() {</span>
<span> return "index";</span>
<span> }</span>
<span>}</span>The corresponding index.html must exist under classpath:/templates/.
2.8 View
Returning a View instance allows custom rendering by overriding its render method.
<span>@GetMapping("/view")</span>
<span>public View view() {</span>
<span> return new View() {</span>
<span> @Override</span>
<span> public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {</span>
<span> response.setContentType("text/html;charset=utf-8");</span>
<span> response.getWriter().println("<h1>《Spring全家桶实战案例源码》,作者:Pack</h1>");</span>
<span> }</span>
<span> };</span>
<span>}</span>2.9 ModelAndView
Encapsulates view name, model data and optional status code.
<span>@GetMapping("modelandview")</span>
<span>public ModelAndView modelandview() {</span>
<span> ModelAndView view = new ModelAndView();</span>
<span> view.setViewName("user");</span>
<span> view.setStatus(HttpStatusCode.valueOf(200));</span>
<span> view.addObject("data", "《Spring全家桶实战案例源码》,作者:Pack");</span>
<span> return view;</span>
<span>}</span>2.10 @ModelAttribute
Allows adding objects to the model before a view is rendered.
<span>@ModelAttribute</span>
<span>public User queryUser() {</span>
<span> return new User("Pack", 22);</span>
<span>}</span>2.11 void
A method returning void (or null) can write directly to the HttpServletResponse or be annotated with @ResponseStatus to set the status code.
<span>@GetMapping("/void")</span>
<span>public void rvoid(HttpServletResponse response) throws Throwable {</span>
<span> response.setContentType("text/html;charset=utf-8");</span>
<span> response.getWriter().println("<h1>《Spring全家桶实战案例源码》,作者:Pack</h1>");</span>
<span>}</span>2.12 DeferredResult
Enables asynchronous production of any of the above return types from a separate thread.
<span>private DeferredResult<String> dr;</span>
<span>@GetMapping("/deferredresult")</span>
<span>public DeferredResult<String> deferredresult() {</span>
<span> dr = new DeferredResult<>();</span>
<span> return dr;</span>
<span>}</span>
<span>@GetMapping("/sendResult")</span>
<span>public void sendResult() {</span>
<span> new Thread(() -> {</span>
<span> try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) {} </span>
<span> dr.setResult("复杂的运算执行完成...");</span>
<span> }).start();</span>
<span>}</span>2.13 Callable
Executes a task in the Spring MVC thread pool and returns the result after completion.
<span>@GetMapping("/callable")</span>
<span>public Callable<String> callable() {</span>
<span> return () -> {</span>
<span> TimeUnit.SECONDS.sleep(3);</span>
<span> return "Callable 结果返回...";</span>
<span> };</span>
<span>}</span>2.14 CompletableFuture & CompletionStage
Alternative asynchronous return types similar to DeferredResult.
<span>@GetMapping("/completablefuture")</span>
<span>public CompletableFuture<String> completablefuture() {</span>
<span> return CompletableFuture.supplyAsync(() -> {</span>
<span> try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) {} </span>
<span> return "CompletableFuture 返回结果...";</span>
<span> });</span>
<span>}</span>2.15 ResponseBodyEmitter & SseEmitter
Streams objects asynchronously to the client using HttpMessageConverter. The emitter can be completed after all data is sent.
<span>private ResponseBodyEmitter emitter;</span>
<span>@GetMapping("/responsebodyemitter")</span>
<span>public ResponseBodyEmitter responsebodyemitter() {</span>
<span> emitter = new ResponseBodyEmitter();</span>
<span> return emitter;</span>
<span>}</span>
<span>@GetMapping("/stream/send")</span>
<span>public void streamSend() {</span>
<span> new Thread(() -> {</span>
<span> int i = 0;</span>
<span> do {</span>
<span> try {</span>
<span> emitter.send(DateTimeFormatter.ofPattern("mm:ss").format(LocalDateTime.now()) + " | ");</span>
<span> TimeUnit.SECONDS.sleep(1);</span>
<span> } catch (Exception e) {}</span>
<span> } while (i++ < 5);
<span> emitter.complete();</span>
<span> }).start();</span>
<span>}</span>
<span>private SseEmitter sse;</span>
<span>@GetMapping(path="/sseemitter", produces=MediaType.TEXT_EVENT_STREAM_VALUE)</span>
<span>public SseEmitter sse() {</span>
<span> sse = new SseEmitter();</span>
<span> return sse;</span>
<span>}</span>2.16 StreamingResponseBody
Writes data directly to the response OutputStream in an asynchronous fashion.
<span>@GetMapping("/stream/logs")</span>
<span>public ResponseEntity<StreamingResponseBody> streamLogs() {</span>
<span> StreamingResponseBody responseBody = outputStream -> {</span>
<span> for (int i = 0; i < 10; i++) {</span>
<span> String log = i + " - " + DateTimeFormatter.ofPattern("mm:ss").format(LocalDateTime.now()) + "
";</span>
<span> outputStream.write(log.getBytes(StandardCharsets.UTF_8));</span>
<span> outputStream.flush();</span>
<span> TimeUnit.SECONDS.sleep(1);
<span> }</span>
<span> };</span>
<span> return ResponseEntity.ok()</span>
<span> .header("Content-Type", "text/plain;charset=utf-8")
<span> .body(responseBody);
<span>}</span>2.17 Flux & Mono
Mono(single value) and Flux (multiple values) are reactive types; Flux can be streamed as text/event-stream when the appropriate media type is set.
<span>@GetMapping("/mono")</span>
<span>public Mono<String> mono() {</span>
<span> return Mono.just("《Spring全家桶实战案例源码》");</span>
<span>}</span>
<span>@GetMapping(value="/flux", produces=MediaType.TEXT_EVENT_STREAM_VALUE)</span>
<span>public Flux<String> flux() {</span>
<span> return Flux.fromStream(Stream.generate(() -> DateTimeFormatter.ofPattern("mm:ss").format(LocalDateTime.now())))
<span> .limit(5)
<span> .delayElements(Duration.ofSeconds(1));</span>
<span>}</span>These examples cover the full range of return value options available in Spring MVC, helping developers choose the appropriate type for their API design.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
