从Spring MVC控制器

时间:2017-11-15 12:02:11

标签: java spring-mvc streaming blob

我在Postgres中的Blob中存储了一些二进制数据。我通过JPA使用db,但在这种情况下这并不重要。我有一个spring MVC @Controller,它应该能够通过端点提供这些数据。我想流式数据,因为为什么要将它全部加载到内存中。大概喜欢:

@Entity
class MyEntity {
    @Lob  
    Blob data;
}

@RequestMapping(...)
public InputStreamResource getResource(...) {
    return new InputStreamResource(myEntityRepository.findById(id).getData().getBinaryStream());
}

不幸的是,这给了我:

  

java.io.IOException:org.postgresql.util.PSQLException:错误:无效   大对象描述符:1

我知道原因:当你使用Blob时,你需要run in transaction。现在我尝试了:

  1. 注释整个控制器方法@Transactional - 没有用,因为当Spring开始将流复制到servlet响应时,它已经在事务方面之外。 :'(

  2. 我还验证了如果我在控制器内将输入流复制到byte[],那么一切正常。但这不是流媒体。

  3. byte[] data = IOUtils.toByteArray(myEntityRepository.findById(id).getData().getBinaryStream()); return new ByteArrayResource(data);

    显然问题是,@Transactional的方面是更接近到控制器方法,获取返回值并将其转换为servlet响应。

    有没有办法重新排序这些方面?还有其他解决办法吗?

    谢谢!

    修改 它似乎应该只是通过@EnableTransactionManagement(order = Ordered.HIGHEST_PRECEDENCE)来完成,但遗憾的是并非如此。可能是由于@EnableAspectJAutoProxy(proxyTargetClass = true)

    EDIT2: 这显然是更普遍的问题。 @RequestMapping带注释的方法只返回Stream,但仅在调用完成后 - 包括所有方面和@Transactional - 进一步处理返回值(Stream)。所以实际上我会希望将事务性扩展到实际调用控制器方法的类,可能是整个Servlet.doXXX方法。没有好消息。

1 个答案:

答案 0 :(得分:0)

原来我忽略了最简单但不那么优雅的解决方案。我仍然可以将HttpServletResponseOutputStream注入控制器的方法,并在控制器的方法中复制Stream。不如返回InputStreamResource那么好但是有效。