网站首页/ 信息中心/ 档案百科/

长春数字档案馆系统:从零到一构建完整实操指南

发布时间:2026年09月13日 13:10:21 浏览量:0

一、系统架构与核心技术选型

长春数字档案馆系统采用微服务架构,核心组件包括档案数字化处理、元数据管理、全文检索、权限控制四大模块。技术栈选择基于实际部署环境考虑:后端使用Java Spring Boot 2.7.8,数据库采用PostgreSQL 14,全文检索使用Elasticsearch 7.17,文件存储用MinIO,前端采用Vue 3 + Element Plus。

1.1 环境准备与依赖安装

在CentOS 7.9服务器上执行以下命令安装基础环境:

```bash 安装JDK 11 yum install -y java-11-openjdk-devel java -version 确认版本为11.0.18+ 安装PostgreSQL yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm yum install -y postgresql14-server /usr/pgsql-14/bin/postgresql-14-setup initdb systemctl start postgresql-14 systemctl enable postgresql-14 创建数据库和用户 sudo -u postgres psql -c "CREATE USER archive_admin WITH PASSWORD 'StrongPass123!';" sudo -u postgres psql -c "CREATE DATABASE digital_archive OWNER archive_admin;" 安装Elasticsearch rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch cat > /etc/yum.repos.d/elasticsearch.repo << EOF [elasticsearch] name=Elasticsearch repository for 7.x packages baseurl=https://artifacts.elastic.co/packages/7.x/yum gpgcheck=1 gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch enabled=1 autorefresh=1 type=rpm-md EOF yum install -y elasticsearch systemctl start elasticsearch systemctl enable elasticsearch ```

二、核心服务部署与配置

2.1 档案数字化处理服务

创建Spring Boot项目,在pom.xml中添加关键依赖:

```xml org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-data-jpa org.postgresql postgresql 42.5.4 org.apache.pdfbox pdfbox 2.0.27 org.apache.tika tika-core 2.7.0 ```

配置application.yml文件:

```yaml server: port: 8080 spring: datasource: url: jdbc:postgresql://localhost:5432/digital_archive username: archive_admin password: StrongPass123! driver-class-name: org.postgresql.Driver jpa: hibernate: ddl-auto: update show-sql: true properties: hibernate: dialect: org.hibernate.dialect.PostgreSQLDialect format_sql: true archive: storage: minio: endpoint: http://localhost:9000 access-key: minioadmin secret-key: minioadmin bucket: archive-files ocr: tessdata-path: /usr/share/tesseract-ocr/4.00/tessdata ```

2.2 文件上传与OCR处理实现

创建FileUploadController处理档案文件上传:

```java @RestController @RequestMapping("/api/archive") public class FileUploadController { @PostMapping("/upload") public ResponseEntity uploadFile( @RequestParam("file") MultipartFile file, @RequestParam("category") String category) throws IOException { // 1. 保存原始文件到MinIO String originalFileName = file.getOriginalFilename(); String fileId = UUID.randomUUID().toString(); String objectName = category + "/" + fileId + "_" + originalFileName; minioClient.putObject( PutObjectArgs.builder() .bucket("archive-files") .object(objectName) .stream(file.getInputStream(), file.getSize(), -1) .contentType(file.getContentType()) .build() ); // 2. 提取文本内容(支持PDF、Word、图片) String extractedText = extractTextFromFile(file); // 3. 执行OCR识别(针对图片类档案) if (isImageFile(originalFileName)) { String ocrText = performOCR(file); extractedText = ocrText + "\n" + extractedText; } // 4. 保存元数据到数据库 ArchiveFile archiveFile = new ArchiveFile(); archiveFile.setFileId(fileId); archiveFile.setFileName(originalFileName); archiveFile.setFileSize(file.getSize()); archiveFile.setCategory(category); archiveFile.setStoragePath(objectName); archiveFile.setExtractedText(extractedText); archiveFile.setUploadTime(LocalDateTime.now()); archiveFileRepository.save(archiveFile); // 5. 索引到Elasticsearch indexToElasticsearch(archiveFile); return ResponseEntity.ok(archiveFile); } private String extractTextFromFile(MultipartFile file) throws IOException { Tika tika = new Tika(); return tika.parseToString(file.getInputStream()); } private String performOCR(MultipartFile file) throws IOException { ITesseract tesseract = new Tesseract(); tesseract.setDatapath("/usr/share/tesseract-ocr/4.00/tessdata"); tesseract.setLanguage("chi_sim+eng"); BufferedImage image = ImageIO.read(file.getInputStream()); return tesseract.doOCR(image); } } ```

三、元数据管理系统实现

3.1 数据库表设计

执行以下SQL创建核心表结构:

