集团档案数字化建设实操指南:从零搭建企业级档案管理系统

一、系统架构设计与核心组件选型

集团档案管理系统采用微服务架构,确保系统可扩展性和高可用性。核心组件包括:

  • 存储层:使用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控制台创建访问密钥:

  1. 点击Access Keys → Create Access Key
  2. 记录生成的Access Key和Secret Key
  3. 为archive-bucket设置访问策略:
``` { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:GetObject", "s3:PutObject", "s3:DeleteObject" ], "Resource": [ "arn:aws:s3:::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 ResponseEntity uploadArchive( @RequestParam("file") MultipartFile file, @RequestParam("title") String title, @RequestParam("categoryCode") String categoryCode, @RequestParam("keywords") String keywords) { // 1. 上传文件到MinIO String filePath = "archive/" + LocalDate.now().getYear() + "/" + LocalDate.now().getMonthValue(); String fileKey = fileStorageService.uploadFile(file, filePath); // 2. 保存档案信息到数据库 ArchiveItem item = new ArchiveItem(); item.setItemCode(generateItemCode(categoryCode)); item.setTitle(title); item.setFileKey(fileKey); item.setFileSize(file.getSize()); item.setFileType(file.getContentType()); item.setKeywords(keywords); ArchiveItem savedItem = archiveItemService.save(item); return ResponseEntity.ok(savedItem); } private String generateItemCode(String categoryCode) { return categoryCode + "-" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")) + "-" + String.format("%04d", getDailySequence(categoryCode)); } } ```

5.2 档案检索接口

实现基于关键词的全文检索:

``` @Repository public interface ArchiveItemRepository extends JpaRepository { @Query(value = "SELECT FROM archive_item WHERE " + "to_tsvector('english', keywords || ' ' || title || ' ' || description) " + "@@ plainto_tsquery('english', :keyword)", nativeQuery = true) List fullTextSearch(@Param("keyword") String keyword); @Query("SELECT a FROM ArchiveItem a WHERE " + "a.category.categoryCode = :categoryCode AND " + "a.status = 'ACTIVE'") List findByCategory(@Param("categoryCode") String categoryCode); } ```

六、权限控制与安全配置

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 功能验证清单

  1. 文件上传测试:使用
AI咨询
热线电话

028-85154420

15388110056

全国售前咨询电话

扫码咨询
安答联动微信公众号二维码

微信扫码关注安答联动

申请试用
热线电话
申请试用

安答联动档案管理系统