一、基础环境与中间件容器化部署
为了确保系统环境的一致性与易维护性,本方案采用Docker Compose一次性编排部署MySQL数据库、MinIO对象存储和Elasticsearch搜索引擎。请在服务器新建docker-compose.yml文件,并将以下完整配置直接复制粘贴。该配置解决了文件存储、元数据管理及全文检索的核心底座问题。
```yaml
version: '3.8'
services:
MySQL数据库:存储档案元数据
mysql:
image: mysql:8.0
container_name: archive_mysql
environment:
MYSQL_ROOT_PASSWORD: root123456
MYSQL_DATABASE: archive_db
TZ: Asia/Shanghai
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
MinIO对象存储:存储电子原文(PDF、OFD等)
minio:
image: minio/minio:latest
container_name: archive_minio
environment:
MINIO_ROOT_USER: minioadmin
MINIO_ROOT_PASSWORD: minioadmin123
ports:
- "9000:9000"
- "9001:9001"
volumes:
- minio_data:/data
command: server /data --console-address ":9001"
Elasticsearch:用于档案内容的全文检索
elasticsearch:
image: elasticsearch:7.17.10
container_name: archive_es
environment:
- discovery.type=single-node
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
- bootstrap.memory_lock=true
ulimits:
memlock:
soft: -1
hard: -1
ports:
- "9200:9200"
volumes:
- es_data:/usr/share/elasticsearch/data
volumes:
mysql_data:
minio_data:
es_data:
```
保存文件后,执行docker-compose up -d启动所有服务。通过docker ps确认所有容器均为Up状态。MinIO控制台访问地址为http://服务器IP:9001,Elasticsearch验证命令为curl http://localhost:9200。
二、后端核心服务架构搭建
后端采用Spring Boot 3.x作为核心框架,集成MyBatis Plus进行数据持久化。首先通过Spring Initializr生成项目,依赖选择Spring Web、MySQL Driver、Validation。随后手动在pom.xml中追加MinIO和Elasticsearch的依赖坐标。
```xml
org.springframework.boot
spring-boot-starter-web
com.baomidou
mybatis-plus-spring-boot3-starter
3.5.5
io.minio
minio
8.5.7
org.springframework.boot
spring-boot-starter-data-elasticsearch
org.projectlombok
lombok
true
```
在src/main/resources/application.yml中配置数据源、文件存储及ES连接信息。请务必修改url中的IP地址为你的实际服务器IP。
```yaml
server:
port: 8080
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.1.100:3306/archive_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: root
password: root123456
Elasticsearch配置
elasticsearch:
uris: http://192.168.1.100:9200
MinIO自定义配置
minio:
endpoint: http://192.168.1.100:9000
accessKey: minioadmin
secretKey: minioadmin123
bucketName: archive-files
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0
```
接下来创建核心实体类Archive.java,对应数据库表t_archive。该类包含档案的基本元数据。
```java
package com.archive.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("t_archive")
public class Archive {
@TableId(type = IdType.AUTO)
private Long id;
private String title; // 档案题名
private String fileCode; // 档案编号
private String category; // 档案分类
private String fileUrl; // 文件在MinIO的路径
private Long fileSize; // 文件大小
private String contentType; // 文件类型
private LocalDateTime createTime;
}
```
编写MinIO工具类MinioUtil.java,封装文件上传和下载的核心逻辑。这是系统与存储层交互的关键。
```java
@Component
public class MinioUtil {
@Value("${minio.endpoint}")
private String endpoint;
@Value("${minio.accessKey}")
private String accessKey;
@Value("${minio.secretKey}")
private String secretKey;
@Value("${minio.bucketName}")
private String bucketName;
private MinioClient minioClient;
@PostConstruct
public void init() {
this.minioClient = MinioClient.builder()
.endpoint(endpoint)
.credentials(accessKey, secretKey)
.build();
checkBucket();
}
private void checkBucket() {
try {
boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
if (!found) {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
}
} catch (Exception e) {
throw new RuntimeException("MinIO初始化失败", e);
}
}
public String uploadFile(MultipartFile file) throws Exception {
String fileName = System.currentTimeMillis() + "_" + file.getOriginalFilename();
minioClient.putObject(
PutObjectArgs.builder()
.bucket(bucketName)
.object(fileName)
.stream(file.getInputStream(), file.getSize(), -1)
.contentType(file.getContentType())
.build()
);
return fileName; // 返回存储的文件名
}
}
```
三、前端档案管理界面开发

