Not Possible to upload images using React, Spring gives a error MultipartException: Current request is not a multipart request

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

Not Possible to upload images using React, Spring gives a error MultipartException: Current request is not a multipart request

问题

It looks like you're facing an issue where your Spring backend is not recognizing the request as a multipart request when you try to upload files. Here are some potential solutions to your problem:

  1. Check Axios Configuration: Ensure that your Axios configuration includes the Content-Type header with the value 'multipart/form-data' when making the POST request for file uploads. You can set this header using Axios like this:

    1. const config = {
    2. headers: {
    3. 'Content-Type': 'multipart/form-data'
    4. }
    5. };
    6. // Make the POST request with the configuration
    7. axios.post(ASSETS_GOT_FROM_REST_API, asset, config);
  2. Verify Frontend Setup: Double-check that your frontend form correctly sets the enctype attribute to "multipart/form-data". You've already done this, but it's essential to make sure there are no typos or issues with HTML structure.

  3. Spring Configuration: Ensure that your Spring application is properly configured to handle multipart requests. You can do this by adding the @EnableMultipartConfig annotation to your Spring configuration class or main application class. Here's an example:

    1. import org.springframework.boot.SpringApplication;
    2. import org.springframework.boot.autoconfigure.SpringBootApplication;
    3. import org.springframework.boot.web.servlet.MultipartConfigFactory;
    4. import org.springframework.context.annotation.Bean;
    5. import javax.servlet.MultipartConfigElement;
    6. @SpringBootApplication
    7. public class YourApplication {
    8. public static void main(String[] args) {
    9. SpringApplication.run(YourApplication.class, args);
    10. }
    11. @Bean
    12. public MultipartConfigElement multipartConfigElement() {
    13. MultipartConfigFactory factory = new MultipartConfigFactory();
    14. // Set your configuration options here if needed
    15. return factory.createMultipartConfig();
    16. }
    17. }
  4. Controller Configuration: In your Spring controller, make sure that the method handling the file upload has the correct signature. It should include @RequestParam for each file and use MultipartFile as the parameter type, like you've done in your AssetsController.

  5. Check File Sizes: Ensure that the files you're trying to upload are not too large for your server's configured limits. Spring has default limits for file size, so you might need to adjust them if your files are large. You can do this in your Spring configuration as well.

  6. Error Handling: If the issue persists, consider implementing error handling in your Spring controller to log more detailed error messages. You can capture and log exceptions to get more insights into what might be causing the MultipartException.

  7. Database Configuration: Although it's less likely related to your problem, check your database configuration to ensure it's not causing issues. Your entities and database setup appear correct, but sometimes database constraints or configurations can lead to unexpected issues.

By following these steps, you should be able to troubleshoot and resolve the issue with file uploads in your Spring Boot application.

英文:

I can not solve the issue with MultipartException? I try to create a new Item with adding the imges React. Every time I receive the error in Spring console, that current request is not Multipart request.

I created a form for adding the item details and images of item and added enctype="multipart/form-data" but it shows the Axios error AxiosError {message: 'Request failed with status code 500', name: 'AxiosError', code: 'ERR_BAD_RESPONSE', config: {…}, request: XMLHttpRequest, …

but Spring console shows me :

  1. org.springframework.web.multipart.MultipartException: Current request is not a multipart request

On spring I created two enities for Items and Images. And on Item add the images should be added together with item ID. For I can take the images from DB by Item id.

Here are the Entities:

Items Entity :

  1. package com.demo.fijinv.Models;
  2. import jakarta.persistence.*;
  3. import lombok.AllArgsConstructor;
  4. import lombok.Getter;
  5. import lombok.NoArgsConstructor;
  6. import lombok.Setter;
  7. import java.time.LocalDateTime;
  8. import java.util.ArrayList;
  9. import java.util.List;
  10. @Entity
  11. @Table(name = "assets")
  12. @Getter
  13. @Setter
  14. @AllArgsConstructor
  15. @NoArgsConstructor
  16. public class Assets {
  17. @Id
  18. @GeneratedValue(strategy = GenerationType.AUTO)
  19. @Column(name = "id")
  20. private Long id;
  21. @Column(name = "asset_type")
  22. private String assettype;
  23. @Column(name = "asset_brand")
  24. private String assetBrand;
  25. @Column(name = "asset_model")
  26. private String assetModel;
  27. @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "assets")
  28. private List<Image> images = new ArrayList<>();
  29. private Long previewImageId;
  30. private LocalDateTime creationDate;
  31. @PrePersist //to read about inversion of control
  32. private void init() {
  33. creationDate = LocalDateTime.now();
  34. }
  35. public void addImageToItemName(Image image) {
  36. image.setAssets(this);
  37. images.add(image);
  38. }
  39. @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
  40. private List<Items> invItem = new ArrayList<>();
  41. }

