ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

SpringBoot+Vue+MySQL社区管理系统源码解析与部署实战

SpringBoot+Vue+MySQL社区管理系统源码解析与部署实战 前阵子折腾了一套中小社区的疫情信息管理系统源码技术栈是 SpringBoot Vue MySQL后端 Java 接口、前端 Vue 页面、MySQL 做持久化三件套齐全拿到手把环境配好就能直接跑起来。这套东西比较适合做毕设、课程设计或者作为社区信息管理的二次开发底子。文章把这套系统的整体结构、前后端核心模块、跑通步骤和踩坑记录都过一遍算是给准备动手的同学一份参考。我分几个部分来写先讲这套系统的整体架构和设计思路再分别拆解后端、前端、数据库的核心实现然后给出从零到一跑起来的完整步骤最后把实操中容易踩的坑汇总成一张问题排查表。内容会写得比较细既有代码层面的说明也有部署层面的经验适合对着源码一起看。1. 项目定位与整体架构思路1.1 这套系统到底解决了什么问题中小社区的信息管理场景有个特点数据量不算大但业务角色杂、状态变化频繁。居民要登记基本信息工作人员要维护每日健康打卡还要记录出入情况特殊人群需要单独跟踪社区公告也要及时通知到人。如果用 Excel 或纸质表格去管这些数据分散、版本混乱、统计困难后期想找某一个人的完整记录要翻好几个文件。这个源码项目的定位就是用一套轻量级 Web 系统把这堆事集中管理起来。居民端能自助登记信息、提交每日健康情况管理端能维护居民档案、审核记录、发布公告、查看统计报表。整体围绕一人一档、每日一报、进出有记录、异常可跟踪这个核心思路来设计信息流闭环清晰没有刻意做得复杂。1.2 为什么选 SpringBoot Vue MySQL 这套组合这个技术组合在国内中小型管理系统里非常主流原因很简单生态成熟、上手门槛适中、招人容易、部署也轻量。SpringBoot 负责后端接口它最大的优势是约定大于配置起步依赖帮你把大部分常用组件都封装好了。你不需要像 SSH 时代那样写一堆 XML 配置几个注解就能把接口暴露出去。MyBatis-Plus 再往上叠一层连基础的 CRUD 都不用写 XML直接调用封装好的方法就行。Vue 负责前端页面核心是组件化和响应式。同一个页面区块可以抽成组件复用数据变了界面自动更新不用自己手动去操作 DOM。配合 Element UI 这套现成的组件库后台管理类的页面基本是拼积木表单、表格、弹窗、菜单都有现成的轮子。MySQL 负责数据存储胜在稳定可靠、资料丰富。中小社区的数据量撑死几十万条记录MySQL 完全扛得住不用上 Redis、MongoDB 这类额外组件增加复杂度。这三个组合在一起的直接好处是拿这套源码跑通一次就能理解一个完整 Web 应用的骨架。前端怎么调接口、后端怎么访问数据库、数据怎么流动整条链路是闭环的对新手特别友好。提示这套系统属于典型的 CRUD 权限 统计类应用技术上没有特别炫的点但胜在结构完整。如果你是想学如何从零搭一个可用系统它的参考价值比单纯学某个框架的高很多。2. 后端工程结构与核心模块实现2.1 SpringBoot 工程的目录划分后端代码的包结构决定了你能不能快速找到想改的地方。这套系统的工程目录大致是src/main/java/com/community/health ├── controller // 接收前端请求返回 JSON 数据 ├── service // 业务逻辑层处理具体的业务规则 ├── mapper // 数据访问层操作数据库表 ├── entity // 实体类对应数据库表结构 ├── config // 配置类注册拦截器、跨域过滤器等 ├── common // 通用工具类、统一返回结果封装 └── HealthApplication.java // SpringBoot 启动入口controller 层只做一件事接收 HTTP 请求、调用 service 层、返回统一格式的结果。不要把业务逻辑堆在 controller 里否则后期改一个业务规则要翻遍所有接口。service 层是核心所有业务规则都在这里处理。比如提交健康登记时要先判断当天是否已经提交过如果重复提交需要给出明确提示这种判断就必须放在 service 层不能指望前端去拦截。entity 层每个类对应一张表字段和表的列一一对应。这里有个细节很多人刚接触时容易忽略表的列名如果是下划线命名比如building_no实体类字段用驼峰命名buildingNo需要在 application.yml 里开启map-underscore-to-camel-case: true否则查询结果映射不上字段全是 null。2.2 核心业务的表结构与接口设计管理系统最重要的就是数据表结构设计直接决定了系统的表达能力。这套系统里几张核心表的设计思路值得说一下。我先用表格梳理一下核心表的作用表名用途关键字段sys_user系统用户管理员、工作人员username、password、roleresident_info居民基本信息档案name、id_card、building_no、unit_no、room_no、phonehealth_record每日健康登记记录resident_id、temperature、symptom、travel_history、statusaccess_record小区出入登记记录resident_id、access_type、access_time、visitor_phonequarantine_info隔离人员专项跟踪信息resident_id、start_date、end_date、quarantine_address、statusnucleic_acid_record核酸采样与结果记录resident_id、test_date、result、organizationnotice_info社区公告信息title、content、publisher_id、publish_timeresident_info表是核心其他业务表基本都通过resident_id关联到它。设计上用了建筑编号加房间号的层级结构通过building_nounit_noroom_no三个字段精确定位一个居民住在哪里这样按楼栋筛选、导出统计都非常方便。health_record里的status字段很典型用状态码表示当前健康状态1 代表正常2 代表异常待关注0 代表未填报。用数字存状态比直接存文字更规范也方便统计聚合。前端展示的时候再通过字典映射成文字标签这是一种非常常见的状态管理玩法。接口设计遵循 RESTful 风格基础路径以/api开头例如POST /api/login // 登录获取 token GET /api/resident/list // 分页查询居民列表 POST /api/resident/save // 新增或修改居民信息 DELETE /api/resident/{id} // 删除居民 GET /api/health/today/statistic // 今日健康打卡统计 POST /api/health/record // 提交健康登记 GET /api/quarantine/list // 隔离人员列表 GET /api/notice/list // 公告列表每个接口返回的数据格式是统一的 JSON 结构包含状态码、消息和数据三个部分{ code: 200, message: 操作成功, data: { total: 186, records: [] } }统一返回格式的好处是前端处理逻辑可以简化为先判断 code 是否为 200不是就直接弹错误提示是就取 data 渲染页面。不需要每个接口单独判断不同的返回结构。2.3 登录认证与权限控制怎么做管理系统的权限控制是逃不掉的需求。这套源码采用的是 JWTJSON Web Token方案核心思路是用户登录成功后后端根据用户信息生成一个带过期时间的 token前端拿到 token 存在本地之后每次请求都在 header 里带上后端用一个拦截器统一校验。实现上关键代码大致是这个思路Component public class JwtInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 放行登录接口 if (request.getRequestURI().contains(/login)) { return true; } String token request.getHeader(Authorization); // 校验 token 的有效性、是否过期 if (token null || !JwtUtil.verify(token)) { response.setStatus(401); return false; } return true; } }拦截器写好后在 config 类里注册拦截路径就生效Configuration public class WebConfig implements WebMvcConfigurer { Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new JwtInterceptor()) .addPathPatterns(/api/**) .excludePathPatterns(/api/login); } }角色权限这块分为管理员和普通工作人员两级。管理员拥有全部权限能管理用户分配工作人员只能操作居民信息登记和健康记录查询。简单的做法是给用户表加一个role字段接口处理前判断当前用户的角色不匹配就直接拒绝。实操建议如果项目只做单机部署或者只服务一个社区权限做成这种轻量级控制就够了不用引入 Spring Security OAuth2 那套重型框架否则反而是负担。3. 前端页面设计与交互细节3.1 Vue 工程结构与路由配置前端工程的标准结构大致是这样src ├── api // 封装 axios 请求统一管理接口地址 ├── assets // 静态资源图片、全局样式 ├── components // 通用组件比如分页、弹窗 ├── router // 路由配置 ├── store // 全局状态管理Vuex ├── views // 页面视图按模块划分 ├── App.vue // 根组件 └── main.js // 入口文件路由是前端跳转的核心。Vue Router 的路由配置比较常规但也需要理解两个概念静态路由和动态路由。静态路由指不依赖用户角色、登录后就能确定的页面比如登录页、首页。动态路由则根据用户权限动态挂载管理员登录后能看到用户管理菜单普通工作人员登录后看不到。实现方式是登录后根据角色生成不同的路由表用router.addRoutes动态追加这个设计贴合不同角色看到不同功能菜单的真实需求。前端路由配置代码大致长这样const routes [ { path: /login, component: () import(/views/Login.vue) }, { path: /dashboard, component: () import(/layout/Layout.vue), redirect: /dashboard/home, children: [ { path: home, component: () import(/views/Dashboard.vue), meta: { title: 数据看板 } }, { path: resident, component: () import(/views/ResidentList.vue), meta: { title: 居民管理 } } ] } ]这里用到了路由懒加载() import(...)这种方式让页面在访问时才加载对应的 JS 文件而不是打包时一次性全部加载。项目小的时候体感不明显但页面多了之后首屏加载速度差距很大属于值得保持的好习惯。3.2 核心页面的实现思路居民信息管理页面是这套系统最典型的 CRUD 页面包含搜索表单、数据表格、新增/编辑弹窗三个部分。搜索表单通过绑定响应式数据、点击查询按钮重新请求列表接口实现。分页是后台管理页面的标配数据表格加上pagination组件切换页码时触发接口重新查询把pageNum和pageSize传给后端。新增和编辑用同一个弹窗组件通过判断是否传入初始数据来决定是新增还是编辑。表单校验用 Element UI 自带的rules规则身份证号格式、手机号格式、必填项校验都在这层做。健康登记页面稍微特殊一点需要处理当天重复提交的逻辑。前端的做法是进入页面时先调用一个查询接口看今天是否已登记如果已登记就把表单禁用展示已经提交的数据没登记就开放表单填写。数据看板页面是这类管理系统的亮点所在。它用 ECharts 渲染图表展示几个关键统计今日打卡人数、异常记录趋势、各楼栋登记人数占比、近七天的登记情况。这个页面虽然难度不大但视觉冲击最强也是评审或展示时最容易被关注的模块。3.3 前后端联调与接口对接前后端分离开发时联调是最容易出问题的环节。这套源码的做法是在vue.config.js里配置代理把前端请求转发到后端服务避免开发环境跨域module.exports { devServer: { port: 8081, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } }开发时的域名是http://localhost:8081前端请求路径写/api/resident/list代理会把请求转发到http://localhost:8080/api/resident/list。这样浏览器里不产生跨域请求前端不用处理跨域后端也不用费劲去配置 CORS联调体验非常顺滑。前端调用接口统一封装在api目录下类似这样import request from /utils/request export function getResidentList(params) { return request({ url: /api/resident/list, method: get, params }) }request模块里统一配置了 axios 实例、请求拦截器自动附加 token和响应拦截器统一处理错误码。这种统一封装的好处是后续切接口地址、换后端地址只需要改一个地方。4. 数据库设计要点与初始化4.1 建库建表与初始化数据数据库是整套系统的地基。拿到源码后建议先认真过一遍 SQL 脚本而不是直接执行完就完事。脚本里包含了建库语句、建表语句和初始数据包括默认的管理员账号。以 MySQL 5.7 或 8.0 为例核心操作是CREATE DATABASE IF NOT EXISTS community_health DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE community_health;建表时几个关键的细节值得注意一是字符集一定要用utf8mb4不要用utf8。utf8在 MySQL 里最多存 3 个字节一些特殊字符无法存储utf8mb4才是完整的 UTF-8 支持。居民信息里有各种生僻字或者特殊符号用了utf8mb4就不会出现写入乱码或报错。二是主键用自增BIGINT就好不要在这里过度设计。中小社区场景没有分布式的需求自增主键简单可靠还方便关联查询。身份证号这类编号字段要注意用VARCHAR而不是BIGINT。身份证号通常以文本形式存储因为可能有前导特征的号码段用数字类型会丢失信息而且身份证号长度超过 BIGINT 的可读极限容易造成精度丢失。4.2 核心业务表的设计细节resident_info表设计上通过几个字段实现精细定位building_no、unit_no、room_no。这样的层级字段设计配合 MySQL 的索引按楼栋统计或筛选时效率很高SQL 写起来也简洁SELECT building_no, COUNT(*) FROM resident_info GROUP BY building_no;health_record表为了应对高频登记在resident_id和create_date上加了联合索引确保查某个人在某个日期的登记记录这个高频查询走索引不扫全表。这类设计属于细节经验数据量小的时候无所谓量大了就是性能和体验的差别。nucleic_acid_record表记录每次检测的机构、时间、结果。设计时要考虑记录追加的特性一次采样对应一条记录居民多次采样就会有同一个人多条记录。查询时用resident_id关联查最近几次的检测结果排序用test_date DESC。提示SQL 脚本里通常还会附带一些测试数据建议保留这些数据。不要因为觉得是脏数据就全部删掉跑通前后端联调时测试数据能帮助你及时发现接口字段对不上的问题。5. 环境搭建与部署运行全流程5.1 后端环境准备与启动先把后端跑起来这是整套系统运行的前置条件。本机需要准备的环境是JDK 8如果源码版本比较新可能需要 JDK 11 或 17以 pom.xml 里的配置为准、Maven 3.6、IDEA 开发工具、MySQL 5.7 或 8.0。第一步是导入数据库脚本用 Navicat 或命令行执行即可mysql -uroot -p community_health.sql第二步是修改后端配置。打开application.yml重点看数据源配置这一块server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/community_health?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalseallowPublicKeyRetrievaltrue username: root password: 123456这里我特别标注两个参数serverTimezoneAsia/Shanghai是为了避免数据库连接时区和本机时区不一致导致的日期时间偏差useSSLfalse是因为本地开发通常不需要走 SSL 加密MySQL 更高版本如果服务端开启了强制 SSL连接时可能报SSL connection error这个参数能直接避免这类报错。第三步是启动后端。IDEA 里直接运行主类HealthApplication.java或者在项目根目录执行mvn clean package java -jar target/community-health.jar启动成功后打开浏览器访问http://localhost:8080/api/login用 GET 请求试一下如果返回 405 表示服务正常因为接口已经收到请求但方法不对如果返回 404 就要检查路径和启动是否报错。5.2 前端环境准备与启动前端的依赖工具是 Node.js 和 npm。安装好 Node.js 后建议在项目根目录执行npm install这一步会安装 package.json 里声明的所有依赖。网络状况不好时可能失败这时可以换成国内镜像源npm config set registry https://registry.npmmirror.com npm install依赖安装完成后启动开发服务器npm run serve启动成功后终端会打印本地访问地址一般是http://localhost:8081。用配置好的管理员账号登录就能看到整套系统的完整页面。5.3 打包部署到服务器开发环境跑通之后如果要部署到服务器前后的处理方式不同。前端执行打包npm run build打包产物会生成在dist目录里面是纯静态文件。后端同样是打包成可执行 jarmvn clean package部署方式这里推荐两种按项目体量选择第一种是简单粗暴前端打包后的dist目录下的文件直接复制到后端工程的src/main/resources/static目录下跟着后端打包进 jar一个 SpringBoot 服务同时提供接口和页面。这种方式适合内部试用、单机部署一台服务器一个 Java 进程搞定一切非常省事。第二种是正式一点的前后端分离部署。后端 jar 跑在 8080 端口前端静态文件放在 Nginx 的 html 目录下Nginx 监听 80 端口把/api路径的请求反向代理到后端的 8080 服务。这种方式更利于后期扩展静态资源由 Nginx 高性能处理后端只专注于接口服务。服务器上跑 jar 包推荐用后台方式启动并记录日志nohup java -jar community-health.jar app.log 21 查看日志用tail -f app.log很多启动问题都能在日志里找到根源。6. 常见问题排查与避坑实录6.1 数据库连接与数据问题现象原因解决方案启动报Access denied for user rootlocalhost用户名或密码错误检查 application.yml 中的 username 和 password注意密码不要带多余空格启动报Unknown database community_health数据库没有创建或名字不一致执行建库语句确认库名与配置完全一致启动报Public Key Retrieval is not allowedMySQL 8.0 的 caching_sha2_password 认证机制JDBC URL 增加allowPublicKeyRetrievaltrue页面中文字乱码数据库字符集或连接字符集配置不当确认建库使用 utf8mb4URL 带characterEncodingutf8查询接口报 SQL 语法错误表字段名与实体类字段不一致开启驼峰映射配置map-underscore-to-camel-case: true数据库连接相关的报错占了整套系统运行问题的很大比例而且往往不是 SQL 本身的问题而是环境参数配置问题。遇到这类报错第一反应不要去改代码优先检查这三个地方账号密码是否正确、库名是否一致、JDBC URL 参数是否完整。6.2 SpringBoot 启动和运行异常SpringBoot 启动失败先看启动日志的最后几行重点看 Caused by 部分那才是根本原因。常见的有几类端口被占用是最简单的一种报错是Port 8080 was already in use。处理方式一个是改配置里的 server.port另一个是找到占用进程干掉。如果这台机器上还有别的服务在用 8080建议把系统端口改成 8081 或 8090。版本兼容性问题比较隐蔽。pom.xml 里 SpringBoot 版本如果过高同时 JDK 版本又是 8可能因为 SpringBoot 高版本要求 JDK 17 而直接启动失败。解决方案是确认 pom.xml 里的父依赖版本配合对应的 JDK 版本。目前网上很多源码用的 SpringBoot 2.7.x对应 JDK 8 是稳妥的组合。依赖冲突也会导致启动异常常表现为某个类找不到或者方法签名不匹配。这种问题处理起来比较烦优先用 IDEA 自带的 Maven 面板看依赖树找到重复依赖后在 pom.xml 里排除冲突项。6.3 Vue 构建和运行问题前端常见的问题是 npm install 卡死或报错。处理思路先清理缓存再装一次npm cache clean --force rm -rf node_modules package-lock.json npm install如果还不行检查 Node.js 版本。Vue 2 的项目用 Node 16、Node 14 这类老版本更稳妥用 Node 20 以上有时候会因为一些依赖包不兼容而失败。开发服务器能启动但页面空白打开浏览器控制台看报错。最常见的两类一类是路由路径问题访问根路径时没有匹配到任何路由一片空白检查路由配置中 path 的写法另一类是 JS 报错通常是某个组件引入路径写错导致编译失败这种在终端里会直接看到编译错误提示。6.4 前后端联调问题联调阶段出现频率最高的是 404 和跨域问题。404 要分清是谁返回的 404。如果浏览器 Network 面板显示请求发出了但响应体是后端风格错误信息说明请求确实到了后端多半是接口路径写错了。如果响应体是 Nginx 或者开发服务器的默认 404 页面说明请求根本没到后端要检查代理配置和后端服务是否在运行。跨域报错在开发环境基本是代理配置没生效导致。检查vue.config.js里 devServer.proxy 配置是否匹配前端的请求前缀。如果前端请求路径没有以/api开头但代理只匹配/api请求就会直接从前端端口发出触发跨域错误。关于登录后请求自动携带 token需要在 axios 请求拦截器中统一设置service.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers[Authorization] token } return config })6.5 部署到服务器之后的常见问题本地跑通部署到服务器后打不开这类问题也不少见。优先级从高到低排查先看防火墙有没有放行对应端口。云服务器不同于家用的路由器开端口控制台的安全组也得放行对应端口服务器本机的firewalld或ufw也要检查。再确认数据库是不是只绑定了本地地址。如果数据库和应用在同一台服务器JDBC URL 写成localhost没问题如果数据库单独一台机器要确认配置的地址正确并且数据库用户权限允许远程访问。MySQL 默认root用户一般只允许本机访问远程连接时需要单独授权。最后看静态资源路径。打包后如果发现图片不显示、样式丢失多半是路径用了绝对路径部署到子目录时找不到资源。建议打包前把publicPath配置成相对路径// vue.config.js module.exports { publicPath: ./ }这样打包出来的静态资源引用都是相对路径不管部署到根路径还是子目录都能正常访问。7. 二次开发与扩展方向7.1 给新手如何快速理解并修改源码拿到源码后建议按照这样的顺序去读先跑通整个项目然后按照前端发起请求 → 后端 controller 接收 → service 处理 → mapper 操作数据库这条链路去追踪一个完整的业务功能。比如跟着管理员新增居民这个操作把前端页面到后端接口到 SQL 执行完整走一遍基本上就理解了这个项目的运行机制。修改功能时的基本原则是先看有没有现成的相似模块复制改。比如要新增一个疫苗接种预约模块就可以参照现有的核酸记录模块表结构、页面、接口都有现成的参照比从零开始写快得多。7.2 给进阶适合扩展的方向这套系统本身是典型的中间型项目扩展空间很大。一是数据可视化当前看板只有基础统计图可以引入更丰富的报表比如按时间段做趋势对比、按楼栋做占比分析前端图表组件用到的 ECharts 扩展能力很足。二是消息通知可以接入短信或微信通知能力比如公告发布时给居民推送通知。这类功能在中小社区场景下有真实需求。三是导入导出社区工作人员手里通常有现成的 Excel 居民台账开发 CSV/Excel 导入功能能显著降低录入成本。后端用 EasyExcel 或者 POI前端下载模板、上传解析这套流程很成熟。四是访问日志和操作审计对管理系统来说操作留痕是刚需可以增加一个简单的操作日志表记录谁在什么时间做了什么操作。我个人在实际操作中的体会是这套项目最值钱的部分不在某一段代码写得多精妙而在它给你提供了一套完整的闭环语义从用户登录、数据录入、审批管理、统计展示到最后部署上线每个环节都能看到实际的产物。跑通它之后再回头看 SpringBoot 官方文档、Vue 官方文档理解深度完全不一样。那些单独学框架时看不懂的配置项放在这样一个真实项目里一下就通了。最后再分享一个小技巧这套系统跑通之后建议自己动手改两个地方一个是把首页的统计接口改成按楼栋维度查询另一个是给居民管理增加一个 Excel 导出按钮。这两个小改动涉及数据库聚合查询、文件流下载、前端文件解析每一个都是实际项目里高频用到、但教程里很少讲透的技能点。改完这两个功能你对这套系统以及这套技术栈的掌握程度会有一个明显的提升。
返回列表