reactjs - 如何使用 spring boot 显示来自 AWS s3 的图像并使用react?

标签 reactjs spring-boot amazon-s3

如何在 React 中显示来自 amazon s3 bucket 的图像? 图像未使用 amazon s3、spring boot 2.5.3、react 显示。

我已经在 postman 中测试了端点,它有效。

React:使用 Axios 连接后端和 MyDropZone

使用 axios 发出 post 请求,我可以确认图像正在保存在 s3 中。 Saved image

这是前 2 位用户发出发布请求后的响应。

[
   {
      "userId":"565c6cbe-7833-482d-b0d4-2edcd7fc6163",
      "userName":"John",
      "imageUrl":"pexels-photo-3147528.jpeg"
   },
   {
      "userId":"3c776990-38e8-4de4-b7c6-7875c0ebb20f",
      "userName":"Anthony",
      "imageUrl":"pexels-photo-3147528.jpeg"
   },
   {
      "userId":"bcac9cf2-5508-4996-953e-b18afe866581",
      "userName":"Peter",
      "imageUrl":null
   }
]

react :

import './App.css';
import axios from 'axios';
import { useState, useEffect,useCallback } from 'react';
import {useDropzone} from 'react-dropzone'



//
const UserProfiles = () => {

  const [userProfiles,setUserProfiles]=useState([])

  const fetchUserProfiles=() => {
    axios.get('http://localhost:5000/api/v1/users').then((response) => {
      console.log(response.data)
      setUserProfiles(response.data)
    })
  }

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

  return userProfiles.map((profile,index) => {
    return (
      <div key={index}>
        <MyDropZone userId={profile.userId}></MyDropZone>
        <h3>{profile.userId}</h3>
        {
          profile.userId ? (<img src={`http://localhost:5000/api/v1/users/${profile.userId}/image/download`} /> ) : <h5>No profile Image Uploaded</h5>
        }
      </div>
    );
  })
}

function MyDropZone({userId}) {
  const onDrop = useCallback(acceptedFiles => {
    // Do something with the files
    console.log(acceptedFiles[0])
    const file=acceptedFiles[0]
    //Form-data
    const formData = new FormData()
    formData.append('file', file)
    
    //Make a post req
    axios.post(`http://localhost:5000/api/v1/users/${userId}/image/upload`, formData, {
      headers: {
        'Content-Type':'multipart/form-data'
      }
    }).then((response) => {
      console.log(response)
      console.log("Uploaded")
    }).catch((error) => {
      console.log(error)
    })
  }, [])
  const {getRootProps, getInputProps, isDragActive} = useDropzone({onDrop})

  return (
    <div {...getRootProps()}>
      <input {...getInputProps()} />
      {
        isDragActive ?
          <p>Drop the files here ...</p> :
          <p>Drag 'n' drop some files here, or click to select files</p>
      }
    </div>
  )
}



function App() {
  return (
    <div className="App">
      <UserProfiles ></UserProfiles>
    </div>
  );
}

export default App;

图像未加载到 UI 中。

{
 profile.userId ? (<img src={`http://localhost:5000/api/v1/users/${profile.userId}/image/download`} /> ) : <h5>No profile Image Uploaded</h5>
}

This is how it looks in the inspect element.

当我通过浏览器转到此 http://localhost:5000/api/v1/users/565c6cbe-7833-482d-b0d4-2edcd7fc6163/image/download URL 时。 它有一个回应

 ÿØÿàJFIFHHÿâICC_PROFILElcmsmntrRGB XYZ Ü)9acspAPPLöÖÓ-lcms descü^cprt\wtpthbkpt|rXYZgXYZ¤bXYZ¸rTRCÌ@gTRCÌ@b

更新添加的后端代码。

Controller

@GetMapping(path = "{userId}/image/download")
public byte[] downloadUserProfileImage(@PathVariable("userId") UUID userId) {
    return userProfileService.downloadUserProfileImage(userId);
}

服务:

private UserProfile getUserProfileOrThrow(UUID userId) {
    UserProfile userProfile = userProfileRepository.getUserProfiles()
            .stream()
            .filter(profile -> profile.getUserId().equals(userId)).findFirst().orElseThrow(() -> new IllegalStateException("User does not exist" + userId)
            );
    return userProfile;
}
public byte[] downloadUserProfileImage(UUID userId) {
    UserProfile userProfile=getUserProfileOrThrow(userId);
    String path = String.format("%s/%s",
            BucketName.PROFILE_IMAGE.getBucketName(),
            userProfile.getUserId());

    return userProfile.getImageUrl()
            .map(key -> fileStore.download(path, key))
            .orElse(new byte[0]);
}

