一、技术栈选型与环境准备
本系统采用前后端分离架构,后端使用Spring Boot 2.7+MyBatis Plus,前端使用Vue 3+Element Plus。在开始编码前,请确保本地已安装以下环境:
- JDK 17:Java开发环境,配置好JAVA_HOME环境变量。
- Maven 3.6+:项目依赖管理工具。
- Node.js 18+:前端运行环境。
- MySQL 8.0:数据存储服务。
- IDE:推荐IntelliJ IDEA(后端)和VS Code(前端)。
二、数据库设计与初始化
首先创建数据库并设计核心表结构。我们需要一张表来存储社保登记证的基础信息及文件存储路径。请在MySQL客户端执行以下SQL脚本:
```sql
CREATE DATABASE IF NOT EXISTS social_archive_db DEFAULT CHARSET utf8mb4;
USE social_archive_db;
CREATE TABLE social_security_archive (
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
company_name VARCHAR(100) NOT NULL COMMENT '企业名称',
social_credit_code VARCHAR(50) NOT NULL UNIQUE COMMENT '统一社会信用代码',
archive_file_name VARCHAR(255) COMMENT '原始文件名',
storage_path VARCHAR(500) NOT NULL COMMENT '服务器存储路径',
file_size BIGINT COMMENT '文件大小(字节)',
upload_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '上传时间',
INDEX idx_credit_code (social_credit_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='社保登记证档案表';
```
三、后端服务搭建与核心功能实现
1. 项目依赖配置
创建Spring Boot项目,在pom.xml中引入必要的依赖。请确保版本号一致以避免冲突:
```xml
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-validation
com.baomidou
mybatis-plus-boot-starter
3.5.3.1
mysql
mysql-connector-java
8.0.33
org.projectlombok
lombok
true
```
2. 核心配置文件
在src/main/resources/application.yml中配置数据库连接及文件上传参数。注意,file.upload-path是文件存储的物理目录,请根据实际情况修改:
```yaml
server:
port: 8080
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/social_archive_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: root
password: 123456 请修改为实际数据库密码
servlet:
multipart:
max-file-size: 50MB
max-request-size: 50MB
file:
upload-path: D:/social_archives/ Windows路径示例,Linux下改为 /var/www/social_archives/
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
```
3. 实体类与数据层
创建实体类SocialSecurityArchive.java,使用Lombok简化代码:
```java
package com.example.social.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class SocialSecurityArchive {
@TableId(type = IdType.AUTO)
private Long id;
private String companyName;
private String socialCreditCode;
private String archiveFileName;
private String storagePath;
private Long fileSize;
private LocalDateTime uploadTime;
}
```

创建Mapper接口ArchiveMapper.java,继承BaseMapper以获得基础CRUD功能:
```java
package com.example.social.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.social.entity.SocialSecurityArchive;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface ArchiveMapper extends BaseMapper
{
}
```
4. 业务控制层实现
编写ArchiveController.java,实现文件上传、列表查询和下载功能。这是核心交互部分,包含文件流处理逻辑:
```java
package com.example.social.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.social.entity.SocialSecurityArchive;
import com.example.social.mapper.ArchiveMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@RestController
@RequestMapping("/api/archive")
public class CorsConfig {
// 此处省略跨域配置代码,实际开发中请使用CorsConfigurationSource配置全局跨域
}
@RestController
@RequestMapping("/api/archive")
@CrossOrigin(origins = "") // 简单跨域处理,生产环境请配置具体域名
public class ArchiveController {
@Value("${file.upload-path}")
private String uploadPath;
@Resource
private ArchiveMapper archiveMapper;
@PostMapping("/upload")
public Map uploadArchive(@RequestParam("file") MultipartFile file,
@RequestParam("companyName") String companyName,
@RequestParam("socialCreditCode") String socialCreditCode) {
Map result = new HashMap<>();
// 校验文件
if (file.isEmpty()) {
result.put("code", 500);
result.put("msg", "文件为空");
return result;
}
try {
// 创建目录
File destDir = new File(uploadPath);
if (!destDir.exists()) {
destDir.mkdirs();
}
// 生成唯一文件名
String originalFilename = file.getOriginalFilename();
String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
String newFileName = UUID.randomUUID().toString() + extension;
String fullPath = Paths.get(uploadPath, newFileName).toString();
// 保存文件
file.transferTo(new File(fullPath));
// 保存数据库记录
SocialSecurityArchive archive = new SocialSecurityArchive();
archive.setCompanyName(companyName);
archive.setSocialCreditCode(socialCreditCode);
archive.setArchiveFileName(originalFilename);
archive.setStoragePath(fullPath);
archive.setFileSize(file.getSize());
archive.setUploadTime(LocalDateTime.now());
archiveMapper.insert(archive);
result.put("code", 200);
result.put("msg", "上传成功");
result.put("data", archive);
} catch (IOException e) {
e.printStackTrace();
result.put("code", 500);
result.put("msg", "上传失败: " + e.getMessage());
}
return result;
}
@GetMapping("/list")
public Map list(@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int size,
@RequestParam(required = false) String keyword) {
Map result = new HashMap<>();
Page pageParam = new Page<>(page, size);
QueryWrapper wrapper = new QueryWrapper<>();
if (keyword != null && !keyword.isEmpty()) {
wrapper.like("company_name", keyword).or().like("social_credit_code", keyword);
}
wrapper.orderByDesc("upload_time");
Page dataPage = archiveMapper.selectPage(pageParam, wrapper);
result.put("code", 200);
result.put("data", dataPage.getRecords());
result.put("total", dataPage.getTotal());
return result;
}
@GetMapping("/download/{id}")
public void downloadFile(@PathVariable Long id, HttpServletResponse response) {
SocialSecurityArchive archive = archiveMapper.selectById(id);
if (archive == null) {
return;
}
File file = new File(archive.getStoragePath());
if (file.exists()) {
try (FileInputStream fis = new FileInputStream(file);
OutputStream os = response.getOutputStream()) {
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(archive.getArchiveFileName(), "UTF-8"));
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
```
四、前端界面开发与交互实现
1. 项目初始化
打开终端,执行以下命令创建Vue 3项目并安装依赖:
```bash
npm create vue@latest social-archive-frontend
cd social-archive-frontend
npm install element-plus axios
```
2. 核心页面代码
修改src/App.vue,实现包含上传弹窗、数据表格和分页的完整界面。这里使用Element Plus组件库快速构建UI:
```html
社保登记证档案管理系统
查询
上传档案
{{ (scope.row.fileSize / 1024).toFixed(2) }} KB
下载
选择文件
取消
确认上传
```
五、功能验证与运行
完成代码编写后,按以下步骤启动系统进行验证:
- 启动后端:在IDEA中运行
SocialApplication主类,确认端口8080启动成功,且MySQL连接正常。
- 启动前端:在终端进入前端项目目录,执行
npm run dev,访问控制台显示的Local地址(通常是 http://localhost:5173)。
- 上传测试:点击“上传档案”,输入企业名称和信用代码,选择一个PDF或图片文件,点击确认上传。
- 查看结果:上传成功后,列表应自动刷新显示刚才上传的记录。点击“下载”按钮,浏览器应能成功下载该文件。