一、系统核心架构与选型
本系统采用微服务架构,确保高可用性与可扩展性。核心组件包括:
- 文件存储层:MinIO对象存储,用于存放非结构化档案文件。
- 元数据与索引层:PostgreSQL数据库存储档案元数据,Elasticsearch提供全文检索。
- 业务处理层:基于Spring Boot的Java服务,处理归档、审批、查询等核心逻辑。
- 前端展示层:Vue.js构建的管理后台。
1.1 基础环境准备
使用Docker Compose一键部署基础设施,确保环境一致。
创建docker-compose.yml文件:
```
version: '3.8'
services:
postgres:
image: postgres:15-alpine
environment:
POSTGRES_DB: digital_archive
POSTGRES_USER: archive_admin
POSTGRES_PASSWORD: YourStrong@Pass123
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
elasticsearch:
image: elasticsearch:8.11.0
environment:
- discovery.type=single-node
- xpack.security.enabled=false
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ports:
- "9200:9200"
volumes:
- es_data:/usr/share/elasticsearch/data
minio:
image: minio/minio:latest
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: minioadmin
MINIO_ROOT_PASSWORD: minioadmin123
ports:
- "9000:9000"
- "9001:9001"
volumes:
- minio_data:/data
volumes:
postgres_data:
es_data:
minio_data:
```
在终端执行docker-compose up -d启动所有服务。
二、数据库与存储初始化
2.1 创建核心数据表
连接PostgreSQL数据库,执行以下SQL创建档案核心表:
```
CREATE TABLE archive_category (
id SERIAL PRIMARY KEY,
code VARCHAR(50) UNIQUE NOT NULL,
name VARCHAR(100) NOT NULL,
parent_id INTEGER REFERENCES archive_category(id),
retention_years INTEGER NOT NULL DEFAULT 10,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE archive_record (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
title VARCHAR(500) NOT NULL,
category_code VARCHAR(50) NOT NULL REFERENCES archive_category(code),
file_key VARCHAR(255) NOT NULL,
original_filename VARCHAR(255) NOT NULL,
file_size BIGINT NOT NULL,
mime_type VARCHAR(100),
metadata JSONB,
status VARCHAR(20) DEFAULT 'DRAFT',
created_by VARCHAR(100) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_archive_category ON archive_record(category_code);
CREATE INDEX idx_archive_status ON archive_record(status);
CREATE INDEX idx_archive_created ON archive_record(created_at);
```
2.2 配置MinIO存储桶
访问http://localhost:9001,使用minioadmin/minioadmin123登录。
创建存储桶:点击“Buckets” -> “Create Bucket”,输入桶名tech-archive,版本控制选择“Enable”。
设置访问策略:进入桶设置,在“Access Policy”中添加以下JSON策略,允许服务端上传下载:
```
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::tech-archive/"
}
]
}
```
三、后端服务搭建
3.1 项目初始化与依赖配置
使用Spring Initializr创建项目,选择依赖:Spring Web, Spring Data JPA, Spring Data Elasticsearch, Validation。
在pom.xml中添加MinIO和数据库驱动:
```
io.minio
minio
8.5.2
org.postgresql
postgresql
runtime
```
3.2 核心配置文件