前端使用Vue 3配合Element Plus组件库,实现文件上传列表展示。执行npm create vite@latest archive-frontend -- --template vue创建项目,进入目录后执行npm install element-plus axios。在src/App.vue中编写如下代码:
```html
数字档案馆管理端
拖拽文件到此处或 点击上传
下载
```
四、全文检索与数据同步
数字档案馆的核心在于内容的可检索性。我们需要在文件上传成功后,将元数据同步写入Elasticsearch。创建ArchiveService.java实现双写逻辑。
```java
@Service
public class ArchiveService {
@Autowired
private ArchiveMapper archiveMapper;
@Autowired
private ElasticsearchRestTemplate esTemplate;
@Autowired
private MinioUtil minioUtil;
@Autowired
private RestHighLevelClient client;
// 上传并归档
@Transactional
public void uploadAndArchive(MultipartFile file, String title, String category) throws Exception {
// 1. 上传到MinIO
String fileName = minioUtil.uploadFile(file);
// 2. 保存元数据到MySQL
Archive archive = new Archive();
archive.setTitle(title);
archive.setCategory(category);
archive.setFileUrl(fileName);
archive.setFileSize(file.getSize());
archive.setContentType(file.getContentType());
archive.setCreateTime(LocalDateTime.now());
archive.setFileCode("ARC-" + System.currentTimeMillis());
archiveMapper.insert(archive);
// 3. 写入ES索引
IndexRequest request = new IndexRequest("archive_index");
request.id(archive.getId().toString());
Map
jsonMap = new HashMap<>();
jsonMap.put("title", title);
jsonMap.put("category", category);
jsonMap.put("fileCode", archive.getFileCode());
jsonMap.put("createTime", archive.getCreateTime().toString());
request.source(jsonMap, XContentType.JSON);
client.index(request, RequestOptions.DEFAULT);
}
}
```
对应的Controller层提供API接口,处理前端的请求。注意跨域配置,允许前端访问。
```java
@RestController
@RequestMapping("/api/archive")
@CrossOrigin(origins = "")
public class ArchiveController {
@Autowired
private ArchiveService archiveService;
@Autowired
private MinioUtil minioUtil;
@PostMapping("/upload")
public Map upload(@RequestParam("file") MultipartFile file,
@RequestParam("title") String title) {
Map result = new HashMap<>();
try {
archiveService.uploadAndArchive(file, title, "default");
result.put("code", 200);
result.put("msg", "success");
} catch (Exception e) {
e.printStackTrace();
result.put("code", 500);
result.put("msg", e.getMessage());
}
return result;
}
@GetMapping("/list")
public Map list() {
Map result = new HashMap<>();
result.put("data", archiveService.list());
return result;
}
}
```
五、系统一键打包与运行
为了简化部署,我们将后端打包为Docker镜像。在项目根目录创建Dockerfile。
```dockerfile
FROM openjdk:17-jdk-alpine
VOLUME /tmp
COPY target/archive-system-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
```
在Maven中执行mvn clean package -DskipTests打包。构建镜像命令如下:
```bash
docker build -t archive-app:1.0 .
```
修改docker-compose.yml,将后端服务加入编排,实现一键启动整套系统。
```yaml
在docker-compose.yml的services下追加
backend:
image: archive-app:1.0
container_name: archive_backend
ports:
- "8080:8080"
depends_on:
- mysql
- minio
- elasticsearch
environment:
- SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/archive_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
- SPRING_ELASTICSEARCH_URIS=http://elasticsearch:9200
```