news 2026/7/16 15:40:12

分享一套锋哥原创的SpringBoot4+Vue3通讯录管理系统

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
分享一套锋哥原创的SpringBoot4+Vue3通讯录管理系统

大家好,我是Java1234_小锋老师,分享一套锋哥原创的SpringBoot4+Vue3通讯录管理系统

项目介绍

随着移动互联网与信息化办公的快速发展,个人与组织对联系人信息的高效管理需求日益增长。传统的纸质通讯录或分散的电子表格方式存在检索困难、数据易丢失、难以多人协同和扩展性差等问题。因此,设计并实现一套基于B/S架构的通讯录管理系统具有较强的实际应用价值。本文以Spring Boot作为后端核心框架,结合MyBatis-Plus完成持久层访问,前端采用Vue3与Element Plus构建交互界面,数据库选用MySQL,认证机制采用JWT,构建了一套功能完整的通讯录管理系统。系统实现了用户注册与登录、联系人增删改查、分组管理、收藏联系人、Excel导入导出、个人中心(头像上传、资料修改、密码修改)、管理员用户管理、首页数据统计图表以及操作日志查询等功能。在数据库设计方面,围绕用户、联系人、联系人分组和操作日志四类核心实体完成概念结构设计与逻辑结构设计,并给出详细的数据表字段说明。在系统实现方面,重点阐述了Spring Boot分层架构、MyBatis-Plus条件构造与分页、Vue3组合式API及前后端分离交互流程。测试结果表明,系统功能运行稳定,界面交互清晰,能够满足日常通讯录管理的基本业务需求。本文的研究与实现过程可为同类中小型信息管理系统的开发提供参考。

源码下载

链接: https://pan.baidu.com/s/1ylAImSIMkYUc47iTmF2nbA?pwd=1234
提取码: 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 Result<User> getProfile() { User user = userService.getById(UserContext.getUserId()); if (user != null) { user.setPassword(null); } return Result.success(user); } /** * 更新个人资料 */ @PutMapping public Result<Void> updateProfile(@RequestBody User user) { user.setId(UserContext.getUserId()); userService.updateProfile(user); return Result.success("资料更新成功", null); } /** * 修改密码 */ @PutMapping("/password") public Result<Void> changePassword(@RequestBody PasswordDTO dto) { userService.changePassword(UserContext.getUserId(), dto.getOldPassword(), dto.getNewPassword()); return Result.success("密码修改成功", null); } }
<template> <div class="page-container"> <!-- 统计卡片 --> <el-row :gutter="16" class="stat-row"> <el-col :span="6"> <div class="stat-card blue"> <div class="stat-label">联系人总数</div> <div class="stat-value">{{ stats.contactCount || 0 }}</div> <el-icon :size="40" style="opacity:0.3;position:absolute;right:20px;top:20px"><User /></el-icon> </div> </el-col> <el-col :span="6"> <div class="stat-card green"> <div class="stat-label">分组数量</div> <div class="stat-value">{{ stats.groupCount || 0 }}</div> <el-icon :size="40" style="opacity:0.3;position:absolute;right:20px;top:20px"><FolderOpened /></el-icon> </div> </el-col> <el-col :span="6"> <div class="stat-card orange"> <div class="stat-label">收藏联系人</div> <div class="stat-value">{{ stats.starredCount || 0 }}</div> <el-icon :size="40" style="opacity:0.3;position:absolute;right:20px;top:20px"><Star /></el-icon> </div> </el-col> <el-col :span="6"> <div class="stat-card purple"> <div class="stat-label">{{ userStore.isAdmin ? '用户总数' : '我的联系人' }}</div> <div class="stat-value">{{ userStore.isAdmin ? (stats.userCount || 0) : (stats.contactCount || 0) }}</div> <el-icon :size="40" style="opacity:0.3;position:absolute;right:20px;top:20px"><Avatar /></el-icon> </div> </el-col> </el-row> <!-- 图表区域 --> <el-row :gutter="16" style="margin-top:16px"> <el-col :span="12"> <div class="chart-card"> <div class="chart-title">联系人分组分布</div> <div ref="pieChartRef" style="height:320px"></div> </div> </el-col> <el-col :span="12"> <div class="chart-card"> <div class="chart-title">近6个月新增趋势</div> <div ref="barChartRef" style="height:320px"></div> </div> </el-col> </el-row> <!-- 生日提醒 --> <div class="chart-card" style="margin-top:16px"> <div class="chart-title">近期生日提醒 (30天内)</div> <el-table :data="stats.birthdays || []" stripe style="width:100%"> <el-table-column prop="name" label="姓名" min-width="120" /> <el-table-column prop="mobile" label="手机号" min-width="140" /> <el-table-column prop="groupName" label="分组" min-width="100" /> <el-table-column label="生日" min-width="120"> <template #default="{ row }"> {{ formatDate(row.birthday) }} </template> </el-table-column> <el-table-column prop="company" label="公司" min-width="160" 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>
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/16 15:37:35

TTKWidgetTools与Qt Designer集成指南:可视化拖拽布局技巧

TTKWidgetTools与Qt Designer集成指南&#xff1a;可视化拖拽布局技巧 【免费下载链接】TTKWidgetTools QWidget 自定义控件集合 持续更新中...... 项目地址: https://gitcode.com/gh_mirrors/tt/TTKWidgetTools TTKWidgetTools是一个功能强大的Qt自定义控件集合&#x…

作者头像 李华
网站建设 2026/7/16 15:37:10

图像分割技术:从传统算法到深度学习的演进与应用

1. 图像分割技术全景概览图像分割作为计算机视觉领域的核心技术之一&#xff0c;其发展历程几乎贯穿了整个计算机视觉学科的历史。简单来说&#xff0c;图像分割就是将数字图像划分成多个具有特定语义的区域或对象的过程。这项技术在医疗影像分析、自动驾驶、工业质检等众多领域…

作者头像 李华
网站建设 2026/7/16 15:34:59

百度网盘Mac版性能优化:开源工具实现SVIP级下载体验

百度网盘Mac版性能优化&#xff1a;开源工具实现SVIP级下载体验 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘Mac版蜗牛般的下载速度而…

作者头像 李华
网站建设 2026/7/16 15:34:39

单卡RTX 3090实现LLaMA-3 8B全参微调技术解析

1. 单卡RTX 3090实现LLaMA-3 8B全参微调的技术背景在2023年大语言模型(LLM)快速发展的背景下&#xff0c;模型参数量呈现指数级增长趋势。LLaMA-3 8B作为Meta最新开源的8B参数规模模型&#xff0c;其全参数微调(Full Parameter Fine-tuning)对显存的需求量极大。传统方法中&…

作者头像 李华
网站建设 2026/7/16 15:33:26

OpenCode安装与使用深度指南:终端智能代理层部署详解

1. 项目概述&#xff1a;这不是又一个“装个插件就完事”的教程OpenCode系列教程的第一课&#xff0c;标题叫“安装与使用”&#xff0c;但如果你真把它当成普通IDE扩展来装&#xff0c;十有八九会在5分钟内卡死在终端里&#xff0c;反复敲opencode --help却收不到任何响应&…

作者头像 李华