建筑版文书档案管理系统从零到一搭建实操指南

一、系统核心需求分析与技术选型

建筑行业文书档案管理需满足图纸、合同、变更单、验收报告等多类型文件管理,同时关联项目、楼栋、楼层等空间维度。

1.1 核心功能需求

  • 多层级项目结构:公司→项目→标段→楼栋→楼层
  • 文件分类管理:设计图纸、施工合同、过程文档、竣工资料
  • 版本控制:图纸变更必须保留历史版本
  • 权限体系:按项目、角色、部门进行数据隔离
  • 全文检索:支持PDF、Word、Excel等格式内容搜索

1.2 技术栈选择

基于快速部署和成本考虑,选择以下开源技术栈:

  • 后端:Spring Boot 2.7 + MyBatis Plus
  • 前端:Vue 3 + Element Plus
  • 数据库:MySQL 8.0
  • 文件存储:MinIO(替代S3的本地存储方案)
  • 全文检索:Elasticsearch 7.17
  • 部署:Docker Compose

二、环境准备与基础框架搭建

2.1 开发环境安装

安装JDK 17:

``` wget https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.tar.gz tar -xzf jdk-17_linux-x64_bin.tar.gz sudo mv jdk-17.0.10 /usr/local/ echo 'export JAVA_HOME=/usr/local/jdk-17.0.10' >> ~/.bashrc echo 'export PATH=$JAVA_HOME/bin:$PATH' >> ~/.bashrc source ~/.bashrc ```

安装Node.js 18:

``` curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash - sudo apt-get install -y nodejs ```

2.2 项目初始化

创建Spring Boot项目:

``` curl https://start.spring.io/starter.zip \ -d type=maven-project \ -d language=java \ -d bootVersion=2.7.18 \ -d baseDir=construction-doc-system \ -d groupId=com.construction \ -d artifactId=doc-system \ -d name=ConstructionDocSystem \ -d dependencies=web,mybatis,mysql,lombok \ -o construction-doc-system.zip unzip construction-doc-system.zip ```

前端项目初始化:

``` npm create vue@latest construction-doc-web cd construction-doc-web npm install element-plus @element-plus/icons-vue vue-router@4 pinia axios ```

三、数据库设计与核心表结构

3.1 数据库创建

登录MySQL执行:

``` CREATE DATABASE construction_doc DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE construction_doc; ```

3.2 核心表SQL

项目结构表:

``` CREATE TABLE project_structure ( id BIGINT PRIMARY KEY AUTO_INCREMENT, parent_id BIGINT DEFAULT 0, code VARCHAR(50) NOT NULL COMMENT '项目编码', name VARCHAR(100) NOT NULL COMMENT '项目名称', type TINYINT NOT NULL COMMENT '1:公司 2:项目 3:标段 4:楼栋 5:楼层', full_path VARCHAR(500) COMMENT '完整路径,如1/2/3/4', created_time DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_parent_id (parent_id), INDEX idx_full_path (full_path(100)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ```

文档分类表:

``` CREATE TABLE doc_category ( id INT PRIMARY KEY AUTO_INCREMENT, category_code VARCHAR(20) NOT NULL UNIQUE COMMENT '分类编码', category_name VARCHAR(50) NOT NULL COMMENT '分类名称', parent_id INT DEFAULT 0, sort_order INT DEFAULT 0, project_type TINYINT DEFAULT 0 COMMENT '适用的项目类型,0:全部', created_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ```

插入初始分类数据:

``` INSERT INTO doc_category (category_code, category_name, parent_id, sort_order) VALUES ('DESIGN', '设计图纸', 0, 1), ('DESIGN_ARCH', '建筑图纸', 1, 1), ('DESIGN_STRU', '结构图纸', 1, 2), ('CONTRACT', '合同文件', 0, 2), ('PROCESS', '过程文档', 0, 3), ('PROCESS_CHANGE', '变更单', 3, 1), ('PROCESS_REPORT', '进度报告', 3, 2), ('COMPLETION', '竣工资料', 0, 4); ```

文档主表:

