1. 核心架构与技术栈选型
构建数字档案馆系统,核心在于解决海量非结构化数据的存储、检索与长期保存问题。本方案采用Spring Boot + Vue3 + MinIO + Elasticsearch的组合。MinIO负责自建对象存储,ES负责全文检索,MySQL存储元数据。此架构无需依赖昂贵的商业存储软件,零门槛即可在服务器落地。
2. 基础设施环境部署
使用Docker Compose一键编排基础设施。请在服务器新建docker-compose.yml文件,直接复制以下内容。该配置包含了MySQL数据库、MinIO对象存储、Elasticsearch搜索引擎以及Redis缓存。
```yaml
version: '3.8'
services:
mysql:
image: mysql:8.0
container_name: archive_mysql
environment:
MYSQL_ROOT_PASSWORD: root123456
MYSQL_DATABASE: archive_db
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
minio:
image: minio/minio:latest
container_name: archive_minio
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: admin
MINIO_ROOT_PASSWORD: admin123456
ports:
- "9000:9000"
- "9001:9001"
volumes:
- minio_data:/data
elasticsearch:
image: elasticsearch:7.17.0
container_name: archive_es
environment:
- discovery.type=single-node
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ports:
- "9200:9200"
volumes:
- es_data:/usr/share/elasticsearch/data
redis:
image: redis:latest
container_name: archive_redis
ports:
- "6379:6379"
volumes:
mysql_data:
minio_data:
es_data:
```
保存文件后,执行docker-compose up -d启动所有服务。启动完成后,访问http://服务器IP:9001即可进入MinIO控制台,创建一个名为archive-bucket的Bucket,并设置权限为Public(生产环境建议Private,此处为演示方便)。
3. 后端核心功能实现
后端使用Spring Boot 2.7版本。首先创建Maven项目,在pom.xml中引入必要的依赖。
```xml
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-data-jpa
mysql
mysql-connector-java
io.minio
minio
8.5.2
org.springframework.boot
spring-boot-starter-data-elasticsearch
```
3.1 配置文件设置
在application.yml中配置数据库连接、MinIO连接信息及ES地址。
```yaml
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/archive_db?useSSL=false&serverTimezone=UTC
username: root
password: root123456
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
elasticsearch:
rest:
uris: http://localhost:9200
minio:
endpoint: http://localhost:9000
accessKey: admin
secretKey: admin123456
bucketName: archive-bucket
```
3.2 实体类与数据层
创建档案实体类ArchiveDocument.java,对应数据库表。
```java
@Entity
@Table(name = "t_archive")
public class ArchiveDocument {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title; // 档案标题
private String fileType; // 文件类型 pdf, jpg
private String fileUrl; // MinIO存储路径
private Long fileSize; // 文件大小
private String content; // OCR识别后的文本内容(用于检索)
// Getters and Setters
}
```
创建JPA接口ArchiveRepository.java。
```java
public interface ArchiveRepository extends JpaRepository
{
}
```
3.3 文件上传与存储服务
这是核心实操部分。创建FileService.java,实现文件流上传到MinIO,并构建元数据。
```java
@Service
public class FileService {
@Value("${minio.endpoint}")
private String endpoint;
@Value("${minio.accessKey}")
private String accessKey;
@Value("${minio.secretKey}")
private String secretKey;
@Value("${minio.bucketName}")
private String bucketName;
@Autowired
private ArchiveRepository archiveRepository;
public String uploadFile(MultipartFile file) throws Exception {
// 1. 初始化MinIO Client
MinioClient minioClient = MinioClient.builder()
.endpoint(endpoint)
.credentials(accessKey, secretKey)
.build();
// 2. 生成唯一文件名
String originalFilename = file.getOriginalFilename();
String fileName = UUID.randomUUID().toString() + "_" + originalFilename;
// 3. 上传文件流
InputStream inputStream = file.getInputStream();
minioClient.putObject(
PutObjectArgs.builder()
.bucket(bucketName)
.object(fileName)
.stream(inputStream, file.getSize(), -1)
.contentType(file.getContentType())
.build()
);
// 4. 保存元数据到数据库
ArchiveDocument document = new ArchiveDocument();
document.setTitle(originalFilename);
document.setFileType(originalFilename.substring(originalFilename.lastIndexOf(".") + 1));
document.setFileUrl(fileName);
document.setFileSize(file.getSize());
// 实际项目中,此处应调用OCR服务提取content字段
document.setContent("模拟OCR提取的档案全文内容...");
archiveRepository.save(document);
return fileName;
}
}
```
3.4 控制器层

创建ArchiveController.java提供上传接口。
```java
@RestController
@RequestMapping("/api/archive")
public class ArchiveController {
@Autowired
private FileService fileService;
@PostMapping("/upload")
public ResponseEntity upload(@RequestParam("file") MultipartFile file) {
try {
String fileName = fileService.uploadFile(file);
return ResponseEntity.ok("上传成功,文件ID: " + fileName);
} catch (Exception e) {
e.printStackTrace();
return ResponseEntity.status(500).body("上传失败: " + e.getMessage());
}
}
}
```
4. 前端交互与预览实现
前端使用Vue 3配合Element Plus组件库。安装依赖:npm install vue-router@4 axios element-plus。
4.1 上传组件封装
在src/components/Upload.vue中编写上传逻辑,直接调用后端接口。
```html
拖拽档案文件到此处或点击上传
```
4.2 PDF在线预览
数字档案馆必须支持在线预览。利用MinIO的Presigned URL功能实现临时预览链接,无需下载到本地。在FileService.java中添加获取预览URL的方法。
```java
public String getPreviewUrl(String fileName) throws Exception {
MinioClient minioClient = MinioClient.builder()
.endpoint(endpoint)
.credentials(accessKey, secretKey)
.build();
// 生成7天有效的预览URL
return minioClient.getPresignedObjectUrl(
GetPresignedObjectUrlArgs.builder()
.method(Method.GET)
.bucket(bucketName)
.object(fileName)
.expiry(60 60 24 7)
.build()
);
}
```
前端页面通过window.open(url)直接打开浏览器原生PDF预览,或者集成pdf.js进行内嵌展示。
5. 系统编译与生产部署
后端打包:在项目根目录执行mvn clean package -DskipTests,生成jar包。
前端打包:执行npm run build,生成dist静态资源目录。
使用Nginx反向代理配置前后端合并部署。这是生产环境的标准做法。
```nginx
server {
listen 80;
server_name your-archive-domain.com;
前端静态资源
location / {
root /var/www/archive/dist;
index index.html;
try_files $uri $uri/ /index.html;
}
后端API接口转发
location /api/ {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
MinIO代理(可选,用于统一域名)
location /minio/ {
proxy_pass http://localhost:9000/;
}
}
```
配置完成后,执行nginx -s reload重载配置。此时,访问域名即可看到数字档案馆系统的上传界面,上传后的文件将自动存储至MinIO,元数据入库,且可通过生成的URL直接预览。