Images Entity:

  1. package com.demo.fijinv.Models;
  2. import jakarta.persistence.*;
  3. import lombok.AllArgsConstructor;
  4. import lombok.Getter;
  5. import lombok.NoArgsConstructor;
  6. import lombok.Setter;
  7. import java.util.List;
  8. @Entity
  9. @Table(name = "images")
  10. @Getter
  11. @Setter
  12. @AllArgsConstructor
  13. @NoArgsConstructor
  14. public class Image {
  15. @Id
  16. @GeneratedValue(strategy = GenerationType.AUTO)
  17. @Column(name = "id")
  18. private Long id;
  19. @Column(name = "name")
  20. private String name;
  21. @Column(name = "originalFileName")
  22. private String originalFileName;
  23. @Column(name = "size")
  24. private Long size;
  25. @Column(name = "contentType")
  26. private String contentType;
  27. @Column(name = "isPreviewImage")
  28. private boolean isPreviewImage;
  29. @Column(length = 10000000)
  30. @Lob
  31. private byte[] bytes;
  32. @ManyToOne(cascade = CascadeType.REFRESH, fetch = FetchType.EAGER)
  33. private Assets assets;
  34. @ManyToMany(cascade = CascadeType.REFRESH, fetch = FetchType.EAGER)
  35. private List<Items> items;
  36. }

And the controllers for these entities:

Items Controller :

  1. package com.demo.fijinv.Conteollers;
  2. import com.demo.fijinv.Models.Assets;
  3. import com.demo.fijinv.Models.Image;
  4. import com.demo.fijinv.Repositories.AssetsRepository;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.http.HttpStatus;
  7. import org.springframework.http.MediaType;
  8. import org.springframework.http.ResponseEntity;
  9. import org.springframework.web.bind.annotation.*;
  10. import org.springframework.web.multipart.MultipartFile;
  11. import java.io.IOException;
  12. import java.util.List;
  13. import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
  14. @CrossOrigin("*")
  15. @RestController
  16. @RequestMapping("/api/assets")
  17. public class AssetsController {
  18. @Autowired
  19. public AssetsRepository assetsRepository;
  20. @GetMapping
  21. public List<Assets> getAllAssets(){
  22. return assetsRepository.findAll();
  23. }
  24. @DeleteMapping("{id}")
  25. public ResponseEntity<Assets> deleteAsset(@PathVariable Long id){
  26. assetsRepository.deleteById(id);
  27. return new ResponseEntity<>(HttpStatus.OK);
  28. }
  29. @PostMapping(consumes = {MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_JSON_VALUE})
  30. public void saveAsset(@RequestBody Assets assets, @RequestParam("file1") MultipartFile file1, @RequestParam("file2") MultipartFile file2, @RequestParam("file3") MultipartFile file3) throws IOException {
  31. Image image1;
  32. Image image2;
  33. Image image3;
  34. if(file1.getSize() != 0){
  35. image1 = toImageEntity(file1);
  36. image1.setPreviewImage(true);
  37. assets.addImageToItemName(image1);
  38. }
  39. if(file2.getSize() != 0){
  40. image2 = toImageEntity(file2);
  41. assets.addImageToItemName(image2);
  42. }
  43. if(file3.getSize() != 0){
  44. image3 = toImageEntity(file3);
  45. assets.addImageToItemName(image3);
  46. }
  47. Assets itemFromDB = assetsRepository.save(assets);
  48. itemFromDB.setPreviewImageId(itemFromDB.getImages().get(0).getId());
  49. assetsRepository.save(assets);
  50. }
  51. private Image toImageEntity(MultipartFile file) throws IOException {
  52. Image image = new Image();
  53. image.setName(file.getName());
  54. image.setOriginalFileName(file.getOriginalFilename());
  55. image.setContentType(file.getContentType());
  56. image.setSize(file.getSize());
  57. image.setBytes(file.getBytes());
  58. return image;
  59. }
  60. }

