2024档案数字化资质申请全攻略:办理条件、流程及材料汇总
很多想要承接档案馆、企事业单位数字化加工项目的服务商,都知道资质是必备的入场门槛,第一次办理很容易踩材料不全、条件不达标的坑。本文整理了业内通用的办理要求,从申请条件到流程注意事项都说得明明白白,不管...
2026年09月01日 10:35:14
鹰潭数字档案馆系统的核心需求包括:电子文件长期保存、元数据管理、全文检索、权限控制和访问审计。我们采用微服务架构,确保系统可扩展性和维护性。
操作系统:Ubuntu Server 22.04 LTS
数据库:PostgreSQL 14 + TimescaleDB(用于时间序列数据)
文件存储:MinIO 对象存储
搜索引擎:Elasticsearch 8.11
后端框架:Spring Boot 3.1 + Java 17
前端框架:Vue 3 + Element Plus
容器化:Docker 24.0 + Docker Compose 2.20
/opt/digital-archive/ ├── docker-compose.yml ├── config/ │ ├── application.yml │ ├── nginx.conf │ └── elasticsearch.yml ├── data/ │ ├── postgres/ │ ├── minio/ │ └── elasticsearch/ └── scripts/ └── init-database.sql
使用SSH连接到服务器,执行以下命令:
更新系统 sudo apt update && sudo apt upgrade -y 安装必要工具 sudo apt install -y curl wget git vim net-tools 安装Docker curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh 安装Docker Compose sudo curl -L "https://github.com/docker/compose/releases/download/v2.20.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose
创建/opt/digital-archive/docker-compose.yml文件:
version: '3.8' services: postgres: image: timescale/timescaledb:2.11-pg14 container_name: archive-postgres environment: POSTGRES_DB: digital_archive POSTGRES_USER: archive_admin POSTGRES_PASSWORD: YourSecurePassword123! volumes: - ./data/postgres:/var/lib/postgresql/data - ./scripts/init-database.sql:/docker-entrypoint-initdb.d/init.sql ports: - "5432:5432" networks: - archive-network minio: image: minio/minio:RELEASE.2023-10 25.16 container_name: archive-minio command: server /data --console-address ":9001" environment: MINIO_ROOT_USER: minioadmin MINIO_ROOT_PASSWORD: YourMinioPassword123! volumes: - ./data/minio:/data ports: - "9000:9000" - "9001:9001" networks: - archive-network elasticsearch: image: elasticsearch:8.11.0 container_name: archive-elasticsearch environment: - discovery.type=single-node - xpack.security.enabled=false - "ES_JAVA_OPTS=-Xms2g -Xmx2g" ulimits: memlock: soft: -1 hard: -1 volumes: - ./data/elasticsearch:/usr/share/elasticsearch/data ports: - "9200:9200" networks: - archive-network networks: archive-network: driver: bridge
创建/opt/digital-archive/scripts/init-database.sql:

