如何使用具有 Spring 启动后端的 React JS、Axios post 多个对象?

How to post more than one object using React JS, Axios with a Spring boot backend?

API在用Postman测试时可以工作,但是,我不知道如何从React JS的前端发送多个post请求。 我必须发送要上传的图像文件以及 int 变量 'root'.

Postman- Post 要求:-

这是SpringBoot上的API

@PostMapping("/cost_image_upload")
    public status uploadFile(@RequestParam("file") MultipartFile file, @RequestParam("root") String root) throws IOException {
        List<cost> costs = costRepository.findAll();
        for(cost cost: costs) {
            if(cost.getRoot().equals(root)) {
                byte[] temp = file.getBytes();
                cost.setImage(temp);
                this.costRepository.save(cost);
                System.out.println("worked" + cost);
                return status.SUCCESS;
            }
        }
        System.out.println("didn't work");
        return status.FAILURE;
    }

这是CostService.js

import axios from 'axios';

const user_base_url = "http://localhost:8080/api";

class CostService{

    addCost(cost) {
        return axios.post(user_base_url + '/cost', cost);
    }

    uploadFile(image, root) {
        return axios.post(user_base_url + '/cost_image_upload', image, root);
    }

    showCost() {
        return axios.get(user_base_url + '/costings');
    }




}
export default new CostService();

这是 React JS 的前端 (StyleComponent.jsx)

import React, { Component } from 'react';
import {Row, Col, Card, Form, Button, Alert} from 'react-bootstrap';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {faSignInAlt} from "@fortawesome/free-solid-svg-icons";
import CostService from '../services/CostService';
// import axios from 'axios';


class StyleComponent extends Component {
    constructor(props) {
        super(props);
        this.state = this.initialState;
        this.isValid = false
        this.addCost = this.addCost.bind(this);
    }


    initialState = {
        temp:null, cID:null, root:null, priMat1:null, priMat2:null, actSize:null, image:null, firstQuote:null, firstComm:null, secQuote:null, secComm:null, vendorTarget1:null, thirdQuote:null, thirdComm:null, vendorTarget2:null, fourthQuote:null, error:null, error_success:null, selectedFile:null
    };

    onFileChange = event => {
    
      // Update the state
      this.setState({ selectedFile: event.target.files[0] });
  };

  onFileChange = event => {
    
    // Update the state
    this.setState({ selectedFile: event.target.files[0] });
  
  };

  uploadFile = (rootID) => {
    

    
    
};

  componentDidMount() {

    // call cost API
    // call COST_IMAGE API
  }

    
    credentialChange = event => {
        this.setState({
            [event.target.name] : event.target.value
        });
    };
    
    addCost = () => {

        let cost = { 

            cID: this.state.cID, 
            root: this.state.root,
            priMat1: this.state.priMat1,
            priMat2: this.state.priMat2,
            actSize: this.state.actSize,
            image: this.state.image,
            firstQuote: this.state.firstQuote,
            firstComm: this.state.firstComm,
            secQuote: this.state.secQuote,
            secComm: this.state.secComm,
            vendorTarget1: this.state.vendorTarget1,
            thirdQuote: this.state.thirdQuote,
            thirdComm: this.state.thirdComm,
            vendorTarget2: this.state.vendorTarget2,
            fourthQuote: this.state.fourthQuote,
        };
        
        CostService.addCost(cost).then((res) => {
            console.log(res.data);
            this.state.temp= res.data;
            console.log(this.state.temp);
            console.log(this.state.selectedFile);
            CostService.uploadFile(this.state.selectedFile, res.data).then((res2) => {
              if(res2.data === 'SUCCESS') {
                console.log("Success");
                  this.setState({error_success:"The file has been uploaded!"});
              } else if(res2.data === 'FAILURE') {
                console.log("Failure");
                  this.setState({error:"The file could not be uploaded!"});
              }
          })
        })
    };

    resetRegisterForm = () => {
        this.setState(() => this.initialState);
    };

    render() {
      const {error, error_success} = this.state;

        return (
        <div>
          <br></br>
          <br></br>
          {error_success && <Alert variant="success">{error_success}</Alert>}
          {error && <Alert variant="danger">{error}</Alert>}
          <Card>
            <Card.Header className={"border border-light bg-light text-black"}>
              <FontAwesomeIcon icon={faSignInAlt}/> Add a New Style!
            </Card.Header>
          <br></br>
            <Form>
            <Row className="mb-3">
            &nbsp; &nbsp;
            <Form.Group as={Col} controlId="formGridcID">
                <Form.Label>Costing Tool ID</Form.Label>
                <Form.Control type="text" name="cID" placeholder="Enter Costing Tool ID" onChange={this.credentialChange}/>
              </Form.Group>
          
              <Form.Group as={Col} controlId="formGridRoot">
                <Form.Label>Style Number</Form.Label>
                <Form.Control type="text" name="root" placeholder="Enter Style Number Root" onChange={this.credentialChange}/>
              </Form.Group>


              <Form.Group as={Col} controlId="formGridPriMat1">
                <Form.Label>Primary Material</Form.Label>
                <Form.Control type="text" name ="priMat1" placeholder="Specify Primary Material" onChange={this.credentialChange}/>
              </Form.Group>

              <Form.Group as={Col} controlId="formGridPriMat2">
                <Form.Label>Secondary Material</Form.Label>
                <Form.Control type="text" name ="priMat2" placeholder="Specify Secondary Material" onChange={this.credentialChange}/>
              </Form.Group>

              <Form.Group as={Col} controlId="formGridSize">
                <Form.Label>Size Range</Form.Label>
                <Form.Control type="text" name ="actSize" placeholder="Specify Size Range" onChange={this.credentialChange}/>
              </Form.Group>

              <input className= "form-control chosen-select" type="file" onChange={this.onFileChange}/><br></br>

              &nbsp; &nbsp;
            </Row>
            <div align="right">
            &nbsp; &nbsp;
            <Button variant="outline-success" type="submit"
              onClick={this.addCost}>
                Register
            </Button>
            &nbsp; &nbsp;
            <Button variant="outline-primary" type="reset">
              Reset
            </Button>
            &nbsp; &nbsp;
            <br></br>
            <br></br> 
            </div>
            </Form>
          </Card>
         </div>
        );
    }
}

export default (StyleComponent);

这是Springboot上的警告信息

2022-03-24 23:20:17.538  WARN 24028 --- [nio-8080-exec-5] .m.m.a.ExceptionHandlerExceptionResolver : Resolved [org.springframework.web.bind.MissingServletRequestParameterException: Required request parameter 'root' for method parameter type String is not present]

请建议如何 post 请求图像文件和 'root'。

请将您的上传文件功能更改为具有多部分 header 并添加图像,root 作为 formData 的一部分,如下所示。 (更新了成本服务文件)。如果以下解决方案有效,请告诉我

import axios from 'axios';

const user_base_url = "http://localhost:8080/api";

class CostService{

    addCost(cost) {
        return axios.post(user_base_url + '/cost', cost);
    }

    uploadFile(image, root) {
       const config = {
           headers: { 'content-type': 'multipart/form-data' }
       }
       const formData = new FormData();
        formData.append('file', image);
        formData.append('root', root);
        return axios.post(user_base_url + '/cost_image_upload', formData, config);
    }

    showCost() {
        return axios.get(user_base_url + '/costings');
    }


}
export default new CostService();