当前位置: 首页 > 知识库问答 >
问题:

如何将标题和图像文件从前端(React.js)传递到后端API(Springboot)?

辛成周
2023-03-14

我正在尝试制作一个应用程序,允许注册用户提交一个图像文件(.jpeg、.png等)以及该图像的标题,但我很难思考如何做到这一点。我需要将图像发送到amazon AWS S3存储桶,我知道如何做到这一点,但添加标题输入让我很困惑,因为如何将文件和标题从我的前端(JSON)获取到后端API,并将其保存到我的帖子数据库(JPA)。我有一个user_post数据库,它有以下列:ID(post ID主键)、user_ID(用户表中的外键)、title、,

这是我的前端截图,只是为了视觉效果,以防有任何帮助。

这是我的代码,我为它的混乱道歉,我正在尽快清理它。我将从前端开始。我相信我需要为我的标题输入设置密钥,以便它被传递到我的后端API,但我甚至不确定我是否做得对。我还需要使用自定义表单验证,因为我正在处理图像上传。最后,我在useForm中调用了我的API。js文件,因为我的表单验证是在该自定义钩子中完成的。

上载jsx:

import '../../components/pages/styles/Uploads.css';
import {Formik, Field, Form, ErrorMessage} from 'formik';
import * as Yup from 'yup';
import {useEffect, useState} from 'react';
import {} from 'react-router-dom';
import {useDispatch, useSelector} from 'react-redux';
import axios from 'axios';
import {clearMessage} from '../../slices/messages';
import authHeader from '../../services/auth-header';
import useForm from '../../hooks/useForm';
const API_URL = 'http://localhost:8080/api/posts';

function Uploads(onUpload) {
    const {user: currentUser} = useSelector((state) => state.auth);
    const [file, setFile] = useState();
    const [title, setTitle] = useState();
    const [description, setDescription] = useState('');
    const [loading, setLoading] = useState(false);
    const [content, setContent] = useState('');
    const [preview, setPreview] = useState(null);
    const initialValues = {
        title: '',
    };

    const [formErrors, setFormErrors] = useState();

    useEffect(() => {}, []);

    const handlePost = (formValue) => {};

    const onAddImage = (file) => {
        window.URL.revokeObjectURL(preview);
        if (!file) return;
        setPreview(window.URL.createObjectURL(file));
    };

    //The postUserImage function below was moved to useForm.js 
    //since my form validations are done there. I might have 
    //messed this up. 

    // const postUserImage = async (event) => {
    //This is the code that will get passed to my backend. I need the image and title to be added here somehow.
    //  event.preventDefault();

    //  const formData = new FormData();
    //  formData.append('file', file);
    //  formData.append('title', title);

    //  const result = await axios.post('/upload', formData, {
    //      headers: {...authHeader(), 'Content-Type': 'multipart/form-data'},
    //  });
    //  console.log(result.data);
    // };

    //Custom hook call
    // const {handleChange, values, errors, handleSubmit} = useForm(postUserImage);
    const initialState = {title: ''};
    const validations = [
        ({title}) => isRequired(title) || {title: 'Title is required'},
    ];
    const {values, isValid, errors, changeHandler, submitHandler, touched} =
        useForm(initialState, validations, onUpload);

    return (
        <div className='page'>
            <div className='upload-card'>
                <div id='preview'>
                    <img
                        src={preview || require('../../assets/user-solid.jpeg')}
                        id='image'
                        alt='Thumbnail'
                        className='user-post'
                    />
                </div>
            </div>
            <div className='upload-container'>
                <div className='post-form-container'>
                    <p id='upload-form-label'>Hello, feel free to post an image!</p>
                    <form
                        // onSubmit={'return Validate(this);'}

                        onSubmit={submitHandler}
                        className='upload-form'
                    >
                        <div className='panel'>
                            <div className='button_outer'>
                                <div className='btn_upload'>
                                    <input
                                        filename={file}
                                        onChange={(e) => onAddImage(e.target.files[0])}
                                        type='file'
                                        accept='.jpeg,.svg,.gif,.png'
                                        id='image-selection-btn'
                                    ></input>
                                    Choose your Art
                                </div>
                            </div>
                        </div>
                        <input
                            name='title'
                            type='text'
                            className='form-control'
                            placeholder='Enter Title'
                            id='cred-input'
                            required
                            value={values.title}
                            onChange={changeHandler}
                        />

                        {touched.title && errors.title && (
                            <p className='error'>{errors.title}</p>
                        )}

                        <button type='submit' id='post-upload-btn' disabled={isValid}>
                            Upload Image
                        </button>
                    </form>
                </div>
            </div>
        </div>
    );
    function isRequired(value) {
        return value != null && value.trim().length > 0;
    }

    function isSame(value1, value2) {
        return value1 === value2;
    }
}

