集团档案数字化建设实操指南:从零搭建企业级档案管理系统
一、系统架构设计与核心组件选型
集团档案管理系统采用微服务架构,确保系统可扩展性和高可用性。核心组件包括:
- 存储层:使用MinIO对象存储,替代传统FTP服务器,支持海量非结构化数据存储。
- 数据库:主业务数据使用PostgreSQL 14,全文检索使用Elasticsearch 8.x。
- 服务层:基于Spring Boot 3.x构建微服务,使用Nacos 2.x作为服务注册与配置中心。
- 前端:采用Vue 3 + Element Plus构建管理后台。
1.1 基础环境准备
在CentOS 7.9服务器执行以下命令安装Docker环境:
``` 安装Docker yum install -y yum-utils device-mapper-persistent-data lvm2 yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo yum install -y docker-ce docker-ce-cli containerd.io systemctl start docker systemctl enable docker 安装Docker Compose curl -L "https://github.com/docker/compose/releases/download/v2.20.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose chmod +x /usr/local/bin/docker-compose ```二、MinIO对象存储部署与配置
MinIO用于存储所有档案的电子文件,包括扫描件、图片、视频等。
2.1 创建存储目录和配置文件
创建配置文件docker-compose-minio.yml:
``` version: '3.8' services: minio: image: minio/minio:latest container_name: minio command: server /data --console-address ":9090" environment: MINIO_ROOT_USER: admin MINIO_ROOT_PASSWORD: YourStrongPassword123! volumes: - /data/minio/data:/data - /data/minio/config:/root/.minio ports: - "9000:9000" - "9090:9090" restart: unless-stopped ```启动MinIO服务:
``` mkdir -p /data/minio/{data,config} docker-compose -f docker-compose-minio.yml up -d ```访问http://服务器IP:9090,使用admin/YourStrongPassword123!登录,创建名为archive-bucket的存储桶。
2.2 配置访问策略
在MinIO控制台创建访问密钥:
- 点击Access Keys → Create Access Key
- 记录生成的Access Key和Secret Key
- 为archive-bucket设置访问策略:
三、PostgreSQL数据库设计与初始化
3.1 数据库部署
创建docker-compose-postgres.yml:
``` version: '3.8' services: postgres: image: postgres:14-alpine container_name: postgres-archive environment: POSTGRES_DB: archive_db POSTGRES_USER: archive_admin POSTGRES_PASSWORD: DbPassword2023! volumes: - /data/postgres/data:/var/lib/postgresql/data - ./init.sql:/docker-entrypoint-initdb.d/init.sql ports: - "5432:5432" restart: unless-stopped ```3.2 核心表结构设计
创建init.sql初始化脚本:
``` -- 档案分类表 CREATE TABLE archive_category ( id SERIAL PRIMARY KEY, category_code VARCHAR(50) NOT NULL UNIQUE, category_name VARCHAR(100) NOT NULL, parent_id INTEGER REFERENCES archive_category(id), retention_years INTEGER NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- 档案条目表 CREATE TABLE archive_item ( id SERIAL PRIMARY KEY, item_code VARCHAR(100) NOT NULL UNIQUE, title VARCHAR(500) NOT NULL, category_id INTEGER NOT NULL REFERENCES archive_category(id), keywords TEXT, description TEXT, storage_location VARCHAR(500), file_key VARCHAR(500), -- MinIO中的文件key file_size BIGINT, file_type VARCHAR(50), created_by VARCHAR(100), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, status VARCHAR(20) DEFAULT 'ACTIVE' ); -- 档案借阅记录表 CREATE TABLE archive_borrow ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES archive_item(id), borrower_id VARCHAR(100) NOT NULL, borrower_name VARCHAR(100) NOT NULL, borrow_purpose TEXT, borrow_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, expected_return TIMESTAMP, actual_return TIMESTAMP, status VARCHAR(20) DEFAULT 'BORROWED' ); -- 创建索引 CREATE INDEX idx_archive_item_category ON archive_item(category_id); CREATE INDEX idx_archive_item_keywords ON archive_item USING gin(to_tsvector('english', keywords)); CREATE INDEX idx_archive_borrow_item ON archive_borrow(item_id); ```四、Spring Boot微服务开发
4.1 项目初始化
使用Spring Initializr创建项目,依赖选择:
- Spring Web
- Spring Data JPA
- PostgreSQL Driver
- Spring Security
- Lombok
4.2 MinIO配置类
创建MinioConfig.java:
``` @Configuration public class MinioConfig { @Value("${minio.endpoint}") private String endpoint; @Value("${minio.accessKey}") private String accessKey; @Value("${minio.secretKey}") private String secretKey; @Bean public MinioClient minioClient() { return MinioClient.builder() .endpoint(endpoint) .credentials(accessKey, secretKey) .build(); } } ```4.3 文件上传服务实现

