Bag*_*rma 6 java jpa-2.0 spring-boot
我正在努力构建一个 REST API,其中来自 Oracle 数据库的大量数据可以通过流式传输到客户端应用程序(如文件下载或直接流)分块发送。
我从 JpaRepository 获取 Stream,如下所示 -
@Query("select u from UsersEntity u")
Stream<UsersEntity> findAllByCustomQueryAndStream();
Run Code Online (Sandbox Code Playgroud)
但现在挑战来了将此流写入 StreamingResponseBody 输出流
我尝试了很多方法但没有成功 -
第一种方法-
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());
}
}
};
Run Code Online (Sandbox Code Playgroud)
出现错误-
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]
Run Code Online (Sandbox Code Playgroud)
第二种方法-
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();
}
});
}
}
};
Run Code Online (Sandbox Code Playgroud)
出现错误-
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.
Run Code Online (Sandbox Code Playgroud)
我已在下面给出的链接中上传了练习代码 - 示例 POC 链接
我对流媒体相关任务没有任何经验,所以请帮助我。
如果我的方向错误,那么建议在Spring Framework中使用任何其他方法来执行此操作。请分享任何可用的参考链接。
最后我通过使用service层解决了这个问题。最初,我在控制器类中编写了导致问题的完整逻辑。
控制器类 -
@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);
}
}
Run Code Online (Sandbox Code Playgroud)
服务等级 -
@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();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
完整代码可在 github 上找到 - https://github.com/bagesh2050/HttpResponseStreamingDemo
尽管如此,我还是愿意提供与 Http Streaming 相关的建议。如果您有更好的想法请提供。