SpringBoot+Vue乡村政府信息管理网站设计与部署实战
发布时间:2026/10/13 21:13:27 锦皓数字建站

乡村政府信息管理网站这个题目我前前后后做了好几个版本从纯 JSP 到前后端分离最后落地到 springboot vue 这套组合上。今天就把整个项目的设计思路、核心代码、部署踩坑完整梳理一遍给正在做类似管理系统的同学一个可参考的模板尤其是计算机专业拿来做毕业设计或者基层单位想搞信息化建设的朋友可以直接照着抄。先说清楚这个系统到底解决什么问题。乡村一级的政府信息管理核心就是三个字管、发、看。管理员要管理用户、发布通知公告、上传政策文件、处理村民的留言反馈村民要能查看到最新的村务信息、政策文件并且能在线上提交意见。如果没有这个网站靠微信群、Excel、电话通知信息分散、传播链长、查询困难更别说留痕存档了。所以这套 springboot乡村政府信息管理网站-vue 项目本质上就是一个面向乡镇村级的轻量级内容管理平台把“信息公开、村民互动、后台管理”这三件套一次性解决。这套技术栈选型非常务实。后端 SpringBoot 负责接口和业务逻辑前端 Vue 负责页面和交互两者通过 JSON 交互非常适合中小型管理系统的场景。我做的是 SpringBoot 2.7 Vue 2 Element UI 的组合这套搭配成熟稳定资料多、坑少特别适合新手入门和毕业设计。下面我从设计到实现把整个项目的每个环节拆开讲。1. 项目整体设计与技术选型思路1.1 为什么选 SpringBoot Vue 这套组合很多第一次做项目的人会纠结到底选 JSP 那套老方案还是前后端分离我的建议是除非学校硬性规定必须用 JSP否则一律走前后端分离。SpringBoot 只负责提供接口Vue 负责渲染页面两边职责清晰。哪怕前端出问题了你不改 Java 代码也能单独调试后端接口用 Postman 测通了前端对接就只是时间问题。SpringBoot 的优势不用多说内置 Tomcat、自动配置、生态完善起步最快。Vue 的生态在中小型后台管理系统里是统治级的Element UI 直接给你拽出一套后台界面表格、表单、分页、弹窗全都是现成的。这两者结合开发效率比传统 JSP 高出不止一倍而且后期维护也要舒服得多。1.2 系统核心模块拆解我按功能把整个系统拆成了六个大模块这也是绝大多数政府信息管理网站的标配系统管理模块用户登录、用户管理、角色权限分配。这是所有后台系统的基础。村务公开模块发布和展示通知公告、村务动态、财务公开等信息。政策文件模块上传和下载政策法规、政府文件支持附件管理。村民互动模块村民在线留言、投诉建议管理员后台回复。信息分类模块对公告、政策等信息进行栏目分类管理方便检索。数据统计看板首页展示信息发布数、访问量、待处理留言数等关键指标。这六个模块跑起来之后网站的基本业务就闭环了。管理员登录后台对各类信息做增删改查村民端访客在网站首页浏览信息提交留言。整个系统用最朴素的角色划分管理员和普通访客也可以扩展村民注册登录不需要复杂的审批流够用即可。1.3 技术选型的几个关键点后端我用了 SpringBoot 2.7.14搭配 MyBatis-Plus 3.5.3。为什么不直接 MyBatis因为 MyBatis-Plus 把单表 CRUD 的 SQL 全都封装好了你只需要在 Mapper 接口继承 BaseMapper就能自动获得 insert、selectById、selectPage 这些方法。对于这种信息管理系统90% 的操作都是单表 CRUD用 MyBatis-Plus 能省掉大量重复工作。认证授权我用的是 JWT 拦截器没有上 Spring Security。原因很简单这个系统的权限模型很简单管理员和普通用户用拦截器校验 token 就足够了。Spring Security 配置繁琐、概念多对于学习者来说理解成本高出问题也难排查。等以后权限模型复杂了再迁移也不迟。前端用了 Vue 2.6.14 Element UI 2.15.6 Axios。Vue 3 虽然更新但 Element UI 对 Vue 2 的支持是最稳定的而且网上现成的后台模板大部分是 Vue 2 写的参考资料多。如果你不是特别想追新Vue 2 绝对是稳妥选择。2. 数据库设计五张核心表撑起整套业务数据库是整个系统的地基设计不好后面全是坑。这个项目我用了一共八张表但真正核心的只有五张用户表、角色表、公告信息表、留言反馈表、文件表。把这五张表的关系理清业务就通了。2.1 用户与角色表设计用户表我放在sys_user核心字段有 id、username、password、real_name、phone、avatar、status、create_time。密码存储用的 BCrypt 加密不是明文。这里特别提醒无论什么项目密码都不能明文存Spring Security 自带的 BCryptPasswordEncoder 拿来即用也可以用 jBCrypt 库。角色表sys_role也没搞复杂就做了 admin 和 user 两种角色。admin 拥有所有权限user 就是普通村民权限可以登录后留言、查看自己的反馈记录。中间不搞 user_role 关联表角色直接用一个字段存在用户表里减少查询复杂度。等以后真有多个角色再拆表。2.2 信息内容类表设计公告信息表cms_article是最核心的表字段包括id、category_id、title、cover_image、content、source、publish_time、view_count、status、create_by。其中 category_id 关联栏目分类表status 控制发布状态0草稿、1已发布view_count 用来记录点击量。留言反馈表cms_feedback字段包括id、user_id、content、reply_content、reply_time、status、create_time。村民提交留言管理员在后台回复回复内容存入 reply_content状态由 wait(待处理) 改为 done(已处理)。政策文件表cms_file其实和公告表类似但多了 file_path 字段用来存上传文件的服务器路径。上传的文件我建议统一放在服务器的一个独立目录下不直接入库数据库只存路径这样数据库体积不会膨胀。分享一下我当时的设计笔记表名用途关键词字段sys_user系统用户username, password, rolecms_category信息栏目分类name, sort_ordercms_article公告/村务/政策文章title, content, statuscms_feedback村民留言反馈content, reply_content, statussys_file附件文件记录file_name, file_path, file_size2.3 建表语句的核心片段直接贴一段我当时用的建表 SQL注意字符集一定要用 utf8mb4不然存生僻字、特殊符号会出乱码CREATE TABLE cms_article ( id bigint NOT NULL AUTO_INCREMENT, category_id bigint DEFAULT NULL COMMENT 栏目ID, title varchar(200) NOT NULL COMMENT 标题, cover_image varchar(500) DEFAULT NULL COMMENT 封面图, content text COMMENT 正文内容, source varchar(100) DEFAULT NULL COMMENT 来源, status tinyint DEFAULT 0 COMMENT 状态0草稿 1已发布, view_count int DEFAULT 0 COMMENT 浏览量, create_by varchar(64) DEFAULT NULL, create_time datetime DEFAULT NULL, update_time datetime DEFAULT NULL, PRIMARY KEY (id) ) ENGINEInnoDB AUTO_INCREMENT1 DEFAULT CHARSETutf8mb4 COMMENT公告/文章信息表;注意create_time和update_time不要用ON UPDATE CURRENT_TIMESTAMP那种复杂机制直接在 MyBatis-Plus 里配置自动填充就可以了代码控制更灵活。3. 后端接口与核心业务实现3.1 SpringBoot 项目初始化我惯用的初始化方式是直接去 Spring 官方脚手架生成一个基础项目依赖选择Spring Web、MySQL Driver、Lombok然后在 pom.xml 里手动加入 MyBatis-Plus 和 JWT 的依赖。手写依赖的好处是你可以很清楚地知道每个包是干什么的。核心依赖如下dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3/version /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt/artifactId version0.9.1/version /dependency dependency groupIdcn.hutool/groupId artifactIdhutool-all/artifactId version5.8.18/version /dependencyHutool 这个工具包强烈推荐里面封装了日期、文件、加密、随机数等一堆常用工具能省下不少写“轮子”的时间。比如生成 token 的工具、MD5 加密工具都是直接调用。3.2 统一返回结果封装前后端分离项目接口返回格式一定要统一。我定义了一个Result类所有接口都返回这个结构{ code: 200, message: 操作成功, data: { ... } }code 为 200 表示成功500 表示业务异常401 表示未登录或 token 过期。前端 axios 拦截器统一处理这些状态码遇到 401 就跳回登录页遇到 500 就弹出错误信息。这样前端逻辑非常干净不用每个页面单独判断。3.3 JWT 登录认证实现登录接口的流程很简单前端传 username 和 password后端根据用户名查用户用 BCrypt 校验密码校验通过后生成 token 返回给前端。前端拿到 token 后存在 localStorage 里每次请求带在 header 的 Authorization 字段上。拦截器负责验证 token。这里要注意拦截器放行的路径列表要配置好。登录接口、首页公开的文章列表接口、文章详情接口都需要放行而用户管理、留言管理等操作必须拦截。我当时就栽过跟头拦截器把静态资源也拦了导致前端拿不到图片后来在配置中加了静态资源放行才解决。public class JwtInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token request.getHeader(Authorization); // 校验token如果无效则抛出401异常 return true; } }3.4 信息发布接口实现细节文章发布接口是典型的保存操作包含字段校验、栏目关联、状态处理三个环节。用 MyBatis-Plus 的save方法即可搞定但要注意标题不能为空长度限制是 200超了会报数据库异常。正文是大字段前端一定要做 XSS 过滤不然用户往 content 里塞一段 script 脚本别人打开页面就会执行脚本这在政府类网站上是绝对不允许的。发布状态要由操作人指定而不是写死为已发布方便存草稿。列表查询接口我加了三个实用的参数keyword 按标题模糊搜索categoryId 按栏目筛选pageNum/pageSize 分页。MyBatis-Plus 的Page对象直接支持public ResultPageArticle pageList(String keyword, Long categoryId, Integer pageNum, Integer pageSize) { LambdaQueryWrapperArticle wrapper new LambdaQueryWrapper(); wrapper.like(StringUtils.isNotBlank(keyword), Article::getTitle, keyword) .eq(categoryId ! null, Article::getCategoryId, categoryId) .eq(Article::getStatus, 1) .orderByDesc(Article::getPublishTime); PageArticle page articleMapper.selectPage(new Page(pageNum, pageSize), wrapper); return Result.success(page); }3.5 文件上传路径处理政策文件上传是乡村门户最常见的功能。我用 Hutool 的FileUtil来处理文件读写配置文件里定义上传目录file: upload-dir: /data/upload/ access-prefix: /uploads/上传接口接收 MultipartFile生成新文件名时间戳随机数保存到磁盘然后把路径返回给前端。这里很多人会踩一个坑本地开发时用 Windows 路径部署到 Linux 服务器时路径分隔符不一样所以我统一用配置文件设置不用写死的路径。另外还要给 Nginx 配一个/uploads/的映射不然前端访问不到文件。4. 前端页面与交互实现4.1 Vue 项目搭建与目录结构前端我依然用 Vue CLI 来创建。创建完项目后第一件事就是装 Element UIvue create village-admin npm install element-ui2.15.6 npm install axios vue-router3 vuex3目录结构我很推荐按模块划分不要所有组件堆在一起src/ ├── api/ # 封装所有接口请求 ├── assets/ # 静态资源 ├── components/ # 公共组件 ├── router/ # 路由配置 ├── store/ # 状态管理 ├── views/ │ ├── home/ # 网站首页村民端 │ ├── article/ # 文章列表/详情页 │ ├── feedback/ # 村民留言区 │ └── admin/ # 后台管理页面 │ ├── Login.vue │ ├── Dashboard.vue │ ├── UserManage.vue │ ├── ArticleManage.vue │ └── FeedbackManage.vue └── utils/ # 工具类request封装等4.2 axios 请求封装前端和后端联调最烦的就是每个组件里都写一遍 axios 的地址和 token。我统一在utils/request.js封装了一个 axios 实例baseURL 设置为/api。为什么用相对路径/api因为部署时我会让 Nginx 把/api开头的请求反向代理到后端 8080 端口前端代码里就不用写死 IP 了搬家换服务器也不用改前端代码。const service axios.create({ baseURL: /api, timeout: 10000 }) service.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers[Authorization] token } return config }) service.interceptors.response.use( response { const res response.data if (res.code ! 200) { this.$message.error(res.message || 请求失败) return Promise.reject(new Error(res.message)) } return res }, error { if (error.response error.response.status 401) { // 跳转登录页 router.push(/login) } return Promise.reject(error) } )4.3 首页信息展示与搜索村民端首页我设计成三个区域顶部导航栏、中部轮播图和公告列表、底部分栏信息。轮播图就是选取置顶的几张封面图公告列表分栏目展示每栏最多显示 8 条点击“更多”进入该栏目的完整列表。搜索功能用到了后端的关键词查询接口。搜索框在前端做一个简单的防抖处理用户停止输入 300ms 后才发请求避免每敲一个字就打一次接口不然服务器压力大。这个细节很多人忽略但对实战项目很重要。4.4 后台管理页面的权限控制后台管理页面通过路由守卫控制访问。在 vue-router 的全局前置守卫里如果访问的是 admin 开头路径则检查 localStorage 是否有 token没有就跳登录页。管理员和普通用户在后端返回的菜单列表不同前端根据角色来控制侧边栏菜单的显示。后台的表格页面我全部用了 Element UI 的el-table组件。文章管理表格的标准做法是第一列为 ID第二列是标题超长省略鼠标悬停显示完整标题第三列是栏目第四列是发布时间第五列是状态最后一列是操作按钮编辑、删除、发布/下架。这里有一个经验删除操作一定要有二次确认弹窗我是用this.$confirm实现的不然误点一下就把数据删了太危险。5. 部署上线与常见问题排查5.1 前后端打包的完整流程后端打包很无脑在项目根目录执行mvn clean package生成target/*.jar把这个 jar 文件丢到服务器上用java -jar village-admin.jar启动就行。但生产环境不建议用这种方式更推荐nohup java -jar village-admin.jar --spring.profiles.activeprod app.log 21 这样即使断开 SSH程序也在后台运行。前端打包更是简单npm run build生成 dist 目录把 dist 下的所有文件复制到 Nginx 配置的 root 目录即可。5.2 Nginx 反向代理配置前后端分离项目部署Nginx 配置是关键。我直接贴出最精简可用的配置server { listen 80; server_name your-domain.com; root /data/dist; index index.html; # 前端路由刷新不404 location / { try_files $uri $uri/ /index.html; } # 后端接口反向代理 location /api/ { proxy_pass http://127.0.0.1:8080/api/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } # 上传文件访问映射 location /uploads/ { alias /data/upload/; } }try_files那行千万别漏Vue 是 SPA 单页应用如果用户直接访问/article/1这种路由Nginx 找不到这个文件会返回 404。加了 try_files 之后就都重定向到 index.html由前端路由接管。5.3 跨域问题解决方案前端开发时本地 dev 服务器和 SpringBoot 后端端口不一致会面临跨域问题。我的习惯是在开发环境用 Vue CLI 的代理解决根本不开启后端跨域这样最干净。在vue.config.js里module.exports { devServer: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } }代理配置后前端请求/api/login时devServer 自动转发到http://localhost:8080/api/login浏览器感知不到跨域。部署时 Nginx 配置同样方式转发所以前端代码不用动。如果你想在后端加跨域配置也有方案但个人不建议因为一旦放开跨域限制所有来源都能调你的接口安全隐患太大。5.4 高频踩坑案例排查表我把实际开发中碰到的坑汇总成一张表直接按图索骥现象原因解决方案前端请求接口返回 404Nginx 没有配置/api代理在 location /api/ 中配置 proxy_pass接口返回 401token 过期或未携带检查 axios 拦截器 header 设置重新登录中文乱码数据库字符集不是 utf8mb4建库指定 utf8mb4连接串加 characterEncodingutf8上传文件后访问 404Nginx 没有映射文件目录增加 location /uploads/ 配置刷新页面变成了 404SPA 路由未配置 try_filesNginx location / 加 try_filesJWT 过期后不跳登录拦截器没有处理 401 状态码在 axios 响应拦截器中统一跳转日期格式显示为 UTC后端没有加格式注解在日期字段上加 JsonFormat(timezoneGMT8)浏览量不增加详情接口没有每次更新 view_count在详情接口中执行 update 语句这里重点说下日期格式问题。Java 序列化 LocalDateTime 默认是 ISO 格式和北京时间差了 8 小时前端的日期全是错的。我统一在application.yml里配置了 Jackson 的日期格式spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8这个配置一步到位。5.5 服务器环境准备清单如果你要部署到云服务器下面这几项是必须提前装好的JDK 8 及以上我用的 JDK 8稳定不死活MySQL 5.7 或 8.0记得初始化数据库导入 SQL 文件Nginx 1.20 以上Redis 非必须我这个项目没用到但如果你加了缓存或验证码就需要装数据库初始化时要注意用source命令导入 SQL 文件或者直接在 Navicat 里运行脚本。导入之前确认数据库字符集否则中文表注释、默认数据会出现乱码。6. 项目实际效果与运营体验6.1 跑通后的真实使用感受系统上线后我拿一个模拟乡镇的数据做了试运行录入了 20 条村务公开公告10 条政策文件模拟了 5 个村民提交留言。整个流程走下来最直接的变化就是“查找信息不用翻聊天记录了”。以前村里发个通知得用微信群转发过期消息被刷走就找不回现在网站有个公告栏目按时间排好随时能打开看后台还有浏览量统计哪个政策大家关注度高一目了然。村民留言模块也很有价值。反馈记录全部留痕管理员处理后村民能在线看到回复内容比原来直接打电话、当面反映更有凭据避免了很多“说了不算、答应了不认”的问题。信息管理网站真正解决的是“信息不对称”和“留痕难”两个痛点。6.2 从技术上还有哪些可以迭代的空间这个项目是个很典型的基础版如果你想继续深入方向非常多。我当时评估后认为下面几个点最值得加也最容易加分数据可视化大屏把公告发布量、留言处理率、村民活跃度做成图表ECharts 直接画放到首页最显眼的位置。村民注册 手机验证码现在只是管理员录入用户真正用起来肯定需要村民自助注册可以用阿里云短信服务或者腾讯云短信。附件类型扩展政策文件目前支持图片和 PDF后续可以增加 DOC、XLS 格式的在线预览。操作日志记录谁在什么时间删了哪条公告全部记录到日志表这是政府网站合规审查的刚需。更细粒度的权限比如乡镇不同科室的管理员只能管理自己的栏目这时权限就复杂了需要上 RBAC 模型。7. 个人经验总结与避坑指南做这个项目前前后后两三个月最大的体会是技术选型真的不要太贪心够用就好。SpringBoot Vue MyBatis-Plus 这套组合做信息管理类系统是绝对的黄金组合。代码量少、结构清晰、资料多无论是新手练手还是真实落地都非常合适。如果你也是第一次写这种全栈项目我建议严格按照这个顺序来推进先设计数据库再写完所有后端接口用 Postman 把每个接口测通再写前端页面。千万不要边写后端边写前端容易两头都乱。我见过太多同学后端的接口还没有稳定就开始调前端结果前端调了半天发现是后端返回的数据格式不对又回头改后端来回折腾心态崩掉。另外一个很实在的建议项目跑通之后一定要完整地走一遍部署流程从打包到放到服务器上启动再到配置 Nginx每一步都记录下来。这一步看起来费时但价值极大。毕业设计答辩或者领导让做演示的时候你直接打开线上地址云服务器一部署随时随地都能展示比在本地演示要专业得多。而且部署过程中遇到的坑比如路径问题、端口占用、内存不足、防火墙拦截全都是面试官最爱问的细节。最后分享一个小技巧上线之前记得在 SpringBoot 的配置里把spring.jpa.show-sql关掉把 MyBatis-Plus 的日志级别调到 warn这样既减少日志输出量也避免把数据库结构暴露出去。前端打包之前去掉 console.log 调试信息体积小一点看起来也更干净。这些细节不复杂但确实能体现一个开发者的工程素养。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。