尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
基于Java+SpringBoot+SSM的智慧乡村治理平台系统设计与实战
不想废话直接说结论这类“基于JavaSpringBootSSM的智慧乡村治理平台系统”不是简单的增删改查练习它背后承载的是一整套基层事务管理的业务逻辑从村民信息采集到村务公开、事件上报、工单流转再到数据大屏可视化都是有真实落地场景的。如果你正在做毕业设计、课程设计或者刚入行想找一个能讲清楚“业务技术”闭环的实战项目这套系统算是一个很典型的样本。我花了不少时间把这套系统从零到一完整梳理过一遍源码、设计文档、调试过程都过手了。这篇文章不打算把代码逐行贴出来而是站在“我要自己复现一个同类系统”的角度把技术选型、数据库设计、核心模块拆解、常见避坑经验一次性讲透。尤其是那几个网上资料很少提的“隐形知识点”我会重点标注方便你少走弯路。1. 项目整体设计与思路拆解1.1 智慧乡村治理到底在解决什么问题先想明白业务再写代码。智慧乡村治理平台本质上是要把乡村基层的“人、地、事、物、组织”五类基础要素管起来。我在拆解这个系统的时候最先看的就是它到底覆盖了哪些角色、哪些业务流程。从系统结构来看可以分成四类主要角色角色核心诉求系统对应能力乡镇/村级管理员掌握全村基础数据处理村民上报事项数据管理、事件派单、统计报表网格员日常巡查、问题上报、任务执行移动端上报、任务接收、处理反馈村民反映问题、查看公开信息、查询补贴小程序/Web端自主上报、村务公开浏览系统超级管理员维护系统数据字典、账号权限、日志审计用户管理、权限配置、日志查看这个系统如果只做成“信息登记表”那没有任何价值。真正有价值的是让事件从“上报→受理→派单→处理→反馈→归档”形成闭环。我在看它的功能模块时重点也是看这个闭环通不通畅。1.2 为什么选择SpringBootSSM组合很多初学者看到标题里同时出现SpringBoot和SSM会犯迷糊这俩不是竞争关系吗其实不是。SSM是SpringSpringMVCMyBatis的组合而SpringBoot本身并没有取代SpringMVC和MyBatis它是把这些框架“自动配置化”了。换句话说SpringBoot可以理解为SSM这套组合的“加速器”和“简化器”。这套系统选择SpringBoot作为主框架核心是看中了几点自动配置能力以前SpringMVC要手动配置视图解析器、处理器映射器、JSON转换器SpringBoot通过spring-boot-starter-web一站式搞定开发效率提升非常明显。内置Tomcat不需要单独部署外部容器java -jar直接启动对调试和部署友好。生态整合方便集成MyBatis、Redis、Shiro、JWT这些常用组件基本就是加一个starter的事情。但为什么标题里还能看到SSM三个字因为在很多教材、面试描述、教学项目里大家习惯性把这套“SpringSpringMVCMyBatis”的底层架构叫SSM。很多老系统的改造过程也是从SSM工程逐步迁移到SpringBoot的所以这两个词被放在一起并不矛盾反而代表了项目从传统架构向快速开发演进的一种状态。1.3 单体架构的取舍判断这个系统并没有用微服务而是保持单体架构这点我觉得非常合理。乡村治理平台的用户规模和应用场景决定了它现阶段不需要分布式那一套复杂的技术栈。把用户、角色、权限、村务、事件、报表都放进一个应用里部署简单、调试方便、资源占用低这本身就符合“合适才是最好的”工程原则。我在设计类似系统时也坚持这个原则如果处理量没有到亿级不要为了技术炫技把系统拆成一堆微服务那只会增加维护成本。单体应用配合后续的集群部署和CDN加速已经完全能支撑乡村级应用的负担。2. 核心细节解析与实操要点2.1 数据库设计的核心表结构这套系统的数据库我仔细看了设计上中规中矩但有几个点是新手容易忽视的。先列出核心表再逐个解释设计意图。基础数据类sys_user用户表包含登录账号、密码加密存储、手机号、所属网格、类型管理员/网格员/村民。sys_role与sys_user_role角色表与用户角色关联表实现RBAC基于角色的访问控制模型。village_info村庄基本信息表包括区域编码、人口数、户数、耕地面积、集体经济收入等。villager_info村民信息表包含姓名、身份证号、户籍地址、是否党员、是否低保户、是否退役军人等标签字段。业务流转类event_report事件上报主表包含事件标题、详情、事发地点经纬度、事发时间、紧急程度、上报人、当前状态。event_handle_log事件处理日志表用于跟踪工单每一步的流转情况包括操作人、操作时间、动作内容、下一处理人。work_order工单表从事件派发后生成包含处理人、办理时限、处理结果、满意度评价。公开管理类notice_info村务公告表发布通知、政策解读、财务公开等信息。party_activity党建活动记录具有乡村特色的模块涵盖活动时间、地点、主题、参与人员。统计与配置类data_dict数据字典表统一管理系统里所有下拉选项如事件类型、紧急级别、处理状态。sys_log操作日志表记录关键操作的痕信息用于审计追溯。我特意把小细节说一下身份证号这类字段建议加密存储比如SM4或AES在列表页展示时要脱敏只显示前6位和后4位。很多项目在这个细节上翻车被安全测试一打一个准。2.2 权限模型用的是经典RBAC这个系统在权限上采用了经典RBAC模型也就是“用户-角色-权限”三层划分。我的经验是对于乡村类管理平台用RBAC已经足够不需要引入更重的ABAC基于属性的权限控制。具体实现上超级管理员拥有所有权限负责账号调配和系统配置。乡镇管理员可以管理多个村庄的数据可以分配网格员账号。网格员只能操作自己网格内的数据看到自己处理的事件列表。村民账号只能查看公开数据并且只能上报和查看自己上报的事件。这个权限拦截逻辑我建议通过自定义HandlerInterceptor或者Spring AOP来做而不是在每个Controller里复制粘贴权限判断代码。使用拦截器的话可以把需要登录认证的接口路径统一配置然后通过角色编码做二次校验。如果是SpringBoot项目更推荐直接集成Spring Security或者Shiro但若不想引入太多依赖手写拦截器也是能跑的方案。2.3 接口设计规范与前端适配我看到这类管理系统常见的接口风格是RESTful。对智慧乡村平台这么一套偏管理端的系统接口设计要注意几个点统一返回格式。推荐用统一的Result对象包含code、message、data三个字段。前端axios拦截器里统一判断code不用每次单独处理。分页参数统一。pageNum和pageSize统一起名不要一个接口用current另一个用page这种细节会让前端疯掉。时间类型统一。建议后端全部返回字符串格式yyyy-MM-dd HH:mm:ss避免前端因时区问题显示错乱。从前端适配角度讲这个系统如果要做成移动端H5或者小程序接口要做成完全前后端分离的。很多课程设计项目还停留在服务端渲染页面阶段但真实企业项目很少这么干了。如果把这套题目往深了做可以把Vue3Element Plus的PC管理端和UniApp的村民端小程序作为两个前端项目对接同一套Java后端这样整个项目工作量更大落地性也更强。2.4 前端框架与页面布局方案当然如果完全自己写前端工作量会暴增。不少同学拿到的源码里可能直接用了Thymeleaf模板引擎控制器返回视图名配合Bootstrap或者AdminLTE之类的后台模板。这种方式不是不能用但SpringBoot对前后端分离的支持越来越完善我更倾向在现有代码上做一次升级把前端抽成Vue项目后端只提供JSON接口。页面布局上管理端推荐左侧菜单栏加右侧内容区的方式菜单项一般包括首页概览、人口管理、事件管理、村务公开、党建管理、数据分析、系统设置。村民端如果做小程序则要简化设计核心就是“爆料上报”和“进度查询”两个功能。首页放一个显眼的大按钮“我要上报”点击后选择事件类型、填写描述、上传图片、选择定位提交后进入“我的上报”查看处理进度。这个交互逻辑要尽量简单因为面向的用户群体中很多人对智能手机操作并不熟练这就是我反复强调的“业务驱动设计”。3. 实操过程与核心环节实现3.1 从零搭建SpringBoot项目框架如果你要自己复现项目第一步肯定是搭建工程骨架。我用的是SpringBoot 2.7.x版本这个版本既稳定又兼容大部分教程Java用1.8Maven管理依赖。主pom.xml里最核心的依赖大概是这样parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.7.18/version relativePath/ /parent dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-validation/artifactId /dependency dependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter/artifactId version2.3.2/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency dependency groupIdcom.alibaba/groupId artifactIddruid-spring-boot-starter/artifactId version1.2.20/version /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency /dependencies配置文件application.yml里的几个关键项我也列一下尤其是数据源和MyBatis的配置最容易踩坑。server: port: 8080 spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/smart_village?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai username: root password: yourpassword druid: initial-size: 5 min-idle: 5 max-active: 20 mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.village.entity configuration: map-underscore-to-camel-case: true这里有个细节map-underscore-to-camel-case一定要设为true否则数据库字段user_name没法自动映射到Java属性userName很容易出现查询结果全是null的情况。这种问题非常隐蔽因为代码不报错但页面就是没数据。3.2 后端分层架构的具体落地我在整理这个系统时采用了经典的四层结构Controller层接收前端请求参数校验调用Service层。Service层业务逻辑编写事务控制。Mapper层数据持久层接口加XML映射。Entity层数据库实体映射。具体到事件上报这个核心业务Controller层关键代码大概长这样RestController RequestMapping(/api/event) public class EventReportController { Resource private EventReportService eventReportService; PostMapping(/report) public Result? report(RequestBody Valid EventReportDTO dto) { // 获取当前登录用户从Token中解析 LoginUser loginUser SecurityUtils.getLoginUser(); dto.setReporterId(loginUser.getUserId()); dto.setReporterName(loginUser.getRealName()); return Result.success(eventReportService.submitEvent(dto)); } GetMapping(/page) public Result? page( RequestParam(defaultValue 1) Integer pageNum, RequestParam(defaultValue 10) Integer pageSize, RequestParam(required false) String status, RequestParam(required false) String keyword) { PageResultEventReportVO page eventReportService.queryEventPage(pageNum, pageSize, status, keyword); return Result.success(page); } }Service层里面最核心的是“事件提交流程”它不能只insert一条记录而要同时处理多个表的状态。我一般用Transactional注解来保证原子性同时将事件状态机和通知逻辑写清楚Transactional(rollbackFor Exception.class) public Long submitEvent(EventReportDTO dto) { // 1. 插入事件主表 EventReport event new EventReport(); BeanUtils.copyProperties(dto, event); event.setEventStatus(PENDING); // 待受理 event.setCreateTime(new Date()); eventReportMapper.insert(event); // 2. 根据事发地址自动匹配网格确定默认处理人 GridInfo grid gridInfoMapper.selectByLocation(dto.getLatitude(), dto.getLongitude()); if (grid ! null) { event.setGridId(grid.getId()); event.setHandlerId(grid.getLeaderId()); eventReportMapper.updateHandler(event.getId(), grid.getLeaderId()); } // 3. 写入流程日志 EventHandleLog log new EventHandleLog(); log.setEventId(event.getId()); log.setAction(SUBMIT); log.setOperatorId(dto.getReporterId()); log.setOperatorName(dto.getReporterName()); log.setOperationTime(new Date()); log.setRemark(村民上报事件); eventHandleLogMapper.insert(log); return event.getId(); }注意第2步要完成乡村治理的“网格化”管理自动匹配责任网格是很有价值的功能。如果事件上报时带了经纬度前端通过腾讯地图或高德地图的定位插件获取坐标后传到后端后端通过点在多边形内的判断算法Ray Casting来匹配网格。这个功能虽然做起来不起眼但能让整个系统比普通课设看起来“聪明”一个档次。3.3 数据大屏的统计数据怎么搞很多智慧乡村项目会做一个数据大屏页面展示人口数据、事件统计、党员分布、产业收入等指标。这个页面好看是好看但背后的数据聚合逻辑如果不处理好前端的饼图柱状图也就是花架子。我的方案是创建一个StatisticService专门写SQL聚合查询不要在前端循环几万条记录做统计。举例select idcountEventByType resultTypemap SELECT dict_label AS name, COUNT(*) AS value FROM event_report e LEFT JOIN data_dict d ON e.event_type d.dict_value WHERE e.deleted 0 GROUP BY e.event_type /select如果数据量真的变大还可以给event_report表的event_type和create_time建联合索引提高聚合查询速度。对于乡村级平台这个量级远不到需要引入ES或ClickHouse的地步不要过度设计。3.4 调试文档与讲解演示的准备思路这套系统销售/共享时带了调试文档和讲解演示这点其实很重要。很多项目代码写得再好如果别人跑不起来价值就会大打折扣。我在准备调试文档时通常按这个顺序来写环境准备清单JDK 1.8、Maven 3.6、MySQL 5.7、IDE推荐IDEA。数据库导入步骤如何创建数据库、导入sql脚本、修改连接账号密码。后端启动步骤Maven刷新依赖、配置application.yml、启动Application.java。前端启动步骤npm install、npm run dev如果是前后端分离项目。初始账号密码管理员、网格员、村民三种角色的测试账号。常见启动报错与解决方法比如端口占用、数据库时区问题、依赖下载失败等。讲解演示时的思路建议按照“业务故事线”来走不要直接一上来就点系统管理。可以模拟一个事件村民小王发现村口路灯坏了通过小程序上报网格员接收工单后联系维修队处理处理完成后小王确认评价。这个完整故事线能把系统所有核心功能都串起来比单纯介绍菜单直观得多。4. 常见问题与排查技巧实录4.1 数据库中文乱码问题这个问题在实操中太常见了。明明数据库表结构没问题但页面上中文全是问号。排查路径我已经形成了肌肉记忆先看数据库编码SHOW CREATE DATABASE smart_village;确认是不是utf8mb4。再看连接串确保URL里带了characterEncodingutf8。最后看IDE控制台或者页面编码。提示建议在创建数据库时就一次性指定CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci不要等到有数据了再改改编码往往会出现索引长度超限等衍生问题。4.2 分页查询数据对不上如果自己写了分页SQL而不是用PageHelper很容易出现两个问题一是count查询和list查询条件不一致二是排序字段没有固定导致页间顺序跳动。用PageHelper的话要记得它生效的原理是拦截器必须确保PageHelper.startPage()和紧跟其后的Mapper查询之间没有别的数据库操作否则分页参数会被后面的查询消费掉这就是非常经典的“PageHelper失效”问题。4.3 文件上传路径的坑事件上报通常要上传图片。很多人用SpringBoot时直接写file.transferTo(new File(uploadPath))本地调试没问题一放到服务器上就报路径不存在。原因是服务器上的目标目录未创建。我在这个系统里加了工具方法启动时自动创建目录同时把上传目录配置到application.yml中避免硬编码。还有一点图片访问记得加静态资源映射否则上传成功但前端无法预览图片Configuration public class WebMvcConfig implements WebMvcConfigurer { Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler(/upload/**) .addResourceHandler(file: uploadPath /); } }4.4 跨域问题如果你把前端改成Vue项目单独跑在8081端口后端8080端口那必然遇到跨域报错。解决方式最简单的就是写一个CorsFilter允许本地开发地址访问。生产部署时用Nginx反向代理就不会有跨域问题了。注意allowedOriginPatterns不要用*和allowCredentials(true)同时设置部分浏览器会直接拦截。4.5 权限拦截后前端路由跳转问题如果手写拦截器的话前端请求返回401之后前端需要做两件事一是跳转到登录页二是把当前路由缓存起来登录成功后再跳回原页面。很多项目没做第二步用户体验就很割裂刷新一下又跑到首页了。我在前端封装axios拦截器时是这么处理的service.interceptors.response.use( response { const res response.data if (res.code 401) { router.push({ path: /login, query: { redirect: router.currentRoute.value.fullPath } }) } return res }, error { // 处理网络错误 } )4.6 定时刷新统计大屏数据大屏上的数据如果长期不刷新会被领导质疑“数据不准”。乡村治理平台通常会有定时刷新需求。我建议两种方案一是前端每隔30秒重新拉数据接口实现简单二是后端加定时任务把统计结果缓存到Redis前端直接读缓存减少DB压力。具体业务场景选第一种已经足够——这也能在答辩时作为一个亮点讲出来说明你考虑过数据实时性和并发问题。4.7 部署上线时需要注意的关键点本地跑通只是第一步真正部署会遇到几个高频问题端口被占用用netstat -ano | findstr 8080查占用进程或者直接换server.port。MySQL远程连接失败检查MySQL用户是否限制了host为localhost需要授权远程访问。内存不足如果是1核2G的云服务器JVM默认堆内存可能过大启动时指定-Xms256m -Xmx512m。日志排查这个项目如果接了logback适合通过/logs目录下的日志文件来排查问题部署阶段可以加Spring Boot Actuator的health端点进行智能探测。5. 项目衍生方向与扩展建议如果这套系统只是做出来交差或者应付答辩那前面的内容已经够用了。但如果你希望这个东西真正有价值后面有几个非常自然的扩展方向。5.1 接入物联网设备数据“智慧乡村”四个字如果只有Web端表单填报说实话不太够“智慧”。可以扩展的思路是接入环境监测传感器通过MQTT协议接收温湿度、空气质量、土壤墒情等数据存入时序数据库或者普通MySQL表再在前端用ECharts实时展示曲线。SpringBoot整合MQTT并不难用spring-integration-mqtt或者Eclipse Paho客户端就行。扩展这个模块后整个系统就从“管理平台”进化成了“物联网管理平台”含金量直接上一个台阶。5.2 引入工作流引擎目前的事件处理逻辑是状态机模式写死的在角色固定、流程固定的场景下没有问题。但如果乡镇办事流程经常调整就需要引入工作流引擎了。轻量级可以用Flowable虽然文档不多但一旦跑通流程配置可视化能带来很强的说服力。5.3 数据可视化分析深化目前的大屏只是统计展示。进一步可以加入地理信息可视化比如用Leaflet或Mapbox在地图上绘制网格边界标注每个网格的事件热力图。这个需要准备乡镇的GeoJSON边界数据数据可以从公开的地理信息平台获取。5.4 对接统一身份认证如果你的学校或单位有统一身份认证系统可以用OAuth2或CAS协议对接。现在很多系统都要满足等保要求第三方认证对接也是加分项。6. 从我实际过手经验出发的几点尾声整体过完这套基于JavaSpringBootSSM的智慧乡村治理平台我最大的感受是它不是一个“高大上”的分布式项目但它足够“真”。你能在里面看到真实业务系统的影子RBAC权限、事件闭环流转、数据字典、操作日志、统计聚合——这些东西在任何企业级系统里都会遇到。把这个项目的每个模块研究透比跟风做一个看似很厉害但完全没有业务逻辑的“秒杀系统”对你的提升要大得多。有几个点再强调一遍因为我真的在这些地方栽过跟头数据库编码在项目一开始就固定为utf8mb4后面会省掉一大半乱码问题。MyBatis里map-underscore-to-camel-case这个配置放错位置会导致悄无声息的数据为空排查思路要优先确认配置文件是否生效。分布式事务、微服务那一套现阶段不要硬塞到这种规模的项目里老老实实把事务边界划清楚用Transactional管理好即可。写讲解文档时一定要模拟“用户故事”主线去串功能这比按菜单罗列功能更容易让对方理解系统价值。最后分享一个小技巧如果时间允许把整个项目用Docker重新打包一遍。写一个Dockerfile把后端镜像化再写一个docker-compose.yml把MySQL和后端一键拉起来。这个动作会让你的项目从“能跑”变成“容易跑”在演示和部署环节非常加分。我最初只是为了省事做的后来发现很多评审老师和面试官都对这个环节印象深刻。
RELATED

相关推荐

PLC状态机编程实践:Sysmac Studio自动送料Demo详解

PLC状态机编程实践:Sysmac Studio自动送料Demo详解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/9/9 2:54:46
STM32智能输液监护调控系统:滴速检测与PID闭环控制全解析

STM32智能输液监护调控系统:滴速检测与PID闭环控制全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/9/9 2:54:46
Unity MVVM最小实现:手写BindingContext与ObservableObject

Unity MVVM最小实现:手写BindingContext与ObservableObject

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/9/9 2:49:46
MORE NEWS

更多资讯

📰

RK3588联调诊断实战:从启动链路到外设驱动的全流程排查指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

CMSIS-5源码级拆解:从内核抽象到工程落地的嵌入式开发指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

OpenCode:开源终端AI编程代理,多模型接入与工程化实战指南

最近终端 AI 编程代理(coding agent)圈子里,OpenCode 的热度蹿得很快。好几个群里都在讨论它,有人把它跟 Claude Code、Codex 放在一起对比,有人说它是“开源版 Claude Code”,还有人刚从 Codex 迁过来问我…

📰

专业视频编辑工作流全解析:从素材管理到交付验收

提到 professional editing,很多人首先想到的是一款高级剪辑软件或者复杂的特效插件。但真正把时间花在这一行之后你会发现,“专业编辑”和“会用剪辑软件”之间,差的根本不是某个炫技功能,而是从素材进场到成片交付的全流程掌控能…

📰

视觉语言模型全解析:从原理到部署微调实战

这几年搞AI的,不管你是做CV还是做NLP,几乎都会撞上同一个词:视觉语言模型。从CLIP到LLaVA,再到Qwen-VL、InternVL,每隔几个月就冒出来一个新名字,让人既兴奋又容易懵。这篇文章我想把这些模型放在一起做个系…

📰

AI视觉赋能排水管网智慧运维:从井盖检测到内涝预警

城市里的排水管网,可能是最不像“高科技”的基础设施。它深埋地下,常年被淤泥、油污、树根包裹着,平时没人注意,一下暴雨就原形毕露。作为长期接触智慧城市和AI落地项目的从业者,我在这类项目里最常见到的场景&#xf…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