文件存储:

@Service
public class FileStore {
    private final AmazonS3 s3;

@Autowired
public FileStore(AmazonS3 s3) {
    this.s3 = s3;
}
public void save(String path,
                 String fileName,
                 Optional<Map<String, String>> optionalMetadata,
                 InputStream inputStream) {
    ObjectMetadata metadata = new ObjectMetadata();

    optionalMetadata.ifPresent(map -> {
        if (!map.isEmpty()) {
            map.forEach(metadata::addUserMetadata);
        }
    });

    try {
        s3.putObject(path, fileName, inputStream, metadata);
    } catch (AmazonServiceException e) {
        throw new IllegalStateException("Failed to store file to s3", e);
    }
}

public byte[] download(String path, String key) {
    try {
        S3Object object = s3.getObject(path, key);
        return IOUtils.toByteArray(object.getObjectContent());
    } catch (AmazonServiceException | IOException e) {
        throw new IllegalStateException("Failed to download file to s3", e);
    }
}
}

亚马逊 s3 配置: @配置 公共(public)类 AmazonConfig {

@Bean
public AmazonS3 s3(){
    AWSCredentials  awsCredentials=new BasicAWSCredentials("my-credentials","my-secret-key");

    return AmazonS3ClientBuilder.standard().withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
            .withRegion(Regions.AP_SOUTH_1)
            .build();
}

用户资料:

public class UserProfile {
    private final UUID userId;
    private final String userName;
    private String imageUrl;

    //This might be null
    public Optional<String> getImageUrl() {
        return Optional.ofNullable(imageUrl);
    }

    public void setImageUrl(String imageUrl) {
        this.imageUrl = imageUrl;
    }
//getters & setters
    }

最佳答案

当我遇到同样的问题时,我不得不以 Base64 格式返回 object.getObjectContent() 图像。

之后在前端展示数据的时候,可以这样尝试:

<img src="data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAAUA
    AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO
        9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot" />

你可以试试this Base64 decoder查看您的 Base64 数据是否正确。

这意味着您事先进行了 GET 调用,保存结果,然后在 img src 中显示 base64 字符串

更新:

根据您的方法,为了下载每个用户配置文件的图像,在 .map 中,您可以有一个为每个配置文件下载图片的函数。


  const fetchUserProfileImage = async (userProfileId) => {
    return axios.get(`http://localhost:5000/api/v1/users/${profile.userId}/image/download`)

  }

  return userProfiles.map(async (profile,index) => {
    const userProfileImageBase64 = await fetchUserProfileImage(profile.userId)
    return (
      <div key={index}>
        <MyDropZone userId={profile.userId}></MyDropZone>
        <h3>{profile.userId}</h3>
        {
          profile.userId ? (<img src={`data:image/png;base64, ${userProfileImageBase64}`}/> ) : <h5>No profile Image Uploaded</h5>
        }
      </div>
    );
  })

或者如果您不喜欢在 .map 中等待,您可以尝试在渲染主体之前下载所有图像并将它们映射到 中已经存在的用户userProfiles 状态。

或者,我认为最好的方法是将另一个 profileImageSrc 字段添加到 User 类,并在您在后端上传图像时将其保存在那里。然后您不必进行额外的调用,只需使用在获取 userProfiles

时收到的数据

关于reactjs - 如何使用 spring boot 显示来自 AWS s3 的图像并使用react?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68936315/

相关文章:

javascript - React Native 中的 Axios - 无法发布 Blob 或文件

javascript - 使用 mobx-state-tree 参数执行异步操作

java - SpringBoot 集成测试 Sybase 和 Testcontainers

java - 如何在 Spring Boot 中创建不可变类和单例类?

java - Spring Boot MVC 在另一个 JSP 文件中包含 JSP 文件

node.js - 在 express/nodejs 应用程序中提供存储在 S3 中的文件

html5 video 标签 - 加载/播放视频延迟

amazon-web-services - CloudFormation S3 Bucket/BucketPolicy 创建 - 模板的资源 block 中 Unresolved 资源依赖关系 [环境]

javascript - 如何仅使用 react-webcam 显示视频 Canvas

javascript - React Router 没有 Router 属性