本系统主要使用以下技术栈:
- 后端:Spring Boot —— 采用此框架可以快速构建和部署RESTful API,并具备良好的可扩展性。
- 数据库:MySQL —— 作为关系型数据库,MySQL具有强大的数据管理能力,适合存储和查询结构化数据。
- 前端:Thymeleaf + HTML/CSS/JavaScript —— Thymeleaf作为模板引擎,可以快速生成动态HTML页面。
- 文件存储:本地文件系统或云存储服务(如 AWS S3)—— 提供灵活的文件存储方案。
以下是系统架构图,展示了各个模块之间的关系:
创建Spring Boot项目:
使用Spring Initializr(start.spring.io/)创建一个新的Spring Boot项目,选择以下依赖:
- Spring Web:用于构建RESTful API。
- Spring Data JPA:简化数据访问层的开发。
- MySQL Driver:用于连接MySQL数据库。
- Thymeleaf:用于生成动态网页。
在生成项目后,将其导入到IDE中(如IntelliJ IDEA或Eclipse),并确保项目可以正常编译和运行。
数据库配置:
在MySQL中创建一个新的数据库,例如 image_sharing_db。可以使用以下SQL命令:
点击查看代码
CREATE DATABASE image_sharing_db;
然后在 application.properties 文件中配置数据库连接:
点击查看代码
# MySQL 数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/image_sharing_db?useSSL=false&serverTimezone=UTC
spring.datasource.username=your_username
spring.datasource.password=your_password
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
添加依赖
确保在 pom.xml 中添加以下依赖:
点击查看代码
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
文件存储目录
为了存储用户上传的图片,需要在项目中创建一个文件存储目录。可以在项目根目录下创建一个名为 uploads 的文件夹,确保该文件夹具有可写权限。
数据模型设计
创建一个 Image 实体类,表示上传的图片信息。包括文件名、上传时间、过期时间等字段。
点击查看代码
import javax.persistence.*;
import java.time.LocalDateTime;
@Entity
public class Image {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; // 图片ID
private String filename; // 文件名
private LocalDateTime uploadTime; // 上传时间
private LocalDateTime expirationTime; // 过期时间
// getters and setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
public LocalDateTime getUploadTime() {
return uploadTime;
}
public void setUploadTime(LocalDateTime uploadTime) {
this.uploadTime = uploadTime;
}
public LocalDateTime getExpirationTime() {
return expirationTime;
}
public void setExpirationTime(LocalDateTime expirationTime) {
this.expirationTime = expirationTime;
}
}
数据访问层
创建一个数据访问接口 ImageRepository,用于与数据库交互。
点击查看代码
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ImageRepository extends JpaRepository<Image, Long> {
}
这里我们使用 JpaRepository 提供的基本CRUD操作,方便对 Image 实体的数据库操作。
控制器实现
创建一个控制器 ImageController,处理图片的上传和查看请求。
点击查看代码
package com.example.demo.controller;
import com.example.demo.entity.Image;
import com.example.demo.repository.ImageRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.Optional;
import java.util.UUID;
/**
* By zhangT
*/
@Controller
@RequestMapping("/images")
public class ImageController {
private static final String UPLOAD_DIR = "src/main/resources/static/uploads/";
@Autowired
private ImageRepository imageRepository;
@GetMapping("/upload")
public String uploadPage() {
return "upload"; // 返回上传页面视图
}
@PostMapping("/upload")
public String uploadImage(@RequestParam("file") MultipartFile file, Model model) {
String filename = UUID.randomUUID().toString() + "_" + file.getOriginalFilename();
Path path = Paths.get(UPLOAD_DIR + filename);
try {
Files.createDirectories(path.getParent());
file.transferTo(path);
// 保存文件信息到数据库
Image image = new Image();
image.setFilename(filename);
image.setUploadTime(LocalDateTime.now());
image.setExpirationTime(LocalDateTime.now().plusMinutes(1)); // 设置过期时间为1分钟
Image savedImage = imageRepository.save(image);
// 添加图片链接和ID到页面模型
model.addAttribute("message", "Image_Uploaded_Successfully.");
model.addAttribute("imageUrl", "/uploads/" + filename);
model.addAttribute("imageId", savedImage.getId());
} catch (IOException e) {
model.addAttribute("message", "Failed to upload image: " + e.getMessage());
}
return "upload"; // 返回上传页面视图
}
@PostMapping("/burn/{id}")
public ResponseEntity<String> burnImage(@PathVariable Long id) {
Optional<Image> imageOptional = imageRepository.findById(id);
if (imageOptional.isPresent()) {
Image image = imageOptional.get();
Path path = Paths.get("src/main/resources/static/uploads/" + image.getFilename());
try {
Files.deleteIfExists(path);
imageRepository.delete(image);
return ResponseEntity.ok("Image burned successfully");
} catch (IOException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Failed to burn image");
}
}
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Image not found");
}
}
用户界面设计
创建 upload.html,让用户可以上传图片,显示用户上传的图片,提示用户图片已过期。
点击查看代码
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>阅后即焚</title>
<style>
body {
font-family: Arial, sans-serif;
display: flex;
flex-direction: column;
align-items: center;
}
.upload-container {
margin-top: 50px;
text-align: center;
}
.preview-container img {
max-width: 100%;
height: auto;
margin-top: 10px;
}
.message {
color: green;
font-weight: bold;
margin-top: 10px;
}
/* 燃烧效果的 CSS */
.burn {
animation: burn 1s forwards;
}
@keyframes burn {
from {
opacity: 1;
}
to {
opacity: 0;
transform: scale(1.5);
}
}
#imageContainer {
position: relative;
}
#burnEffect {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(255, 0, 0, 0.5);
display: none;
z-index: 10;
}
</style>
</head>
<body>
<div class="upload-container">
<h1>阅后即焚</h1>
<form action="/images/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file" required>
<button type="submit">Upload</button>
</form>
<p th:text="${message}" class="message"></p>
</div>
<div d="imageContainer" class="preview-container" th:if="${imageUrl}">
<h2>图片预览</h2>
<img th:src="${imageUrl}" alt="上传图片">
<div id="burnEffect"></div>
</div>
<button id="burnButton">阅后即焚</button>
<script>
// 点击阅后即焚按钮的事件
document.getElementById("burnButton").onclick = function() {
const burnEffect = document.getElementById("burnEffect");
burnEffect.style.display = "block"; // 显示燃烧效果
burnEffect.classList.add("burn"); // 添加燃烧动画效果
// 延迟后删除图片
setTimeout(function() {
document.querySelector("img").style.display = "none"; // 隐藏图片
burnEffect.style.display = "none"; // 隐藏燃烧效果
alert("图片已阅后即焚,无法恢复。");
}, 2000); // 1秒后删除
};
// 向服务器发送阅后即焚请求
<!-- const imageId = /*[[${imageId}]]*/ 0;-->
<!-- fetch(`/burn/${imageId}`, { method: 'POST' })-->
<!-- .then(response => {-->
<!-- if (response.ok) {-->
<!-- response.text().then(msg => {-->
<!-- console.log(msg);-->
<!-- setTimeout(() => {-->
<!-- imageElement.style.display = 'none';-->
<!-- burnButton.style.display = 'none';-->
<!-- }, 2000); // 燃烧效果结束后隐藏图片-->
<!-- });-->
<!-- } else {-->
<!-- console.error("Failed to burn image.");-->
<!-- }-->
<!-- });-->
</script>
</body>
</html>
错误处理
在 ImageController 中实现统一的错误处理机制,捕获并处理可能出现的异常。可以通过 @ControllerAdvice 来实现全局异常处理:
点击查看代码
import org.springframework.http.HttpStatus;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(RuntimeException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public String handleRuntimeException(RuntimeException e, Model model) {
model.addAttribute("message", "An error occurred: " + e.getMessage());
return "error"; // 返回错误页面视图
}
}
系统优化
为了提高系统性能,可以考虑以下优化策略:
图片压缩:在上传图片时,压缩图片以减少存储空间和上传时间。可以使用第三方库如 Thumbnailator 进行图片处理。
异步处理:将图片的处理和存储任务异步化,避免阻塞用户请求。可以使用 @Async 注解或消息队列实现。
安全性
文件名安全性:为了避免文件名冲突和安全隐患,上传的文件名可以使用UUID进行重命名。
点击查看代码
import java.util.UUID;
// 在uploadImage方法中生成新的文件名
String newFilename = UUID.randomUUID().toString() + "_" + filename;
Path path = Paths.get(UPLOAD_DIR + newFilename);
点击查看代码
String contentType = file.getContentType();
if (!contentType.startsWith("image/")) {
model.addAttribute("message", "Please upload a valid image file.");
return "upload";
}
日志记录
使用 SLF4J 和 Logback 记录系统运行日志,包括上传、查看和错误信息,以便后期分析和监控。
点击查看代码
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ImageController {
private static final Logger logger = LoggerFactory.getLogger(ImageController.class);
// 在相应的位置记录日志
logger.info("Image uploaded successfully: {}", filename);
}
部署
可以使用Docker容器化部署Spring Boot应用,确保其在各个环境中都能稳定运行。编写 Dockerfile,配置相应的基础镜像和运行环境。点击查看代码
FROM openjdk:11-jre-slim
VOLUME /tmp
COPY target/image-sharing-app.jar app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
来源:juejin.cn/post/7433068127786909731
标签:阅后,SpringBoot,image,springframework,org,import,打造,上传,public From: https://www.cnblogs.com/ls-syh/p/18543590