export default Uploads;

使用表单。js:

import React, {useState} from 'react';
import {omit} from 'lodash';
import authHeader from '../services/auth-header';
import axios from 'axios';

function useForm(initialState = {}, validations = [], onSubmit = () => {}) {
    const API_URL = 'http://localhost:8080/api/posts';
    // Add the 'onSubmit' argument
    const {isValid: initialIsValid, errors: initialErrors} = validate(
        validations,
        initialState
    );
    const [values, setValues] = useState(initialState);
    const [errors, setErrors] = useState(initialErrors);
    const [isValid, setValid] = useState(initialIsValid);
    const [touched, setTouched] = useState({});
    const [file, setFile] = useState();
    const [title, setTitle] = useState();
    const changeHandler = (event) => {
        const newValues = {...values, [event.target.name]: event.target.value};
        const {isValid, errors} = validate(validations, newValues);
        setValues(newValues);
        setValid(isValid);
        setErrors(errors);
        setTouched({...touched, [event.target.name]: true});
    };
    // Add this
    const submitHandler = async (event) => {
        event.preventDefault();
        onSubmit(values);
        const formData = new FormData();
        formData.append('file', file);
        formData.append('title', values.title);

        const result = await axios.post('/upload', formData, {
            headers: {...authHeader(), 'Content-Type': 'multipart/form-data'},
        });
        console.log(result.data);
    };
    return {values, changeHandler, isValid, errors, touched, submitHandler}; // Add 'submitHandler'
}

function validate(validations, values) {
    const errors = validations
        .map((validation) => validation(values))
        .filter((validation) => typeof validation === 'object');
    return {
        isValid: errors.length === 0,
        errors: errors.reduce((errors, error) => ({...errors, ...error}), {}),
    };
}

export default useForm;

后端代码:

使用者爪哇:

package com.Application.models;

import javax.persistence.*;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;

@Entity
@Table( name = "users",
        uniqueConstraints = {
                @UniqueConstraint(columnNames = "username"),


        })

public class User {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;


    @Column(name = "username")
    @NotBlank
    @Size(max = 20)
    private String username;

    @Column(name = "email")
    @NotBlank
    @Size(max = 50)
    @Email
    private String email;

    @NotBlank
    @Size(max = 120)
    private String password;

    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable( name = "user_roles",
            joinColumns = @JoinColumn(name = "user_id"),
            inverseJoinColumns = @JoinColumn(name = "role_id"))
    private Set<Role> roles = new HashSet<>();

    @OneToMany(cascade = CascadeType.ALL,
            fetch = FetchType.LAZY,
            mappedBy = "user")
    @Column(name = "user_post")
    private Set<UserPosts> userPosts = new HashSet<>();

    public User(String username, String email
                ,String password) {

        this.username = username;
        this.email = email;
        this.password = password;
    }

    public User() {

    }

public Long getId() {
    return id;
}
    public void setId(Long id) {
        this.id = id;
    }
    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
    public Set<Role> getRoles() {
        return roles;
    }
    public void setRoles(Set<Role> roles) {
        this.roles = roles;
    }
}

用户存储库。爪哇:

package com.Application.repository;
import java.util.Optional;
import java.util.UUID;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.HashTek.HashTekApplication.models.User;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByUsername(String username);
    Optional<User> findByEmail(String email);

    Boolean existsByUsername(String username);
    Boolean existsByEmail(String email);
}

UserPost。爪哇:

package com.Application.models;

import javax.persistence.*;

@Entity
@Table(name = "user_posts")
public class UserPosts {
    @Id
    @Column(name = "id")
    private Long id;

