如何使用MultipartException解决问题?我尝试使用imges创建一个新的Item,使用Spring作为后端,React作为前端。
我创建了一个表单,用于添加项目的详细信息和图像,并添加了enctype="multipart/form-data"
,但它显示Axios错误AxiosError {message: 'Request failed with status code 500', name: 'AxiosError', code: 'ERR_BAD_RESPONSE', config: {…}, request: XMLHttpRequest, …
Spring console显示:
org.springframework.web.multipart.MultipartException: Current request is not a multipart request
在spring上,我为Items和Images创建了两个实体。在项目添加上,图像应与项目ID一起添加。因为我可以从数据库中按项目ID获取图像。
以下是实体:
项目实体:
package com.demo.fijinv.Models;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "assets")
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Assets {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
@Column(name = "asset_type")
private String assettype;
@Column(name = "asset_brand")
private String assetBrand;
@Column(name = "asset_model")
private String assetModel;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "assets")
private List<Image> images = new ArrayList<>();
private Long previewImageId;
private LocalDateTime creationDate;
@PrePersist //to read about inversion of control
private void init() {
creationDate = LocalDateTime.now();
}
public void addImageToItemName(Image image) {
image.setAssets(this);
images.add(image);
}
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<Items> invItem = new ArrayList<>();
}
镜像实体:
package com.demo.fijinv.Models;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.List;
@Entity
@Table(name = "images")
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Image {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
@Column(name = "name")
private String name;
@Column(name = "originalFileName")
private String originalFileName;
@Column(name = "size")
private Long size;
@Column(name = "contentType")
private String contentType;
@Column(name = "isPreviewImage")
private boolean isPreviewImage;
@Column(length = 10000000)
@Lob
private byte[] bytes;
@ManyToOne(cascade = CascadeType.REFRESH, fetch = FetchType.EAGER)
private Assets assets;
@ManyToMany(cascade = CascadeType.REFRESH, fetch = FetchType.EAGER)
private List<Items> items;
}
以及这些实体的控制器:
项目控制器:
package com.demo.fijinv.Conteollers;
import com.demo.fijinv.Models.Assets;
import com.demo.fijinv.Models.Image;
import com.demo.fijinv.Repositories.AssetsRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.List;
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
@CrossOrigin("*")
@RestController
@RequestMapping("/api/assets")
public class AssetsController {
@Autowired
public AssetsRepository assetsRepository;
@GetMapping
public List<Assets> getAllAssets(){
return assetsRepository.findAll();
}
@DeleteMapping("{id}")
public ResponseEntity<Assets> deleteAsset(@PathVariable Long id){
assetsRepository.deleteById(id);
return new ResponseEntity<>(HttpStatus.OK);
}
@PostMapping(consumes = {MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_JSON_VALUE})
public void saveAsset(@RequestBody Assets assets, @RequestParam("file1") MultipartFile file1, @RequestParam("file2") MultipartFile file2, @RequestParam("file3") MultipartFile file3) throws IOException {
Image image1;
Image image2;
Image image3;
if(file1.getSize() != 0){
image1 = toImageEntity(file1);
image1.setPreviewImage(true);
assets.addImageToItemName(image1);
}
if(file2.getSize() != 0){
image2 = toImageEntity(file2);
assets.addImageToItemName(image2);
}
if(file3.getSize() != 0){
image3 = toImageEntity(file3);
assets.addImageToItemName(image3);
}
Assets itemFromDB = assetsRepository.save(assets);
itemFromDB.setPreviewImageId(itemFromDB.getImages().get(0).getId());
assetsRepository.save(assets);
}
private Image toImageEntity(MultipartFile file) throws IOException {
Image image = new Image();
image.setName(file.getName());
image.setOriginalFileName(file.getOriginalFilename());
image.setContentType(file.getContentType());
image.setSize(file.getSize());
image.setBytes(file.getBytes());
return image;
}
}
镜像控制器:
package com.demo.fijinv.Conteollers;
import com.demo.fijinv.Models.Image;
import com.demo.fijinv.Repositories.ImageRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.io.ByteArrayInputStream;
import java.util.List;
@CrossOrigin("*")
@RestController //no needed to present anything
@RequestMapping("/api/assets/images")
public class ImageController {
@Autowired
public ImageRepository imageRepository;
@GetMapping
private List<Image> getAllImages(){
return imageRepository.findAll();
}
@GetMapping("{id}")
private ResponseEntity<?> getImageByID(@PathVariable Long id){
Image image = imageRepository.findById(id).orElse(null);
return ResponseEntity.ok()
.header("filename", image.getOriginalFileName())
.contentType(MediaType.valueOf(image.getContentType()))
.contentLength(image.getSize())
.body(new InputStreamResource(new ByteArrayInputStream(image.getBytes())));
}
}
两个控制器都配置为通过添加@CrossOrigin("*")
来允许来自所有服务的请求,这意味着spring应该接收请求。
而对于前端我做了一个简单的页面与形式在模态,我应该能够广告的项目与图像:
import React, { useEffect, useState } from 'react'
import { Link } from 'react-router-dom';
import { Modal, Button } from 'react-bootstrap'
import AssetsSetvice from "./../../Services/AssetsService"
const AssetsComponenet = () => {
const [show, setShow] = useState(false);
const modalShow = () => setShow(true);
const modalHide = () => setShow(false);
// getting all assets
const [assets, setAssets] = useState([]);
useEffect(() => {
AssetsSetvice.getAllAssets().then((res) => {
setAssets(res.data);
}).catch(err => {
console.log(err)
})
}, []);
const [assettype, setAssettype] = useState('');
const [assetBrand, setAssetBrand] = useState('');
const [assetModel, setAssetModel] = useState('');
const [image1, setImage1] = useState();
const [image2, setImage2] = useState();
const [image3, setImage3] = useState();
const [showImage1, setShowImage1] = useState();
const [showImage2, setShowImage2] = useState();
const [showImage3, setShowImage3] = useState();
const saveAsset = (event) => {
event.preventDefault()
const asset = {
assettype,
assetBrand,
assetModel,
image1,
image2,
image3
}
console.log(asset)
AssetsSetvice.addNewAsset(asset).then((res) => {
console.log(res.data)
event.preventDefault();
}).catch(err => {
console.log(err)
})
}
const saveAndClose = (ev) => {
saveAsset(ev);
setShow(false);
}
const deleteAsset = (id) => {
if (window.confirm("Are you sure want to delete this asset?")) {
AssetsSetvice.deleteAsset(id).then((response) => {
console.log(`Asset with ${id} was deleted`);
// window.location.replace("/users");
}).catch(error => {
console.log(`Something went worng : \n ${error}`);
})
}
}
let count = 1;
return (
<>
<div className='container'>
<h2 className='text-center mt-4 mb-4 bold'> List of Items</h2>
<div className='mb-3'>
<button type='button' className='btn btn-primary' data-toggle="modal" onClick={modalShow} data-target="#addNewItemModal">
Add new Asset
</button>
</div>
<table className='table table-bordered table-striped'>
<thead>
<tr>
<th className="th-sm">№</th>
<th className="th-sm">Name</th>
<th className="th-sm">Brand</th>
<th className="th-sm">Model</th>
<th className="th-sm"> Action </th>
</tr>
</thead>
<tbody>
{
assets.map(
function (item) {
return <tr key={item.id}>
{/* <tr> */}
<th className="th-sm">{count++}</th>
<th className="th-sm">Asset Name</th>
<th className="th-sm">Asset Brand</th>
<th className="th-sm">Asset Model</th>
<th className="th-sm">
{/* <Link to={`/item-delete/${item.id}`} className="btn btn-primary"> Delete Item </Link> */}
<Link onClick={(id) => { deleteAsset(id) }} className="btn btn-primary"> Delete Asset </Link>
</th>
</tr>
}
)
}
</tbody>
</table>
<Modal show={show} size='lg' onHide={modalHide} centered>
<Modal.Header closeButton>
<Modal.Title center>
Add New Item
</Modal.Title>
</Modal.Header>
<Modal.Body>
<div className='container-fluid'>
<form className='row' method='POST' enctype="multipart/form-data">
{/* <form className='row' > */}
<div className='col-md-4'>
<label className='form-label'> Item Name </label>
<input type='text'
placeholder='Item Name'
className='form-control'
// value={itemname}
onChange={(e) => {
if (e.target.value != "") {
setAssettype(e.target.value)
}
}}
required
/>
</div>
<div className='col-md-4'>
<label className='form-label'> Item Brand </label>
<input type='text'
placeholder='Item Brand'
className='form-control'
// value={itembrand}
onChange={(e) => {
if (e.target.value != "") {
setAssetBrand(e.target.value)
}
}}
required
/>
</div>
<div className='col-md-4'>
<label className='form-label'> Item Model </label>
<input type='text'
placeholder='Item Model'
className='form-control'
// value={itemmodel}
onChange={(e) => {
if (e.target.value != "") {
setAssetModel(e.target.value)
}
}}
required
/>
</div>
<div className='col-md-4'>
<label className='form-label'> First Image </label>
<input type='file'
className='form-control'
// value={file1}
onChange={(e) => {
if (e.target.value != "") {
setShowImage1(URL.createObjectURL(e.target.files[0]))
setImage1(e.target.files[0])
}
}}
/>
</div>
<div className='col-md-4'>
<label className='form-label'> First Image </label>
<input type='file'
className='form-control'
// value={file2}
onChange={(e) => {
if (e.target.value != "") {
setShowImage2(URL.createObjectURL(e.target.files[0]))
setImage2(e.target.files[0])
}
}}
required
/>
</div>
<div className='col-md-4'>
<label className='form-label'> First Image </label>
<input type='file'
className='form-control'
// value={file3}
onChange={(e) => {
if (e.target.value != "") {
setShowImage3(URL.createObjectURL(e.target.files[0]))
setImage3(e.target.files[0])
}
}}
/>
</div>
</form>
</div>
<div className='row mt-4'>
<div className='col-md-4'>
<img style={{ width: "150px" }} className="rounded mx-auto d-block" src={showImage1} />
</div>
<div className='col-md-4'>
<img style={{ width: "150px" }} className="rounded mx-auto d-block" src={showImage2} />
</div>
<div className='col-md-4'>
<img style={{ width: "150px" }} className="rounded mx-auto d-block" src={showImage3} />
</div>
</div>
</Modal.Body>
<Modal.Footer center>
<Button center onClick={(e) => { saveAndClose(e) }} variant="primary">Add New Asset</Button>
</Modal.Footer>
</Modal>
</div>
</>
)
}
export default AssetsComponenet
正如你可以看到,在形式有encription类型- multipart:<form className='row' method='POST' enctype="multipart/form-data">
但无论如何我都收到错误。
我使用Axios从后端接收数据,并为Items创建了服务:
import axios from "axios";
const ASSETS_GOT_FROM_REST_API = "http://localhost:8082/api/assets";
const IMAGES_GOT_FROM_REST_API = "http://localhost:8082/api/assets/images";
class AssetsSetvice {
getAllAssets() {
return axios.get(ASSETS_GOT_FROM_REST_API);
}
addNewAsset(asset) {
return axios.post(ASSETS_GOT_FROM_REST_API, asset);
}
deleteAsset(assetId) {
return axios.delete(ASSETS_GOT_FROM_REST_API + "/" + assetId);
}
getAllImages() {
return axios.get(IMAGES_GOT_FROM_REST_API);
}
addNewImages(images) {
return axios.addNewImage(IMAGES_GOT_FROM_REST_API, images);
}
}
export default new AssetsSetvice();
当我尝试控制台记录我尝试添加的项目时,我收到:
assetBrand : "fgdfgerg"
assetModel : "gvcvbdxbt"
assettype : "rterte"
image1 :
File {name: 'lenovo-3.jpg', lastModified: 1684826589057, lastModifiedDate: Tue May 23 2023 10:23:09 GMT+0300 (Eastern European Summer Time), webkitRelativePath: '', size: 4437, …}
image2 :
File {name: 'm700-1.jfif', lastModified: 1684826441152, lastModifiedDate: Tue May 23 2023 10:20:41 GMT+0300 (Eastern European Summer Time), webkitRelativePath: '', size: 3221, …}
image3 :
undefined
我可以向服务器发送帖子请求,但服务器拒绝了。
我做错了什么?我该如何解决这个问题?
提前感谢!
1条答案
按热度按时间zz2j4svz1#
在ItemsController类中,变量的名称是file 1、file 2和file 3,因此您的axios请求变量的名称必须相同,而不是当前的image 1、image 2、image 3。试试看。你的后端代码部分:
public void saveAsset(@RequestBody Assets assets,@RequestParam(“file1”)MultipartFile file1,@RequestParam(“file2”)MultipartFile file2,@RequestParam(“file3”)MultipartFile file3)