Images Controller :

  1. package com.demo.fijinv.Conteollers;
  2. import com.demo.fijinv.Models.Image;
  3. import com.demo.fijinv.Repositories.ImageRepository;
  4. import lombok.RequiredArgsConstructor;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.core.io.InputStreamResource;
  7. import org.springframework.http.MediaType;
  8. import org.springframework.http.ResponseEntity;
  9. import org.springframework.web.bind.annotation.*;
  10. import java.io.ByteArrayInputStream;
  11. import java.util.List;
  12. @CrossOrigin("*")
  13. @RestController //no needed to present anything
  14. @RequestMapping("/api/assets/images")
  15. public class ImageController {
  16. @Autowired
  17. public ImageRepository imageRepository;
  18. @GetMapping
  19. private List<Image> getAllImages(){
  20. return imageRepository.findAll();
  21. }
  22. @GetMapping("{id}")
  23. private ResponseEntity<?> getImageByID(@PathVariable Long id){
  24. Image image = imageRepository.findById(id).orElse(null);
  25. return ResponseEntity.ok()
  26. .header("filename", image.getOriginalFileName())
  27. .contentType(MediaType.valueOf(image.getContentType()))
  28. .contentLength(image.getSize())
  29. .body(new InputStreamResource(new ByteArrayInputStream(image.getBytes())));
  30. }
  31. }

Both controllers are configured for allow the requests from all the services by adding @CrossOrigin("*"), which means that spring should receive the requests.

