在 Spring Boot REST API 中上传文件

Posted

技术标签:

【中文标题】在 Spring Boot REST API 中上传文件【英文标题】:Upload file in Spring Boot REST API 【发布时间】:2018-10-08 23:54:54 【问题描述】:

我正在尝试使用 Spring Boot @RestController 上传文件:

    @RequestMapping(value = "/register", method = RequestMethod.POST)
public AppResponse registerUserFromApp(
        @RequestBody UserInfo userInfo,
        @RequestParam(value = "file", required = false) CommonsMultipartFile file,
        @RequestParam(value = "inviteCode", required = false) String inviteCode)

有了这个定义,我尝试了这个 Postman 请求: 这不起作用。

我尝试将此添加到我的RequestMapping

@RequestMapping(value = "/register", method = RequestMethod.POST, consumes = "multipart/form-data")

这给了我同样的错误。

对于userInfo,我按照another SO answer 的建议将值作为JSON 发送到表单数据字段本身。不起作用,同样的错误。

正如其他一些 SO 答案中所建议的那样,我还确保我没有在 Postman 中发送任何标题。

我也尝试在application.properties 中添加以下属性:

spring.http.multipart.enabled=false

同样的错误。我也试过MultipartFile而不是CommonsMultipartFile,完全没有区别。

我做错了什么?我也想在请求中将图像作为文件和UserInfo 对象发送。邮递员的例子将不胜感激。

【问题讨论】:

【参考方案1】:

我通过在 DTO-Bean 中添加多个部分文件并将邮递员中的每个字段添加为字符串来完成。 spring boot 将匹配文件并分配值,请参见下面的示例

这是我的Account Bean,用于接受邮递员的请求

// done test 100%
@JsonPropertyOrder( "email", "password", "file" )
public class AccountBean 

    @ApiModelProperty(notes = "Enter Email", name = "email", value = "nabeel.amd93@gmail.com", required = true)
    @NotNull(message = "Email contain null")
    @NotBlank(message = "Email Contain blank")
    @Email(message = "Email wrong type")
    private String email;

    @ApiModelProperty(notes = "Enter Password", name = "password", value = "ballistic", required = true)
    @NotNull(message = "Password contain null")
    @NotBlank(message = "Password contain blank")
    private String password;

    @ApiModelProperty(notes = "Enter file", name = "file", value = "xyz", required = true)
    @NotNull(message = "File contain null")
    @ValidImage(message = "File support type => \"image/jpeg\", \"image/png\", \"image/jpg\"")
    private MultipartFile file;

    public AccountBean()  

    public String getEmail()  return email; 
    public void setEmail(String email)  this.email = email; 

    public String getPassword()  return password; 
    public void setPassword(String password)  this.password = password; 

    public MultipartFile getFile()  return file; 
    public void setFile(MultipartFile file)  this.file = file; 

    @Override
    public String toString()  return "AccountBean" + "email='" + email + '\'' + ", password='" + password + '\'' + ", repository=" + file + ''; 


Rest-Api

@ApiOperation(value = "File upload with object field", response = APIResponse.class)
@ApiResponses(value = 
        @ApiResponse(code = 200, message = "Success", response = String.class),
        @ApiResponse(code = 404, message = "Not Found"))
@RequestMapping(value = "/save/account/local", method = RequestMethod.POST)
public ResponseEntity<APIResponse<?>> saveAccountWithSingleFile(
        @ApiParam(name = "account", value = "Select File with Dto field", required = true)
        @Valid AccountBean accountBean, BindingResult bindingResult) throws IllegalBeanFieldException 
    long sTime = System.nanoTime();
    logger.info("save file with account process");
    if(bindingResult.hasErrors()) 
        AtomicInteger bind = new AtomicInteger();
        HashMap<String, HashMap<String, Object>> error = new HashMap<>();
        bindingResult.getFieldErrors().forEach(fieldError -> 
            String key = "key-"+bind;
            HashMap<String, Object> value = new HashMap<>();
            value.put("objectName", fieldError.getObjectName());
            value.put("field", fieldError.getField() != null ? fieldError.getField() : "null");
            value.put("reject", fieldError.getRejectedValue() != null ? fieldError.getRejectedValue() : "null");
            value.put("message", fieldError.getDefaultMessage());
            error.put(key, value);
            bind.getAndIncrement();
        );
        throw new IllegalBeanFieldException(error.toString());
    
    this.apiResponse = this.uploadFile(accountBean.getFile()).getBody();
    logger.debug("account file save time " + ((System.nanoTime() - sTime) / 1000000) + ".ms");

    if(this.apiResponse.getReturnCode().equals(HttpStatus.OK)) 
        // add-info to the account
        Account account = new Account();
        account.setEmail(accountBean.getEmail());
        account.setPassword(accountBean.getPassword());
        account.setFileInfo((FileInfo) this.apiResponse.getEntity());
        account = this.iAccountService.saveAccount(account);
        logger.info("account with file single file info save time :- " + ((System.nanoTime() - sTime) / 1000000) + ".ms");
        this.apiResponse = new APIResponse<Account>("File save with account", HttpStatus.OK, account);
        logger.info("account added " + this.apiResponse.toString());
        logger.info("total response time :- " + ((System.nanoTime() - sTime) / 1000000) + ".ms");
   

    return new ResponseEntity<APIResponse<?>>(this.apiResponse, HttpStatus.OK);

邮递员输入

以https://github.com/NABEEL-AHMED-JAMIL/fserver项目为例

【讨论】:

【参考方案2】:

带有自定义对象的多部分表单数据将被接受为字符串。所以你的控制器如下所示。

@RequestMapping(value = "/register", method = RequestMethod.POST)
public AppResponse registerUserFromApp(
    @RequestBody String userInfo,
    @RequestParam(value = "file", required = false) CommonsMultipartFile file,
    @RequestParam(value = "inviteCode", required = false) String inviteCode)

    ObjectMapper obj=new ObjectMapper();
    UserInfo userInfo=obj.readValue(clientData, UserInfo.class);


您必须使用 ObjectMapper 将 String 转换为 pojo。希望这会有所帮助。

【讨论】:

或者检查这个***.com/questions/21329426/…

以上是关于在 Spring Boot REST API 中上传文件的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot 2 Rest Api Example

如何在 Spring Boot REST API 上设置超时?

Spring Boot - 模拟对外部 API 的 POST REST 请求

Spring boot 和 Jira REST API 在 maven 中给出依赖错误

使用 Spring Boot 和 JWT 保护 REST Api

Spring Boot Rest api 与 Spring Kafka