1

So I am struggling for a while with sending files and other data to the backend with FormData in the frontend and RequestParam in the backend. I tried so many different things and I have searched so long for solutions and nothing that could fix it. I already made sure that the values are not empty by way of console.logs.

Code:

//Front-End
async addProduct(itemDetails) {
        const url = `${this.resourcesUrl}/addProduct`;

        const formData = new FormData();
        formData.append('name', itemDetails.name);
        formData.append('description', itemDetails.description);
        formData.append('file1', itemDetails.file1);
        formData.append('file2', itemDetails.file2);

        const response = await fetch(url, {
            method: 'POST',
            body: formData,
        });

        if (response.ok) {
            return await response.json();
        } else {
            const errorResponse = await response.json();
            throw new Error(errorResponse.message || 'Failed to add product');
        }
    }


//Back-End
@PostMapping("/addProduct")
    public ResponseEntity<Product> addProduct(
            @RequestParam(value = "name") String name,
            @RequestParam(value = "description") String description,
            @RequestPart(value = "file1") MultipartFile file1,
            @RequestPart(value = "file2") MultipartFile file2
    ) {
        try {
            String file1Path = fileStorageService.saveFile(name, file1);
            String file2Path = fileStorageService.saveFile(name, file2);

            Product product = new Product(name, description, file1Path , file2Path);

            productRepository.save(product);

            return ResponseEntity.ok(product);
        } catch (Exception e) {
            return ResponseEntity.badRequest().build();
        }
    }

pom and application.properties:

//relavant part of application.properties
spring.servlet.multipart.enabled=true
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB


//pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.2</version>
        <relativePath/>
    </parent>
    <groupId>com.example</groupId>
    <artifactId>app</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>app</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>22</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- JWT jackson -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-api</artifactId>
            <version>0.11.2</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-impl</artifactId>
            <version>0.11.2</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-jackson</artifactId>
            <version>0.11.2</version>
            <scope>runtime</scope>
        </dependency>
        <!-- end JWT jackson -->

        <dependency>
            <groupId>jakarta.persistence</groupId>
            <artifactId>jakarta.persistence-api</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

So when I try to add a new product with this values:

name: Test description: Test file1: (file1) file2: (file2)

I get the error: "Required request parameter 'name' for method parameter type String is not present"

The Content-Type of Request Headers in the network tab is application/json but from what I understand is that it should be automatically set to multipart/form-data but it does not do that, even if I explicitly set the Content-Type in the fetch request to multipart/form-data. I think that this is the reason that the passed parameter value is not being recognized.

2 Answers 2

1

After having this issue for so long I found out it had to do with a fetch interceptor implementation in my codebase (it sets in each fetch explicitly as Content-Type: application/json) and after removing the explicit Content-Type it worked.

So if you also have this problem you should look if you did set the Content-Type explicitly anywhere in your codebase.

Sign up to request clarification or add additional context in comments.

Comments

0

Use @RequestPart for all parameters to handle the multipart/form-data correctly. Because you have files in request, Content-type is automatically set to multipart/form-data.

@PostMapping("/addProduct")
    public ResponseEntity<Product> addProduct(
            @RequestPart(value = "name") String name,
            @RequestPart(value = "description") String description,
            @RequestPart(value = "file1") MultipartFile file1,
            @RequestPart(value = "file2") MultipartFile file2
    ) {...}

2 Comments

Thank you for responding. I have changed it to @RequestPart and now I do get a different error message ("Failed to parse multipart servlet request"). When I inspect the network tab I see that in the request Headers the Content-Type is still set on application/json while performing the right steps for sending multipart/form-data.
The error I get in the springboot console: "the request doesn't contain a multipart/form-data or multipart/mixed stream, content type header is application/json"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.