```sql -- 档案文件主表 CREATE TABLE archive_files ( file_id VARCHAR(36) PRIMARY KEY, file_name VARCHAR(500) NOT NULL, file_size BIGINT NOT NULL, file_type VARCHAR(50), category VARCHAR(100) NOT NULL, storage_path VARCHAR(1000) NOT NULL, extracted_text TEXT, upload_time TIMESTAMP NOT NULL, upload_user VARCHAR(100), archive_year INTEGER, security_level VARCHAR(20) DEFAULT '公开', retention_period INTEGER DEFAULT 30 ); -- 档案元数据表 CREATE TABLE file_metadata ( metadata_id SERIAL PRIMARY KEY, file_id VARCHAR(36) REFERENCES archive_files(file_id), metadata_key VARCHAR(100) NOT NULL, metadata_value TEXT NOT NULL, created_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- 全文检索索引表 CREATE TABLE search_index ( index_id SERIAL PRIMARY KEY, file_id VARCHAR(36) REFERENCES archive_files(file_id), indexed_text TEXT NOT NULL, index_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- 创建索引优化查询性能 CREATE INDEX idx_archive_category ON archive_files(category); CREATE INDEX idx_archive_year ON archive_files(archive_year); CREATE INDEX idx_metadata_key ON file_metadata(metadata_key); CREATE INDEX idx_search_file ON search_index(file_id); ```

3.2 Elasticsearch索引配置

长春数字档案馆系统:从零到一构建完整实操指南

创建Elasticsearch索引映射:

```bash curl -X PUT "localhost:9200/archive_documents" -H 'Content-Type: application/json' -d' { "mappings": { "properties": { "fileId": {"type": "keyword"}, "fileName": { "type": "text", "analyzer": "ik_max_word", "search_analyzer": "ik_smart" }, "category": {"type": "keyword"}, "content": { "type": "text", "analyzer": "ik_max_word", "search_analyzer": "ik_smart" }, "uploadTime": {"type": "date"}, "archiveYear": {"type": "integer"}, "securityLevel": {"type": "keyword"}, "metadata": { "type": "nested", "properties": { "key": {"type": "keyword"}, "value": {"type": "text"} } } } } } ' ```

四、全文检索服务实现

4.1 搜索接口开发

实现高级搜索功能:

```java @Service public class ArchiveSearchService { @Autowired private RestHighLevelClient elasticsearchClient; public SearchResponse searchArchives(SearchRequest request) throws IOException { SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); // 构建布尔查询 BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); // 关键词搜索(支持中文分词) if (StringUtils.isNotBlank(request.getKeyword())) { boolQuery.must(QueryBuilders.multiMatchQuery(request.getKeyword()) .field("fileName", 3.0f) // 文件名权重更高 .field("content") .type(MultiMatchQueryBuilder.Type.BEST_FIELDS)); } // 分类筛选 if (StringUtils.isNotBlank(request.getCategory())) { boolQuery.filter(QueryBuilders.termQuery("category", request.getCategory())); } // 年份范围查询 if (request.getStartYear() != null && request.getEndYear() != null) { boolQuery.filter(QueryBuilders.rangeQuery("archiveYear") .gte(request.getStartYear()) .lte(request.getEndYear())); } // 安全级别过滤 if (StringUtils.isNotBlank(request.getSecurityLevel())) { boolQuery.filter(QueryBuilders.termQuery("securityLevel", request.getSecurityLevel())); } sourceBuilder.query(boolQuery); sourceBuilder.from((request.getPage() - 1) request.getSize()); sourceBuilder.size(request.getSize()); // 高亮显示 HighlightBuilder highlightBuilder = new HighlightBuilder(); highlightBuilder.field("fileName"); highlightBuilder.field("content"); highlightBuilder.preTags(""); highlightBuilder.postTags(""); sourceBuilder.highlighter(highlightBuilder); // 执行搜索 SearchRequest searchRequest = new SearchRequest("archive_documents"); searchRequest.source(sourceBuilder); return elasticsearchClient.search(searchRequest, RequestOptions.DEFAULT); } // 自动补全建议 public List getSuggestions(String prefix) throws IOException { CompletionSuggestionBuilder suggestionBuilder = SuggestBuilders.completionSuggestion("fileName.suggest") .prefix(prefix) .skipDuplicates(true) .size(10); SuggestBuilder suggestBuilder = new SuggestBuilder(); suggestBuilder.addSuggestion("file-suggest", suggestionBuilder); SearchRequest searchRequest = new SearchRequest("archive_documents"); searchRequest.source().suggest(suggestBuilder); SearchResponse response = elasticsearchClient.search( searchRequest, RequestOptions.DEFAULT); return response.getSuggest() .getSuggestion("file-suggest") .getEntries().get(0) .getOptions().stream() .map(CompletionSuggestion.Entry.Option::getText) .collect(Collectors.toList()); } } ```

五、权限控制与审计日志

5.1 基于角色的访问控制

创建权限控制表和执行SQL:

