ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

SpringBoot+Vue+微信小程序全栈开发社区医养系统实战

SpringBoot+Vue+微信小程序全栈开发社区医养系统实战 最近在做一个社区医养结合系统的项目发现很多开发者对如何将 Spring Boot 后端与 Vue 前端整合并打包成微信小程序感到困惑。网上的资料要么只讲后端要么只讲前端完整打通全栈流程的实战教程很少。本文将分享一套从零开始的“SpringBoot Vue 微信小程序”社区医养结合系统开发方案包含完整的环境搭建、核心代码、前后端联调以及小程序发布流程。无论你是想学习全栈开发的学生还是需要快速搭建类似系统的开发者都能从本文中找到可复用的代码和清晰的思路。1. 项目背景与核心概念1.1 什么是社区医养结合系统社区医养结合系统顾名思义是服务于社区内老年人群体的综合性服务平台。它旨在将基础的医疗服务与日常的养老照料服务进行数字化整合。传统模式下老人看病、拿药、预约护理需要跑多个地方或打多个电话流程繁琐。本系统通过一个小程序入口为老人或其家属提供线上挂号、健康档案查询、药品配送、护工预约、活动报名等一站式服务同时为社区管理员和医护人员提供高效的后台管理工具。从技术角度看这类系统属于典型的“管理后台 用户端小程序”的B/S架构应用。后端负责核心业务逻辑、数据存储和接口提供前端管理后台负责内容与用户管理微信小程序则作为面向社区居民的轻量级、高触达的交互入口。1.2 技术选型为什么是 SpringBoot Vue 微信小程序Spring Boot (后端)作为Java领域最主流的快速开发框架它简化了配置内嵌了Tomcat服务器能让我们快速搭建起稳定、安全、易于扩展的RESTful API后端。其强大的生态如Spring Security, MyBatis-Plus, Spring Data JPA能完美支撑用户认证、数据持久化、事务管理等复杂业务需求。Vue.js (管理后台前端)Vue以其轻量、渐进式和易上手的特点成为构建单页面应用(SPA)管理后台的首选。配合Element UI或Ant Design Vue等成熟的UI组件库可以极大地提升中后台系统的开发效率实现优雅的交互界面。微信小程序 (用户端)对于社区服务类应用微信小程序拥有无可比拟的优势无需下载安装、即用即走、依托微信巨大的用户基数和高频使用场景。它能以最低的成本触达社区内的老年用户及其家属是服务落地的最佳载体。三者关系Spring Boot 提供数据接口Vue 管理后台和微信小程序作为两个不同的客户端通过 HTTP 请求调用这些接口实现前后端分离的架构。2. 环境准备与项目结构在开始编码前请确保你的开发环境已就绪。版本无需完全一致但建议使用较新的稳定版以避免兼容性问题。2.1 开发环境清单后端环境JDK1.8 或 11推荐11Maven3.6.x 或更高版本IDEIntelliJ IDEA 或 Eclipse数据库MySQL 5.7 或 8.0前端环境 (管理后台)Node.js14.x 或 16.x可从官网下载安装npm 或 yarnNode.js 自带 npmIDEVisual Studio Code 或 WebStorm小程序环境微信开发者工具从微信公众平台下载一个已注册的微信小程序账号用于获取AppID2.2 项目整体结构一个清晰的项目结构是良好开发的开始。我们将创建两个独立的工程。community-medical-care/ ├── server/ # Spring Boot 后端项目 │ ├── src/ │ │ ├── main/ │ │ │ ├── java/com/example/community/ │ │ │ │ ├── controller/ # 控制器接收请求 │ │ │ │ ├── service/ # 业务逻辑层 │ │ │ │ ├── service/impl/ │ │ │ │ ├── mapper/ # MyBatis Mapper 接口 │ │ │ │ ├── entity/ # 实体类对应数据库表 │ │ │ │ ├── dto/ # 数据传输对象 │ │ │ │ ├── vo/ # 视图对象 │ │ │ │ └── config/ # 配置类如跨域、Swagger │ │ │ └── resources/ │ │ │ ├── application.yml # 主配置文件 │ │ │ └── mapper/ # MyBatis XML 文件 │ │ └── test/ │ └── pom.xml # Maven 依赖管理 │ ├── admin-web/ # Vue 管理后台项目 │ ├── public/ │ ├── src/ │ │ ├── api/ # 封装所有后端接口请求 │ │ ├── assets/ # 静态资源 │ │ ├── components/ # 公共组件 │ │ ├── router/ # 路由配置 │ │ ├── store/ # Vuex 状态管理 │ │ ├── views/ # 页面组件 │ │ └── utils/ # 工具函数 │ ├── package.json │ └── vue.config.js # Vue 特定配置 │ └── miniprogram/ # 微信小程序项目 ├── pages/ # 小程序页面 │ ├── index/ # 首页 │ ├── appointment/ # 预约页面 │ └── ... ├── components/ # 小程序自定义组件 ├── utils/ # 工具类如 request.js ├── app.js # 小程序入口文件 ├── app.json # 小程序全局配置 ├── app.wxss # 全局样式 └── project.config.json # 项目配置文件3. 后端开发SpringBoot 核心实现我们使用 Spring Boot 来构建 RESTful API。这里以用户管理和预约挂号两个核心模块为例。3.1 项目初始化与依赖配置使用 Spring Initializr 或 IDEA 创建项目主要依赖包括Spring Web, MyBatis, MySQL Driver, Lombok。pom.xml关键依赖片段dependencies !-- Spring Boot Web -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- MyBatis Plus (简化CRUD) -- dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.2/version /dependency !-- MySQL 驱动 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency !-- Lombok -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency !-- 参数校验 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-validation/artifactId /dependency /dependencies3.2 数据库设计与实体类创建核心表例如用户表sys_user和预约表appointment。-- 用户表 CREATE TABLE sys_user ( id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 主键, username varchar(50) NOT NULL COMMENT 用户名, password varchar(100) NOT NULL COMMENT 密码加密后, nick_name varchar(50) DEFAULT NULL COMMENT 昵称, phone varchar(20) DEFAULT NULL COMMENT 手机号, user_type tinyint(4) NOT NULL DEFAULT 1 COMMENT 用户类型1-居民2-医生3-管理员, avatar varchar(255) DEFAULT NULL COMMENT 头像, create_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, PRIMARY KEY (id), UNIQUE KEY uk_username (username) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT系统用户表; -- 预约挂号表 CREATE TABLE appointment ( id bigint(20) NOT NULL AUTO_INCREMENT, user_id bigint(20) NOT NULL COMMENT 预约用户ID, doctor_id bigint(20) NOT NULL COMMENT 医生ID, appoint_date date NOT NULL COMMENT 预约日期, time_slot varchar(20) NOT NULL COMMENT 时间段如09:00-10:00, status tinyint(4) NOT NULL DEFAULT 0 COMMENT 状态0-待确认1-已确认2-已完成3-已取消, symptoms text COMMENT 症状描述, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_user_id (user_id), KEY idx_doctor_id (doctor_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT预约挂号表;对应的实体类User.javapackage com.example.community.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import java.time.LocalDateTime; Data TableName(sys_user) public class User { TableId(type IdType.AUTO) private Long id; private String username; private String password; private String nickName; private String phone; private Integer userType; // 1-居民2-医生3-管理员 private String avatar; private LocalDateTime createTime; }3.3 核心业务逻辑与接口实现我们实现一个简单的用户注册和预约查询接口。1. Service 层UserService.javapackage com.example.community.service; import com.baomidou.mybatisplus.extension.service.IService; import com.example.community.entity.User; import com.example.community.vo.UserVO; public interface UserService extends IServiceUser { /** * 用户注册 * param user 用户信息 * return 注册后的用户信息脱敏 */ UserVO register(User user); /** * 用户登录 * param username 用户名 * param password 密码 * return JWT Token 或用户信息 */ String login(String username, String password); }2. Controller 层UserController.javapackage com.example.community.controller; import com.example.community.common.Result; import com.example.community.entity.User; import com.example.community.service.UserService; import com.example.community.vo.UserVO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.validation.Valid; RestController RequestMapping(/api/user) Validated public class UserController { Autowired private UserService userService; PostMapping(/register) public ResultUserVO register(Valid RequestBody User user) { // Valid 注解会触发实体类中的校验规则如NotBlank UserVO registeredUser userService.register(user); return Result.success(registeredUser, 注册成功); } PostMapping(/login) public ResultString login(RequestParam String username, RequestParam String password) { String token userService.login(username, password); return Result.success(token, 登录成功); } GetMapping(/{id}) public ResultUserVO getUserInfo(PathVariable Long id) { // 这里省略service调用实际应从数据库或缓存查询 // 返回时注意脱敏不要返回密码等敏感信息 return Result.success(null); } }3. 统一返回对象Result.javapackage com.example.community.common; import lombok.Data; Data public class ResultT { private Integer code; private String msg; private T data; public static T ResultT success(T data) { return success(data, 操作成功); } public static T ResultT success(T data, String msg) { ResultT result new Result(); result.setCode(200); result.setMsg(msg); result.setData(data); return result; } public static T ResultT error(String msg) { return error(500, msg); } public static T ResultT error(Integer code, String msg) { ResultT result new Result(); result.setCode(code); result.setMsg(msg); return result; } }3.4 配置文件与跨域处理application.yml配置数据库和服务器端口server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/community_medical?useUnicodetruecharacterEncodingUTF-8serverTimezoneAsia/Shanghai username: root password: your_password mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 控制台打印SQL生产环境关闭 global-config: db-config: logic-delete-field: deleted # 全局逻辑删除字段名 logic-delete-value: 1 # 逻辑已删除值 logic-not-delete-value: 0 # 逻辑未删除值由于前端Vue和小程序运行在不同端口或域名下需要配置跨域。创建一个配置类package com.example.community.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; Configuration public class CorsConfig { Bean public CorsFilter corsFilter() { CorsConfiguration config new CorsConfiguration(); // 允许所有域名访问生产环境应指定具体前端域名 config.addAllowedOriginPattern(*); // 允许携带cookie config.setAllowCredentials(true); // 允许所有请求方法 config.addAllowedMethod(*); // 允许所有请求头 config.addAllowedHeader(*); // 暴露哪些响应头给前端 config.addExposedHeader(Authorization); UrlBasedCorsConfigurationSource source new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration(/**, config); return new CorsFilter(source); } }4. 前端开发Vue管理后台管理后台使用 Vue CLI 创建并引入 Element Plus 作为UI框架。4.1 项目初始化与基础配置# 在 admin-web 目录下 npm create vuelatest . # 按提示选择配置或使用默认配置 npm install element-plus element-plus/icons-vue npm install axios npm install vue-router4 pinia # 路由和状态管理在main.js中引入 Element Plusimport { createApp } from vue import App from ./App.vue import ElementPlus from element-plus import element-plus/dist/index.css import router from ./router import { createPinia } from pinia const app createApp(App) app.use(ElementPlus) app.use(router) app.use(createPinia()) app.mount(#app)4.2 封装网络请求创建src/utils/request.js使用 axios 封装请求拦截器统一处理 token 和错误。import axios from axios import { ElMessage } from element-plus import router from ../router // 创建axios实例 const service axios.create({ baseURL: http://localhost:8080, // 后端API地址 timeout: 10000 // 请求超时时间 }) // 请求拦截器 service.interceptors.request.use( config { // 从本地存储获取token const token localStorage.getItem(token) if (token) { config.headers[Authorization] Bearer token } return config }, error { console.log(error) return Promise.reject(error) } ) // 响应拦截器 service.interceptors.response.use( response { const res response.data // 假设后端统一返回格式为 { code, msg, data } if (res.code ! 200) { ElMessage.error(res.msg || 请求失败) // 如果是401未授权跳转到登录页 if (res.code 401) { router.push(/login) } return Promise.reject(new Error(res.msg || Error)) } else { return res } }, error { console.log(err error) ElMessage.error(error.message || 网络错误) return Promise.reject(error) } ) export default service4.3 实现用户登录页面创建src/views/Login.vuetemplate div classlogin-container el-card classlogin-card h2社区医养系统 - 管理后台/h2 el-form :modelloginForm :rulesrules refloginFormRef el-form-item propusername el-input v-modelloginForm.username placeholder请输入用户名 prefix-iconUser / /el-form-item el-form-item proppassword el-input v-modelloginForm.password typepassword placeholder请输入密码 prefix-iconLock keyup.enterhandleLogin / /el-form-item el-form-item el-button typeprimary clickhandleLogin :loadingloading stylewidth:100%登录/el-button /el-form-item /el-form /el-card /div /template script setup import { ref, reactive } from vue import { useRouter } from vue-router import { ElMessage } from element-plus import request from /utils/request const router useRouter() const loginFormRef ref() const loading ref(false) const loginForm reactive({ username: , password: }) const rules { username: [{ required: true, message: 请输入用户名, trigger: blur }], password: [{ required: true, message: 请输入密码, trigger: blur }] } const handleLogin () { loginFormRef.value.validate((valid) { if (valid) { loading.value true // 调用后端登录接口 request.post(/api/user/login, null, { params: { username: loginForm.username, password: loginForm.password } }).then(res { // 假设返回的data就是token字符串 localStorage.setItem(token, res.data) ElMessage.success(登录成功) router.push(/) }).catch(() { // 错误已在request拦截器中统一处理 }).finally(() { loading.value false }) } }) } /script style scoped .login-container { display: flex; justify-content: center; align-items: center; height: 100vh; background-color: #f0f2f5; } .login-card { width: 400px; padding: 30px; } h2 { text-align: center; margin-bottom: 30px; color: #409EFF; } /style5. 小程序端开发小程序端使用原生开发或 uni-app 等框架。这里以原生开发为例展示如何调用后端接口。5.1 封装网络请求在小程序根目录创建utils/request.js// utils/request.js const BASE_URL http://localhost:8080 // 后端地址上线需改为HTTPS域名 const request (options) { return new Promise((resolve, reject) { wx.request({ url: BASE_URL options.url, method: options.method || GET, data: options.data || {}, header: { content-type: application/json, Authorization: wx.getStorageSync(token) ? Bearer wx.getStorageSync(token) : }, success(res) { if (res.statusCode 200) { // 假设后端统一返回格式 if (res.data.code 200) { resolve(res.data.data) } else { wx.showToast({ title: res.data.msg || 请求失败, icon: none }) reject(res.data) } } else { reject(res) } }, fail(err) { wx.showToast({ title: 网络错误, icon: none }) reject(err) } }) }) } export default request5.2 实现小程序登录与首页pages/login/login.js// pages/login/login.js import request from ../../utils/request.js Page({ data: { username: , password: }, // 输入框绑定 onUsernameInput(e) { this.setData({ username: e.detail.value }) }, onPasswordInput(e) { this.setData({ password: e.detail.value }) }, // 登录 handleLogin() { const { username, password } this.data if (!username || !password) { wx.showToast({ title: 请输入用户名和密码, icon: none }) return } wx.showLoading({ title: 登录中..., }) request({ url: /api/user/login, method: POST, data: { username, password } }).then(res { // res 是接口返回的 data 字段这里假设是token字符串 wx.setStorageSync(token, res) wx.showToast({ title: 登录成功, icon: success }) // 跳转到首页 wx.switchTab({ url: /pages/index/index, }) }).catch(err { console.error(登录失败:, err) }).finally(() { wx.hideLoading() }) }, // 跳转到注册页 goToRegister() { wx.navigateTo({ url: /pages/register/register, }) } })pages/index/index.wxml首页模板!--pages/index/index.wxml-- view classcontainer view classuser-info wx:if{{userInfo}} image classavatar src{{userInfo.avatar || /images/default-avatar.png}}/image text classnickname{{userInfo.nickName}}您好/text /view view classmenu-grid navigator url/pages/appointment/list classmenu-item image src/images/icon-appointment.png/image text我的预约/text /navigator navigator url/pages/doctor/list classmenu-item image src/images/icon-doctor.png/image text医生团队/text /navigator navigator url/pages/health/record classmenu-item image src/images/icon-health.png/image text健康档案/text /navigator navigator url/pages/medicine/delivery classmenu-item image src/images/icon-medicine.png/image text药品配送/text /navigator /view /view6. 前后端联调与部署6.1 联调关键步骤启动后端在server目录下运行mvn spring-boot:run或直接运行Application主类确保http://localhost:8080可以访问。启动前端管理后台在admin-web目录下运行npm run dev通常运行在http://localhost:5173。配置小程序在微信开发者工具中导入miniprogram项目并在详情 - 本地设置中勾选“不校验合法域名...”仅用于开发。正式上线前必须在小程序管理后台配置 request 合法域名必须是 HTTPS。测试接口使用 Postman 或浏览器直接访问http://localhost:8080/api/user/测试后端接口是否正常。解决跨域确保后端CorsConfig已正确配置允许前端域名。开发阶段可以设置为“*”生产环境务必修改为具体的前端域名。6.2 常见联调问题与解决思路问题现象可能原因解决思路前端请求后端返回 4041. 后端服务未启动。2. 请求URL路径错误。3. 后端Controller未添加RestController或RequestMapping。1. 检查后端控制台日志确认启动成功。2. 对比前端请求URL与后端接口定义。3. 使用 Postman 直接测试后端接口。前端请求报跨域错误 (CORS)后端未配置跨域或配置的允许来源不包含前端地址。1. 检查后端CorsConfig配置。2. 开发环境可临时使用config.addAllowedOriginPattern(“*”)。3. 生产环境配置精确的域名。小程序无法请求本地后端小程序要求请求的域名必须是 HTTPS 且在合法域名列表中。1. 开发阶段在开发者工具中勾选“不校验合法域名”。2. 生产部署将后端API部署到支持HTTPS的服务器并在小程序后台添加该域名。请求成功但数据不对1. 参数传递方式错误如RequestBody与RequestParam混用。2. 后端返回的数据结构不符合前端预期。1. 检查前后端接口文档确认传参方式。2. 在后端打断点或打印日志查看接收到的参数和返回的数据。登录成功后 token 无效1. token 未正确存储或传递。2. 后端 token 验证逻辑有问题。3. token 过期。1. 检查前端 request 拦截器是否将 token 正确放入 header如Authorization: Bearer token。2. 检查后端 Spring Security 或 JWT 过滤器配置。6.3 生产环境部署建议后端使用mvn clean package打包成 jar 文件在服务器上通过java -jar your-app.jar运行。建议使用nohup或 systemd 守护进程并配置 JVM 参数。对于微服务架构可考虑使用 Docker 容器化部署。Vue管理后台运行npm run build生成静态文件在dist目录将其部署到 Nginx 或 Apache 等 Web 服务器上。小程序在微信开发者工具中点击“上传”提交代码审核审核通过后即可发布。确保后端 API 域名已备案且支持 HTTPS。7. 项目扩展与最佳实践7.1 功能扩展方向权限管理引入 Spring Security JWT实现基于角色的接口访问控制RBAC。区分居民、医生、管理员的不同权限。微信登录集成微信小程序官方登录能力获取用户openid和unionid实现一键登录提升用户体验。WebSocket 消息推送用于实现医生接诊通知、药品配送状态实时更新、系统公告等即时消息功能。文件上传集成阿里云 OSS 或腾讯云 COS用于用户上传头像、健康报告图片等。数据可视化在管理后台使用 ECharts 等库展示用户增长、预约趋势、药品销量等统计图表。定时任务使用 SpringScheduled或 Quartz实现自动取消超时未支付的订单、定期生成健康报告等。7.2 工程化最佳实践API 文档使用 Swagger 或 Knife4j 自动生成后端接口文档便于前后端协作。在项目中添加依赖并简单配置即可。参数校验在 Controller 层使用Validated注解和NotBlank、Size等注解对入参进行校验避免无效请求进入业务逻辑。全局异常处理使用ControllerAdvice和ExceptionHandler定义全局异常处理器统一处理业务异常、参数校验异常等并返回友好的错误信息格式。数据库操作使用 MyBatis-Plus 的Service和Mapper层减少大量简单 CRUD 代码。注意复杂查询仍需手写 XML 或注解 SQL。密码安全用户密码切勿明文存储。使用BCryptPasswordEncoder等强哈希算法进行加密。配置分离使用application-dev.yml、application-prod.yml区分开发和生产环境配置通过spring.profiles.active指定激活的环境。日志记录使用 SLF4J Logback 记录详细的业务日志和错误日志便于线上问题排查。关键业务操作如创建订单、修改状态务必记录操作人、时间、前后状态变化。
返回列表