``` CREATE TABLE document ( id BIGINT PRIMARY KEY AUTO_INCREMENT, doc_no VARCHAR(50) NOT NULL UNIQUE COMMENT '文档编号', doc_name VARCHAR(200) NOT NULL COMMENT '文档名称', category_id INT NOT NULL COMMENT '分类ID', project_id BIGINT NOT NULL COMMENT '所属项目节点ID', version INT DEFAULT 1 COMMENT '版本号', current_version TINYINT DEFAULT 1 COMMENT '是否当前版本', file_size BIGINT COMMENT '文件大小(字节)', file_path VARCHAR(500) COMMENT '文件存储路径', file_hash VARCHAR(64) COMMENT '文件哈希值,用于去重', upload_user_id BIGINT NOT NULL, upload_time DATETIME DEFAULT CURRENT_TIMESTAMP, description TEXT COMMENT '文档描述', INDEX idx_project_category (project_id, category_id), INDEX idx_doc_no (doc_no), INDEX idx_upload_time (upload_time), FOREIGN KEY (category_id) REFERENCES doc_category(id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ```

四、文件存储服务配置

4.1 MinIO安装与配置

使用Docker启动MinIO:

``` docker run -d \ -p 9000:9000 \ -p 9001:9001 \ --name minio \ -v /data/minio/data:/data \ -v /data/minio/config:/root/.minio \ -e "MINIO_ROOT_USER=admin" \ -e "MINIO_ROOT_PASSWORD=your_strong_password_here" \ minio/minio server /data --console-address ":9001" ```

创建存储桶:

``` 安装MinIO客户端 wget https://dl.min.io/client/mc/release/linux-amd64/mc chmod +x mc sudo mv mc /usr/local/bin/ 配置访问 mc alias set local http://localhost:9000 admin your_strong_password_here 创建建筑文档专用桶 mc mb local/construction-docs mc anonymous set download local/construction-docs ```

4.2 Spring Boot集成MinIO

建筑版文书档案管理系统从零到一搭建实操指南

添加依赖到pom.xml:

``` io.minio minio 8.5.7 ```

创建MinIO配置类:

``` @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(); } } ```

application.yml配置:

``` minio: endpoint: http://localhost:9000 accessKey: admin secretKey: your_strong_password_here bucket: construction-docs ```

五、文档上传与版本控制实现

5.1 文件上传服务

创建文件上传Service:

``` @Service public class FileUploadService { @Autowired private MinioClient minioClient; @Value("${minio.bucket}") private String bucketName; public String uploadFile(MultipartFile file, String objectName) throws Exception { // 检查文件是否已存在 String fileHash = calculateFileHash(file); // 生成存储路径:年/月/日/UUID_原文件名 String datePath = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd")); String fileName = file.getOriginalFilename(); String extension = fileName.substring(fileName.lastIndexOf(".")); String finalObjectName = datePath + "/" + UUID.randomUUID() + extension; // 上传到MinIO minioClient.putObject( PutObjectArgs.builder() .bucket(bucketName) .object(finalObjectName) .stream(file.getInputStream(), file.getSize(), -1) .contentType(file.getContentType()) .build() ); return finalObjectName; } private String calculateFileHash(MultipartFile file) throws Exception { try (InputStream is = file.getInputStream()) { MessageDigest digest = MessageDigest.getInstance("SHA-256"); byte[] buffer = new byte[8192]; int bytesRead; while ((bytesRead = is.read(buffer)) != -1) { digest.update(buffer, 0, bytesRead); } return bytesToHex(digest.digest()); } } } ```

5.2 版本控制逻辑

文档版本更新Service:

``` @Service public class DocumentVersionService { @Autowired private DocumentMapper documentMapper; @Transactional public Long createNewVersion(Long docId, MultipartFile newFile, String description) throws Exception { // 查询当前文档 Document currentDoc = documentMapper.selectById(docId); // 将当前文档标记为非最新版本 currentDoc.setCurrentVersion(0); documentMapper.updateById(currentDoc); // 创建新版本 Document newVersion = new Document(); BeanUtils.copyProperties(currentDoc, newVersion); newVersion.setId(null); newVersion.setVersion(currentDoc.getVersion() + 1); newVersion.setCurrentVersion(1); newVersion.setDescription(description); newVersion.setUploadTime(new Date()); // 上传新文件并更新文件信息 String newFilePath = fileUploadService.uploadFile(newFile, currentDoc.getDocNo() + "_v" + newVersion.getVersion()); newVersion.setFilePath(newFilePath); newVersion.setFileSize(newFile.getSize()); documentMapper.insert(newVersion); return newVersion.getId(); } } ```

六、全文检索集成

6.1 Elasticsearch安装

使用Docker Compose部署:

