档案制度建设少走弯路 实战教育手把手带你全流程落地
家人们谁懂啊,我去年帮3个小微企业搭档案制度的时候,踩的坑能绕公司前台的奶茶堆三圈。那时候我还是个抱着《档案管理学》啃的理论党,总觉得不就是归个纸嘛有啥难的,直到把公司攒了5年的合同翻得乱七八糟找不到...
2026年08月22日 05:35:25
本系统采用前后端分离架构,前端使用Vue 3 + Element Plus,后端使用Spring Boot 2.7,数据库使用MySQL 8.0,文件存储采用MinIO。
安装Node.js 18.17.0:
``` curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash - sudo apt-get install -y nodejs ```安装Java 17:
``` sudo apt update sudo apt install openjdk-17-jdk ```安装MySQL 8.0:
``` sudo apt install mysql-server-8.0 sudo mysql_secure_installation ```创建数据库和用户:
``` mysql -u root -p CREATE DATABASE research_archive CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER 'archive_admin'@'localhost' IDENTIFIED BY 'YourPassword123!'; GRANT ALL PRIVILEGES ON research_archive. TO 'archive_admin'@'localhost'; FLUSH PRIVILEGES; ```创建核心表结构:
``` USE research_archive; CREATE TABLE users ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) UNIQUE NOT NULL, password_hash VARCHAR(255) NOT NULL, real_name VARCHAR(100) NOT NULL, department VARCHAR(200), role ENUM('admin', 'teacher', 'researcher', 'student') NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, INDEX idx_username (username), INDEX idx_department (department) ); CREATE TABLE research_projects ( id INT PRIMARY KEY AUTO_INCREMENT, project_code VARCHAR(50) UNIQUE NOT NULL, project_name VARCHAR(500) NOT NULL, principal_id INT NOT NULL, funding_source VARCHAR(200), start_date DATE NOT NULL, end_date DATE, status ENUM('planning', 'ongoing', 'completed', 'archived') DEFAULT 'planning', FOREIGN KEY (principal_id) REFERENCES users(id) ON DELETE CASCADE, INDEX idx_project_code (project_code), INDEX idx_status (status) ); CREATE TABLE archive_files ( id INT PRIMARY KEY AUTO_INCREMENT, file_uuid VARCHAR(36) UNIQUE NOT NULL, original_name VARCHAR(500) NOT NULL, storage_path VARCHAR(1000) NOT NULL, file_size BIGINT NOT NULL, mime_type VARCHAR(100), project_id INT NOT NULL, uploader_id INT NOT NULL, category ENUM('proposal', 'report', 'data', 'paper', 'other') NOT NULL, upload_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, description TEXT, FOREIGN KEY (project_id) REFERENCES research_projects(id) ON DELETE CASCADE, FOREIGN KEY (uploader_id) REFERENCES users(id) ON DELETE CASCADE, INDEX idx_project_category (project_id, category), INDEX idx_upload_time (upload_time) ); ```使用Spring Initializr创建项目:
``` curl https://start.spring.io/starter.zip \ -d type=maven-project \ -d language=java \ -d bootVersion=2.7.15 \ -d baseDir=research-archive-backend \ -d groupId=com.example \ -d artifactId=archive \ -d name=research-archive \ -d description="Research Archive Management System" \ -d packageName=com.example.archive \ -d packaging=jar \ -d javaVersion=17 \ -d dependencies=web,data-jpa,mysql,security,validation \ -o archive-backend.zip unzip archive-backend.zip ```application.yml配置:
``` server: port: 8080 servlet: context-path: /api spring: datasource: url: jdbc:mysql://localhost:3306/research_archive?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: archive_admin password: YourPassword123! driver-class-name: com.mysql.cj.jdbc.Driver jpa: hibernate: ddl-auto: update show-sql: true properties: hibernate: format_sql: true dialect: org.hibernate.dialect.MySQL8Dialect minio: endpoint: http://localhost:9000 accessKey: minioadmin secretKey: minioadmin bucket: research-archive jwt: secret: your-jwt-secret-key-at-least-256-bits-long-here expiration: 86400000 ```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(); } } ```文件上传服务:
``` @Service @Slf4j public class FileStorageService { @Value("${minio.bucket}") private String bucketName; @Autowired private MinioClient minioClient; public String uploadFile(MultipartFile file, String category) throws Exception { String originalFilename = file.getOriginalFilename(); String fileExtension = originalFilename.substring(originalFilename.lastIndexOf(".")); String objectName = UUID.randomUUID().toString() + fileExtension; // 确保存储桶存在 boolean found = minioClient.bucketExists(BucketExistsArgs.builder() .bucket(bucketName).build()); if (!found) { minioClient.makeBucket(MakeBucketArgs.builder() .bucket(bucketName).build()); } // 上传文件 minioClient.putObject( PutObjectArgs.builder() .bucket(bucketName) .object(objectName) .stream(file.getInputStream(), file.getSize(), -1) .contentType(file.getContentType()) .build() ); return objectName; } public InputStream downloadFile(String objectName) throws Exception { return minioClient.getObject( GetObjectArgs.builder() .bucket(bucketName) .object(objectName) .build() ); } } ```JWT工具类:
``` @Component public class JwtTokenUtil { @Value("${jwt.secret}") private String secret; @Value("${jwt.expiration}") private Long expiration; public String generateToken(UserDetails userDetails) { Map创建Vue项目:
``` npm create vue@latest research-archive-frontend cd research-archive-frontend npm install ```安装依赖:
``` npm install element-plus axios vue-router pinia npm install @element-plus/icons-vue npm install vue-axios ```创建以下目录结构:
``` src/ ├── api/ API接口 ├── components/ 公共组件 ├── router/ 路由配置 ├── store/ 状态管理 ├── utils/ 工具函数 └── views/ 页面组件 ```Login.vue实现:
```FileUpload.vue实现:
```
使用Docker部署MinIO:
``` docker run -d \ -p 9000:9000 \ -p 9001:9001 \ --name minio \ -v /mnt/data:/data \ -e "MINIO_ROOT_USER=minioadmin" \ -e "MINIO_ROOT_PASSWORD=minioadmin" \ minio/minio server /data --console-address ":9001" ```访问 http://localhost:9001 使用minioadmin/minioadmin登录,创建research-archive存储桶。
打包Spring Boot应用:
``` cd research-archive-backend mvn clean package -DskipTests ```创建Dockerfile:
``` FROM openjdk:17-jdk-slim WORKDIR /app COPY target/archive-0.0.1-SNAPSHOT.jar app.jar EXPOSE 8080 ENTRYPOINT ["java", "-jar", "app.jar"] ```构建并运行:
``` docker build -t research-archive-backend . docker run -d -p 8080:8080 --name archive-backend research-archive-backend ```构建前端应用:
``` cd research-archive-frontend npm run build ```创建nginx配置文件:
``` server { listen 80; server_name localhost; location / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ /index.html; } location /api { proxy_pass http://archive-backend:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } ```使用Docker部署:
``` docker run -d \ -p 80:80 \ --name archive-frontend \ -v $(pwd)/dist:/usr/share/nginx/html \ -v $(pwd)/nginx.conf:/etc/nginx/conf.d/default.conf \ nginx:alpine ```创建管理员账户:
``` INSERT INTO users (username, password_hash, real_name, role) VALUES ('admin', '$2a$10$YourBcryptHashHere', '系统管理员', 'admin'); ```注意:password_hash需要使用BCrypt加密,可以使用在线工具生成或通过注册功能创建。
创建数据库备份脚本:
``` !/bin/bash BACKUP_DIR="/backup/research-archive" DATE=$(date +%Y%m%d_%H%M%S) DB_NAME="research_archive" mkdir -p $BACKUP_DIR 备份数据库 mysqldump -u archive_admin -pYourPassword123! $DB_NAME > $BACKUP_DIR/${DB_NAME}_${DATE}.sql 备份MinIO数据(需要安装mc客户端) mc mirror --overwrite minio/research-archive $BACKUP_DIR/minio-backup/ 保留最近7天的备份 find $BACKUP_DIR -name ".sql" -mtime +7 -delete ```设置定时任务:
``` crontab -e 每天凌晨2点执行备份 0 2 /path/to/backup_script.sh ```Spring Boot日志配置:
``` logging: level: com.example.archive: DEBUG file: name: logs/archive.log logback: rollingpolicy: max-file-size: 10MB max-history: 30 ```使用logrotate管理日志:
``` /etc/logrotate.d/research-archive /var/log/research-archive/.log { daily rotate 30 compress delaycompress missingok notifempty create 644 root root postrotate systemctl reload research-archive endscript } ```MySQL性能优化配置:
``` /etc/mysql/my.cnf [mysqld] innodb_buffer_pool_size = 1G innodb_log_file_size = 256M innodb_flush_log_at_trx_commit = 2 query_cache_type = 1 query_cache_size = 64M max_connections = 200 ```Nginx缓存配置:
``` location ~ \.(jpg|j