如何以restful方式使用Spring3.2SpringMVC上传/流式传输大型图像

如何以restful方式使用Spring3.2SpringMVC上传/流式传输大型图像,spring,rest,spring-mvc,Spring,Rest,Spring Mvc,我尝试将一个大图像上传/流式传输到REST控制器,该控制器获取文件并将其存储到数据库中 @Controller @RequestMapping("/api/member/picture") public class MemberPictureResourceController { @RequestMapping(value = "", method = RequestMethod.POST) @ResponseStatus(HttpStatus.NO_CONTENT) publi

我尝试将一个大图像上传/流式传输到REST控制器,该控制器获取文件并将其存储到数据库中

@Controller
@RequestMapping("/api/member/picture")
public class MemberPictureResourceController {

  @RequestMapping(value = "", method = RequestMethod.POST)
  @ResponseStatus(HttpStatus.NO_CONTENT)
  public void addMemberPictureResource(@RequestBody InputStream image) {
    // Process and Store image in database
  }
}
这是我试图实现的一个不起作用的示例(当然,或者我猜InputStream不起作用)。我想通过@RequestBody流式传输/读取图像

我到处都找过,但找不到一个好的例子来说明如何做到这一点。大多数人似乎只问如何通过表单上传图像,而不使用REST/RestTemplate来完成。有人能帮我吗

我很感激你给了我任何正确方向的暗示

亲切问候,, 克里斯

解决方案

下面我试着发布在Dirk和Gigadot输入后对我有效的解决方案。目前,我认为这两种解决方案都值得研究。首先,我尝试在Dirk的帮助下发布一个工作示例,然后在Gigadot的帮助下创建一个。我将把Dirks的答案标记为正确答案,因为我一直在明确询问如何通过@RequestBody上传文件。但我也很好奇测试Gigadot的解决方案,因为它可能更容易使用,也更常见

在下面的示例中,我将文件存储在MongoDB GridFS中

解决方案1-德克斯建议后的示例

控制器(注释中带有用于测试的curl命令):

解决方案2-Gigadots推荐后的示例

弹簧手册中对此进行了说明:

这非常简单,默认情况下还包含所有信息。我想我会选择这个解决方案,至少对于二进制上传


谢谢大家的发帖和回复。非常感谢。

我最近做了这件事,请参阅

在浏览器上,我们可以使用文件API加载文件,然后使用Base64编码对其内容进行编码,最后在发布之前将编码的内容分配给javascript对象

在服务器上,我们有一个Spring控制器来处理请求。作为将请求主体转换为java对象的json解组的一部分,图像字节的base64编码值将转换为标准java字节[],并作为LOB存储在数据库中

@Controller
@RequestMapping("/api/member/picture")
public class MemberPictureResourceController {

  @RequestMapping(value = "", method = RequestMethod.POST)
  @ResponseStatus(HttpStatus.NO_CONTENT)
  public void addMemberPictureResource(@RequestBody InputStream image) {
    // Process and Store image in database
  }
}
为了检索图像,另一种Spring控制器方法可以通过直接流式传输字节来提供图像


我在上面链接的博客文章假定您想将图像用作另一个对象的一部分,但如果您只想直接处理图像,则原则应该是相同的。如果有什么需要澄清的,请告诉我。

因为看起来您使用的是spring,所以可以使用HttpEntity()

使用它,你会得到如下结果(看看“有效载荷”这个词):

@控制器
公共类ImageServerEndpoint扩展了AbstractEndpoint{
@自动连线专用ImageMetadataFactory metaDataFactory;
@自动连线专用文件服务文件服务;
@RequestMapping(value=“/product/{spn}/image”,method=RequestMethod.PUT)
公共模型和视图handleImageUpload(
@路径变量(“spn”)字符串spn,
HttpEntity请求实体,
HttpServletResponse(响应)引发IOException{
字节[]有效负载=requestEntity.getBody();
HttpHeaders=requestEntity.getHeaders();
试一试{
ProductImageMetadata元数据=metaDataFactory.newSpnInstance(spn,头);
存储(元数据、负载);
response.setStatus(HttpStatus.NO_CONTENT.value());
返回null;
}捕获(IOEX异常){
返回internalServerError(响应);
}捕获(IllegalArgumentException ex){
返回badRequest(响应,“内容类型缺失或未知”);
}
}

我们在这里使用PUT是因为它是一个RESTfull“将图像放入产品”。'spn'是产品编号,imagename是由fileService.store()创建的。当然,您也可以发布图像以创建图像资源。

当您发送POST请求时,有两种类型的编码可用于将表单/参数/文件发送到服务器,即
应用程序/x-www-form-urlencoded
多部分/表单数据
。以下是详细信息

如果您的POST请求中有大量内容,则使用
application/x-www-form-urlencoded
不是一个好主意,因为它通常会使web浏览器崩溃(根据我的经验)。因此, 建议使用多部分/表单数据

如果向dispatcher中添加多部分解析器,Spring可以自动处理
多部分/表单数据
内容。Spring处理此问题的实现是使用apache commons fileupload完成的,因此您需要将此库添加到项目中

现在,关于如何真正做到这一点的主要答案已经在这里发表了博客


我希望这能帮助您找到解决方案。您可能想了解一下REST是什么。听起来您有点困惑。基本上,几乎所有http请求都是RESTful的,即使URL很难看。

如果您想将请求正文作为输入流处理,您可以直接从请求中获取它

@Controller
@RequestMapping("/api/member/picture")
public class MemberPictureResourceController {

    @RequestMapping(value = "", method = RequestMethod.POST)
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void addMemberPictureResource(HttpServletRequest request) {
        try {
            InputStream is = request.getInputStream();
            // Process and Store image in database
        } catch (IOException e) {
            // handle exception
        }
    }
}

您应该为post方法使用multipart表单谢谢gigadot,但我将使用resttemplate将文件解析到控制器,我希望将其保存在requestbody中。我不知道使用multipart是否真的符合rest。是吗?谢谢gigadot。我将研究此解决方案。您的意思是我应该使用apache commons fileupload wi吗上传文件而不是REST的流媒体功能?我可以使用RestTemplate解析文件吗?我已经发布了答案。我希望这可能会有所帮助。如果没有,你可以在谷歌上搜索“multipart spring mvc”。有很多例子,但是如果你使用的是新版本的spring,你可能想试试最近的例子。嗨,Jay,谢谢你发布这个例子。你能告诉我为什么图像必须是base64编码的吗?基本上我会假设Sprin
@Controller
public class ImageServerEndpoint extends AbstractEndpoint {

@Autowired private ImageMetadataFactory metaDataFactory;
@Autowired private FileService fileService;

@RequestMapping(value="/product/{spn}/image", method=RequestMethod.PUT) 
public ModelAndView handleImageUpload(
        @PathVariable("spn") String spn,
        HttpEntity<byte[]> requestEntity, 
        HttpServletResponse response) throws IOException {
    byte[] payload = requestEntity.getBody();
    HttpHeaders headers = requestEntity.getHeaders();

    try {
        ProductImageMetadata metaData = metaDataFactory.newSpnInstance(spn, headers);
        fileService.store(metaData, payload);
        response.setStatus(HttpStatus.NO_CONTENT.value());
        return null;
    } catch (IOException ex) {
        return internalServerError(response);
    } catch (IllegalArgumentException ex) {
        return badRequest(response, "Content-Type missing or unknown.");
    }
}
@Controller
@RequestMapping("/api/member/picture")
public class MemberPictureResourceController {

    @RequestMapping(value = "", method = RequestMethod.POST)
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void addMemberPictureResource(HttpServletRequest request) {
        try {
            InputStream is = request.getInputStream();
            // Process and Store image in database
        } catch (IOException e) {
            // handle exception
        }
    }
}