With React I created a simple page with form in modal where I scan add the item with images :

  1. import React, { useEffect, useState } from 'react'
  2. import { Link } from 'react-router-dom';
  3. import { Modal, Button } from 'react-bootstrap'
  4. import AssetsSetvice from "./../../Services/AssetsService"
  5. const AssetsComponenet = () => {
  6. const [show, setShow] = useState(false);
  7. const modalShow = () => setShow(true);
  8. const modalHide = () => setShow(false);
  9. // getting all assets
  10. const [assets, setAssets] = useState([]);
  11. useEffect(() => {
  12. AssetsSetvice.getAllAssets().then((res) => {
  13. setAssets(res.data);
  14. }).catch(err => {
  15. console.log(err)
  16. })
  17. }, []);
  18. const [assettype, setAssettype] = useState('');
  19. const [assetBrand, setAssetBrand] = useState('');
  20. const [assetModel, setAssetModel] = useState('');
  21. const [image1, setImage1] = useState();
  22. const [image2, setImage2] = useState();
  23. const [image3, setImage3] = useState();
  24. const [showImage1, setShowImage1] = useState();
  25. const [showImage2, setShowImage2] = useState();
  26. const [showImage3, setShowImage3] = useState();
  27. const saveAsset = (event) => {
  28. event.preventDefault()
  29. const asset = {
  30. assettype,
  31. assetBrand,
  32. assetModel,
  33. image1,
  34. image2,
  35. image3
  36. }
  37. console.log(asset)
  38. AssetsSetvice.addNewAsset(asset).then((res) => {
  39. console.log(res.data)
  40. event.preventDefault();
  41. }).catch(err => {
  42. console.log(err)
  43. })
  44. }
  45. const saveAndClose = (ev) => {
  46. saveAsset(ev);
  47. setShow(false);
  48. }
  49. const deleteAsset = (id) => {
  50. if (window.confirm("Are you sure want to delete this asset?")) {
  51. AssetsSetvice.deleteAsset(id).then((response) => {
  52. console.log(`Asset with ${id} was deleted`);
  53. // window.location.replace("/users");
  54. }).catch(error => {
  55. console.log(`Something went worng : \n ${error}`);
  56. })
  57. }
  58. }
  59. let count = 1;
  60. return (
  61. <>
  62. <div className='container'>
  63. <h2 className='text-center mt-4 mb-4 bold'> List of Items</h2>
  64. <div className='mb-3'>
  65. <button type='button' className='btn btn-primary' data-toggle="modal" onClick={modalShow} data-target="#addNewItemModal">
  66. Add new Asset
  67. </button>
  68. </div>
  69. <table className='table table-bordered table-striped'>
  70. <thead>
  71. <tr>
  72. <th className="th-sm">№</th>
  73. <th className="th-sm">Name</th>
  74. <th className="th-sm">Brand</th>
  75. <th className="th-sm">Model</th>
  76. <th className="th-sm"> Action </th>
  77. </tr>
  78. </thead>
  79. <tbody>
  80. {
  81. assets.map(
  82. function (item) {
  83. return <tr key={item.id}>
  84. {/* <tr> */}
  85. <th className="th-sm">{count++}</th>
  86. <th className="th-sm">Asset Name</th>
  87. <th className="th-sm">Asset Brand</th>
  88. <th className="th-sm">Asset Model</th>
  89. <th className="th-sm">
  90. {/* <Link to={`/item-delete/${item.id}`} className="btn btn-primary"> Delete Item </Link> */}
  91. <Link onClick={(id) => { deleteAsset(id) }} className="btn btn-primary"> Delete Asset </Link>
  92. </th>
  93. </tr>
  94. }
  95. )
  96. }
  97. </tbody>
  98. </table>
  99. <Modal show={show} size='lg' onHide={modalHide} centered>
  100. <Modal.Header closeButton>
  101. <Modal.Title center>
  102. Add New Item
  103. </Modal.Title>
  104. </Modal.Header>
  105. <Modal.Body>
  106. <div className='container-fluid'>
  107. <form className='row' method='POST' enctype="multipart/form-data">
  108. {/* <form className='row' > */}
  109. <div className='col-md-4'>
  110. <label className='form-label'> Item Name </label>
  111. <input type='text'
  112. placeholder='Item Name'
  113. className='form-control'
  114. // value={itemname}
  115. onChange={(e) => {
  116. if (e.target.value != "") {
  117. setAssettype(e.target.value)
  118. }
  119. }}
  120. required
  121. />
  122. </div>
  123. <div className='col-md-4'>
  124. <label className='form-label'> Item Brand </label>
  125. <input type='text'
  126. placeholder='Item Brand'
  127. className='form-control'
  128. // value={itembrand}
  129. onChange={(e) => {
  130. if (e.target.value != "") {
  131. setAssetBrand(e.target.value)
  132. }
  133. }}
  134. required
  135. />
  136. </div>
  137. <div className='col-md-4'>
  138. <label className='form-label'> Item Model </label>
  139. <input type='text'
  140. placeholder='Item Model'
  141. className='form-control'
  142. // value={itemmodel}
  143. onChange={(e) => {
  144. if (e.target.value != "") {
  145. setAssetModel(e.target.value)
  146. }
  147. }}
  148. required
  149. />
  150. </div>
  151. <div className='col-md-4'>
  152. <label className='form-label'> First Image </label>
  153. <input type='file'
  154. className='form-control'
  155. // value={file1}
  156. onChange={(e) => {
  157. if (e.target.value != "") {
  158. setShowImage1(URL.createObjectURL(e.target.files[0]))
  159. setImage1(e.target.files[0])
  160. }
  161. }}
  162. />
  163. </div>
  164. <div className='col-md-4'>
  165. <label className='form-label'> First Image </label>
  166. <input type='file'
  167. className='form-control'
  168. // value={file2}
  169. onChange={(e) => {
  170. if (e.target.value != "") {
  171. setShowImage2(URL.createObjectURL(e.target.files[0]))
  172. setImage2(e.target.files[0])
  173. }
  174. }}
  175. required
  176. />
  177. </div>
  178. <div className='col-md-4'>
  179. <label className='form-label'> First Image </label>
  180. <input type='file'
  181. className='form-control'
  182. // value={file3}
  183. onChange={(e) => {
  184. if (e.target.value != "") {
  185. setShowImage3(URL.createObjectURL(e.target.files[0]))
  186. setImage3(e.target.files[0])
  187. }
  188. }}
  189. />
  190. </div>
  191. </form>
  192. </div>
  193. <div className='row mt-4'>
  194. <div className='col-md-4'>
  195. <img style={{ width: "150px" }} className="rounded mx-auto d-block" src={showImage1} />
  196. </div>
  197. <div className='col-md-4'>
  198. <img style={{ width: "150px" }} className="rounded mx-auto d-block" src={showImage2} />
  199. </div>
  200. <div className='col-md-4'>
  201. <img style={{ width: "150px" }} className="rounded mx-auto d-block" src={showImage3} />
  202. </div>
  203. </div>
  204. </Modal.Body>
  205. <Modal.Footer center>
  206. <Button center onClick={(e) => { saveAndClose(e) }} variant="primary">Add New Asset</Button>
  207. </Modal.Footer>
  208. </Modal>
  209. </div>
  210. </>
  211. )
  212. }
  213. export default AssetsComponenet

