# Java實現文件上傳的方法
## 一、文件上傳概述
文件上傳是Web開發中常見的功能需求,允許用戶將本地文件傳輸到服務器端存儲。在Java生態系統中,有多種技術可以實現文件上傳功能,包括但不限于:
1. 原生Servlet API實現
2. Spring框架的MultipartFile
3. Apache Commons FileUpload
4. 第三方云存儲SDK集成
本文將詳細介紹這些方法的實現原理和具體代碼示例。
## 二、Servlet原生實現
### 2.1 基本原理
Servlet 3.0之前,需要借助第三方庫(如Apache Commons FileUpload)處理multipart/form-data請求。Servlet 3.0及以后版本內置了對文件上傳的支持。
#### 關鍵步驟:
1. 表單設置`enctype="multipart/form-data"`
2. 使用`@MultipartConfig`注解標記Servlet
3. 通過`request.getParts()`獲取上傳文件
### 2.2 代碼實現
```java
@WebServlet("/upload")
@MultipartConfig(
maxFileSize = 1024 * 1024 * 5, // 5MB
maxRequestSize = 1024 * 1024 * 10 // 10MB
)
public class FileUploadServlet extends HttpServlet {
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// 獲取上傳目錄的物理路徑
String uploadPath = getServletContext().getRealPath("") + File.separator + "uploads";
File uploadDir = new File(uploadPath);
if (!uploadDir.exists()) uploadDir.mkdir();
try {
for (Part part : request.getParts()) {
String fileName = extractFileName(part);
if (fileName != null && !fileName.isEmpty()) {
part.write(uploadPath + File.separator + fileName);
}
}
response.getWriter().println("文件上傳成功");
} catch (Exception e) {
response.getWriter().println("上傳失敗: " + e.getMessage());
}
}
private String extractFileName(Part part) {
String contentDisp = part.getHeader("content-disposition");
String[] items = contentDisp.split(";");
for (String s : items) {
if (s.trim().startsWith("filename")) {
return s.substring(s.indexOf("=") + 2, s.length() - 1);
}
}
return null;
}
}
<form action="upload" method="post" enctype="multipart/form-data">
<input type="file" name="file" multiple>
<button type="submit">上傳</button>
</form>
Spring框架提供了更簡潔的文件上傳方式,需要先配置MultipartResolver:
@Bean
public MultipartResolver multipartResolver() {
CommonsMultipartResolver resolver = new CommonsMultipartResolver();
resolver.setMaxUploadSize(10 * 1024 * 1024); // 10MB
return resolver;
}
@Controller
public class FileUploadController {
@PostMapping("/upload")
public String handleFileUpload(
@RequestParam("file") MultipartFile file,
RedirectAttributes redirectAttributes) {
if (file.isEmpty()) {
redirectAttributes.addFlashAttribute("message", "請選擇文件");
return "redirect:/status";
}
try {
// 獲取文件并保存
byte[] bytes = file.getBytes();
Path path = Paths.get("uploads/" + file.getOriginalFilename());
Files.write(path, bytes);
redirectAttributes.addFlashAttribute("message",
"成功上傳: " + file.getOriginalFilename());
} catch (IOException e) {
redirectAttributes.addFlashAttribute("message",
"上傳失敗: " + e.getMessage());
}
return "redirect:/status";
}
}
在application.properties中配置:
spring.servlet.multipart.max-file-size=5MB
spring.servlet.multipart.max-request-size=10MB
public class LegacyUploadServlet extends HttpServlet {
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// 檢查是否是multipart請求
if (!ServletFileUpload.isMultipartContent(request)) {
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
return;
}
// 配置上傳參數
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(1024 * 1024); // 內存緩沖區1MB
factory.setRepository(new File(System.getProperty("java.io.tmpdir")));
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setFileSizeMax(5 * 1024 * 1024); // 5MB
upload.setSizeMax(10 * 1024 * 1024); // 10MB
try {
List<FileItem> items = upload.parseRequest(request);
for (FileItem item : items) {
if (!item.isFormField()) {
String fileName = new File(item.getName()).getName();
String filePath = "uploads" + File.separator + fileName;
File storeFile = new File(filePath);
item.write(storeFile);
}
}
response.getWriter().println("上傳成功");
} catch (Exception ex) {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
}
}
// 使用File API進行分片
function uploadByChunks(file) {
const chunkSize = 5 * 1024 * 1024; // 5MB每片
const totalChunks = Math.ceil(file.size / chunkSize);
let currentChunk = 0;
while (currentChunk < totalChunks) {
const start = currentChunk * chunkSize;
const end = Math.min(start + chunkSize, file.size);
const chunk = file.slice(start, end);
const formData = new FormData();
formData.append('file', chunk);
formData.append('chunkNumber', currentChunk + 1);
formData.append('totalChunks', totalChunks);
formData.append('originalName', file.name);
// 發送AJAX請求
axios.post('/upload-chunk', formData);
currentChunk++;
}
}
@PostMapping("/upload-chunk")
public ResponseEntity<?> uploadChunk(
@RequestParam("file") MultipartFile file,
@RequestParam("chunkNumber") int chunkNumber,
@RequestParam("totalChunks") int totalChunks,
@RequestParam("originalName") String originalName) {
try {
// 創建臨時目錄
String tempDir = "temp/" + originalName;
Files.createDirectories(Paths.get(tempDir));
// 保存分片
String chunkFilename = chunkNumber + ".part";
Files.copy(file.getInputStream(),
Paths.get(tempDir, chunkFilename),
StandardCopyOption.REPLACE_EXISTING);
// 如果是最后一個分片,合并文件
if (chunkNumber == totalChunks) {
mergeFiles(tempDir, originalName, totalChunks);
}
return ResponseEntity.ok().build();
} catch (Exception e) {
return ResponseEntity.status(500).build();
}
}
private void mergeFiles(String tempDir, String filename, int totalChunks)
throws IOException {
Path outputFile = Paths.get("uploads", filename);
try (OutputStream out = Files.newOutputStream(outputFile,
StandardOpenOption.CREATE, StandardOpenOption.APPEND)) {
for (int i = 1; i <= totalChunks; i++) {
Path chunkFile = Paths.get(tempDir, i + ".part");
Files.copy(chunkFile, out);
Files.delete(chunkFile);
}
}
// 刪除臨時目錄
Files.delete(Paths.get(tempDir));
}
// 檢查MIME類型 if (!file.getContentType().startsWith(“image/”)) { throw new IllegalArgumentException(“只允許上傳圖片”); }
2. **文件重命名**:
```java
// 使用UUID重命名文件
String newName = UUID.randomUUID().toString() + "." + fileExt;
病毒掃描:
權限控制:
// 添加依賴:aws-java-sdk-s3
public class S3Uploader {
private AmazonS3 s3Client;
private String bucketName = "my-bucket";
public S3Uploader() {
this.s3Client = AmazonS3ClientBuilder.standard()
.withRegion(Regions.AP_EAST_1)
.build();
}
public void uploadFile(MultipartFile file) throws IOException {
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(file.getSize());
metadata.setContentType(file.getContentType());
s3Client.putObject(
bucketName,
"uploads/" + file.getOriginalFilename(),
file.getInputStream(),
metadata
);
}
}
使用NIO進行文件操作:
Files.copy(file.getInputStream(),
Paths.get(uploadPath, fileName),
StandardCopyOption.REPLACE_EXISTING);
異步處理:
@Async
public void asyncUpload(MultipartFile file) {
// 上傳邏輯
}
內存優化:
本文詳細介紹了Java中實現文件上傳的多種方法,從原生的Servlet API到Spring框架的封裝方案,再到分片上傳和云存儲集成。實際開發中應根據項目需求選擇合適的技術方案,并始終注意安全性問題。
通過合理的技術選擇和優化,可以構建出安全、高效的文件上傳功能。 “`
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。