```sql -- 用户表 CREATE TABLE system_users ( user_id VARCHAR(36) PRIMARY KEY, username VARCHAR(100) UNIQUE NOT NULL, password_hash VARCHAR(255) NOT NULL, real_name VARCHAR(100), department VARCHAR(200), email VARCHAR(200), is_active BOOLEAN DEFAULT true, created_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- 角色表 CREATE TABLE user_roles ( role_id SERIAL PRIMARY KEY, role_name VARCHAR(50) UNIQUE NOT NULL, description TEXT ); -- 权限表 CREATE TABLE permissions ( permission_id SERIAL PRIMARY KEY, permission_code VARCHAR(100) UNIQUE NOT NULL, permission_name VARCHAR(200), resource_type VARCHAR(50) ); -- 用户角色关联 CREATE TABLE user_role_mapping ( user_id VARCHAR(36) REFERENCES system_users(user_id), role_id INTEGER REFERENCES user_roles(role_id), PRIMARY KEY (user_id, role_id) ); -- 角色权限关联 CREATE TABLE role_permission_mapping ( role_id INTEGER REFERENCES user_roles(role_id), permission_id INTEGER REFERENCES permissions(permission_id), PRIMARY KEY (role_id, permission_id) ); -- 插入基础权限数据 INSERT INTO permissions (permission_code, permission_name, resource_type) VALUES ('ARCHIVE:READ', '查看档案', 'ARCHIVE'), ('ARCHIVE:WRITE', '上传档案', 'ARCHIVE'), ('ARCHIVE:DELETE', '删除档案', 'ARCHIVE'), ('ARCHIVE:EXPORT', '导出档案', 'ARCHIVE'), ('METADATA:MANAGE', '管理元数据', 'METADATA'), ('SYSTEM:CONFIG', '系统配置', 'SYSTEM'); ```

5.2 Spring Security配置

配置安全过滤器链:

```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .csrf().disable() .authorizeRequests() .antMatchers("/api/auth/").permitAll() .antMatchers("/api/archive/upload").hasAuthority('ARCHIVE:WRITE') .antMatchers("/api/archive/search").hasAuthority('ARCHIVE:READ') .antMatchers("/api/archive/delete/").hasAuthority('ARCHIVE:DELETE') .antMatchers("/api/admin/").hasAuthority('SYSTEM:CONFIG') .anyRequest().authenticated() .and() .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); } @Bean public JwtAuthenticationFilter jwtAuthenticationFilter() { return new JwtAuthenticationFilter(); } } ```

5.3 操作审计日志实现

创建AOP切面记录所有关键操作:

```java @Aspect @Component public class AuditLogAspect { @Autowired private AuditLogRepository auditLogRepository; @Around("@annotation(com.example.archive.annotation.OperationLog)") public Object logOperation(ProceedingJoinPoint joinPoint) throws Throwable { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); OperationLog annotation = signature.getMethod() .getAnnotation(OperationLog.class); String operation = annotation.value(); String operator = SecurityContextHolder.getContext() .getAuthentication().getName(); LocalDateTime startTime = LocalDateTime.now(); try { Object result = joinPoint.proceed(); LocalDateTime endTime = LocalDateTime.now(); // 保存成功日志 saveAuditLog(operation, operator, "SUCCESS", startTime, endTime, null); return result; } catch (Exception e) { // 保存失败日志 saveAuditLog(operation, operator, "FAILED", startTime, LocalDateTime.now(), e.getMessage()); throw e; } } private void saveAuditLog(String operation, String operator, String status, LocalDateTime startTime, LocalDateTime endTime, String errorMsg) { AuditLog log = new AuditLog(); log.setOperation(operation); log.setOperator(operator); log.setStatus(status); log.setStartTime(startTime); log.setEndTime(endTime); log.setDuration(Duration.between(startTime, endTime).toMillis()); log.setErrorMsg(errorMsg); log.setIpAddress(getClientIp()); auditLogRepository.save(log); } } ```

六、系统部署与监控

6.1 Docker容器化部署

创建docker-compose.yml文件:

```yaml version: '3.8' services: postgres: image: postgres:14-alpine environment: POSTGRES_DB: digital_archive POSTGRES_USER: archive_admin POSTGRES_PASSWORD: StrongPass123! volumes: - postgres_data:/var/lib/postgresql/data ports: - "5432:5432" elasticsearch: image: elasticsearch:7.17.10 environment: - discovery.type=single-node - "ES_JAVA_OPTS=-Xms512m -Xmx512m" volumes: - es_data:/usr/share/elasticsearch/data ports: - "9200:9200" minio: image: minio/minio:latest command: server /data --console-address ":9001" environment: MINIO_ROOT_USER: minioadmin MINIO_ROOT_PASSWORD: minioadmin volumes: - minio_data:/data ports:

抓好档案制度建设落地 盘活档案资源利用实操经验
抓好档案制度建设落地 盘活档案资源利用实操经验
你有没有发现很多单位的档案制度都是打印出来塑封好往墙上一贴,就等于完成任务了?真到要查个老合同、找个过往项目资料的时候,要么翻遍库房找不到,要么调个档要走七八道流程,等拿到手黄花菜都凉了。
2026年09月13日 13:10:21
微信咨询
电话联系
QQ客服
微信咨询一对一服务
服务热线: 028-8744 4417
QQ客服: 2305721818