Content-Type 'multipart/form-data;boundary=charset=UTF-8' is not supported] when using Multipartfile

322 Views Asked by At

I try the upload of a user picture with the MultipartFile process but I always get the same error message of "charset=UTF-8" is not supported ... I tried many annotations as @PostMapping(path="/new", consumes={MediaType.APPLICATION_JSON_UTF8_VALUE}) and others solutions I found here in SOF but nothing works!

May the Spring Security configuration be faulty in this case (I assume no) ? ... I run a basic mirror project without Spring Security and it's working ...

I run my tests with Postman Postman

It seems that the entire request made with Body/form-data is rejected but if I run it with Body/raw/json (without the file) it's going perfectly!

** user entity **

@Entity
@Table(name="user", uniqueConstraints = {
        @UniqueConstraint(columnNames = "username"),
        @UniqueConstraint(columnNames = "email")
})
public class User {
    @Id
    @Column(name="id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long Id;
    @Column(name="username")
    private String username;
    @Column(name="password")
    private String password;
    @Column(name="avatar")
    private String avatar;
    @Column(name="email")
    private String email;
    @Column(name="bio")
    private String bio;
    @Column(name = "created_at")
    private Date createdAt;
    @Column(name="updated_at")
    private Date updatedAt;
    @ManyToMany(fetch = FetchType.LAZY)
    @JsonIgnore
    @JoinTable(name="user_role",
            joinColumns = @JoinColumn(name="user_id"),
            inverseJoinColumns = @JoinColumn(name="role_id"))
    private Set<Role> roles = new HashSet<>();
    @OneToMany(mappedBy = "donor", cascade = CascadeType.ALL)
    @JsonIgnore
    // liste des donations par donateurs
    private Set<Donation> donationsByDonor = new HashSet<>();
    @OneToMany(mappedBy = "beneficiary", cascade = CascadeType.ALL)
    @JsonIgnore
    // liste des donations par bénéficiaire
    private Set<Donation> donationsByBeneficiary = new HashSet<>();
    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
    // liste des evaluations par user
    private Set<Evaluation> evaluations = new HashSet<>();
    @OneToMany(mappedBy = "author", cascade = CascadeType.ALL)
    @JsonIgnore
    // Liste des pdfs par user
    private Set<Pdf> pdfs = new HashSet<>();
    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
    @JsonIgnore
    // liste des recherches par user
    private Set<Search> searches = new HashSet<>();
    @OneToMany(mappedBy = "alertLauncher", cascade = CascadeType.ALL)
    @JsonIgnore
    // liste alerts par user
    private Set<Alert> alertList = new HashSet<>();

    public User() {
    }

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public User(String username, String email, String password, String avatar) {
        this.username = username;
        this.email = email;
        this.password = password;
        this.avatar = avatar;
    }

    public User(String username, String password, String avatar, String email, String bio, Date createdAt, Date updatedAt, Set<Role> roles, Set<Donation> donationsByBeneficiary, Set<Donation> donationsByDonor, Set<Evaluation> evaluations, Set<Pdf> pdfs, Set<Search> searches, Set<Alert> alertList) {
        this.username = username;
        this.password = password;
        this.avatar = avatar;
        this.email = email;
        this.bio = bio;
        this.createdAt = createdAt;
        this.updatedAt = updatedAt;
        this.roles = roles;
        this.donationsByBeneficiary = donationsByBeneficiary;
        this.donationsByDonor = donationsByDonor;
        this.evaluations = evaluations;
        this.pdfs = pdfs;
        this.searches = searches;
        this.alertList = alertList;
    }

    public Long getId() {
        return Id;
    }

    public void setId(Long id) {
        Id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getAvatar() {
        return avatar;
    }

    public void setAvatar(String avatar) {
        this.avatar = avatar;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getBio() {
        return bio;
    }

    public void setBio(String bio) {
        this.bio = bio;
    }

    public Date getCreatedAt() {
        return createdAt;
    }

    public void setCreatedAt(Date createdAt) {
        this.createdAt = createdAt;
    }

    public Date getUpdatedAt() {
        return updatedAt;
    }

    public void setUpdatedAt(Date updatedAt) {
        this.updatedAt = updatedAt;
    }

    public Set<Role> getRoles() {
        return roles;
    }

    public void setRoles(Set<Role> roles) {
        this.roles = roles;
    }

    public Set<Donation> getDonationsByDonor() {
        return donationsByDonor;
    }

    public void setDonationsByDonor(Set<Donation> donationsByDonor) {
        this.donationsByDonor = donationsByDonor;
    }

    public Set<Donation> getDonationsByBeneficiary() {
        return donationsByBeneficiary;
    }

    public void setDonationsByBeneficiary(Set<Donation> donationsByBeneficiary) {
        this.donationsByBeneficiary = donationsByBeneficiary;
    }

    public Set<Evaluation> getEvaluations() {
        return evaluations;
    }

    public void setEvaluations(Set<Evaluation> evaluations) {
        this.evaluations = evaluations;
    }

    public Set<Pdf> getPdfs() {
        return pdfs;
    }

    public void setPdfs(Set<Pdf> pdfs) {
        this.pdfs = pdfs;
    }

    public Set<Search> getSearches() {
        return searches;
    }

    public void setSearches(Set<Search> searches) {
        this.searches = searches;
    }

    public Set<Alert> getAlertList() {
        return alertList;
    }

    public void setAlertList(Set<Alert> alertList) {
        this.alertList = alertList;
    }
}

**Dto from client **

@Data
public class UserDTOWayIN {
    String username;
    String password;
    String avatar;
    String email;
    String bio;
    Date createdAt;
    Date updatedAt;
    Set<Role> roles;
}

**Dto to client **

@Data
public class UserDTO {
     Long Id;
     String username;
     String bio;
     Date createdAt;
     Date updatedAt;
     Set<Role> roles;
}

**UserController with the signup endpoint **

@CrossOrigin(origins = "http://localhost:4200", maxAge = 3600)
@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService service;
    @Autowired
    private ModelMapper modelMapper;
    public static String uploadDirectory = System.getProperty("user.dir")+"/src/main/webapp/avatars/";

    @PostMapping(path="/new", consumes={MediaType.APPLICATION_JSON_UTF8_VALUE})
    @PreAuthorize("hasRole('ADMIN'), hasRole('USER')")
    public ResponseEntity<UserDTO> saveUser(@ModelAttribute UserDTOWayIN clientDatas, @RequestParam("file")MultipartFile file) throws IOException {
        String originalFilename = file.getOriginalFilename();
        Path fileNameAndPath= Paths.get(uploadDirectory, originalFilename);
        Files.write(fileNameAndPath, file.getBytes());
        clientDatas.setAvatar(originalFilename);
        // Conversion des datas front en DTOWayIN
        UserDTOWayIN userDTOWayIN = modelMapper.map(clientDatas, UserDTOWayIN.class);
        // Conversion sens DTOWayIN à Entité
        User user = service.saveUser(userDTOWayIN);
        // Conversion sens Entité à DTO
        UserDTO userDTO = modelMapper.map(user, UserDTO.class);
        return new ResponseEntity<UserDTO>(userDTO, HttpStatus.CREATED);
    }
1

There are 1 best solutions below

1
Akshay Babar On

If we want to send json and multipartFile in same API request refer below example

@PostMapping("/uploadJsonAndMultipartData")
    public ResponseEntity<String> handleJsonAndMultipartInput(@RequestPart("data") UserRequestDTO userRequestDTO, @RequestPart("file") MultipartFile file) {
        return ResponseEntity.ok()
                .body(userRequestDTO.getId() + userRequestDTO.getName());
    }

Postman curl for above API

curl --location 'http://localhost:8083/api/v1/users/uploadJsonAndMultipartData' \
--form 'file=@"/C:/Users/AkshayB/Downloads/money.jpg"' \
--form 'data="{\"firstName\":\"firstName\",\"lastName\":\"lastName\",\"email\":\"email\",\"password\":\"password\",\"phone\":\"phone\"}";type=application/json'