一、数据库设计与环境初始化
系统采用MySQL 8.0作为核心数据存储,主要用于存储档案元数据。首先需要创建数据库并初始化表结构。请直接执行以下SQL脚本完成数据库搭建。
```sql
CREATE DATABASE IF NOT EXISTS funeral_archive DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE funeral_archive;
CREATE TABLE t_archive (
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
archive_no VARCHAR(64) NOT NULL COMMENT '档案编号,唯一标识',
deceased_name VARCHAR(50) NOT NULL COMMENT '逝者姓名',
id_card VARCHAR(18) NOT NULL COMMENT '身份证号',
archive_type TINYINT NOT NULL DEFAULT 1 COMMENT '档案类型:1-火化证 2-安葬证 3-影像资料',
file_path VARCHAR(255) NOT NULL COMMENT '文件存储在MinIO的路径',
file_name VARCHAR(255) NOT NULL COMMENT '原始文件名',
file_size BIGINT DEFAULT 0 COMMENT '文件大小(字节)',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
creator VARCHAR(50) DEFAULT 'system' COMMENT '创建人',
UNIQUE KEY uk_archive_no (archive_no),
KEY idx_id_card (id_card)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数字档案表';
```
执行完毕后,请确保数据库服务已开启,并记录下数据库连接信息:地址localhost:3306,用户名root,密码123456(请根据实际环境修改,后续配置需保持一致)。
二、对象存储服务MinIO搭建
档案文件(如扫描件、录音、录像)采用MinIO进行私有化部署存储。使用Docker可以快速拉起一个单机实例。请在服务器终端执行以下命令:
```bash
docker run -d \
-p 9000:9000 \
-p 9001:9001 \
--name funeral-minio \
-e "MINIO_ROOT_USER=admin" \
-e "MINIO_ROOT_PASSWORD=admin123456" \
-v /data/minio/data:/data \
minio/minio server /data --console-address ":9001"
```
命令执行后,等待容器启动完成。接下来进行初始化配置:
- 访问控制台:http://服务器IP:9001
- 使用账号
admin / 密码admin123456登录。
- 点击左侧菜单【Buckets】,点击【Create Bucket】,创建名为
funeral-files的存储桶。
- 点击刚创建的桶名,进入【Access Policy】设置,将权限设置为
Public(仅用于开发测试,生产环境请设置为Private并通过PresignedURL访问)。
三、后端核心功能开发
后端使用Spring Boot 3.x + MyBatis Plus构建。首先创建Maven项目,pom.xml核心依赖如下:
```xml
org.springframework.boot
spring-boot-starter-web
com.baomidou
mybatis-plus-spring-boot3-starter
3.5.5
mysql
mysql-connector-java
8.0.33
io.minio
minio
8.5.7
org.projectlombok
lombok
true
```
配置文件application.yml完整配置如下,请务必替换数据库和MinIO的密码:
```yaml
server:
port: 8080
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/funeral_archive?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: root
password: 123456
minio:
endpoint: http://localhost:9000
accessKey: admin
secretKey: admin123456
bucketName: funeral-files
```
接下来编写核心业务代码。首先是实体类Archive.java:
```java
package com.funeral.archive.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class Archive {
@TableId(type = IdType.AUTO)
private Long id;
private String archiveNo;
private String deceasedName;
private String idCard;
private Integer archiveType;
private String filePath;
private String fileName;
private Long fileSize;
private LocalDateTime createTime;
private String creator;
}
```
编写MinIO配置类MinioConfig.java:
```java
package com.funeral.archive.config;
import io.minio.MinioClient;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
@ConfigurationProperties(prefix = "minio")
public class MinioConfig {
private String endpoint;
private String accessKey;
private String secretKey;
private String bucketName;
@Bean
public MinioClient minioClient() {
return MinioClient.builder()
.endpoint(endpoint)
.credentials(accessKey, secretKey)
.build();
}
}
```
核心上传与查询服务ArchiveService.java:
```java
package com.funeral.archive.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.funeral.archive.entity.Archive;
import com.funeral.archive.mapper.ArchiveMapper;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.UUID;
@Service
@RequiredArgsConstructor
public class ArchiveService extends ServiceImpl
{
private final MinioClient minioClient;
private final MinioConfig minioConfig;
public String uploadArchive(MultipartFile file, String deceasedName, String idCard, Integer type) throws Exception {
// 1. 生成唯一文件名
String originalFilename = file.getOriginalFilename();
String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
String fileName = UUID.randomUUID().toString() + suffix;
// 2. 按日期归档目录
String datePath = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
String objectName = datePath + "/" + fileName;
// 3. 上传到MinIO
minioClient.putObject(
PutObjectArgs.builder()
.bucket(minioConfig.getBucketName())
.object(objectName)
.stream(file.getInputStream(), file.getSize(), -1)
.contentType(file.getContentType())
.build()
);
// 4. 保存元数据到数据库
Archive archive = new Archive();
archive.setArchiveNo("ARC-" + System.currentTimeMillis());
archive.setDeceasedName(deceasedName);
archive.setIdCard(idCard);
archive.setArchiveType(type);
archive.setFilePath(objectName);
archive.setFileName(originalFilename);
archive.setFileSize(file.getSize());
archive.setCreateTime(LocalDateTime.now());
archive.setCreator("admin");
save(archive);
return "上传成功,档案编号: " + archive.getArchiveNo();
}
}
```

