Shubham A.
Shubham A.

Reputation: 2534

Upload file in Spring Boot REST API

I am trying to upload a file using 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){

With this definition, I tried this Postman request: Register API This doesn't work.

I tried adding this to my RequestMapping:

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

This gives me the same error.

For userInfo, I am sending the values as JSON in form-data fields itself as suggested by another SO answer. Doesn't work, same error.

As suggested in some other SO answers, I also made sure that I wasn't sending any headers in Postman.

I tried adding the following property in application.properties as well:

spring.http.multipart.enabled=false

Same error. I also tried MultipartFile instead of CommonsMultipartFile, no difference at all.

What am I doing wrong? I want to send an image as a File and UserInfo object in the request as well. Postman examples will be really appreciated.

Upvotes: 4

Views: 6611

Answers (2)

Nabeel Ahmed
Nabeel Ahmed

Reputation: 267

I done by adding the Multiple part file in DTO-Bean and adding each field in postman as string. spring boot will match the file and assign the value see the below example

This is my Account Bean for accept the request from the postman

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

    @ApiModelProperty(notes = "Enter Email", name = "email", value = "[email protected]", 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);
}

PostMan Input

enter image description here

https://github.com/NABEEL-AHMED-JAMIL/fserver project for example

Upvotes: 0

Bhargav Patel
Bhargav Patel

Reputation: 1128

Multipart form data with custom object will be accepted as string. so your controller would be like as follows.

@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);

}

you will have to convert String to pojo by using ObjectMapper. Hope this will help.

Upvotes: 2

Related Questions