技术栈:vue+springboot+mybatis,其中后端省略service操作
1.数据库表设计
CREATE TABLE file_content (
id INT PRIMARY KEY AUTO_INCREMENT,
file_name VARCHAR(255) NOT NULL,
file_type VARCHAR(50) NOT NULL,
file_content LONGBLOB NOT NULL,
upload_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-
file_name
:文件名 -
file_type
:文件类型(如application/pdf
、application/zip
等) -
file_content
:文件内容,使用LONGBLOB
类型存储二进制数据 -
upload_time
:文件上传时间
2.后端实现
2.1 创建实体类
import java.util.Date;
public class FileContent {
private Integer id;
private String fileName;
private String fileType;
private byte[] fileContent;
private Date uploadTime;
// Getters and Setters
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getFileType() {
return fileType;
}
public void setFileType(String fileType) {
this.fileType = fileType;
}
public byte[] getFileContent() {
return fileContent;
}
public void setFileContent(byte[] fileContent) {
this.fileContent = fileContent;
}
public Date getUploadTime() {
return uploadTime;
}
public void setUploadTime(Date uploadTime) {
this.uploadTime = uploadTime;
}
}
2.2创建Mapper接口
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface FileContentMapper {
@Insert("INSERT INTO file_content(file_name, file_type, file_content) VALUES(#{fileName}, #{fileType}, #{fileContent})")
void insertFileContent(FileContent fileContent);
@Select("SELECT * FROM file_content WHERE id = #{id}")
FileContent getFileContentById(Integer id);
}
2.3实现文件上传和下载接口
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.Date;
@RestController
@RequestMapping("/api/file")
public class FileController {
@Autowired
private FileContentMapper fileContentMapper;
@PostMapping("/upload")
public ResponseEntity<String> handleFileUpload(@RequestParam("file") MultipartFile file) {
try {
// 将文件内容转换为字节数组
byte[] fileContent = file.getBytes();
// 创建FileContent对象
FileContent fileContentEntity = new FileContent();
fileContentEntity.setFileName(file.getOriginalFilename());
fileContentEntity.setFileType(file.getContentType());
fileContentEntity.setFileContent(fileContent);
fileContentEntity.setUploadTime(new Date());
// 将文件内容存入数据库
fileContentMapper.insertFileContent(fileContentEntity);
return ResponseEntity.ok("File uploaded successfully: " + file.getOriginalFilename());
} catch (IOException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Failed to upload file");
}
}
@GetMapping("/download/{id}")
public ResponseEntity<ByteArrayResource> downloadFile(@PathVariable Integer id) {
// 从数据库获取文件内容
FileContent fileContent = fileContentMapper.getFileContentById(id);
if (fileContent != null) {
// 返回文件内容
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType(fileContent.getFileType()))
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileContent.getFileName() + "\"")
.body(new ByteArrayResource(fileContent.getFileContent()));
} else {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
}
}
}
3.前端实现
3.1文件上传
使用vue实现文件上传
<template>
<div>
<input type="file" @change="handleFileUpload" />
<button @click="uploadFile">Upload</button>
</div>
</template>
<script>
export default {
data() {
return {
file: null,
};
},
methods: {
handleFileUpload(event) {
this.file = event.target.files[0];
},
async uploadFile() {
if (!this.file) {
alert("Please select a file first.");
return;
}
const formData = new FormData();
formData.append("file", this.file);
try {
const response = await this.$http.post("/api/file/upload", formData, {
headers: {
"Content-Type": "multipart/form-data",
},
});
alert(response.data);
} catch (error) {
alert("Failed to upload file.");
}
},
},
};
</script>
3.2文件下载
使用a标签进行文件下载
<template>
<div>
<a :href="downloadLink" download>Download File</a>
</div>
</template>
<script>
export default {
data() {
return {
fileId: 1, // 文件ID
};
},
computed: {
downloadLink() {
return `/api/file/download/${this.fileId}`;
},
},
};
</script>
4.注意事项
-
性能问题:将大文件存入数据库可能会导致性能问题,建议仅对小文件使用此方法。
-
数据库配置:确保数据库支持
BLOB
或LONGBLOB
类型,并调整数据库的最大包大小(如MySQL的max_allowed_packet
)。 -
文件大小限制:Spring Boot默认的文件上传大小限制是1MB,可以通过以下配置调整,properties文件或者yml文件
spring.servlet.multipart.max-file-size=10MB spring.servlet.multipart.max-request-size=10MB