Spring Boot – 方法 ‘POST’ 不受支持 (multipart/form-data)

huangapple go评论57阅读模式
英文:

Spring boot - method 'POST' is not supported (multipart/form-data)

问题

我正在尝试通过multipart/form-data从我的产品控制器发送POST请求,在这个请求中,我上传了图像文件和产品信息的JSON数据。

在我的Postman中,我像这样发送请求,并且收到了405错误。

在我的控制台中,我收到了以下错误信息:

"Request method 'POST' is not supported."

我不明白为什么会出现这个错误,因为我已经使用@PostMapping注解定义了POST请求。

在Postman中更新的错误信息如下:

{
    "cause": null,
    "stackTrace": [
        {
            "classLoaderName": "app",
            "moduleName": null,
            "moduleVersion": null,
            "methodName": "from",
            "fileName": "UnrecognizedPropertyException.java",
            "lineNumber": 61,
            "nativeMethod": false,
            "className": "com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException"
        },
        {
            "classLoaderName": "app",
            "moduleName": null,
            "moduleVersion": null,
            "methodName": "handleUnknownProperty",
            "fileName": "DeserializationContext.java",
            "lineNumber": 1132,
            "nativeMethod": false,
            "className": "com.fasterxml.jackson.databind.DeserializationContext"
        },
        {
            "classLoaderName": "app",
            "moduleName": null,
            "moduleVersion": null,
            "methodName": "handleUnknownProperty",
            "fileName": "StdDeserializer.java",
            "lineNumber": 2202,
            "nativeMethod": false,
            "className": "com.fasterxml.jackson.databind.deser.std.StdDeserializer"
        }, ...

希望这些信息有助于解决你的问题。如果你需要进一步的帮助,请告诉我。

英文:

I'm trying to send through multipart/form-data a post request from my products controller, where I upload a file of images and information of my product in json


@RestController
@CrossOrigin(origins = "*", maxAge = 3600)
@RequestMapping("/product")
public class ProductController {
    final ProductService productService;
    final CategoryService categoryService;
    final ProductMapper productMapper;
    final S3Client s3Client;

    private final String BUCKET_NAME = "awstockproducts" + System.currentTimeMillis();

    public ProductController(ProductService productService, ProductMapper productMapper, CategoryService categoryService, S3Client s3Client) {
        this.productService = productService;
        this.productMapper = productMapper;
        this.categoryService = categoryService;
        this.s3Client = s3Client;
    }
    @PostMapping(MediaType.MULTIPART_FORM_DATA_VALUE)
    public ResponseEntity<Object> saveProduct (@RequestPart("productDto") @Valid ProductDto productDto, @RequestPart(value = "file")MultipartFile file) {
        try {
            if (productService.existsByProduct(productDto.getProduct())) {
                return ResponseEntity.status(HttpStatus.CONFLICT).body("Product already exists!");
            }
            ProductModel productModel = productMapper.toProductModel(productDto);
            CategoryModel categoryModel = categoryService.findById(productDto.getProductCategory().getCategory_id())
                    .orElseThrow(() -> new RuntimeException("Category not found"));
            productModel.setProductCategory(categoryModel);

            String fileName = "/products/images/" + UUID.randomUUID().toString() + "-" + file.getOriginalFilename();

            s3Client.putObject(PutObjectRequest
                            .builder()
                            .bucket(BUCKET_NAME)
                            .key(fileName)
                            .build(),
                        software.amazon.awssdk.core.sync.RequestBody.fromString("Testing java sdk"));
            return ResponseEntity.status(HttpStatus.CREATED).body(productService.save(productModel));
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.CONFLICT).body("Cannot create product. Check if the fields sent in your request are correct.");
        }
    }



in my postman I'm sending it like this, and getting the error 405
Spring Boot – 方法 ‘POST’ 不受支持 (multipart/form-data)

In my console I am getting the error:

Request method 'POST' is not supported]

I don't understand why since I am sending a postMapping

updated error in postman:


{
    "cause": null,
    "stackTrace": [
        {
            "classLoaderName": "app",
            "moduleName": null,
            "moduleVersion": null,
            "methodName": "from",
            "fileName": "UnrecognizedPropertyException.java",
            "lineNumber": 61,
            "nativeMethod": false,
            "className": "com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException"
        },
        {
            "classLoaderName": "app",
            "moduleName": null,
            "moduleVersion": null,
            "methodName": "handleUnknownProperty",
            "fileName": "DeserializationContext.java",
            "lineNumber": 1132,
            "nativeMethod": false,
            "className": "com.fasterxml.jackson.databind.DeserializationContext"
        },
        {
            "classLoaderName": "app",
            "moduleName": null,
            "moduleVersion": null,
            "methodName": "handleUnknownProperty",
            "fileName": "StdDeserializer.java",
            "lineNumber": 2202,
            "nativeMethod": false,
            "className": "com.fasterxml.jackson.databind.deser.std.StdDeserializer"
        }, ...

答案1

得分: 0

更改您的@PostMapping(MediaType.MULTIPART_FORM_DATA_VALUE),因为在那里放置媒体类型实际上会将URL映射到/product/multipart/form-data而不是/product/

将其更改为:

@PostMapping(value = "/", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)

此外,您需要更新方法签名,类似于以下内容(将@RequestPart更改为@RequestParam):

@PostMapping(value = "/", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<Object> saveProduct(@RequestParam("productDto") String jsonString, @RequestParam("file") MultipartFile file) {
    ObjectMapper objectMapper = new ObjectMapper();
    ProductDto productDto = objectMapper.readValue(jsonString, ProductDto.class);
}

确保您具有相关的依赖项commons-fileuploadcommons-io

此外,我建议在上传时设置文件的最大上传大小,可以像这样实现:

@Bean
public MultipartResolver multipartResolver() {
    CommonsMultipartResolver resolver = new CommonsMultipartResolver();
    resolver.setMaxUploadSize(1024 * 1024 * 5); // 5 MB
    return resolver;
}

然后,在Postman中调用http://localhost:8078/product/

另一种解决方案是在Spring中创建适当的转换器:

public class ProductDtoConverter extends AbstractHttpMessageConverter<ProductDto> {

    public ProductDtoConverter() {
        super(MediaType.APPLICATION_JSON);
    }

    @Override
    protected boolean supports(Class<?> clazz) {
        return ProductDto.class.isAssignableFrom(clazz);
    }

    @Override
    protected ProductDto readInternal(Class<? extends ProductDto> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        String productDtoString = IOUtils.toString(inputMessage.getBody(), StandardCharsets.UTF_8);
        ObjectMapper objectMapper = new ObjectMapper();
        return objectMapper.readValue(productDtoString, ProductDto.class);
    }
}

然后,在您的AppConfig中:

@Configuration
public class AppConfig {

    @Bean
    public ProductDtoConverter productDtoConverter() {
        return new ProductDtoConverter();
    }
}
英文:

Change your @PostMapping(MediaType.MULTIPART_FORM_DATA_VALUE)
because putting the media type there will actually map the URL to /product/multipart/form-data and not /product/

change it to this

@PostMapping(value = &quot;/&quot;, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)

also, you need to update the method signature to something like this (Change @RequestPart to @RequestParam)

@PostMapping(value = &quot;/&quot;, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity&lt;Object&gt; saveProduct (@RequestParam(&quot;productDto&quot;) String jsonString, @RequestParam(&quot;file&quot;) MultipartFile file) {
       ObjectMapper objectMapper = new ObjectMapper();
       ProductDto productDto = objectMapper.readValue(jsonString, ProductDto.class);
    }

and make sure you have the relevant dependencies commons-fileupload and commons-io

also I recomemend when Uploading set a maximum upload size for the file you can do it like this:

@Bean
public MultipartResolver multipartResolver() {
    CommonsMultipartResolver resolver = new CommonsMultipartResolver();
    resolver.setMaxUploadSize(1024 * 1024 * 5); // 5 MB
    return resolver;
}

and then in postman call http://localhost:8078/product/

A second solution you can create the suitable converter in Spring:
the solution is like

public class ProductDtoConverter extends AbstractHttpMessageConverter&lt;ProductDto&gt; {
    
    public ProductDtoConverter() {
        super(MediaType.APPLICATION_JSON);
    }
    
    @Override
    protected boolean supports(Class&lt;?&gt; clazz) {
        return ProductDto.class.isAssignableFrom(clazz);
    }
    
    @Override
    protected ProductDto readInternal(Class&lt;? extends ProductDto&gt; clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        String productDtoString = IOUtils.toString(inputMessage.getBody(), StandardCharsets.UTF_8);
        ObjectMapper objectMapper = new ObjectMapper();
        return objectMapper.readValue(productDtoString, ProductDto.class);
    }
}

and in you AppConfig:

@Configuration
public class AppConfig {
    
    @Bean
    public ProductDtoConverter productDtoConverter() {
        return new ProductDtoConverter();
    }
}

huangapple
  • 本文由 发表于 2023年3月4日 04:14:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/75631512.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定