最后是控制器ArchiveController.java:
```java
package com.funeral.archive.controller;
import com.funeral.archive.entity.Archive;
import com.funeral.archive.service.ArchiveService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@RestController
@RequestMapping("/api/archive")
@RequiredArgsConstructor
public class ArchiveController {
private final ArchiveService archiveService;
@PostMapping("/upload")
public String upload(@RequestParam("file") MultipartFile file,
@RequestParam("deceasedName") String deceasedName,
@RequestParam("idCard") String idCard,
@RequestParam(value = "type", defaultValue = "1") Integer type) {
try {
return archiveService.uploadArchive(file, deceasedName, idCard, type);
} catch (Exception e) {
e.printStackTrace();
return "上传失败: " + e.getMessage();
}
}
@GetMapping("/list/{idCard}")
public List listByIdCard(@PathVariable String idCard) {
return archiveService.lambdaQuery()
.eq(Archive::getIdCard, idCard)
.orderByDesc(Archive::getCreateTime)
.list();
}
}
```
四、前端界面与交互实现
前端使用Vue 3配合Element Plus组件库,实现文件上传和列表展示。在项目根目录执行:
```bash
npm install axios element-plus
```
修改src/main.js引入组件:
```javascript
import { createApp } from 'vue'
import App from './App.vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import axios from 'axios'
const app = createApp(App)
app.use(ElementPlus)
app.config.globalProperties.$http = axios
app.mount('app')
```
编写src/App.vue,实现完整的上传和查询逻辑:
```html
殡仪馆数字档案管理
选择文件
提交归档
查询
下载
```
五、Docker容器化部署
为了实现一键交付,编写docker-compose.yml文件编排MySQL、MinIO和后端应用。首先需要将后端项目打包为Jar包:
```bash
mvn clean package -DskipTests
```
在项目根目录创建docker-compose.yml:
```yaml
version: '3.8'
services:
mysql:
image: mysql:8.0
container_name: funeral-mysql
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: funeral_archive
ports:
- "3306:3306"
volumes:
- ./sql:/docker-entrypoint-initdb.d
minio:
image: minio/minio
container_name: funeral-minio
environment:
MINIO_ROOT_USER: admin
MINIO_ROOT_PASSWORD: admin123456
ports:
- "9000:9000"
- "9001:9001"
command: server /data --console-address ":9001"
volumes:
- minio-data:/data
backend:
image: openjdk:17-jdk-alpine
container_name: funeral-backend
ports:
- "8080:8080"
volumes:
- ./target/funeral-archive-0.0.1-SNAPSHOT.jar:/app.jar
depends_on:
- mysql
- minio
command: ["java", "-jar", "/app.jar"]
volumes:
minio-data:
```
确保将第二步编写的SQL脚本保存为sql/init.sql。最后执行启动命令:
```bash
docker-compose up -d
```
启动后,查看日志确认服务状态:
```bash
docker-compose logs -f backend
```
当看到Started FuneralArchiveApplication字样时,即可访问前端页面进行操作。至此,一套完整的殡仪馆数字档案馆系统已从零搭建完成,实现了档案的安全存储、元数据结构化管理以及Web端的高效交互。