本文将指导你从零构建一个符合证券行业标准的数字档案馆系统。该系统采用前后端分离架构,核心功能包括非结构化数据的存储、元数据管理以及证券业务特有的合规性校验。整个技术栈选型均为业界稳定版本,确保生产环境可用。
核心技术栈:
基础环境安装命令:
在开始编码前,请确保服务器已安装JDK 17和Maven。执行以下命令进行快速安装(以CentOS为例):
安装 JDK 17
yum install -y java-17-openjdk java-17-openjdk-devel
验证版本
java -version
安装 Maven 3.8+
wget https://archive.apache.org/dist/maven/maven-3/3.8.6/binaries/apache-maven-3.8.6-bin.tar.gz
tar -zxvf apache-maven-3.8.6-bin.tar.gz -C /usr/local/
export PATH=/usr/local/apache-maven-3.8.6/bin:$PATH
证券档案系统对数据的结构化要求较高,我们需要设计一张核心表来存储档案的元数据。请登录MySQL执行以下SQL脚本初始化数据库。
CREATE DATABASE sec_archive_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE sec_archive_db;
CREATE TABLE sec_archive_record (
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
archive_title VARCHAR(255) NOT NULL COMMENT '档案标题',
security_code VARCHAR(20) NOT NULL COMMENT '证券代码',
report_type VARCHAR(50) NOT NULL COMMENT '报告类型:年报/半年报/公告',
file_path VARCHAR(500) NOT NULL COMMENT '文件在MinIO中的存储路径',
file_size BIGINT DEFAULT 0 COMMENT '文件大小(字节)',
file_hash VARCHAR(64) DEFAULT NULL COMMENT '文件SHA256哈希值,用于防篡改',
uploader VARCHAR(50) DEFAULT 'system' COMMENT '上传人',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
INDEX idx_security_code (security_code),
INDEX idx_create_time (create_time)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='证券档案记录表';
创建Spring Boot项目,配置`pom.xml`引入必要的依赖。请确保包含以下核心依赖项:
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-data-jpa
mysql
mysql-connector-java
8.0.33
io.minio
minio
8.5.7
org.projectlombok
lombok
true
在`src/main/resources/application.yml`中配置数据库连接及MinIO参数。这里假设MinIO与MySQL在同一网络环境下。
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://mysql-server:3306/sec_archive_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: Root@123
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
minio:
endpoint: http://minio-server:9000
accessKey: minioadmin
secretKey: minioadmin
bucketName: sec-archives
为了实现文件的上传与下载,我们需要编写MinIO的配置类和工具类。创建`MinioConfig.java`:

import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@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层。`SecArchiveRecord.java`实体类映射数据库表:
import jakarta.persistence.;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@Entity
@Table(name = "sec_archive_record")
public class SecArchiveRecord {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String archiveTitle;
private String securityCode;
private String reportType;
private String filePath;
private Long fileSize;
private String fileHash;
private String uploader;
private LocalDateTime createTime;
}
编写`ArchiveService.java`处理文件上传逻辑。这里包含自动创建Bucket和计算SHA256的逻辑:
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.messages.Bucket;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import jakarta.transaction.Transactional;
import java.io.InputStream;
import java.security.MessageDigest;
import java.util.List;
@Service
public class ArchiveService {
@Autowired
private MinioClient minioClient;
@Autowired
private SecArchiveRepository repository = repository;
@Value("${minio.bucketName}")
private String bucketName;
@PostConstruct
public void init() {
try {
boolean found = false;
List buckets = minioClient.listBuckets();
for (Bucket b : buckets) {
if (b.name().equals(bucketName)) {
found = true;
break;
}
}
if (!found) {
minioClient.makeBucket(io.minio.MakeBucketArgs.builder().bucket(bucketName).build());
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Transactional
public void uploadArchive(MultipartFile file, String title, String securityCode, String reportType) throws Exception {
// 1. 计算文件哈希
String fileHash = calculateSHA256(file.getInputStream());
// 2. 生成存储路径
String fileName = System.currentTimeMillis() + "_" + file.getOriginalFilename();
String filePath = securityCode + "/" + fileName;
// 3. 上传到MinIO
InputStream inputStream = file.getInputStream();
minioClient.putObject(
PutObjectArgs.builder()
.bucket(bucketName)
.object(filePath)
.stream(inputStream, file.getSize(), -1)
.contentType(file.getContentType())
.build()
);
// 4. 保存元数据到数据库
SecArchiveRecord record = new SecArchiveRecord();
record.setArchiveTitle(title);
record.setSecurityCode(securityCode);
record.setReportType(reportType);
record.setFilePath(filePath);
record.setFileSize(file.getSize());
record.setFileHash(fileHash);
record.setUploader("admin");
repository.save(record);
}
private String calculateSHA256(InputStream is) throws Exception {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] buffer = new byte[8192];
int read;
while ((read = is.read(buffer)) != -1) {
digest.update(buffer, 0, read);
}
byte[] hashBytes = digest.digest();
StringBuilder sb = new StringBuilder();
for (byte b : hashBytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
}
前端使用Vue 3配合Element Plus快速构建档案上传界面。首先安装依赖:
npm create vite@latest sec-archive-frontend -- --template vue
cd sec-archive-frontend
npm install element-plus axios
在`App.vue`中编写上传组件,包含证券代码和报告类型的校验:
选择文件
提交归档
为了实现一键启动,我们在项目根目录创建`docker-compose.yml`文件。该文件将同时启动MySQL、MinIO和后端服务。
version: '3.8'
services:
mysql-server:
image: mysql:8.0
container_name: sec-mysql
environment:
MYSQL_ROOT_PASSWORD: Root@123
MYSQL_DATABASE: sec_archive_db
ports:
- "3306:3306"
volumes:
- mysql-data:/var/lib/mysql
networks:
- sec-net
minio-server:
image: minio/minio:latest
container_name: sec-minio
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: minioadmin
MINIO_ROOT_PASSWORD: minioadmin
ports:
- "9000:9000"
- "9001:9001"
volumes:
- minio-data:/data
networks:
- sec-net
backend-app:
build: ./backend 假设后端代码在backend目录下,且包含Dockerfile
container_name: sec-backend
ports:
- "8080:8080"
depends_on:
- mysql-server
- minio-server
networks:
- sec-net
volumes:
mysql-data:
minio-data:
networks:
sec-net:
driver: bridge
在`backend`目录下创建`Dockerfile`用于构建后端镜像:
FROM maven:3.8.6-openjdk-17-slim AS build
WORKDIR /app
COPY pom.xml .
COPY src ./src
RUN mvn clean package -DskipTests
FROM openjdk:17-slim
WORKDIR /app
COPY --from=build /app/target/.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
最终启动步骤:
将上述所有文件配置完成后,在项目根目录执行以下命令即可启动整个证券数字档案馆系统:
docker-compose up -d --build
启动成功后,访问前端页面(需单独部署前端Nginx或使用`npm run dev`),输入证券代码(如600000)并上传一份PDF年报,系统将自动完成文件存储、哈希计算及元数据入库。通过访问MinIO控制台(http://localhost:9001)可验证文件是否正确存储在对应的Bucket中。