一、环境准备与基础架构搭建
在开始构建茂名档案管理系统之前,我们需要统一开发环境。本系统采用前后端分离架构,后端使用Spring Boot 2.7.x,前端使用Vue 3,数据库选用MySQL 8.0,文件存储使用MinIO。请确保你的电脑已安装JDK 11、Node.js 16和Docker(用于快速启动数据库和文件存储)。
1.1 基础环境检查
我们需要验证基础环境是否就绪。打开终端,依次执行以下命令,确保版本号正常输出:
```bash
java -version
node -v
docker -v
```
1.2 启动数据库与文件存储服务
为了不手动安装MySQL和MinIO,我们使用Docker Compose一键启动。在项目根目录下创建docker-compose.yml文件,并复制以下内容:
```yaml
version: '3.8'
services:
mysql:
image: mysql:8.0
container_name: mm_mysql
environment:
MYSQL_ROOT_PASSWORD: root123
MYSQL_DATABASE: mm_archive
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
minio:
image: minio/minio
container_name: mm_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
volumes:
mysql_data:
minio_data:
```
保存文件后,在终端执行docker-compose up -d。等待约30秒,服务即启动完毕。MySQL端口为3306,MinIO API端口为9000,管理控制台端口为9001。
二、数据库表结构设计
我们需要一张核心表来存储档案的元数据。档案元信息包括标题、档案编号(针对茂名地区编号规则)、归档日期、存储路径等。请在MySQL客户端(如Navicat或DBeaver)连接到本地MySQL,执行以下SQL脚本:
```sql
USE mm_archive;
CREATE TABLE `archive_info` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`archive_no` varchar(50) NOT NULL COMMENT '档案编号',
`title` varchar(200) NOT NULL COMMENT '档案标题',
`category` varchar(50) DEFAULT NULL COMMENT '档案分类',
`file_url` varchar(500) DEFAULT NULL COMMENT '文件存储路径',
`file_name` varchar(200) DEFAULT NULL COMMENT '原始文件名',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_archive_no` (`archive_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='茂名档案管理-档案信息表';
```
三、后端核心功能开发
后端项目我们命名为mm-archive-backend。你可以使用Spring Initializr (https://start.spring.io/) 生成项目,选择Maven、Java 11,依赖勾选Spring Web、Spring Data JPA、MySQL Driver、Lombok。
3.1 补充POM依赖
除了基础依赖,我们需要引入MinIO的Java SDK和Hutool工具包。打开pom.xml,在标签内添加:
```xml
io.minio
minio
8.5.2
cn.hutool
hutool-all
5.8.16
```
3.2 配置文件与实体类
修改src/main/resources/application.yml,填入数据库连接和MinIO配置信息:
```yaml
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:MM_ARCHIVE?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: root
password: root123
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
minio:
endpoint: http://localhost:9000
accessKey: minioadmin
secretKey: minioadmin
bucketName: mm-archives
```
创建实体类ArchiveInfo.java:
```java
package com.mm.archive.entity;
import lombok.Data;
import javax.persistence.;
import java.time.LocalDateTime;
@Data
@Entity
@Table(name = "archive_info")
public class ArchiveInfo {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true, length = 50)
private String archiveNo;
@Column(nullable = false, length = 200)
private String title;
@Column(length = 50)
private String category;
@Column(length = 500)
private String fileUrl;
@Column(length = 200)
private String fileName;
@Column(name = "create_time")
private LocalDateTime createTime;
}
```
3.3 MinIO配置类
为了方便注入MinIO客户端,创建配置类MinioConfig.java:
```java
package com.mm.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();
}
}
```
3.4 业务层与控制层实现
创建Repository接口ArchiveRepository.java:
```java
package com.mm.archive.repository;
import com.mm.archive.entity.ArchiveInfo;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ArchiveRepository extends JpaRepository
{
}
```
创建核心业务ServiceArchiveService.java,包含上传和列表查询逻辑。注意:代码中会自动检查Bucket是否存在,不存在则创建。
```java
package com.mm.archive.service;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import com.mm.archive.config.MinioConfig;
import com.mm.archive.entity.ArchiveInfo;
import com.mm.archive.repository.ArchiveRepository;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.List;
@Service
public class ArchiveService {
@Autowired
private ArchiveRepository archiveRepository;
@Autowired
private MinioClient minioClient;
@Autowired
private MinioConfig minioConfig;
public String upload(MultipartFile file, String title, String category) throws Exception {
// 1. 生成档案编号:MM + 时间戳 + 随机数
String archiveNo = "MM" + System.currentTimeMillis() + IdUtil.randomUUID().substring(0, 4);
String fileName = file.getOriginalFilename();
String objectName = archiveNo + "/" + fileName;
// 2. 上传文件到MinIO
try (InputStream inputStream = file.getInputStream()) {
minioClient.putObject(
PutObjectArgs.builder()
.bucket(minioConfig.getBucketName())
.object(objectName)
.stream(inputStream, file.getSize(), -1)
.contentType(file.getContentType())
.build());
}
// 3. 保存元数据到数据库
ArchiveInfo archive = new ArchiveInfo();
archive.setArchiveNo(archiveNo);
archive.setTitle(title);
archive.setCategory(category);
archive.setFileName(fileName);
archive.setFileUrl(objectName); // 存储对象路径
archive.setCreateTime(LocalDateTime.now());
archiveRepository.save(archive);
return "上传成功,档案编号:" + archiveNo;
}
public List list() {
return archiveRepository.findAll();
}
}
```

创建控制器ArchiveController.java暴露接口:
```java
package com.mm.archive.controller;
import com.mm.archive.entity.ArchiveInfo;
import com.mm.archive.service.ArchiveService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@RestController
@RequestMapping("/api/archive")
@CrossOrigin(origins = "") // 允许前端跨域访问
public class ArchiveController {
@Autowired
private ArchiveService archiveService;
@PostMapping("/upload")
public String upload(@RequestParam("file") MultipartFile file,
@RequestParam("title") String title,
@RequestParam("category") String category) {
try {
return archiveService.upload(file, title, category);
} catch (Exception e) {
e.printStackTrace();
return "上传失败:" + e.getMessage();
}
}
@GetMapping("/list")
public List list() {
return archiveService.list();
}
}
```
四、前端页面交互实现
前端使用Vue 3配合Element Plus组件库,实现文件上传和列表展示。
4.1 项目初始化
在终端执行以下命令创建Vue项目:
```bash
npm create vue@latest mm-archive-frontend
选择默认配置即可
cd mm-archive-frontend
npm install element-plus axios
```
4.2 修改入口文件
修改src/main.js,引入Element Plus:
```javascript
import { createApp } from 'vue'
import App from './App.vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
const app = createApp(App)
app.use(ElementPlus)
app.mount('app')
```
4.3 编写主页面组件
修改src/App.vue,直接在此文件中实现所有逻辑,包含上传表单和数据表格:
```html
茂名档案管理系统 - 实操演示
选择文件
提交归档
{{ new Date(scope.row.createTime).toLocaleString() }}
```
五、系统启动与验证
至此,所有代码已编写完成。我们按照以下顺序启动系统进行验证。
5.1 启动后端服务
在IDEA中打开mm-archive-backend项目,找到包含main方法的主类(通常带有@SpringBootApplication注解),直接运行该类。观察控制台日志,确认Tomcat在8080端口启动成功,且没有报错信息。
5.2 启动前端服务
在终端进入mm-archive-frontend目录,执行:
```bash
npm run dev
```
终端会输出本地访问地址,通常是 http://localhost:5173。
5.3 功能实操验证
打开浏览器访问前端地址。你将看到一个简洁的界面。
步骤1:在“档案标题”输入“茂名市2023年度水利工程建设报告”,选择分类为“科技档案”,点击“选择文件”上传任意一个PDF或图片文件。
步骤2:点击“提交归档”。如果一切正常,右上角会提示“归档成功”,下方的表格会自动刷新,显示刚才录入的数据。
步骤3:为了验证文件确实存储到了MinIO,打开浏览器访问 http://localhost:9001(MinIO控制台),使用minioadmin/minioadmin登录。点击左侧“Buckets”,进入mm-archives桶,你应该能看到以档案编号命名的文件夹下存在刚才上传的文件。