从零搭建企业级档案数字化视频系统全攻略

本文将手把手指导你,从零开始搭建一个功能完整、运行稳定的企业级档案数字化视频系统。该系统将实现档案视频的采集、存储、转码、检索和播放。我们将使用开源技术栈,确保零成本部署。

一、系统架构与核心组件

整个系统由四个核心模块构成:前端应用、后端服务、转码集群和存储系统。我们将采用以下技术:

  • 前端: Vue.js + Element UI,负责用户界面和视频播放。
  • 后端: Spring Boot + MyBatis,提供RESTful API。
  • 转码服务: FFmpeg,处理视频格式转换与截图。
  • 存储: 文件系统(用于原始视频)+ MinIO(用于转码后视频和封面图)。
  • 数据库: MySQL,存储元数据。
  • 检索: Elasticsearch,实现基于档案信息的全文检索。

二、环境准备与依赖安装

在一台安装了CentOS 7或Ubuntu 20.04的服务器上操作,确保拥有root或sudo权限。

1. 安装基础依赖

执行以下命令安装Java、Node.js、MySQL和Nginx。

 Ubuntu/Debian
sudo apt update
sudo apt install -y openjdk-11-jdk nodejs npm mysql-server nginx
CentOS/RHEL
sudo yum install -y java-11-openjdk-devel nodejs npm mysql-server nginx

2. 安装并配置MinIO对象存储

MinIO用于存储转码后的视频和图片,替代昂贵的商业云存储。

 下载MinIO二进制文件
wget https://dl.min.io/server/minio/release/linux-amd64/minio
chmod +x minio
sudo mv minio /usr/local/bin/
创建存储目录和启动脚本
sudo mkdir -p /data/minio
sudo useradd -r minio-user -s /sbin/nologin
sudo chown -R minio-user:minio-user /data/minio
创建systemd服务文件 /etc/systemd/system/minio.service

将以下内容写入/etc/systemd/system/minio.service

[Unit]
Description=MinIO
After=network.target
[Service]
User=minio-user
Group=minio-user
ExecStart=/usr/local/bin/minio server /data/minio --console-address ":9001"
Restart=always
[Install]
WantedBy=multi-user.target
 启动MinIO
sudo systemctl daemon-reload
sudo systemctl enable minio
sudo systemctl start minio

访问 http://你的服务器IP:9001,使用默认账号minioadmin和密码minioadmin登录,并创建一个名为archive-video的存储桶。

3. 安装并配置Elasticsearch

 导入Elasticsearch GPG密钥并安装
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -
echo "deb https://artifacts.elastic.co/packages/7.x/apt stable main" | sudo tee -a /etc/apt/sources.list.d/elastic-7.x.list
sudo apt update
sudo apt install -y elasticsearch
修改配置文件 /etc/elasticsearch/elasticsearch.yml
设置 network.host: 0.0.0.0 和 discovery.type: single-node
sudo systemctl enable elasticsearch
sudo systemctl start elasticsearch

4. 安装FFmpeg

 Ubuntu
sudo apt install -y ffmpeg
CentOS
sudo yum install -y epel-release
sudo yum install -y ffmpeg ffmpeg-devel

三、后端服务搭建与配置

后端负责业务逻辑、API接口和调度转码任务。

1. 数据库初始化

从零搭建企业级档案数字化视频系统全攻略

 登录MySQL,密码安装时已设置
mysql -u root -p
执行以下SQL创建数据库和表
CREATE DATABASE archive_video_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE archive_video_db;
CREATE TABLE video_archive (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
archive_number VARCHAR(100) NOT NULL COMMENT '档案编号',
title VARCHAR(255) NOT NULL COMMENT '视频标题',
description TEXT COMMENT '描述',
original_file_path VARCHAR(500) COMMENT '原始文件路径',
converted_file_path VARCHAR(500) COMMENT '转码后文件路径(MinIO路径)',
cover_image_path VARCHAR(500) COMMENT '封面图路径',
duration INT COMMENT '视频时长(秒)',
status TINYINT DEFAULT 0 COMMENT '状态:0-待处理,1-转码中,2-完成,3-失败',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX idx_archive_number (archive_number),
INDEX idx_status (status)
);