``` version: '3.8' services: elasticsearch: image: elasticsearch:7.17.21 container_name: es-doc-search environment: - discovery.type=single-node - ES_JAVA_OPTS=-Xms512m -Xmx512m - xpack.security.enabled=false ports: - "9200:9200" volumes: - es-data:/usr/share/elasticsearch/data networks: - es-net kibana: image: kibana:7.17.21 container_name: kibana-doc ports: - "5601:5601" environment: - ELASTICSEARCH_HOSTS=http://elasticsearch:9200 networks: - es-net volumes: es-data: driver: local networks: es-net: driver: bridge ```

启动服务:

``` docker-compose up -d ```

6.2 文档索引创建

创建文档索引mapping:

``` PUT /construction-documents { "mappings": { "properties": { "docId": {"type": "long"}, "docNo": {"type": "keyword"}, "docName": { "type": "text", "analyzer": "ik_max_word", "search_analyzer": "ik_smart" }, "content": { "type": "text", "analyzer": "ik_max_word", "search_analyzer": "ik_smart" }, "category": {"type": "keyword"}, "projectPath": {"type": "keyword"}, "uploadTime": {"type": "date"}, "uploadUser": {"type": "keyword"} } } } ```

6.3 文件内容提取

集成Tika提取文件内容:

``` org.apache.tika tika-core 2.9.1 org.apache.tika tika-parser-standard-module 2.9.1 ```

内容提取工具类:

``` @Component public class ContentExtractor { private final Tika tika = new Tika(); public String extractContent(File file) throws Exception { try (InputStream is = new FileInputStream(file)) { // 设置元数据 Metadata metadata = new Metadata(); metadata.set(Metadata.RESOURCE_NAME_KEY, file.getName()); // 提取文本内容 return tika.parseToString(is, metadata, -1); } } public String extractContent(MultipartFile file) throws Exception { return tika.parseToString(file.getInputStream()); } } ```

七、权限控制系统实现

7.1 权限表设计

用户-项目权限关联表:

``` CREATE TABLE user_project_permission ( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id BIGINT NOT NULL, project_id BIGINT NOT NULL, permission_type TINYINT NOT NULL COMMENT '1:只读 2:编辑 3:管理', created_time DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_user_project (user_id, project_id), INDEX idx_project_id (project_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ```

7.2 权限拦截器

创建权限检查拦截器:

``` @Component public class PermissionInterceptor implements HandlerInterceptor { @Autowired private UserProjectPermissionService permissionService; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 获取当前用户ID(从Session或Token中) Long userId = getCurrentUserId(request); // 获取请求的项目ID Long projectId = getProjectIdFromRequest(request); // 获取请求的权限级别 Integer requiredPermission = getRequiredPermission(request); // 检查权限 boolean hasPermission = permissionService.checkPermission(userId, projectId, requiredPermission); if (!hasPermission) { response.setStatus(HttpStatus.FORBIDDEN.value()); response.getWriter().write("{\"code\":403,\"message\":\"权限不足\"}"); return false; } return true; } } ```

八、系统部署与运维

8.1 生产环境Docker部署

创建docker-compose.prod.yml:

``` version: '3.8' services: mysql: image: mysql:8.0 container_name: construction-mysql environment: MYSQL_ROOT_PASSWORD: your_mysql_root_password MYSQL_DATABASE: construction_doc ports: - "3306:3306" volumes: - mysql-data:/var/lib/mysql - ./init.sql:/docker-entrypoint-initdb.d/init.sql command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci minio: image: minio/minio container_name: construction-minio command: server /data --console-address ":9001" environment: MINIO_ROOT_USER: admin MINIO_ROOT_PASSWORD: your_minio_password ports: - "9000:9000" - "9001:9001" volumes: - minio-data:/data elasticsearch: image: elasticsearch:7.17.21 container_name: construction-es environment: - discovery.type=single-node - ES_JAVA_OPTS=-Xms1g -Xmx1g - xpack.security.enabled=false ports: - "9200:9200" volumes: - es-data:/usr/share/elasticsearch/data ulimits: memlock: soft: -1 hard: -1 backend: build: ./backend container_name: construction-backend ports: - "8080:8080" environment: - SPRING_PROFILES_ACTIVE=prod - DB_HOST=mysql - MINIO_ENDPOINT=http://minio:9000 - ES_HOST=elasticsearch depends_on: - mysql - minio - elasticsearch frontend: build: ./frontend container_name: construction-frontend ports: - "80:80" depends_on:
AI咨询
热线电话

028-85154420

15388110056

全国售前咨询电话

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

微信扫码关注安答联动

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

安答联动档案管理系统