几种异步接口实现demo
package org.dromara.controller.app;
import cn.dev33.satoken.annotation.SaIgnore;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;
import org.springframework.web.context.request.async.WebAsyncTask;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.util.Map;
import java.util.concurrent.*;
@Slf4j
@SaIgnore
@RestController
@RequestMapping("testAsync")
public class TestAsyncController {
private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private static final Map<String, DeferredResult<String>> DEFERRED_RESULT_MAP = new ConcurrentHashMap<>();
@GetMapping("/emitter")
public ResponseEntity<ResponseBodyEmitter> handle() {
ResponseBodyEmitter emitter = new ResponseBodyEmitter();
scheduler.scheduleAtFixedRate(() -> {
try {
emitter.send(String.format("timestamp: %d\n", System.currentTimeMillis()), MediaType.TEXT_PLAIN);
} catch (IOException e) {
throw new RuntimeException(e);
}
}, 0, 2, TimeUnit.SECONDS);
emitter.onTimeout(emitter::complete);
return new ResponseEntity<>(emitter, HttpStatus.OK);
}
@GetMapping("/sse")
public SseEmitter handleSse() {
SseEmitter emitter = new SseEmitter();
scheduler.scheduleAtFixedRate(() -> {
try {
SseEmitter.SseEventBuilder event = SseEmitter.event().name("sse").
data(String.format("timestamp: %d", System.currentTimeMillis()));
emitter.send(event);
} catch (IOException e) {
emitter.completeWithError(e);
}
}, 0, 3, TimeUnit.SECONDS);
emitter.onTimeout(emitter::complete);
return emitter;
}
@GetMapping("/stream")
public ResponseEntity<StreamingResponseBody> handleStream() throws MalformedURLException {
Resource resource = new UrlResource("https://blog.youkuaiyun.com/lcj_star/");
StreamingResponseBody stream = outputStream -> {
try (InputStream inputStream = resource.getInputStream()) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
} catch (IOException e) {
log.error("文件读取失败: {}", e.getMessage(), e);
}
};
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headers.setContentDispositionFormData("attachment", resource.getFilename());
return ResponseEntity.ok()
.headers(headers)
.body(stream);
}
@GetMapping("/callAble")
public Callable<String> testCallAble() {
return () -> {
Thread.sleep(4000);
return "hello";
};
}
@GetMapping("/webAsyncTask")
public WebAsyncTask<String> webAsyncTask() {
WebAsyncTask<String> result = new WebAsyncTask<>(30003, () -> {
return "success";
});
result.onTimeout(() -> {
log.info("timeout callback");
return "timeout callback";
});
result.onCompletion(() -> log.info("finish callback"));
return result;
}
@GetMapping("/deferredResult")
public DeferredResult<String> testDeferredResult() {
DeferredResult<String> deferredResult = new DeferredResult<>();
DEFERRED_RESULT_MAP.put("demo", deferredResult);
return deferredResult;
}
@GetMapping("/setDeferredResult")
public String testSetDeferredResult() {
DeferredResult<String> deferredResult = DEFERRED_RESULT_MAP.get("demo");
boolean flag = deferredResult.setResult("DeferredResult hello");
if (!flag) {
log.info("结果已经被处理,此次操作无效");
}
return "success";
}
}
总结
技术 | 适用场景 | 特点 |
---|
ResponseBodyEmitter | 持续文本流传输 | 手动控制发送时机 |
SseEmitter | 服务端事件推送 | SSE协议支持 |
StreamingResponseBody | 文件流传输 | 适用于大文件下载 |
Callable | 简单异步处理 | 自动包装异步执行 |
WebAsyncTask | 需回调控制 | 支持超时/完成回调 |
DeferredResult | 外部触发 | 可跨请求设置结果 |