世界你好!
这是关于我在 Makers 构建社交网络克隆的经历的第二篇文章。第一篇文章的链接 - https://dev.to/olnov/working-with-http-requests-in-spring-boot-5el0。 当前的一个专门用于存储用户个人资料的图像。
步骤#1。计划。
作为 MVP 的一部分,我们决定实现以下用户故事:
作为用户,
我想更新我的个人资料以包含我的照片,
以便其他用户可以轻松在应用程序中找到我
我们还就非功能性需求达成了一致。
步骤#2。分析和设计。
我们提出了不同的图像存储位置选项 - 远程服务器文件夹、数据库和对象存储。尽管我们的应用程序负载不高,但我们决定使用 S3 作为分布式系统最合适的解决方案。 (P.S. 和我已经从之前的项目订阅了 iDrive e2)。
在数据库中,只有 iDrive 存储的公共 URL 的链接。
这是数据库图:
高级应用图:
步骤#3。构建。
后端部分需要完成以下内容:
在 pom.xml 中我添加了以下内容:
<dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>s3</artifactId> <version>2.28.18</version> </dependency>
图像服务类:
package com.makersacademy.acebook.service; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.PutObjectRequest; import software.amazon.awssdk.services.s3.model.PutObjectResponse; import java.io.InputStream; import java.net.URI; import java.util.UUID; @Service public class ImageService { private final S3Client s3Client; @Value("${idrive.e2.bucket-name}") private String bucketName; @Value("${idrive.e2.endpoint}") private String endpoint; @Value("${idrive.e2.public_endpoint}") private String public_endpoint; public ImageService(@Value("${idrive.e2.access-key}") String accessKey, @Value("${idrive.e2.secret-key}") String secretKey, @Value("${idrive.e2.endpoint}") String endpoint) { AwsBasicCredentials credentials = AwsBasicCredentials.create(accessKey, secretKey); this.s3Client = S3Client.builder() .credentialsProvider(StaticCredentialsProvider.create(credentials)) .endpointOverride(URI.create(endpoint)) .region(Region.AWS_GLOBAL) // I dind't see exact instructions from iDrive, so I set this parameter to AWS_GLOBAL .build(); } public String uploadImage(InputStream imageStream, long contentLength, String contentType) { String key = "media/" + UUID.randomUUID(); PutObjectRequest putObjectRequest = PutObjectRequest.builder() .bucket(bucketName) .key(key) .contentType(contentType) .contentLength(contentLength) // Specify the content length .build(); s3Client.putObject(putObjectRequest, software.amazon.awssdk.core.sync.RequestBody.fromInputStream(imageStream, contentLength)); // Return the image URL return public_endpoint + "/" + bucketName + "/" + key; } }
Idrive 连接变量存储在 application.properties 文件中:
#S3 storage settings idrive.e2.access-key=${E2_ACCESS_KEY} idrive.e2.secret-key=${E2_SECRET_KEY} idrive.e2.endpoint=${E2_ENDPOINT} idrive.e2.bucket-name=${E2_BUCKET_NAME} idrive.e2.public_endpoint=${E2_PUBLIC_ENDPOINT}
好的,现在 ImageController 类:
package com.makersacademy.acebook.controller; import com.makersacademy.acebook.model.Post; import com.makersacademy.acebook.repository.PostRepository; import com.makersacademy.acebook.service.ImageService; import com.makersacademy.acebook.model.User; import com.makersacademy.acebook.repository.UserRepository; import jakarta.servlet.http.HttpSession; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.view.RedirectView; import java.io.IOException; @Controller public class ImageController { @Autowired private ImageService imageService; @Autowired private UserRepository userRepository; @Autowired private PostRepository postRepository; @PostMapping("/upload/{userId}") public RedirectView uploadImage(@PathVariable Long userId, @RequestParam("file") MultipartFile file) { try { // Check if the user exists User user = userRepository.findById(userId).orElseThrow(()->new RuntimeException("User not found")); // Upload image to IDrive e2 and get image URL String imageUrl = imageService.uploadImage(file.getInputStream(), file.getSize(), file.getContentType()); // Save the image URL in the user's profile user.setUser_photo(imageUrl); userRepository.save(user); return new RedirectView("/media/"+userId); } catch (IOException e) { throw new RuntimeException("Error uploading file:"+e.getMessage()); } } @PostMapping("/upload/post") public RedirectView uploadImageAsPost(@RequestParam("file") MultipartFile file, HttpSession session){ try { Long userId = (Long) session.getAttribute("user_id"); if (userId == null) { throw new RuntimeException("Not authorized"); } String imageUrl = imageService.uploadImage(file.getInputStream(), file.getSize(), file.getContentType()); User user = userRepository.findById(userId) .orElseThrow(() -> new RuntimeException("User not found")); Post post = new Post(imageUrl,user,true); postRepository.save(post); return new RedirectView("/"); } catch (IOException e) { throw new RuntimeException("Error uploading file:"+e.getMessage()); } } }
在上传个人资料图片的前端我添加了以下内容:
<div class="mb-3"> <form id="image-form" th:action="@{/api/images/upload/{id}(id=${user.id})}" method="post" enctype="multipart/form-data"> <"formFile" class="form-label btn btn-primary">Upload Image</label> <input class="form-control" type="file" name="file" id="formFile" accept=".jpg,.jpeg,.png" onchange="autoSubmitImage()" hidden/> </form> </div> <script th:inline="javascript"> /*<![CDATA[*/ const autoSubmitImage = ()=> { document.getElementById("image-form").submit(); } /*]]>*/ </script>
结果。
就是这个。
干杯!
以上是使用 Spring Boot 和 iDrive E3 存储 UGC 应用程序的图像的详细内容。更多信息请关注PHP中文网其他相关文章!