As you can see that in the form there is encription type - multipart: <form className='row' method='POST' enctype="multipart/form-data"> but any way I receive the error.

I use Axios for receive the data from backend, and I created the service for Items:

  1. import axios from "axios";
  2. const ASSETS_GOT_FROM_REST_API = "http://localhost:8082/api/assets";
  3. const IMAGES_GOT_FROM_REST_API = "http://localhost:8082/api/assets/images";
  4. class AssetsSetvice {
  5. getAllAssets() {
  6. return axios.get(ASSETS_GOT_FROM_REST_API);
  7. }
  8. addNewAsset(asset) {
  9. return axios.post(ASSETS_GOT_FROM_REST_API, asset);
  10. }
  11. deleteAsset(assetId) {
  12. return axios.delete(ASSETS_GOT_FROM_REST_API + "/" + assetId);
  13. }
  14. getAllImages() {
  15. return axios.get(IMAGES_GOT_FROM_REST_API);
  16. }
  17. addNewImages(images) {
  18. return axios.addNewImage(IMAGES_GOT_FROM_REST_API, images);
  19. }
  20. }
  21. export default new AssetsSetvice();

when I try to console log the item, which I try to add, I receive :

  1. assetBrand : "fgdfgerg"
  2. assetModel : "gvcvbdxbt"
  3. assettype : "rterte"
  4. file1 : File {name: 'lenovo-3.jpg', lastModified: 1684826589057, lastModifiedDate: Tue May 24 2023 10:23:09 GMT+0300 (Eastern European Summer Time), webkitRelativePath: '', size: 4437, …}
  5. file2 : File {name: 'm700-1.jfif', lastModified: 1684826441152, lastModifiedDate: Tue May 24 2023 10:20:41 GMT+0300 (Eastern European Summer Time), webkitRelativePath: '', size: 3221, …}
  6. file3 : File {name: 'm700-1.jfif', lastModified: 1684826441152, lastModifiedDate: Tue May 23 2023 10:20:41 GMT+0300 (Eastern European Summer Time), webkitRelativePath: '', size: 3221, …}

seams that I am able to send the post request to server, but server refuse it.
And I tried by the different ways.

What I do wrong? How can I solve tis issue?
Can it be related with ManyToOne or OneToMany which were configured in Entity calsses? Because I dont see any other problems.... seams that something blocking in backend side...

答案1

得分: 0

我认为问题出在你的控制器上:

@RequestBody 表示解析 JSON 数据为映射或 Java Bean,并仅支持内容类型为 "application/json;charset=UTF-8"。

也许你可以尝试使用 @ModelAttribute

  1. @PostMapping(consumes = {MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_JSON_VALUE})
  2. public ResponseEntity<Object> saveAsset(@ModelAttribute Assets assets,
  3. @RequestParam MultipartFile file1,
  4. @RequestParam MultipartFile file2,
  5. @RequestParam MultipartFile file3) throws IOException {
英文:

I think the problem is in your controller:

@RequestBody means to parse JSON data into map or java beans and only support content type is "application/json;charset=UTF-8"

Maybe you can try with @ModelAttribute:

  1. @PostMapping(consumes = {MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_JSON_VALUE})
  2. public ResponseEntity&lt;Object&gt; saveAsset(@ModelAttribute Assets assets,
  3. @RequestParam MultipartFile file1,
  4. @RequestParam MultipartFile file2,
  5. @RequestParam MultipartFile file3) throws IOException {

huangapple
  • 本文由 发表于 2023年5月24日 17:42:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/76322145.html
匿名

发表评论

匿名网友

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

确定