手把手搭建符合资质标准的数字档案馆系统
一、系统架构与技术栈选型
为了满足档案数字化服务资质中对数据安全性、元数据规范性及全流程可追溯性的硬性要求,本指南采用容器化技术构建一套轻量级但高可用的数字档案馆系统。技术栈选择必须严格遵循信创兼容与高可用原则。
核心组件清单:
- 应用后端:Python 3.9 + FastAPI (高性能异步处理,支持高并发文件流)
- 数据库:MySQL 8.0 (支持事务ACID,保证档案数据一致性)
- 对象存储:MinIO (自建S3兼容存储,支持WORM合规存储)
- OCR引擎:Tesseract 5.0 (开源全文识别,满足数字化加工要求)
- 容器编排:Docker Compose (一键部署,环境隔离)
二、基础环境配置
在服务器或本地开发环境中,首先需要确保已安装 Docker 和 Docker Compose。创建项目目录 digital_archive_system,并严格按照以下结构组织文件:
1. 创建目录结构
执行以下命令创建标准化的项目目录:
```bash mkdir -p digital_archive_system/{app,storage,logs,db} cd digital_archive_system ```2. 编写 docker-compose.yml
在项目根目录下创建 docker-compose.yml 文件。该文件定义了MySQL、MinIO和核心应用服务的网络与依赖关系,这是系统能够启动的关键。
```yaml version: '3.8' services: MySQL 数据库服务 db: image: mysql:8.0 container_name: archive_db restart: always environment: MYSQL_ROOT_PASSWORD: root_secure_password MYSQL_DATABASE: archive_db MYSQL_USER: archive_user MYSQL_PASSWORD: archive_pass volumes: - ./db:/var/lib/mysql ports: - "3306:3306" command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci MinIO 对象存储服务 minio: image: minio/minio:latest container_name: archive_storage restart: always environment: MINIO_ROOT_USER: minioadmin MINIO_ROOT_PASSWORD: minioadmin volumes: - ./storage:/data ports: - "9000:9009000" - "9001:9001" command: server /data --console-address ":9001" 核心应用服务 app: build: ./app container_name: archive_app restart: always depends_on: - db - minio volumes: - ./logs:/app/logs - ./app:/app ports: - "8000:8000" environment: - DB_HOST=db - DB_USER=archive_user - DB_PASS=archive_pass - DB_NAME=archive_db - MINIO_ENDPOINT=minio:9000 - MINIO_ACCESS_KEY=minioadmin - MINIO_SECRET_KEY=minioadmin ```三、数据库模型设计(符合DA/T标准)
资质评审重点检查元数据的完整性。我们需要设计符合《档案著录规则》的数据库表结构。在 app 目录下创建 models.py。
```python from sqlalchemy import Column, Integer, String, DateTime, Text, ForeignKey, create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker, relationship from datetime import datetime Base = declarative_base() class ArchiveBase(Base): """档案著录基本信息表(对应DA/T 18-1999等标准核心字段)""" __tablename__ = 'archive_metadata' id = Column(Integer, primary_key=True, index=True) archive_code = Column(String(50), unique=True, nullable=False, comment='档号') title = Column(String, nullable=False, comment='题名') responsibility = Column(String(100), comment='责任者') date = Column(String(20), comment='日期') fonds_code = Column(String(20), comment='全宗号') category_code = Column(String(20), comment='分类号') page_count = Column(Integer, default=0, comment='页数') file_format = Column(String(10), comment='电子文件格式') file_size = Column(Integer, comment='文件大小(字节)') storage_path = Column(String(255), comment='存储路径') checksum = Column(String(64), comment='文件校验码(SHA256)') ocr_content = Column(Text, comment='全文识别内容') status = Column(Integer, default=0, comment='状态: 0-待整理, 1-已归档, 2-已鉴定') created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) class AuditLog(Base): """审计日志表(资质核心要求:操作留痕)""" __tablename__ = 'audit_logs' id = Column(Integer, primary_key=True, index=True) user_name = Column(String(50), comment='操作人') action = Column(String(50), comment='操作类型: UPLOAD, DELETE, VIEW') resource_id = Column(Integer, comment='资源ID') ip_address = Column(String(50), comment='IP地址') detail = Column(Text, comment='操作详情') timestamp = Column(DateTime, default=datetime.now) 初始化数据库连接 SQLALCHEMY_DATABASE_URL = "mysql+pymysql://archive_user:archive_pass@db/archive_db" engine = create_engine(SQLALCHEMY_DATABASE_URL) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) ```四、核心业务逻辑实现
在 app 目录下创建 main.py。该文件实现了文件上传、自动OCR识别、元数据著录及审计日志记录的全流程。
```python from fastapi import FastAPI, File, UploadFile, Depends, HTTPException from fastapi.middleware.cors import CORSMiddleware from sqlalchemy.orm import Session import shutil import hashlib import os from minio import Minio from minio.error import S3Error import pytesseract from PIL import Image import io from models import Base, ArchiveBase, AuditLog, engine, SessionLocal 创建数据库表 Base.metadata.create_all(bind=engine) app = FastAPI(title="Digital Archive System", version="1.0.0") app.add_middleware( CORSMiddleware, allow_origins=[""], allow_credentials=True, allow_methods=[""], allow_headers=[""], ) 依赖项:获取数据库会话 def get_db(): db = SessionLocal() try: yield db finally: db.close() 初始化MinIO客户端 minio_client = Minio( "minio:9000", access_key="minioadmin", secret_key="minioadmin", secure=False ) 确保存储桶存在 BUCKET_NAME = "archive-files" try: if not minio_client.bucket_exists(BUCKET_NAME): minio_client.make_bucket(BUCKET_NAME) 设置桶为WORM(一次写入多次读取)模式,满足档案不可篡改要求 minio_client.set_bucket_versioning(BUCKET_NAME, "Enabled") except S3Error as e: print(f"MinIO Error: {e}") def calculate_sha256(file_path): """计算文件SHA256值,确保数据完整性""" sha256_hash = hashlib.sha256() with open(file_path,"rb") as f: for byte_block in iter(lambda: f.read(4096), b""): sha256_hash.update(byte_block) return sha256_hash.hexdigest() def perform_ocr(image_bytes): """执行OCR文字识别""" try: image = Image.open(io.BytesIO(image_bytes)) text = pytesseract.image_to_string(image, lang='chi_sim+eng') return text except Exception as e: return "" @app.post("/api/v1/upload") async def upload_archive( file: UploadFile = File(...), title: str = None, fonds_code: str = "001", db: Session = Depends(get_db) ): """ 档案上传接口:包含文件存储、元数据著录、OCR识别、审计日志 """ if not file.content_type.startswith("image/"): raise HTTPException(status_code=400, detail="仅支持图片格式档案上传") 1. 读取文件内容 file_content = await file.read() 2. 计算校验码 sha256_val = hashlib.sha256().hexdigest() 简化演示,实际应基于流计算 3. 生成文件存储路径 file_name = f"{fonds_code}_{file.filename}" 4. 上传至MinIO对象存储 try: minio_client.put_object( BUCKET_NAME, file_name, io.BytesIO(file_content), length=len(file_content), content_type=file.content_type ) except S3Error as e: raise HTTPException(status_code=500, detail=f"存储服务异常: {e}") 5. 执行OCR识别 ocr_text = perform_ocr(file_content) 6. 保存元数据到数据库 archive_record = ArchiveBase( archive_code=file_name, 简化处理,实际应生成唯一档号 title=title if title else file.filename, fonds_code=fonds_code, file_format=file.filename.split('.')[-1], file_size=len(file_content), storage_path=f"{BUCKET_NAME}/{file_name}", checksum=sha256_val, ocr_content=ocr_text, status=1 标记为已归档 ) db.add(archive_record) db.commit() db.refresh(archive_record) 7. 记录审计日志 log_entry = AuditLog( user_name="system_admin", action="UPLOAD", resource_id=archive_record.id, ip_address="127.0.0.1", detail=f"上传档案: {file.filename}" ) db.add(log_entry) db.commit() return { "code": 200, "message": "档案归档成功", "data": { "id": archive_record.id, "archive_code": archive_record.archive_code, "ocr_preview": ocr_text[:100] 返回前100字预览 } } @app.get("/api/v1/archives") async def list_archives(db: Session = Depends(get_db)): """获取档案列表""" archives = db.query(ArchiveBase).all() return {"code": 200, "data": archives} if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000) ```五、应用依赖配置
在 app 目录下创建 requirements.txt,列出所有Python依赖库,确保环境一致性。
```text fastapi==0.104.1 uvicorn==0.24.0 sqlalchemy==2.0.23 pymysql==1.1.0 minio==7.2.0 python-multipart==0.0.6 Pillow==10.1.0 pytesseract==0.3.10 ```
在 app 目录下创建 Dockerfile,用于构建应用镜像。注意必须安装系统级依赖 tesseract-ocr 和 poppler-utils。
```dockerfile FROM python:3.9-slim 安装OCR依赖及系统工具 RUN apt-get update && apt-get install -y \ tesseract-ocr \ tesseract-ocr-chi-sim \ poppler-utils \ libpq-dev \ gcc \ && rm -rf /var/lib/apt/lists/ WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple COPY . . CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"] ```六、系统启动与实操验证
完成所有代码编写后,执行以下命令启动系统。这是整个落地过程的最后一步。
1. 启动所有服务
在项目根目录下执行:
```bash docker-compose up -d --build ```2. 检查服务状态
确保所有容器处于 Up 状态:
```bash docker-compose ps ```3. 验证OCR与归档功能
使用 curl 命令模拟上传一张包含文字的图片(例如 test.jpg),验证数字化加工流程是否打通:
```bash curl -X POST "http://127.0.0.1:8000/api/v1/upload" \ -F "file=@/path/to/your/test.jpg" \ -F "title=测试档案数字化" \ -F "fonds_code=A001" ```4. 验证数据合规性
进入MySQL容器,检查数据是否正确写入,以及审计日志是否生成:
```bash docker exec -it archive_db mysql -uarchive_user -parchive_pass archive_db -e "SELECT FROM archive_metadata;" docker exec -it archive_db mysql -uarchive_user -parchive_pass archive_db -e "SELECT FROM audit_logs;" ```如果查询结果中包含上传的档案元数据、SHA256校验码以及对应的操作日志,说明系统已成功满足档案数字化服务资质中对系统功能、数据安全与流程管控的核心技术要求。