不支持内容类型'multipart/form-data;boundary=----...;charset=UTF-8'。

50
我想向控制器发送一个对象,其中包含带有文件的几个列表和带有纯文本的几个字段。
public class ContributionNew<T extends MovieInfoDTO> {
    private List<T> elementsToAdd;
    private Map<Long, T> elementsToUpdate;
    private Set<Long> idsToDelete;
    private Set<String> sources;
    private String comment;
}

public class Photo extends MovieInfoDTO {
    private MultipartFile photo;
}

@PostMapping(value = "/{id}/contributions/photos")
@ResponseStatus(HttpStatus.CREATED)
public
ResponseEntity<Void> createPhotoContribution(
        @ApiParam(value = "The movie ID", required = true)
        @PathVariable("id") final Long id,
        @ApiParam(value = "The contribution", required = true)
        @RequestBody @Valid final ContributionNew<Photo> contribution
) {

我正在使用Postman发送数据。然而,它抛出了我。

org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'multipart/form-data;boundary=----WebKitFormBoundarywY7ByvgonAjDoaCT;charset=UTF-8' not supported

我应该设置什么样的Content-type来发送一个包含纯文本字段和文件列表的对象?

如果我在header中设置了header,则应该如何处理?

Content-type: multipart/form-data; charset=utf-8

它把我扔进了控制台

org.apache.tomcat.util.http.fileupload.FileUploadException: the request was rejected because no multipart boundary was found

不知道是否重要,但是 multipart/form-data 不应该有 charset。但是它确实需要一个 boundary。请参考 WWW Specification - Andreas
更有可能的是,boundary中的----会导致问题,因为对于边界标记来说,--具有特殊的含义。 - Andreas
@RequestBody 表示将 JSON 数据解析为 Map 或 Java Bean,并且仅支持内容类型为 "application/json;charset=UTF-8"。 - dknight
9个回答

61

如dknight所说,@RequestBody表示将JSON或XML数据与DTO对象映射使用。在MultipartFile情况下,您不能使用JSON数据,因此无法使用@RequestBody。请尝试使用@ModelAttribute注释。

工作示例:

@PostMapping("/promoters")
@Timed
public ResponseEntity<PromoterDTO> createPromoter(@ModelAttribute PromoterDTO promoterDTO) throws URISyntaxException { ... }

有了这样的 PromoterDTO:

    public class PromoterDTO implements Serializable {

        private Long id; 

        private String name;

        private String address;

        private MultipartFile logo;
    }

6
实施后,我的对象中出现了空值。所有字段都为空。 - Ahmed Aziz
3
你设置了获取器(getters)和设置器(setters)吗? - uncleBounty
1
如果我在我的情况下使用@ModelAttribute,我会得到无法将字符串转换为我的子DTO(我的主DTO中有其他DTO)的错误。我该如何解决这个问题? - 2dor
2
按照这个说明操作后,DTO 被正确填充,但变量"logo" 仍然为 null。有什么想法吗? - nonNumericalFloat
在我的情况下,文件字段为空。使用ModelAttribute时,对象会保存到数据库中(使用RequestBody无法实现此功能),但文件字段为空。有什么想法吗? - Ilze

34
在Postman中,您需要将请求体的类型设置为原始格式,并从下拉菜单中选择JSON。我曾遇到类似的问题,这种方法解决了我的问题。 在此查看屏幕

6
这句话是如何允许上传文件的呢? - Zap

6

不要使用 @RequestBody,而是使用 @RequestParam


1
你能详细解释一下这将如何解决OP的问题吗? - Secespitus
1
发送文件时,内容类型应为multipart/form-data,因此RequestParam接受FormData。但是对于请求体,内容类型应为application/json,不处理文件。 - Shadab Reza

5

大家好,只需要将@RequestBody替换为@ModelAttribute即可。

public ResponseEntity<DTO> exemple(@ModelAttribute Dto dto) throws TechnicalException

愉快编程。


4

使用@ModelAttribute而不是@ResponseBody,因为前者采用键值对的数据形式,后者用于对象类型,例如json。 在调用api时,只需传递多部分类型和对象的json键值对。它可以正常工作!

关于此问题的Stack Overflow问答


4
import org.springframework.web.bind.annotation.ModelAttribute;

使用@ModelAttribute代替@RequestBody。这对我很有效。


嗨,我的朋友,这对我有效... - chenio

3

不要使用 @RequestBody,而应该使用类似于 @ModelAttribute 的方式,

@PostMapping(value = "/{id}/contributions/photos")
@ResponseStatus(HttpStatus.CREATED)
public
ResponseEntity<Void> createPhotoContribution(
        @ApiParam(value = "The movie ID", required = true)
        @PathVariable("id") final Long id,
        @ApiParam(value = "The contribution", required = true)
        @ModelAttribute @Valid final ContributionNew<Photo> contribution
) {

2

在控制器中,应该写成produces = { "application/json" },而不是consumes = { "application/json}"。


1

这是一个使用Spring Boot 2.1.7编写的Kotlin完整代码示例。

示例使用了一个ProfileRepository,当然你需要自己实现它。

Kotlin很好用,因为data class已经实现了可序列化。

请注意,在模型对象属性中,必须使用var而不是val,否则日志消息中的字段值将为空。

import org.springframework.web.bind.annotation.ModelAttribute
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.multipart.MultipartFile

@RestController
class ExampleController(private val myProfileRepository: ProfileRepository) {
    
    @PostMapping("/api/uploadFile")
    fun createProvider(@ModelAttribute request: CreateProfileRequest): Provider {
        println("received create request with photo: ${request.photo} for the following person ${request.name}")
        return myProfileRepository.save(Provider(name = request.name!!))
    }
}

data class CreateProfileRequest(
    var name: String? = null,
    var photo: MultipartFile? = null
)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接