创建FileStorageService.java:
``` @Service @Slf4j public class FileStorageService { @Autowired private MinioClient minioClient; @Value("${minio.bucket-name}") private String bucketName; public String uploadFile(MultipartFile file, String filePath) { try { // 检查存储桶是否存在 boolean found = minioClient.bucketExists( BucketExistsArgs.builder().bucket(bucketName).build()); if (!found) { minioClient.makeBucket( MakeBucketArgs.builder().bucket(bucketName).build()); } // 生成唯一文件名 String fileName = UUID.randomUUID().toString() + getFileExtension(file.getOriginalFilename()); String objectName = filePath + "/" + fileName; // 上传文件 minioClient.putObject( PutObjectArgs.builder() .bucket(bucketName) .object(objectName) .stream(file.getInputStream(), file.getSize(), -1) .contentType(file.getContentType()) .build()); return objectName; } catch (Exception e) { log.error("文件上传失败", e); throw new RuntimeException("文件上传失败"); } } public InputStream downloadFile(String objectName) { try { return minioClient.getObject( GetObjectArgs.builder() .bucket(bucketName) .object(objectName) .build()); } catch (Exception e) { log.error("文件下载失败", e); throw new RuntimeException("文件下载失败"); } } private String getFileExtension(String filename) { if (filename == null) return ""; int lastIndex = filename.lastIndexOf('.'); return lastIndex == -1 ? "" : filename.substring(lastIndex); } } ```4.4 应用配置文件
application.yml配置:
``` server: port: 8080 spring: datasource: url: jdbc:postgresql://localhost:5432/archive_db username: archive_admin password: DbPassword2023! driver-class-name: org.postgresql.Driver jpa: hibernate: ddl-auto: update show-sql: true properties: hibernate: dialect: org.hibernate.dialect.PostgreSQLDialect minio: endpoint: http://localhost:9000 accessKey: 你的AccessKey secretKey: 你的SecretKey bucket-name: archive-bucket ```五、档案管理核心功能实现
5.1 档案入库接口
创建ArchiveItemController.java:
``` @RestController @RequestMapping("/api/archive") @RequiredArgsConstructor public class ArchiveItemController { private final ArchiveItemService archiveItemService; private final FileStorageService fileStorageService; @PostMapping("/upload") public ResponseEntity5.2 档案检索接口
实现基于关键词的全文检索:
``` @Repository public interface ArchiveItemRepository extends JpaRepository六、权限控制与安全配置
6.1 Spring Security配置
创建SecurityConfig.java:
``` @Configuration @EnableWebSecurity @RequiredArgsConstructor public class SecurityConfig { private final JwtAuthenticationFilter jwtAuthFilter; @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .csrf().disable() .authorizeHttpRequests() .requestMatchers("/api/auth/").permitAll() .requestMatchers("/api/archive/download/").permitAll() .requestMatchers("/api/archive/upload").hasRole("ARCHIVE_ADMIN") .requestMatchers("/api/archive/delete/").hasRole("ARCHIVE_ADMIN") .anyRequest().authenticated() .and() .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class); return http.build(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } } ```6.2 基于角色的访问控制
创建权限注解:
``` @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @PreAuthorize("hasRole('ARCHIVE_ADMIN') or " + "(hasRole('DEPARTMENT_ADMIN') and @archiveSecurityService.isDepartmentArchive(categoryCode))") public @interface ArchivePermission { } ```七、系统部署与监控
7.1 Docker Compose整体部署
创建docker-compose.yml整合所有服务:
``` version: '3.8' services: postgres: image: postgres:14-alpine environment: POSTGRES_DB: archive_db POSTGRES_USER: archive_admin POSTGRES_PASSWORD: DbPassword2023! volumes: - postgres_data:/var/lib/postgresql/data ports: - "5432:5432" minio: image: minio/minio:latest command: server /data --console-address ":9090" environment: MINIO_ROOT_USER: admin MINIO_ROOT_PASSWORD: YourStrongPassword123! volumes: - minio_data:/data ports: - "9000:9000" - "9090:9090" archive-app: build: . ports: - "8080:8080" depends_on: - postgres - minio environment: SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/archive_db MINIO_ENDPOINT: http://minio:9000 nginx: image: nginx:alpine volumes: - ./nginx.conf:/etc/nginx/nginx.conf ports: - "80:80" depends_on: - archive-app volumes: postgres_data: minio_data: ```7.2 Nginx反向代理配置
创建nginx.conf:
``` events { worker_connections 1024; } http { upstream archive_backend { server archive-app:8080; } server { listen 80; server_name archive.yourcompany.com; location / { proxy_pass http://archive_backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location /minio/ { proxy_pass http://minio:9000/; proxy_set_header Host $http_host; } location /minio-console/ { proxy_pass http://minio:9090/; proxy_set_header Host $http_host; } } } ```7.3 启动完整系统
在项目根目录执行:
``` 构建Spring Boot应用 ./mvnw clean package -DskipTests 启动所有服务 docker-compose up -d 查看服务状态 docker-compose ps 查看日志 docker-compose logs -f archive-app ```八、数据备份与恢复策略
8.1 数据库自动备份
创建backup.sh脚本:
``` !/bin/bash BACKUP_DIR="/backup/archive_db" DATE=$(date +%Y%m%d_%H%M%S) BACKUP_FILE="$BACKUP_DIR/archive_db_$DATE.sql" 备份PostgreSQL数据库 docker exec postgres-archive pg_dump -U archive_admin archive_db > $BACKUP_FILE 压缩备份文件 gzip $BACKUP_FILE 保留最近30天的备份 find $BACKUP_DIR -name ".gz" -mtime +30 -delete 上传到MinIO备份存储桶 mc cp $BACKUP_FILE.gz minio/backup-bucket/ ```8.2 MinIO存储桶跨区域复制
配置MinIO存储桶复制策略:
``` 在MinIO控制台配置 1. 进入Bucket → Replication 2. 添加复制规则 3. 选择目标存储桶(位于不同机房的MinIO实例) 4. 设置复制所有对象 5. 启用删除标记复制 ```执行crontab -e添加定时任务:
``` 每天凌晨2点执行备份 0 2 /opt/scripts/backup.sh 每周日凌晨3点执行完整性检查 0 3 0 /opt/scripts/check_integrity.sh ```九、系统验证与测试
9.1 功能验证清单
- 文件上传测试:使用