网站首页 > 教程文章 正文
环境:SpringBoot3.4.2
1. 简介
在Spring Boot开发中,使用@RestController或@Controller注解,开发者可以轻松定义Controller类,并借助@RequestMapping等注解将请求路径映射到具体的处理方法上。Controller接收请求参数,调用Service层处理业务逻辑,然后返回响应结果,如JSON数据或视图页面。
但你知道Controller接口都能返回哪些具体的数据类型吗?本篇文章将为你详细的展开介绍多达17种的返回值类型。
2. 实战案例
2.1 @ResponseBody
你可以在方法上使用 @ResponseBody 注解,Spring MVC底层会通过 HttpMessageConverter 将返回序列化为响应体。如下示例:
@GetMapping("/{id}")
@ResponseBody
public Account query(@PathVariable Long id) {
return new Account(id, "Spring全家桶实战案例源码") ;
}
类级别也支持 @ResponseBody,在这种情况下,所有控制器方法都会继承它。这就是 @RestController 的效果,它只不过是一个标有 @Controller 和 @ResponseBody 的元注解。上面示例输出结果:
2.2 HttpEntity
指定完整响应(包括HTTP头和正文)的返回值将通过HttpMessageConverter实现进行转换,并写入到响应中。
@GetMapping("/httpentity")
public HttpEntity<Account> httpentity() {
Account data = new Account(1L, "Pack") ;
HttpHeaders headers = new HttpHeaders() ;
headers.add("Content-Type", "application/xml") ;
HttpEntity<Account> entity = new HttpEntity<Account>(data, headers) ;
return entity ;
}
在该示例中,我们设置了响应的数据,以及响应的头信息。该示例输出结果:
如果你的接口无法输出xml内容,那么你还需要引入如下依赖:
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
2.3 ResponseEntity
该类型是上面2.2介绍的HttpEntity的子类。通常我们使用该类相对来说是比较多的。但是,HttpEntity不仅可以用来当作返回值,还可以用来接收请求参数;而ResponseEntity只能用来表示响应结果。
@GetMapping("/responseentity")
public ResponseEntity<Account> responseentity() {
Account data = new Account(1L, "Pack/Spring全家桶实战案例源码") ;
return ResponseEntity.ok()
.header("Content-Type", "application/xml")
.body(data) ;
}
你不仅仅可以设置header,body内容,还可以设置状态码,输出结果:
2.4 HttpHeaders
返回一个带有头信息但没有正文的响应。
@GetMapping("/httpheaders")
public HttpHeaders httpheaders() {
HttpHeaders headers = new HttpHeaders() ;
headers.add("x-token", UUID.randomUUID().toString().replace("-", "")) ;
return headers ;
}
该接口中我们通过HttpHeaders只输出头数据x-token。输出结果:
2.5 ErrorResponse
若要渲染包含正文详细信息的RFC 9457错误响应,可以使用该接口。要详细了解RFC 9457请查看下面链接:
https://www.rfc-editor.org/rfc/rfc9457.html
@GetMapping("/errorresponse")
public ErrorResponse errorresponse() {
URI uri = MvcUriComponentsBuilder
.fromMethodName(ReturnValueController.class, "errorresponse")
.build()
.toUri() ;
ErrorResponse errorResponse = ErrorResponse.builder(
new RuntimeException("接口发生异常"),
HttpStatusCode.valueOf(500), "错误的参数信息")
.title("API错误")
.instance(uri)
.build() ;
return errorResponse ;
}
运行该接口输出结果如下:
我们可以通过全局异常进行处理器来统一规范输出错误数据。
2.6 ProblemDetail
与2.5介绍的ErrorResponse一样都是用来输出RFC 9457错误响应。
@GetMapping("/problemdetail")
public ProblemDetail problemdetail() {
ProblemDetail detail = ProblemDetail.forStatus(500) ;
detail.setDetail("请求接口的参数不正确") ;
detail.setInstance(URI.create("http://localhost:8888/api/query")) ;
detail.setTitle("API错误") ;
return detail ;
}
输出结果
2.7 String
这里返回的是String是视图名称,也就是你的html或jsp页面名称。
@Controller
@RequestMapping("/view")
public class ViewController {
@GetMapping("home")
public String index() {
return "index";
}
}
下面我们还需要在classpath:/templates/ 下新建index.html页面
输出结果
2.8 View
直接返回View实例对象,会自动调用View#render方法输出内容到页面。
@GetMapping("/view")
public View view() {
return new View() {
@Override
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
response.setContentType("text/html;charset=utf-8") ;
response.getWriter().println("<h1>《Spring全家桶实战案例源码》,作者:Pack</h1>") ;
}
};
}
输出结果
2.9 ModelAndView
通过该对象,我们可以定义返回视图名称、模型数据以及一个可选的响应状态码。
@GetMapping("modelandview")
public ModelAndView modelandview() {
ModelAndView view = new ModelAndView() ;
view.setViewName("user") ;
view.setStatus(HttpStatusCode.valueOf(200)) ;
view.addObject("data", "《Spring全家桶实战案例源码》,作者:Pack") ;
return view ;
}
输出结果
2.10 @ModelAttribute
通过该注解我们可以像模型中添加数据,如下示例:
@ModelAttribute
public User queryUser() {
// 查询User信息
return new User("Pack", 22) ;
}
页面定义
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>ModelAndView</title>
</head>
<body>
<h1 th:text="${data}"></h1>
姓名:<b th:text="${user.name}"></b>
年龄:<b th:text="${user.age}"></b>
</body>
</html>
接下来,我们还是使用2.9中定义的接口;输出结果:
2.11 void
返回类型为 void(或返回值为 null)的方法,如果它还具有 ServletResponse 参数、OutputStream 参数,或者带有 @ResponseStatus 注解,则被视为已完全处理了响应。
@GetMapping("/void")
public void rvoid(HttpServletResponse response) throws Throwable {
response.setContentType("text/html;charset=utf-8") ;
response.getWriter().println("<h1>《Spring全家桶实战案例源码》,作者:Pack</h1>") ;
}
输出结果
也可以在方法上使用@ResponseStatus
@GetMapping("/void")
@ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR)
public void rvoid() {}
输出结果
2.12 DeferredResult
从任意线程异步地生成上述任意一种返回值。
private DeferredResult<String> dr ;
@GetMapping("/deferredresult")
public DeferredResult<String> deferredresult() {
dr = new DeferredResult<>();
return dr ;
}
@GetMapping("/sendResult")
public void sendResult() {
new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(3) ;
} catch (InterruptedException e) {}
dr.setResult("复杂的运算执行完成...") ;
}).start() ;
}
说明:
- /deferredresult接口创建了DeferredResult对象返回,当我们请求该接口时该接口在没有得到数据前会一直等待。如下:
一直等待结果中。
- /sendResult接口用来对/deferredresult接口创建的DeferredResult设置最终的结果数据,如下:
2.13 Callable
在 Spring MVC 管理的线程中异步地生成上述任意一种返回值。
@GetMapping("/callable")
public Callable<String> callable() {
return () -> {
TimeUnit.SECONDS.sleep(3) ;
return "Callable 结果返回..." ;
} ;
}
输出结果
等待3s后输出内容。
2.14 CompletableFuture & CompletionStage
这里还有一个返回值类型:ListenableFuture。他们都是DeferredResult的替代方案。
@GetMapping("/completablefuture")
public CompletableFuture<String> completablefuture() {
return CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(3) ;
} catch (InterruptedException e) {}
return "CompletableFuture 返回结果..." ;
}) ;
}
等待3s输出结果
2.15 ResponseBodyEmitter & SseEmitter
以异步方式将对象流发送出去,并利用 HttpMessageConverter 实现将其写入响应中。同时,这种对象流也可以作为 ResponseEntity 的主体(body)来支持。
private ResponseBodyEmitter emitter ;
@GetMapping("/responsebodyemitter")
public ResponseBodyEmitter responsebodyemitter() {
emitter = new ResponseBodyEmitter();
return emitter;
}
@GetMapping("/stream/send")
public void streamSend() {
new Thread(() -> {
int i = 0 ;
do {
try {
emitter.send(DateTimeFormatter.ofPattern("mm:ss").format(LocalDateTime.now()) + " | ") ;
TimeUnit.SECONDS.sleep(1) ;
}
} while (i++ < 5) ;
emitter.complete() ;
}).start() ;
}
在异步线程中,我们多次调用send方法输出数据,当最终调用complete方法后会结束当前的业务处理。
注意:这里在调用complete后才会输出所有的内容。
SseEmitter示例
private SseEmitter sse ;
@GetMapping(path="/sseemitter", produces=MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter sse() {
sse = new SseEmitter();
return sse ;
}
// 异步线程发送数据接口我们还是使用上面的/stream/send
输出结果
注意:这里会逐条的输出,调用send方法就将结果输出。
2.16 StreamingResponseBody
以异步方式向响应的 OutputStream 写入数据。
@GetMapping("/stream/logs")
public ResponseEntity<StreamingResponseBody> streamLogs() {
StreamingResponseBody responseBody = outputStream -> {
for (int i = 0; i < 10; i++) {
String log = i + " - " + DateTimeFormatter.ofPattern("mm:ss").format(LocalDateTime.now()) + "\n";
outputStream.write(log.getBytes(StandardCharsets.UTF_8)) ;
outputStream.flush() ;
// 模拟延迟
try {
TimeUnit.SECONDS.sleep(1) ;
} catch (InterruptedException e) {}
}
};
return ResponseEntity.ok()
.header("Content-Type", "text/plain;charset=utf-8")
.body(responseBody) ;
}
注意:必须调用flush,否则不会实时输出。
输出结果
2.17 Flux & Mono
单一值类型(例如,Mono)可类比为返回 DeferredResult。多值类型(例如,Flux)可以根据请求的媒体类型(如 "text/event-stream"、"application/json+stream")被视为一个流,否则会被收集到一个 List 中并以单一值的形式进行渲染。
@GetMapping("/mono")
public Mono<String> mono() {
return Mono.just("《Spring全家桶实战案例源码》") ;
}
返回单一值。
@GetMapping(value = "/flux", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> flux() {
return Flux.fromStream(
Stream.generate(() -> {
return DateTimeFormatter.ofPattern("mm:ss").format(LocalDateTime.now());
})
.limit(5)
).delayElements(Duration.ofSeconds(1));
}
返回多值,同时设置了响应类型为text/event-stream,会每隔1s输出一个元素,并且最多五个。
猜你喜欢
- 2025-05-27 还在为 Spring Boot3 整合 Easy Excel 发愁?一文搞定!
- 2025-05-27 7种方式,教你提升 SpringBoot 项目的吞吐量
- 2025-05-27 Tomcat处理HTTP请求流程解析
- 2025-05-27 SpringBoot中六种设计模式应用案例二
- 2025-05-27 生产实战:循环继承依赖 导致web 项目启动失败,总是超时
- 2025-05-27 Java Web应用调优线程池:没你想的那么复杂
- 2025-05-27 SpringMVC异常处理句柄这些细节你知道吗?
- 2025-05-27 【干货】EasyExcel确实好用,Springboot+EasyExcel实操
- 2025-05-27 Spring Boot 应用如何防护 XSS 攻击
- 2025-05-27 java验证码生成
- 最近发表
- 标签列表
-
- location.href (44)
- document.ready (36)
- git checkout -b (34)
- 跃点数 (35)
- 阿里云镜像地址 (33)
- qt qmessagebox (36)
- mybatis plus page (35)
- vue @scroll (38)
- 堆栈区别 (33)
- 什么是容器 (33)
- sha1 md5 (33)
- navicat导出数据 (34)
- 阿里云acp考试 (33)
- 阿里云 nacos (34)
- redhat官网下载镜像 (36)
- srs服务器 (33)
- pico开发者 (33)
- https的端口号 (34)
- vscode更改主题 (35)
- 阿里云资源池 (34)
- os.path.join (33)
- redis aof rdb 区别 (33)
- 302跳转 (33)
- http method (35)
- js array splice (33)