2. 创建Spring Boot项目并配置

使用Spring Initializr (https://start.spring.io) 生成项目,依赖选择:Web, MyBatis, MySQL Driver, Lombok

下载后解压,主要配置文件src/main/resources/application.yml内容如下:

server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/archive_video_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: root
password: 你的数据库密码
driver-class-name: com.mysql.cj.jdbc.Driver
servlet:
multipart:
max-file-size: 10GB
max-request-size: 10GB
mybatis:
mapper-locations: classpath:mapper/.xml
configuration:
map-underscore-to-camel-case: true
archive:
video:
upload-dir: /data/archive-video/original/  原始视频上传目录
minio:
endpoint: http://localhost:9000
accessKey: minioadmin
secretKey: minioadmin
bucket: archive-video
ffmpeg-path: /usr/bin/ffmpeg  FFmpeg可执行文件路径

3. 核心功能实现

a. 文件上传控制器:接收前端上传的原始视频文件。

// VideoUploadController.java
@RestController
@RequestMapping("/api/upload")
public class VideoUploadController {
@Value("${archive.video.upload-dir}")
private String uploadDir;
@PostMapping
public ApiResponse upload(@RequestParam("file") MultipartFile file,
@RequestParam String archiveNumber,
@RequestParam String title) throws IOException {
// 1. 检查文件格式
String originalFilename = file.getOriginalFilename();
if (!originalFilename.endsWith(".mp4") && !originalFilename.endsWith(".avi") && !originalFilename.endsWith(".mov")) {
return ApiResponse.error("仅支持mp4, avi, mov格式");
}
// 2. 创建存储目录
File dir = new File(uploadDir);
if (!dir.exists()) dir.mkdirs();
// 3. 保存文件
String savedFileName = System.currentTimeMillis() + "_" + originalFilename;
File savedFile = new File(uploadDir + savedFileName);
file.transferTo(savedFile);
// 4. 插入数据库记录,状态为0(待处理)
VideoArchive archive = new VideoArchive();
archive.setArchiveNumber(archiveNumber);
archive.setTitle(title);
archive.setOriginalFilePath(savedFile.getAbsolutePath());
archive.setStatus(0);
videoArchiveMapper.insert(archive);
// 5. 异步触发转码任务(此处可集成消息队列如RabbitMQ)
// videoConvertService.asyncConvert(archive.getId());
return ApiResponse.success("上传成功", archive.getId());
}
}

b. 视频转码服务:调用FFmpeg进行转码并上传至MinIO。

// VideoConvertService.java
@Service
public class VideoConvertService {
@Value("${archive.video.ffmpeg-path}")
private String ffmpegPath;
@Autowired
private MinioClient minioClient;
@Value("${archive.video.minio.bucket}")
private String bucketName;
public void convertVideo(Long archiveId) {
// 1. 查询档案记录
VideoArchive archive = videoArchiveMapper.selectById(archiveId);
archive.setStatus(1); // 转码中
videoArchiveMapper.updateById(archive);
String originalPath = archive.getOriginalFilePath();
String outputFileName = archiveId + "_converted.mp4";
String outputPath = "/tmp/" + outputFileName;
String coverImagePath = "/tmp/" + archiveId + "_cover.jpg";
try {
// 2. 执行FFmpeg转码命令:转换为H.264编码的MP4,兼容Web播放
String[] convertCmd = {ffmpegPath, "-i", originalPath, "-c:v", "libx264", "-preset", "medium", "-crf", "23", "-c:a", "aac", "-b:a", "128k", outputPath};
Process process = Runtime.getRuntime().exec(convertCmd);
int exitCode = process.waitFor(); // 等待转码完成
if (exitCode != 0) {
throw new RuntimeException("FFmpeg转码失败");
}
// 3. 生成封面图(截取第10秒的画面)
String[] coverCmd = {ffmpegPath, "-i", originalPath, "-ss", "00:00:10", "-vframes", "1", "-q:v", "2", coverImagePath};
Process coverProcess = Runtime.getRuntime().exec(coverCmd);
coverProcess.waitFor();
// 4. 上传转码后视频和封面图到MinIO
minioClient.putObject(PutObjectArgs.builder()
.bucket(bucketName)
.object("videos/" + outputFileName)
.stream(new FileInputStream(outputPath), new File(outputPath).length(), -1)
.build());
archive.setConvertedFilePath("videos/" + outputFileName);
minioClient.putObject(PutObjectArgs.builder()
.bucket(bucketName)
.object("covers/" + archiveId + "_cover.jpg")
.stream(new FileInputStream(coverImagePath), new File(coverImagePath).length(), -1)
.build());
archive.setCoverImagePath("covers/" + archiveId + "_cover.jpg");
// 5. 获取视频时长
String[] durationCmd = {ffmpegPath, "-i", outputPath, "2>&1", "|", "grep", "Duration", "|", "awk", "'{print $2}'", "|", "tr", "-d", ","};
// ... 解析时长并设置到archive
archive.setStatus(2); // 完成
videoArchiveMapper.updateById(archive);
// 6. 清理临时文件
new File(outputPath).delete();
new File(coverImagePath).delete();
} catch (Exception e) {
archive.setStatus(3); // 失败
videoArchiveMapper.updateById(archive);
e.printStackTrace();
}
}
}

四、前端界面开发

前端使用Vue CLI创建项目,并安装Element UI和video.js播放器。

 创建Vue项目
npm install -g @vue/cli
vue create archive-video-frontend
cd archive-video-frontend
npm install element-ui video.js axios

1. 视频上传组件

src/components/UploadVideo.vue中实现:



2. 视频播放与检索组件

使用video.js播放MinIO中的视频(需确保MinIO桶策略为公开或通过预签名URL访问)。检索组件调用后端搜索接口,后端需将数据同步至Elasticsearch。

五、系统部署与优化

1. 使用Nginx配置反向代理与负载均衡

编辑/etc/nginx/nginx.conf,在http块内添加:

upstream backend_servers {
server localhost:8080 weight=1;
可以添加更多后端服务器
}
server {
listen 80;
server_name your_domain.com;  你的域名或IP
location /api/ {
proxy_pass http://backend_servers;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location / {
root /path/to/your/vue/project/dist;  Vue项目构建后的dist目录
index index.html;
try_files $uri $uri/ /index.html;
}
}
 重启Nginx
sudo systemctl restart nginx

2. 关键优化点

  • 转码任务队列化:将VideoConvertService.convertVideo方法改为由消息队列(如RabbitMQ)触发,避免同步处理阻塞请求。
  • MinIO分片上传:对于超大视频文件,使用MinIO SDK的分片上传接口。
  • Elasticsearch索引优化:为archive_number, title, description字段设置合适的分析器,并定期重建索引。
  • 视频流播放:确保转码输出MP4时包含moov atom在文件头部(使用FFmpeg的-movflags faststart参数),以支持HTML5视频的快速加载和拖拽。

六、故障排查与日常维护

  • 转码失败:检查/usr/bin/ffmpeg路径是否正确,以及服务器是否有足够的磁盘空间(df -h)。查看应用日志tail -f logs/application.log
  • 上传文件过大失败:检查Spring Boot的max-file-size配置和Nginx的client_max_body_size指令。
  • MinIO连接失败:检查MinIO服务状态systemctl status minio,以及防火墙是否开放了9000和9001端口。
  • 日常维护:定期清理/data/archive-video/original/目录下的原始文件(可在转码成功并确认后由脚本删除),监控MinIO存储桶容量。

至此,一个具备完整工作流的档案数字化视频系统已部署完成。你可以根据实际业务需求,在此基础上扩展权限管理、水印添加、自动归档等功能。

AI咨询
热线电话

028-85154420

15388110056

全国售前咨询电话

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

微信扫码关注安答联动

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

安答联动档案管理系统