    @ManyToOne(cascade = {CascadeType.ALL}, fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id", nullable = false)
    private User user;

    @Column(name = "title")
    private String title;

    @Column(name = "post_image")
    private String postImage;

    @Column(name = "likes")
    private Long likes;

    @Column(name = "views")
    private Long views;


    public void setId(Long id) {
        this.id = id;
    }


    public Long getId() {
        return id;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getPostImage() {
        return postImage;
    }

    public String getPostImageComplete() {
        return " https://hashtekbucket.s3.us-east-2.amazonaws.com/" + postImage;
    }

    public void setPostImage(String postImage) {
        this.postImage = postImage;
    }

    public Long getLikes() {
        return likes;
    }

    public void setLikes(Long likes) {
        this.likes = likes;
    }

    public Long getViews() {
        return views;
    }

    public void setViews(Long views) {
        this.views = views;
    }


}

UserPostController.java:

package com.Application.controller;

import com.Application.models.User;
import com.Application.models.UserPosts;
import com.Application.payload.response.MessageResponse;
import com.Application.repository.UserPostsRepository;
import com.Application.security.jwt.JwtUtils;
import com.Application.security.services.CustomUserDetails;
import com.Application.security.services.CustomUserDetailsService;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.PutObjectRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;

import static org.apache.http.entity.ContentType.*;
import static org.apache.http.entity.ContentType.IMAGE_GIF;

@CrossOrigin(origins = "http://localhost:3000")
@RestController
@RequestMapping("/api/posts")
public class UserPostsController {
    private static final String AUTH_HEADER = "authorization";

    //  @Autowired
    //  private final UserPostsRepository userPostRepo;
    @Autowired
    private CustomUserDetailsService userDetailsService;
    @Autowired
    JwtUtils jwtUtils;

    /**  AWS CREDENTIALS SOURCE
     For AWS Builder  **/
    @Value("${cloud.aws.credentials.access-key}")
    private String accessKey;
    @Value("${cloud.aws.credentials.secret-key}")
    private String accessSecret;
    @Value("${cloud.aws.region.static}")
    private String region;

    //    public UserPostsController(UserPostsRepository userPostRepo) {
    //        this.userPostRepo = userPostRepo;
    //    }

    @PostMapping(
        path = "/upload",
        consumes = MediaType.MULTIPART_FORM_DATA_VALUE,
        produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity < ? > userPostUpload(@RequestParam("file") MultipartFile file,
        RedirectAttributes redirectAttributes,
        Model model,
        UserPosts userPosts, HttpServletRequest request, User user) {

        //Check if POST is empty
        if (file.isEmpty()) {

            return ResponseEntity.ok(new MessageResponse("Please select a file to upload"));
        }



        isImage(file);


        //Hard coded bucketName -> linked to AWS
        String bucketName = "hashtekbucket";

        //Add timestamp to name to prevent duplicate names
        String fileName = System.currentTimeMillis() + "_" + file.getOriginalFilename();

        //getting aws access
        AWSCredentials credentials = new BasicAWSCredentials(accessKey, accessSecret);

        //Building S3Client connection
        AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
            .withRegion(Regions.US_EAST_2)
            .withCredentials(new AWSStaticCredentialsProvider(credentials))
            .withRegion(region).build();


        try {
            //            //PUSH TO BUCKET
            File fileObj = convertMultiPartFileToFile(file);
            s3Client.putObject(new PutObjectRequest(bucketName, fileName, fileObj));
            fileObj.delete();
            //Show Successful Upload
            redirectAttributes.addFlashAttribute("message_2", fileName + ": SuccessFully Uploaded On AWS S3");

            //JWT Token retrieval from HTTP request header
            final String authHeader = request.getHeader(AUTH_HEADER);
            String username = null;
            String jwt = null;

            if (authHeader != null && authHeader.startsWith("Bearer")) {
                jwt = authHeader.substring(7);
                username = jwtUtils.getUserNameFromJwtToken(jwt);
            }

            //Load logged in Username from JWT Token obtained
            CustomUserDetails customUser = (CustomUserDetails) userDetailsService.loadUserByUsername(username);
            Long userId = customUser.getId();

            UserPosts myUserPost = new UserPosts();

            myUserPost.setId(userId);
            myUserPost.setPostImage(fileName);

            // The code under here is how I saved a user profile by ID,               // but I am getting an error in my post repo
            // since there is no post Id until a user creates one.

            //            //Find User by id
            //            userProfile = userProfRepo.findByUserId(userId);
            //
            //            //Set resource name to
            //            userProfile.setProfile_banner(fileName);
            //
            //            //Save database changes
            //            userProfRepo.save(userProfile);
        } catch (Exception e) {
            e.printStackTrace();
        }
        model.addAttribute("userPosts", userPosts);
        return ResponseEntity.ok(new MessageResponse("File Upload Successful"));

    }

    private void isImage(MultipartFile file) {
        if (!Arrays.asList(
                IMAGE_JPEG.getMimeType(),
                IMAGE_SVG.getMimeType(),
                IMAGE_PNG.getMimeType(),
                IMAGE_GIF.getMimeType()).contains(file.getContentType())) {
            throw new IllegalStateException("File must be an image [" + file.getContentType() + "]");
        }

    }

    /**
     File Conversion
     **/
    private File convertMultiPartFileToFile(MultipartFile file) {
        File convertedFile = new File(file.getOriginalFilename());
        try (FileOutputStream fos = new FileOutputStream(convertedFile)) {
            fos.write(file.getBytes());
        } catch (IOException e) {
            // log.error("Error converting multipartFile to file", e);
        }
        return convertedFile;
    }


}

如果有人能帮助我,任何信息、提示或任何东西,那就意味着整个世界。如果我错过了什么重要的东西,请让我知道。

共有1个答案

许茂才
2023-03-14

所以基本上,我需要弄清楚如何同时获取输入(文件和标题),

您需要向后端发送一个带有图像和标题的POST请求。它超文本标记语言5,标准的方法是使用输入类型文件的表单

实际上还有JavaScript API来设置文件输入只接受图像文件;我认为这是使用文件扩展名工作的。

把它发送到我的后端并保存在发布数据库中。我需要在我的发布控制器中传递标题作为参数吗?

标准文件帖子包含文件名

由于UserPost DB是与用户的一对多关系,我需要将登录用户的ID传递给我的控制器,以便将其发送到post DB,只是不确定如何。

您不应该发送用户id。事实上,您通常应该对将用户id发送到前端持谨慎态度。用户可以检查javascript中的所有内容。。。或者坐在他/她的办公桌旁的其他人。

相反,您可以依赖当前会话(在后端创建)进行用户标识。

 类似资料:
  • 问题内容: 我这里有一些有角度的js代码。 以及带有MySQL代码的node js。我能够从此节点代码将数据传递到MySQL DB。如何继续对Node JS进行角度测试?我来自PHP背景。我应该能够将数据从angular js表单发送到MySQL数据库。我可以从这里的节点代码向MySQL数据库发送数据。 问题答案: 它可能是您入门的垫脚石: Index.html 角度代码app.js server

  • 我希望能够从开发和生产的前端直接将图像上传到ReactJS公共文件夹。对于生产,我使用带有nodejs后端的heroku应用程序。 从我在网上找到的所有使用ReactJS上传图像的教程中,他们都使用服务器端将图像上传到云,但我想知道是否有可能像Lavarel那样将图像上传到公共文件夹,这样做是否有任何缺点?

  • 制作生产构建并将其与后端绑定。这再次调用访问计算机上的localhost,但失败。 使用window.location.hostname+“getform”操作URL。当我有不同的服务器承载前端和后端时,这将失败。 Edit*好的,我通过向package.json添加以下行,成功地向节点服务器添加了一个代理。它将前端的localhost:3000/api/getform转发到后端的localhos

  • 我正试图通过React将文件上载到s3存储桶,我正在与4xx和5xx进行斗争:( 下面是我的代码库: 如果我发了这篇文章,我会得到500英镑,而这个错误是: java.io.IOException:UT000036:解析多部分数据时连接终止 我还注意到documents属性为空: 这是后端的API文档: 谢谢!

  • 我在后端使用spring-boot 2.0.4,在前端使用vue 2.5.16 / axios 0.18.0,我希望将PDF文件上传到后端数据库,并从前端检索它们。 最初,我的灵感来自于spring部分的这个例子:https://grokonez . com/frontend/angular/angular-6/angular-6-client-upload-files-download-file

  • 我正在尝试将一个图像文件(驻留在本地)从我的react单页前端应用程序发送到我的flask后端。我尝试过但不限于捕获我的内容类型并在前端指示encType。尽管如此,post请求表明它是成功的。但是,当我记录请求时。文件,请求。表格,请求。值,我没有数据输入。显然,有些东西我错过了,我真的需要任何人的帮助。谢谢 网页前端工程师: 后端: