[英]How to write java.util.stream.Stream to StreamingResponseBody output stream
我正在構建一個 REST API ,其中來自 Oracle 數據庫的大量數據可以通過流式傳輸到客戶端應用程序(如文件下載或直接流)以塊的形式發送
我從 JpaRepository 獲得 Stream,如下所示 -
@Query("select u from UsersEntity u")
Stream<UsersEntity> findAllByCustomQueryAndStream();
但是現在挑戰將這個 stream 寫入 StreamingResponseBody Output stream
我嘗試了很多方法但沒有成功 -
第一種方法-
Stream<UsersEntity> usersResultStream = usersRepository.findAllByCustomQueryAndStream();
StreamingResponseBody stream = outputStream -> {
Iterator<UsersEntity> iterator = usersResultStream.iterator();
try (ObjectOutputStream oos = new ObjectOutputStream(outputStream)) {
while (iterator.hasNext()) {
oos.write(iterator.next().toString().getBytes());
}
}
};
出現錯誤-
java.sql.SQLException: Closed Resultset: next
at oracle.jdbc.driver.InsensitiveScrollableResultSet.next(InsensitiveScrollableResultSet.java:565) ~[ojdbc7-12.1.0.2.jar:12.1.0.2.0]
第二種方法-
StreamingResponseBody stream = new StreamingResponseBody() {
@Transactional(readOnly = true)
@Override
public void writeTo(OutputStream outputStream) throws IOException {
Stream<UsersEntity> usersResultStream = usersRepository.findAllByCustomQueryAndStream();
try (ObjectOutputStream oos = new ObjectOutputStream(outputStream)) {
usersResultStream.forEach(user->{
try {
oos.write(user.toString().getBytes());
} catch (IOException e) {
e.printStackTrace();
}
});
}
}
};
出現錯誤-
org.springframework.dao.InvalidDataAccessApiUsageException: You're trying to execute a streaming query method without a surrounding transaction that keeps the connection open so that the Stream can actually be consumed. Make sure the code consuming the stream uses @Transactional or any other way of declaring a (read-only) transaction.
我已經在下面給出的鏈接上傳了練習代碼 - 示例 POC 鏈接
我對流媒體相關任務沒有任何經驗,所以請幫助我。
如果我的方向錯誤,則建議在Spring Framework中執行此操作。 如果可用,請分享任何參考鏈接。
最后,我通過使用服務層解決了這個問題。 最初,我在 Controller Class 中編寫了完整的邏輯,這導致了這個問題。
Controller Class -
@RestController
@RequestMapping("/api")
public class UsersController {
@Autowired
private UserService service;
@GetMapping(value = "/userstream")
public ResponseEntity<StreamingResponseBody> fetchUsersStream() {
StreamingResponseBody stream = this::writeTo;
return new ResponseEntity<>(stream, HttpStatus.OK);
}
private void writeTo(OutputStream outputStream) {
service.writeToOutputStream(outputStream);
}
}
服務 Class -
@Service
public class UserService {
@Autowired
private UsersRepository usersRepository;
@Transactional(readOnly = true)
public void writeToOutputStream(final OutputStream outputStream) {
try (Stream<UsersEntity> usersResultStream = usersRepository.findAllByCustomQueryAndStream()) {
try (ObjectOutputStream oos = new ObjectOutputStream(outputStream)) {
usersResultStream.forEach(emp -> {
try {
oos.write(emp.toString().getBytes());
} catch (IOException e) {
e.printStackTrace();
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
完整代碼可在 github - https://github.com/bagesh2050/HttpResponseStreamingDemo
不過,我願意提供有關 Http 流媒體的建議。 如果您有更好的想法,請提供。
沒有示例顯示StreamingResponseBody
的“如此復雜”的用法,我擔心這是“不可能的”(至少我無法使用 StreamingResponseBody和Stream 查詢來管理/修復它)
...但是,有什么可能:
在 StreamingResponseBody 中使用findAll()
(正常的非流式 List-repo 方法)。
(但我理解異步執行 web 請求的“需要”......並且數據庫請求“流式傳輸”......)
使用Callable
(異步 web 請求)和@Async CompletableFuture<..>
(異步數據庫請求):
@RestController @RequestMapping("/api") public class UsersController { @Autowired private UsersRepository usersRepository; @GetMapping(value = "/async/users") public Callable<List<UsersEntity>> fetchUsersAsync() { Callable callable = () -> { return usersRepository.readAllBy().get(); }; return callable; } }
..和像這樣的存儲庫:
@Repository public interface UsersRepository extends JpaRepository<UsersEntity, Integer> { @Async CompletableFuture<List<UsersEntity>> readAllBy(); }
(請參閱spring-samples )..不要忘記在您的應用程序/配置上@EnableAsync
:
@org.springframework.scheduling.annotation.EnableAsync @SpringBootApplication public class Application {... }
抱歉,這甚至不是答案,而是我的發現——評論太長了。
異步 web 請求可以通過多種方式實現。 (見https://spring.io/blog/2012/05/10/spring-mvc-3-2-preview-making-a-controller-method-asynchronous/,https ://niels.nu/blog/2016 /spring-async-rest.html ,甚至沒有提到“反應式”api)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.