行业资讯
📅 2026/7/16 15:40:17
分享一套锋哥原创的SpringBoot4+Vue3通讯录管理系统
大家好我是Java1234_小锋老师分享一套锋哥原创的SpringBoot4Vue3通讯录管理系统项目介绍随着移动互联网与信息化办公的快速发展个人与组织对联系人信息的高效管理需求日益增长。传统的纸质通讯录或分散的电子表格方式存在检索困难、数据易丢失、难以多人协同和扩展性差等问题。因此设计并实现一套基于B/S架构的通讯录管理系统具有较强的实际应用价值。本文以Spring Boot作为后端核心框架结合MyBatis-Plus完成持久层访问前端采用Vue3与Element Plus构建交互界面数据库选用MySQL认证机制采用JWT构建了一套功能完整的通讯录管理系统。系统实现了用户注册与登录、联系人增删改查、分组管理、收藏联系人、Excel导入导出、个人中心头像上传、资料修改、密码修改、管理员用户管理、首页数据统计图表以及操作日志查询等功能。在数据库设计方面围绕用户、联系人、联系人分组和操作日志四类核心实体完成概念结构设计与逻辑结构设计并给出详细的数据表字段说明。在系统实现方面重点阐述了Spring Boot分层架构、MyBatis-Plus条件构造与分页、Vue3组合式API及前后端分离交互流程。测试结果表明系统功能运行稳定界面交互清晰能够满足日常通讯录管理的基本业务需求。本文的研究与实现过程可为同类中小型信息管理系统的开发提供参考。源码下载链接: https://pan.baidu.com/s/1ylAImSIMkYUc47iTmF2nbA?pwd1234提取码: 1234系统展示核心代码package com.java1234.addressbook.controller; import com.java1234.addressbook.common.Result; import com.java1234.addressbook.common.UserContext; import com.java1234.addressbook.dto.PasswordDTO; import com.java1234.addressbook.entity.User; import com.java1234.addressbook.service.UserService; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; /** * 个人中心控制器 * * author addressbook */ RestController RequestMapping(/api/profile) RequiredArgsConstructor public class ProfileController { private final UserService userService; /** * 获取当前用户信息 */ GetMapping public ResultUser getProfile() { User user userService.getById(UserContext.getUserId()); if (user ! null) { user.setPassword(null); } return Result.success(user); } /** * 更新个人资料 */ PutMapping public ResultVoid updateProfile(RequestBody User user) { user.setId(UserContext.getUserId()); userService.updateProfile(user); return Result.success(资料更新成功, null); } /** * 修改密码 */ PutMapping(/password) public ResultVoid changePassword(RequestBody PasswordDTO dto) { userService.changePassword(UserContext.getUserId(), dto.getOldPassword(), dto.getNewPassword()); return Result.success(密码修改成功, null); } }template div classpage-container !-- 统计卡片 -- el-row :gutter16 classstat-row el-col :span6 div classstat-card blue div classstat-label联系人总数/div div classstat-value{{ stats.contactCount || 0 }}/div el-icon :size40 styleopacity:0.3;position:absolute;right:20px;top:20pxUser //el-icon /div /el-col el-col :span6 div classstat-card green div classstat-label分组数量/div div classstat-value{{ stats.groupCount || 0 }}/div el-icon :size40 styleopacity:0.3;position:absolute;right:20px;top:20pxFolderOpened //el-icon /div /el-col el-col :span6 div classstat-card orange div classstat-label收藏联系人/div div classstat-value{{ stats.starredCount || 0 }}/div el-icon :size40 styleopacity:0.3;position:absolute;right:20px;top:20pxStar //el-icon /div /el-col el-col :span6 div classstat-card purple div classstat-label{{ userStore.isAdmin ? 用户总数 : 我的联系人 }}/div div classstat-value{{ userStore.isAdmin ? (stats.userCount || 0) : (stats.contactCount || 0) }}/div el-icon :size40 styleopacity:0.3;position:absolute;right:20px;top:20pxAvatar //el-icon /div /el-col /el-row !-- 图表区域 -- el-row :gutter16 stylemargin-top:16px el-col :span12 div classchart-card div classchart-title联系人分组分布/div div refpieChartRef styleheight:320px/div /div /el-col el-col :span12 div classchart-card div classchart-title近6个月新增趋势/div div refbarChartRef styleheight:320px/div /div /el-col /el-row !-- 生日提醒 -- div classchart-card stylemargin-top:16px div classchart-title近期生日提醒 (30天内)/div el-table :datastats.birthdays || [] stripe stylewidth:100% el-table-column propname label姓名 min-width120 / el-table-column propmobile label手机号 min-width140 / el-table-column propgroupName label分组 min-width100 / el-table-column label生日 min-width120 template #default{ row } {{ formatDate(row.birthday) }} /template /el-table-column el-table-column propcompany label公司 min-width160 show-overflow-tooltip / /el-table el-empty v-if!stats.birthdays?.length description近期暂无生日提醒 / /div /div /template script setup import { ref, onMounted, onUnmounted } from vue import * as echarts from echarts import dayjs from dayjs import { getDashboard } from /api import { useUserStore } from /store/user const userStore useUserStore() const stats ref({}) const pieChartRef ref() const barChartRef ref() let pieChart null let barChart null /** 格式化日期 */ function formatDate(date) { return date ? dayjs(date).format(YYYY-MM-DD) : } /** 加载统计数据 */ async function loadData() { const res await getDashboard() stats.value res.data renderPieChart(res.data.groupDistribution || []) renderBarChart(res.data.monthlyTrend || []) } /** 渲染饼图 */ function renderPieChart(data) { if (!pieChartRef.value) return pieChart echarts.init(pieChartRef.value) pieChart.setOption({ tooltip: { trigger: item, formatter: {b}: {c} ({d}%) }, legend: { bottom: 0, type: scroll }, color: [#667eea, #11998e, #f5576c, #4facfe, #f093fb, #38ef7d], series: [{ type: pie, radius: [40%, 70%], center: [50%, 45%], itemStyle: { borderRadius: 8, borderColor: #fff, borderWidth: 2 }, label: { show: true, formatter: {b}\n{c}人 }, data: data.length ? data : [{ name: 暂无数据, value: 0 }] }] }) } /** 渲染柱状图 */ function renderBarChart(data) { if (!barChartRef.value) return barChart echarts.init(barChartRef.value) barChart.setOption({ tooltip: { trigger: axis }, grid: { left: 3%, right: 4%, bottom: 3%, containLabel: true }, xAxis: { type: category, data: data.map(d d.month), axisLabel: { rotate: 30 } }, yAxis: { type: value, minInterval: 1 }, series: [{ type: bar, data: data.map(d d.count), barWidth: 40%, itemStyle: { borderRadius: [6, 6, 0, 0], color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ { offset: 0, color: #667eea }, { offset: 1, color: #764ba2 } ]) } }] }) } /** 窗口大小变化时重绘图表 */ function handleResize() { pieChart?.resize() barChart?.resize() } onMounted(() { loadData() window.addEventListener(resize, handleResize) }) onUnmounted(() { window.removeEventListener(resize, handleResize) pieChart?.dispose() barChart?.dispose() }) /script style scoped .stat-row .stat-card { position: relative; overflow: hidden; } /style