-- 创建扩展
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "timescaledb";
-- 档案元数据表
CREATE TABLE archive_metadata (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
file_name VARCHAR(500) NOT NULL,
file_size BIGINT NOT NULL,
mime_type VARCHAR(100),
original_path VARCHAR(1000),
storage_path VARCHAR(1000) NOT NULL,
checksum VARCHAR(64) NOT NULL,
create_time TIMESTAMPTZ DEFAULT NOW(),
modify_time TIMESTAMPTZ DEFAULT NOW(),
retention_years INTEGER DEFAULT 30,
status VARCHAR(20) DEFAULT 'ACTIVE'
);
-- 创建时间序列超表
SELECT create_hypertable('archive_metadata', 'create_time');
-- 访问日志表
CREATE TABLE access_log (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id VARCHAR(100),
action VARCHAR(50),
target_id UUID REFERENCES archive_metadata(id),
ip_address INET,
user_agent TEXT,
access_time TIMESTAMPTZ DEFAULT NOW()
);
-- 创建索引
CREATE INDEX idx_metadata_filename ON archive_metadata(file_name);
CREATE INDEX idx_metadata_checksum ON archive_metadata(checksum);
CREATE INDEX idx_access_log_time ON access_log(access_time);
创建application.yml配置文件:
server: port: 8080 spring: datasource: url: jdbc:postgresql://localhost:5432/digital_archive username: archive_admin password: YourSecurePassword123! driver-class-name: org.postgresql.Driver jpa: hibernate: ddl-auto: validate properties: hibernate: dialect: org.hibernate.dialect.PostgreSQLDialect minio: endpoint: http://localhost:9000 accessKey: minioadmin secretKey: YourMinioPassword123! bucket: digital-archive elasticsearch: uris: http://localhost:9200
创建FileStorageService.java:
@Service
public class FileStorageService {
@Value("${minio.bucket}")
private String bucketName;
@Autowired
private MinioClient minioClient;
public ArchiveFile uploadFile(MultipartFile file,
String originalPath) throws Exception {
// 生成文件唯一标识
String fileId = UUID.randomUUID().toString();
String objectName = fileId + "/" + file.getOriginalFilename();
// 计算文件哈希值
String checksum = calculateSHA256(file);
// 上传到MinIO
minioClient.putObject(
PutObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.stream(file.getInputStream(),
file.getSize(), -1)
.contentType(file.getContentType())
.build()
);
// 保存元数据到数据库
ArchiveMetadata metadata = new ArchiveMetadata();
metadata.setFileName(file.getOriginalFilename());
metadata.setFileSize(file.getSize());
metadata.setMimeType(file.getContentType());
metadata.setOriginalPath(originalPath);
metadata.setStoragePath(objectName);
metadata.setChecksum(checksum);
// 保存到数据库
metadataRepository.save(metadata);
// 索引到Elasticsearch
indexToElasticsearch(metadata);
return new ArchiveFile(metadata,
minioClient.getPresignedObjectUrl(
GetPresignedObjectUrlArgs.builder()
.method(Method.GET)
.bucket(bucketName)
.object(objectName)
.expiry(3600)
.build()
)
);
}
private String calculateSHA256(MultipartFile file)
throws IOException, NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(file.getBytes());
return Hex.encodeHexString(hash);
}
}
创建SearchService.java:
@Service
public class SearchService {
@Autowired
private ElasticsearchRestTemplate elasticsearchTemplate;
public List search(String keyword,
int page,
int size) {
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.multiMatchQuery(keyword)
.field("fileName", 3.0f)
.field("content", 1.0f)
.type(MultiMatchQueryBuilder.Type.BEST_FIELDS))
.withPageable(PageRequest.of(page, size))
.build();
SearchHits hits =
elasticsearchTemplate.search(searchQuery,
ArchiveMetadata.class);
return hits.stream()
.map(SearchHit::getContent)
.collect(Collectors.toList());
}
public void indexToElasticsearch(ArchiveMetadata metadata) {
elasticsearchTemplate.save(metadata);
}
}
创建FileUpload.vue组件:
将文件拖到此处,或点击上传
创建SearchPanel.vue组件:
{{ scope.row.fileName }} {{ formatFileSize(scope.row.fileSize) }} {{ formatDate(scope.row.createTime) }} 下载
创建Dockerfile:
FROM openjdk:17-jdk-slim WORKDIR /app 复制构建文件 COPY target/digital-archive.jar app.jar COPY config/application.yml config/ 设置时区 RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 暴露端口 EXPOSE 8080 启动应用 ENTRYPOINT ["java", "-jar", "app.jar", \ "--spring.config.location=file:/app/config/application.yml"]
构建并启动应用:
构建Docker镜像 docker build -t digital-archive:1.0 . 启动所有服务 cd /opt/digital-archive docker-compose up -d 查看服务状态 docker-compose ps 查看日志 docker-compose logs -f
创建nginx.conf:
server {
listen 80;
server_name archive.yuantan.gov.cn;
前端静态文件
location / {
root /usr/share/nginx/html;
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;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
文件上传超时设置
client_max_body_size 100m;
proxy_read_timeout 300s;
proxy_connect_timeout 75s;
}
MinIO控制台
location /minio/ {
proxy_pass http://localhost:9001/;
}
访问日志
access_log /var/log/nginx/archive_access.log;
error_log /var/log/nginx/archive_error.log;
}
创建backup.sh:
!/bin/bash BACKUP_DIR="/backup/archive" DATE=$(date +%Y%m%d_%H%M%S) 创建备份目录 mkdir -p $BACKUP_DIR/$DATE 备份PostgreSQL数据库 docker exec archive-postgres pg_dump -U archive_admin \ digital_archive > $BACKUP_DIR/$DATE/database.sql 备份MinIO数据(使用mc客户端) docker run --rm -v $BACKUP_DIR/$DATE:/backup \ minio/mc mirror minio/digital-archive /backup/minio 备份Elasticsearch索引 curl -X GET "localhost:9200/_snapshot/backup_repo/snapshot_$DATE?wait_for_completion=true" 压缩备份文件 cd $BACKUP_DIR tar -czf archive_$DATE.tar.gz $DATE 删除7天前的备份 find $BACKUP_DIR -name ".tar.gz" -mtime +7 -delete echo "备份完成: $BACKUP_DIR/archive_$DATE.tar.gz"
创建prometheus.yml:
global: scrape_interval: 15s scrape_configs: - job_name: 'archive-service' static_configs: - targets: ['localhost:8080'] labels: service: 'digital-archive' - job_name: 'postgres' static_configs: - targets: ['localhost:9187'] - job_name: 'elasticsearch' static_configs: - targets: ['localhost:9114']
创建test-api.sh:
!/bin/bash API_BASE="http://localhost:8080/api" echo "1. 测试健康检查接口" curl -s $API_BASE/health | jq . echo "2. 测试文件上传" curl -X POST $API_BASE/archive/upload \ -H "Authorization: Bearer $TOKEN" \ -F "file=@test.pdf" \ -