创建application.yml:
```
spring:
datasource:
url: jdbc:postgresql://localhost:5432/digital_archive
username: archive_admin
password: YourStrong@Pass123
driver-class-name: org.postgresql.Driver
jpa:
hibernate:
ddl-auto: validate
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
jdbc:
lob:
non_contextual_creation: true
elasticsearch:
uris: http://localhost:9200
minio:
endpoint: http://localhost:9000
accessKey: minioadmin
secretKey: minioadmin123
bucket: tech-archive
```
3.3 实现文件上传服务
创建MinioService.java:
```
@Service
public class MinioService {
@Value("${minio.endpoint}")
private String endpoint;
@Value("${minio.accessKey}")
private String accessKey;
@Value("${minio.secretKey}")
private String secretKey;
@Value("${minio.bucket}")
private String bucket;
private MinioClient minioClient;
@PostConstruct
public void init() throws Exception {
minioClient = MinioClient.builder()
.endpoint(endpoint)
.credentials(accessKey, secretKey)
.build();
}
public String uploadFile(MultipartFile file, String objectName) throws Exception {
// 检查存储桶是否存在
boolean found = minioClient.bucketExists(BucketExistsArgs.builder()
.bucket(bucket).build());
if (!found) {
minioClient.makeBucket(MakeBucketArgs.builder()
.bucket(bucket).build());
}
// 上传文件
minioClient.putObject(
PutObjectArgs.builder()
.bucket(bucket)
.object(objectName)
.stream(file.getInputStream(),
file.getSize(), -1)
.contentType(file.getContentType())
.build());
return objectName;
}
public String getFileUrl(String objectName) {
return endpoint + "/" + bucket + "/" + objectName;
}
}
```
3.4 实现档案归档API
创建ArchiveController.java:
```
@RestController
@RequestMapping("/api/archive")
public class ArchiveController {
@Autowired
private ArchiveService archiveService;
@PostMapping("/upload")
public ResponseEntity
uploadArchive(
@RequestParam("file") MultipartFile file,
@RequestParam String title,
@RequestParam String categoryCode,
@RequestParam(required = false) String createdBy) {
ArchiveRecord record = archiveService.saveArchive(
file, title, categoryCode, createdBy);
return ResponseEntity.ok(record);
}
@GetMapping("/search")
public ResponseEntity> search(
@RequestParam String keyword,
@RequestParam(required = false) String categoryCode) {
List records = archiveService
.searchArchives(keyword, categoryCode);
return ResponseEntity.ok(records);
}
}
```
四、前端管理界面开发
4.1 安装必要依赖
创建Vue项目并安装Element Plus和Axios:
```
npm create vue@latest digital-archive-admin
cd digital-archive-admin
npm install element-plus @element-plus/icons-vue axios
npm install
```
4.2 实现文件上传组件
创建ArchiveUpload.vue:
```
```
五、自动化归档流程配置
5.1 设置定时扫描任务
创建AutoArchiveScheduler.java:
```
@Component
public class AutoArchiveScheduler {
@Autowired
private ArchiveService archiveService;
@Value("${archive.scan.path:/data/to-archive}")
private String scanPath;
@Scheduled(cron = "0 0 2 ?") // 每天凌晨2点执行
public void autoArchiveFiles() {
Path scanDir = Paths.get(scanPath);
try (Stream paths = Files.walk(scanDir)) {
paths.filter(Files::isRegularFile)
.forEach(this::processFile);
} catch (IOException e) {
log.error("扫描目录失败", e);
}
}
private void processFile(Path filePath) {
try {
String filename = filePath.getFileName().toString();
// 从文件名解析分类和标题
ArchiveInfo info = parseFilename(filename);
// 上传到MinIO
String objectKey = archiveService.uploadToStorage(filePath);
// 保存元数据
archiveService.saveMetadata(info, objectKey);
// 移动已处理文件
Files.move(filePath,
Paths.get(scanPath, "processed", filename));
} catch (Exception e) {
log.error("处理文件失败: " + filePath, e);
// 移动到失败目录
try {
Files.move(filePath,
Paths.get(scanPath, "failed", filename));
} catch (IOException ex) {
log.error("移动失败文件出错", ex);
}
}
}
}
```
5.2 配置监控与告警
在application.yml中添加监控配置:
```
management:
endpoints:
web:
exposure:
include: health,metrics,prometheus
metrics:
export:
prometheus:
enabled: true
archive:
monitor:
存储空间告警阈值(GB)
storage-alert-threshold: 100
每日归档数量阈值
daily-count-threshold: 1000
```
六、系统部署与验证
6.1 构建与打包
后端打包:mvn clean package -DskipTests
前端构建:npm run build
6.2 部署配置
创建docker-compose.prod.yml生产环境配置:
```
version: '3.8'
services:
archive-backend:
build: ./backend
ports:
- "8080:8080"
environment:
SPRING_PROFILES_ACTIVE: prod
depends_on:
- postgres
- elasticsearch
- minio
archive-frontend:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./frontend/dist:/usr/share/nginx/html
- ./nginx.conf:/etc/nginx/nginx.conf
```
6.3 验证步骤
- 服务健康检查:访问
http://localhost:8080/actuator/health,确认所有组件状态为UP。
- 文件上传测试:通过前端界面上传测试文件,确认文件成功存入MinIO且元数据存入数据库。
- 搜索功能验证:在前端搜索框输入测试关键词,确认能从Elasticsearch返回正确结果。
- 自动化流程测试:在
/data/to-archive目录放入测试文件,等待定时任务执行或手动触发,确认文件被自动归档。