本文目录导读:

- 项目结构
- Maven依赖 (pom.xml)
- 配置文件 (application.yml)
- 主应用类
- 文件上传配置类
- 文件存储服务
- 文件上传控制器
- 前端页面 (static/upload.html)
- 运行测试
- 高级功能
- 注意事项
我来为您提供一个完整的Java文件上传案例,包含前端和后端的实现。
项目结构
file-upload-demo/
├── pom.xml
├── src/
│ └── main/
│ ├── java/
│ │ └── com/example/
│ │ ├── FileUploadApplication.java
│ │ ├── controller/
│ │ │ └── FileUploadController.java
│ │ ├── service/
│ │ │ └── FileStorageService.java
│ │ └── config/
│ │ └── FileUploadConfig.java
│ └── resources/
│ ├── application.yml
│ └── static/
│ └── index.html
Maven依赖 (pom.xml)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.0</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>file-upload-demo</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- Web starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Thymeleaf 模板引擎 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- 文件上传处理 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<!-- Lombok 简化代码 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
配置文件 (application.yml)
server:
port: 8080
spring:
servlet:
multipart:
# 单个文件最大大小
max-file-size: 10MB
# 请求中所有文件总大小
max-request-size: 50MB
# 文件上传阈值
file-size-threshold: 2KB
# 上传文件存储位置
location: ./uploads/
# 自定义文件上传配置
file:
upload:
# 上传目录
path: ./uploads/
# 允许的文件类型
allowed-types: image/jpeg,image/png,image/gif,application/pdf,application/msword
# 最大文件大小(字节)
max-size: 10485760
主应用类
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class FileUploadApplication {
public static void main(String[] args) {
SpringApplication.run(FileUploadApplication.class, args);
}
}
文件上传配置类
package com.example.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import lombok.Data;
@Data
@Configuration
@ConfigurationProperties(prefix = "file.upload")
public class FileUploadConfig {
// 上传路径
private String path;
// 允许的文件类型
private String[] allowedTypes;
// 最大文件大小
private long maxSize;
// 是否创建目录
private boolean createDirectory = true;
}
文件存储服务
package com.example.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import com.example.config.FileUploadConfig;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
@Service
public class FileStorageService {
@Autowired
private FileUploadConfig fileUploadConfig;
private Path fileStoragePath;
/**
* 存储单个文件
*/
public String storeFile(MultipartFile file) throws IOException {
// 检查文件是否为空
if (file.isEmpty()) {
throw new IOException("文件不能为空");
}
// 检查文件类型
if (!isAllowedFileType(file.getContentType())) {
throw new IOException("不支持的文件类型: " + file.getContentType());
}
// 检查文件大小
if (file.getSize() > fileUploadConfig.getMaxSize()) {
throw new IOException("文件大小超出限制");
}
// 创建存储目录
initStoragePath();
// 生成唯一的文件名
String originalFilename = StringUtils.cleanPath(file.getOriginalFilename());
String fileExtension = getFileExtension(originalFilename);
String uniqueFilename = UUID.randomUUID().toString() + fileExtension;
// 构建完整的存储路径
Path targetLocation = this.fileStoragePath.resolve(uniqueFilename);
// 复制文件到目标位置
Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING);
return uniqueFilename;
}
/**
* 存储多个文件
*/
public List<String> storeFiles(MultipartFile[] files) throws IOException {
java.util.List<String> storedFiles = new java.util.ArrayList<>();
for (MultipartFile file : files) {
if (!file.isEmpty()) {
String storedFilename = storeFile(file);
storedFiles.add(storedFilename);
}
}
return storedFiles;
}
/**
* 删除文件
*/
public boolean deleteFile(String filename) throws IOException {
if (filename == null || filename.isEmpty()) {
return false;
}
Path filePath = this.fileStoragePath.resolve(filename);
return Files.deleteIfExists(filePath);
}
/**
* 获取文件
*/
public Path getFile(String filename) {
return this.fileStoragePath.resolve(filename);
}
/**
* 检查文件类型是否允许
*/
private boolean isAllowedFileType(String contentType) {
if (contentType == null) {
return false;
}
return Arrays.asList(fileUploadConfig.getAllowedTypes()).contains(contentType);
}
/**
* 获取文件扩展名
*/
private String getFileExtension(String filename) {
int lastDotIndex = filename.lastIndexOf(".");
if (lastDotIndex == -1) {
return "";
}
return filename.substring(lastDotIndex);
}
/**
* 初始化存储路径
*/
private void initStoragePath() throws IOException {
if (fileStoragePath == null) {
fileStoragePath = Paths.get(fileUploadConfig.getPath())
.toAbsolutePath()
.normalize();
// 创建目录
if (fileUploadConfig.isCreateDirectory()) {
Files.createDirectories(fileStoragePath);
}
}
}
}
文件上传控制器
package com.example.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
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 org.springframework.web.servlet.mvc.support.RedirectAttributes;
import com.example.service.FileStorageService;
import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.file.Path;
import java.util.List;
@Controller
public class FileUploadController {
@Autowired
private FileStorageService fileStorageService;
/**
* 显示上传页面
*/
@GetMapping("/")
public String index() {
return "upload";
}
/**
* 处理单个文件上传
*/
@PostMapping("/upload")
public String uploadFile(@RequestParam("file") MultipartFile file,
RedirectAttributes redirectAttributes) {
try {
String storedFilename = fileStorageService.storeFile(file);
redirectAttributes.addFlashAttribute("message",
"文件上传成功: " + file.getOriginalFilename());
redirectAttributes.addFlashAttribute("filename", storedFilename);
} catch (IOException e) {
redirectAttributes.addFlashAttribute("error",
"文件上传失败: " + e.getMessage());
}
return "redirect:/";
}
/**
* 处理多个文件上传
*/
@PostMapping("/uploadMultiple")
public String uploadMultipleFiles(@RequestParam("files") MultipartFile[] files,
RedirectAttributes redirectAttributes) {
try {
List<String> storedFilenames = fileStorageService.storeFiles(files);
redirectAttributes.addFlashAttribute("message",
"成功上传 " + storedFilenames.size() + " 个文件");
} catch (IOException e) {
redirectAttributes.addFlashAttribute("error",
"文件上传失败: " + e.getMessage());
}
return "redirect:/";
}
/**
* 下载文件
*/
@GetMapping("/download/{filename:.+}")
public ResponseEntity<Resource> downloadFile(@PathVariable String filename) {
try {
Path filePath = fileStorageService.getFile(filename);
Resource resource = new UrlResource(filePath.toUri());
if (resource.exists()) {
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + resource.getFilename() + "\"")
.body(resource);
} else {
return ResponseEntity.notFound().build();
}
} catch (MalformedURLException e) {
return ResponseEntity.badRequest().build();
}
}
/**
* 删除文件
*/
@PostMapping("/delete/{filename}")
public String deleteFile(@PathVariable String filename,
RedirectAttributes redirectAttributes) {
try {
fileStorageService.deleteFile(filename);
redirectAttributes.addFlashAttribute("message", "文件删除成功: " + filename);
} catch (IOException e) {
redirectAttributes.addFlashAttribute("error", "文件删除失败: " + e.getMessage());
}
return "redirect:/";
}
}
前端页面 (static/upload.html)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">Java文件上传案例</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 40px 20px;
}
.container {
max-width: 800px;
margin: 0 auto;
background: white;
border-radius: 15px;
padding: 40px;
box-shadow: 0 15px 30px rgba(0, 0, 0, 0.1);
}
h1 {
color: #333;
margin-bottom: 30px;
text-align: center;
font-size: 28px;
}
h2 {
color: #555;
margin-bottom: 20px;
font-size: 20px;
}
.upload-section {
background: #f5f5f5;
border: 2px dashed #ccc;
border-radius: 10px;
padding: 30px;
margin-bottom: 20px;
transition: border-color 0.3s;
}
.upload-section:hover {
border-color: #667eea;
}
.file-input {
margin: 20px 0;
width: 100%;
padding: 15px;
border: 1px solid #ddd;
border-radius: 5px;
background: white;
}
.upload-btn {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
padding: 12px 30px;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
transition: transform 0.2s;
}
.upload-btn:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
}
.message {
margin: 20px 0;
padding: 15px;
border-radius: 5px;
font-size: 14px;
line-height: 1.6;
}
.success {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.error {
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.divider {
border: none;
border-top: 2px solid #eee;
margin: 30px 0;
}
.file-info {
background: #f8f9fa;
padding: 10px;
border-radius: 5px;
margin: 10px 0;
font-size: 14px;
}
</style>
</head>
<body>
<div class="container">
<h1>📁 Java 文件上传案例</h1>
<!-- 消息提示 -->
<div th:if="${message}" class="message success" th:text="${message}"></div>
<div th:if="${error}" class="message error" th:text="${error}"></div>
<!-- 单个文件上传 -->
<h2>单个文件上传</h2>
<div class="upload-section">
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file" class="file-input" required>
<button type="submit" class="upload-btn">📤 上传文件</button>
</form>
</div>
<hr class="divider">
<!-- 多个文件上传 -->
<h2>多个文件上传</h2>
<div class="upload-section">
<form action="/uploadMultiple" method="post" enctype="multipart/form-data">
<input type="file" name="files" class="file-input" multiple required>
<button type="submit" class="upload-btn">📤 上传多个文件</button>
</form>
</div>
<hr class="divider">
<!-- 已上传文件信息 -->
<div th:if="${filename}" class="file-info">
<h3 style="margin-bottom: 15px;">📄 已上传文件:</h3>
<p><strong>文件名:</strong><span th:text="${filename}"></span></p>
<a th:href="@{'/download/' + ${filename}}"
class="upload-btn"
style="display: inline-block; text-decoration: none; margin-top: 10px;">
⬇️ 下载文件
</a>
</div>
<!-- 上传提示信息 -->
<div style="margin-top: 30px; padding: 20px; background: #e3f2fd; border-radius: 5px;">
<h3 style="margin-bottom: 10px;">📋 上传规范</h3>
<ul style="margin-left: 20px; line-height: 1.8;">
<li>允许的文件类型:图片(JPG/PNG/GIF)、PDF、Word 文档</li>
<li>单个文件最大大小:10MB</li>
<li>多个文件总大小:50MB</li>
</ul>
</div>
</div>
</body>
</html>
运行测试
1 启动应用
mvn spring-boot:run
2 测试方法
- 浏览器访问:打开
http://localhost:8080 - 单个文件上传:选择一个文件,点击"上传文件"
- 多个文件上传:选择多个文件(Ctrl+Click 或 Cmd+Click),点击"上传多个文件"
- 下载测试:上传成功后,点击"下载文件"链接
高级功能
1 增加文件预览
@GetMapping("/preview/{filename:.+}")
public ResponseEntity<Resource> previewFile(@PathVariable String filename) {
try {
Path filePath = fileStorageService.getFile(filename);
Resource resource = new UrlResource(filePath.toUri());
if (resource.exists()) {
// 根据文件扩展名返回不同的 Content-Type
String contentType = determineContentType(filename);
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType(contentType))
.body(resource);
} else {
return ResponseEntity.notFound().build();
}
} catch (Exception e) {
return ResponseEntity.badRequest().build();
}
}
private String determineContentType(String filename) {
if (filename.endsWith(".pdf")) return "application/pdf";
if (filename.endsWith(".jpg") || filename.endsWith(".jpeg")) return "image/jpeg";
if (filename.endsWith(".png")) return "image/png";
return "application/octet-stream";
}
2 增加进度条
// 前端使用 XMLHttpRequest 实现上传进度
const xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', (event) => {
if (event.lengthComputable) {
const percentCompleted = (event.loaded / event.total) * 100;
// 更新进度条
progressBar.style.width = percentCompleted + '%';
}
});
xhr.open('POST', '/upload');
const formData = new FormData();
formData.append('file', fileInput.files[0]);
xhr.send(formData);
注意事项
- 安全性:建议添加文件类型校验和病毒扫描
- 性能:大文件上传建议使用分片上传
- 存储:生产环境建议使用云存储(OSS/S3)
- 限制:合理设置文件大小限制,防止恶意攻击
- 日志:记录文件上传日志,便于追踪
这个案例提供了完整的Java文件上传功能,包含前后端实现、文件校验、多文件上传等特性,您可以根据实际需求进行调整和扩展。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播