尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

SSM+Vue病人跟踪治疗信息管理系统:从后台权限到文件上传的完整实践

SSM+Vue病人跟踪治疗信息管理系统:从后台权限到文件上传的完整实践 简介病人跟踪治疗信息管理系统采用Spring、SpringMVC、MyBatis后端框架与Vue前端技术构建覆盖管理员、病人及前台访客三类角色包含病例采集、预约管理、核酸检测报告上传、行动轨迹上报、治疗状况跟踪、留言板和在线咨询等模块适合作为Java Web课程设计或毕业设计的完整参考。压缩包内文件总数为835个大小约63.92MB主要包含Java程序源码、Vue组件、JavaScript逻辑、SVG图标、SQL数据库脚本、Word文档、PPT演示稿和操作演示视频前后端结构清晰便于按模块学习与二次开发。项目已经在标准开发环境中亲测运行随包附带的论文文档、PPT和视频能够帮助理解业务设计、展示操作过程并支撑答辩汇报可以看作是一份从代码到文档的完整毕设方案。目前已有235人学习/下载适合需要快速上手SSM整合项目、完成毕业设计或课程设计的计算机专业学生。1. 病人跟踪治疗信息管理系统的定位从 Excel 跟进到全流程线上化企业内部的随访管理通常是从出院登记开始的拿到病人名单后护士在 Excel 里维护病例、预约、核酸报告和行动轨迹信息分散还容易漏。这套病人跟踪治疗信息管理系统SSMVue把“病例采集、预约、治疗状况更新、报告上传”合成一条可追溯的线管理员、医生、病人分别从前台和后台维护自己的数据。后端采用 SpringSpringMVCMyBatis 经典组合前端由 Vue 完成交互数据库落在 MySQL整个项目按毕业设计/课程设计的要求覆盖了前后台模块和演示文档。适合两类人准备答辩、需要快速理清 SSM 项目源码的 Java 学生以及想在不写业务的前提下看一套完整前后端串联思路的 Java 开发者。2. SSM 后台骨架拆解SpringMVC 控制器、MyBatis 映射与角色数据表拿到这份资源的第一件事不是直接打开代码而是先确认依赖版本和.m2仓库里的缓存。SSM 项目最常见的翻车点就是 spring、mybatis、数据库驱动之间的版本错位尤其这套资源把开发环境锁在 JDK1.8、tomcat7、maven3.3.9、mysql5.7依赖版本一旦选错哪怕源码完整也会在启动时报一堆 ClassNotFoundException。2.1 Maven 依赖版本怎么选哪些版本容易相互打架properties maven.compiler.source1.8/maven.compiler.source maven.compiler.target1.8/maven.compiler.target spring.version5.1.9.RELEASE/spring.version /properties dependency groupIdorg.springframework/groupId artifactIdspring-webmvc/artifactId version${spring.version}/version /dependency dependency groupIdorg.springframework/groupId artifactIdspring-jdbc/artifactId version${spring.version}/version /dependency dependency groupIdorg.mybatis/groupId artifactIdmybatis/artifactId version3.4.6/version /dependency dependency groupIdorg.mybatis/groupId artifactIdmybatis-spring/artifactId version1.3.2/version /dependency dependency groupIdcom.alibaba/groupId artifactIddruid/artifactId version1.1.20/version /dependency这段配置里 spring 直接选 5.1.x RELEASE不要为了“求稳”降到 4.x。Spring 5 对 JDK8 的支持已经非常成熟而且RestController、GetMapping这类常用注解在 5.x 里语义更统一答辩时被问到也容易说清。mybatis 3.4.6 和 mybatis-spring 1.3.2 是配套组合mybatis-spring 是用来把 SqlSessionFactoryBean 交给 Spring 容器管理的核心依赖版本差太多会导致 Mapper 扫描不到。druid 作为连接池1.1.20 在 mysql5.7 环境下表现稳定后续要监控 SQL 执行可以直接启用它的 stat 插件。提示Windows 下依赖下载慢时在 maven 的 conf/settings.xml 里配置阿里云 mirror比反复删本地仓库更有效。2.2 资源包里的 .bak 文件是什么包结构与分层职责解压后能看到IndexAsideStatic.vue.bak、BreadCrumbs.vue.bak、IndexHeader.vue.bak、update-password.vue.bak这类备份文件。它们是开发阶段用 vue-element-admin 模板搭建后台布局时IDE 自动生成的备份IndexAsideStatic对应左侧菜单IndexHeader对应顶部导航BreadCrumbs是面包屑update-password是个人中心改密码弹窗。想复用素材时把.bak改回.vue放到 views 对应目录即可但要注意检查里面引用的组件路径是否在当前工程里存在。src/main/java/com/patient ├─ controller # 接收前端请求返回 Result 或跳转页面 ├─ service # 业务接口 ├─ service/impl # 业务实现 ├─ dao # MyBatis Mapper 接口 ├─ entity # 数据库表映射实体 ├─ vo # 页面展示值对象 ├─ config # 拦截器、资源映射配置 src/main/resources ├─ mapper # MyBatis XML ├─ spring-mvc.xml ├─ applicationContext.xml └─ db.properties分层上这就是最常见的四层结构Controller 只做参数接收和结果包装Service 放业务规则DAO 只负责 SQL 交互entity 和表字段一一对应。vo 目录容易被忽略但病人列表要展示的字段往往来自多张表比如病人姓名加账号状态就必须用 vo 承接而不是往 entity 里塞冗余字段。.bak文件在源码包里可以保留不影响编译但建议二次开发时删掉或者移出工程目录避免 IDE 误当成 Vue 组件扫描。2.3 SpringMVC 与 MyBatis 的配置落点SpringMVC 的配置集中在 spring-mvc.xmlMyBatis 的 SqlSessionFactory 也在这里统一声明到容器。context:component-scan base-packagecom.patient.controller / bean idsqlSessionFactory classorg.mybatis.spring.SqlSessionFactoryBean property namedataSource refdataSource/ property namemapperLocations valueclasspath:mapper/*.xml/ property nametypeAliasesPackage valuecom.patient.entity/ /bean bean classorg.mybatis.spring.mapper.MapperScannerConfigurer property namebasePackage valuecom.patient.dao/ /beancomponent-scan 的 base-package 只写 controller 包这是很多 SSM 项目埋雷的地方。如果把 com.patient 整个扫进来Service 会被当成 Controller 二次代理启动时要么报重复 bean要么事务切面失效。mapperLocations 指定 XML 文件路径数据库方言变化时只需要替换这个目录。typeAliasesPackage 让 XML 里写resultTypePatient时不用带全限定路径省去一长串包名。MapperScannerConfigurer 的 basePackage 指向 dao 接口包它会自动为每个接口生成代理实现这也是 MyBatis 面试里常被追问的 MapperProxy 动态代理机制在项目里的实际入口。2.4 后台角色表设计权限只细分到菜单级别表名说明核心字段sys_user登录账号表id、username、password、role、patient_idpatient病人档案id、real_name、phone、id_card、medical_historydoctor医生档案id、name、dept_id、specialty、avatarcategory分类表id、name、sort这套资源里的权限做得比较务实role 字段区分 admin、patient、doctor前端根据 role 渲染不同菜单后端登录后用 session 里的用户信息判断接口访问范围。实际运行流程是病人先注册账号管理员在后台把账号关联到 patient 表医生账号由管理员直接维护。数据库没有单独建权限表所以做 java 毕业设计答辩时重点讲清楚 role 字段如何驱动菜单和接口隔离就够了。想提高完整度可以增加一个 HandlerInterceptor 拦截非登录请求并排除/login、/register和静态资源路径这个点比单纯在 Controller 里反复判断用户状态要高级。3. 病人核心流程的数据链路病例采集、预约防冲突与文件上传这个系统的业务主线很清晰病人登记建档 → 录入病例采集信息 → 发起预约 → 医生确认 → 上传核酸报告和行动轨迹 → 更新治疗状况。顺着这条链路看代码比逐个模块点开更容易理解设计意图。3.1 实体关系到模块表哪张表是主表表名用途需要关注的字段关系说明case_collect病例采集patient_id、symptom、temperature、diagnosis、collect_time多条记录挂在同一个病人下appointment预约管理patient_id、doctor_id、appoint_time、status与 patient、doctor 关联nucleic_report核酸检测报告patient_id、file_url、result、report_time病人上传后由医生查看track_record行动轨迹patient_id、places、longitude、latitude、create_time按日期追加记录treatment_status病人治疗状况patient_id、current_status、submit_time每次状态变更新增一条从表结构看这是一个典型的“主表-从表”模型patient 是主表其他业务表统一用 patient_id 关联。这样设计的好处是查询简单所有模块都用WHERE patient_id ?就能过滤缺点是不适合跨病人的复合统计。status 字段在 appointment 里默认值是 PENDING表示待就诊医生操作后更新为 CONFIRMED完成治疗后置为 FINISHED。治疗状况和预约状态是两套独立状态这里很容易写混业务上允许病人边预约边更新治疗状况两个状态互不阻塞。3.2 病人列表多条件查询的 Mapper 写法后台病人管理页需要支持按姓名、手机号和身份证号模糊搜索常见写法是直接用注解在 Mapper 接口上写 SQL。Select(SELECT u.id, u.username, p.real_name, p.phone, p.id_card, p.medical_history FROM sys_user u LEFT JOIN patient p ON u.patient_id p.id WHERE u.role PATIENT AND (#{keyword} IS NULL OR p.real_name LIKE CONCAT(%, #{keyword}, %)) ORDER BY u.create_time DESC LIMIT #{offset}, #{pageSize}) ListPatientVO selectPatientPage(Param(keyword) String keyword, Param(offset) int offset, Param(pageSize) int pageSize);这里用 LEFT JOIN 而不是 JOIN是因为可能出现账号已经创建、但 patient 档案还没补齐的情况。如果使用内连接这类数据会在列表里莫名消失排查时又很难发现。#{keyword} IS NULL OR这个写法可以让参数为空时跳过过滤条件避免在代码里拼接动态 SQL。LIMIT 的 offset 和 pageSize 分别是从第几条开始取、取多少条前端传的是页码和每页条数Service 层负责把页码转成 offset计算方式是(pageNum - 1) * pageSize。3.3 预约防冲突和状态流转的 Service 处理预约模块最核心的校验是“同一病人同一时间段不能重复预约”这个规则放在 Service 层数据层再加一层兜底约束。public Result createAppointment(AppointmentDTO dto) { if (patientDao.selectById(dto.getPatientId()) null) { return Result.fail(病人不存在); } Appointment query new Appointment(); query.setPatientId(dto.getPatientId()); query.setDoctorId(dto.getDoctorId()); query.setAppointTime(dto.getAppointTime()); int conflictCount appointmentDao.countForConflict(query); if (conflictCount 0) { return Result.fail(该时段已有预约记录请换一个时间); } Appointment appointment new Appointment(); BeanUtils.copyProperties(dto, appointment); appointment.setStatus(PENDING); appointmentDao.insert(appointment); return Result.ok(appointment.getId()); }countForConflict 在 XML 里对应一条SELECT COUNT(*)统计相同 patient_id、doctor_id、appoint_time 的数据条数。这里要注意 DTO 里的 appointTime 通常是前端传来的字符串存入前要统一解析成 java.util.Date否则 MySQL 会按默认格式转换时区不对时容易差 8 小时。BeanUtils.copyProperties 能把 DTO 中同名字段拷贝到实体但两个类字段名不一致时静默跳过所以比较稳妥的做法是先手动 set 必填字段再调用拷贝。状态流转上我一般会加一个updateStatus(id, fromStatus, toStatus)方法用WHERE status PENDING作为条件更新防止并发请求把已取消的预约又重新激活。3.4 核酸报告和行动轨迹的统一上传存储文件上传在这套系统里属于高危模块常见问题是 Windows 路径分隔符、文件名中文乱码、目录不存在。String suffix file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(.)); String fileName UUID.randomUUID().toString().replace(-, ) suffix; String dateFolder LocalDate.now().toString(); String fullPath uploadPath / dateFolder / fileName; File dest new File(fullPath); if (!dest.getParentFile().exists()) { dest.getParentFile().mkdirs(); } file.transferTo(dest);用 UUID 重命名是为了避免用户上传的文件名里带中文和特殊字符在 Tomcat 不同编码环境下出现乱码按日期分目录既方便后续清理过期文件也容易用 Nginx 做静态映射。transferTo 是 SpringMVC 的 MultipartFile 直接落盘方法但一定要先检查父目录否则会报 FileNotFoundException。上传接口还需要做两件事一是后缀白名单校验只允许 jpg、png、pdf防止上传 jsp 文件被容器执行二是限制单文件大小在 spring-mvc.xml 里配置 maxUploadSize不给配置的话默认几 MB 限制会让前端误以为接口没反应。4. Vue 前端对接axios 封装、路由守卫与后台页面复用前端部分不是传统的 JSP而是独立的 Vue 工程。开发时通过 devServer 代理请求到后端 Tomcat构建后把 dist 目录部署到 Nginx 或直接放进 Tomcat 的 webapps 下。4.1 前后台页面和路由映射模块页面路径对应角色前台首页/home游客医生列表/doctor/list游客医疗资讯/news/index游客留言反馈/message/index游客个人中心/user/profile所有登录用户后台管理/admin/indexadmin、doctor在线咨询/consult/index所有登录用户路由设计上后台管理的所有页面统一挂在/admin父路由下子路由按功能模块拆比如病人管理、病例采集、预约管理、核酸报告、行动轨迹、治疗状况、留言板和系统管理。这种父子路由结构最大好处是左侧菜单可以根据children自动生成不用在IndexAsideStatic组件里硬编码菜单新增模块时只需要加一个路由文件和对应页面组件。4.2 axios 实例与统一响应处理前端请求统一走 axios 封装避免每个页面重复写 token 和错误处理。import axios from axios const service axios.create({ baseURL: process.env.VUE_APP_BASE_API, timeout: 15000 }) service.interceptors.request.use( config { const token localStorage.getItem(token) if (token) { config.headers[Authorization] Bearer token } return config }, error Promise.reject(error) ) service.interceptors.response.use( response response.data, error { if (error.response error.response.status 401) { localStorage.removeItem(token) window.location.href /login } return Promise.reject(error) } )baseURL 在开发和构建环境用.env.development、.env.production区分开发环境指向http://localhost:8080生产环境指向实际域名。request 拦截器在每次请求发出前从 localStorage 取 token 并放进 header这样后端可以从 Authorization 里解析用户身份。response 拦截器直接返回 response.data后续页面调用request.get()拿到的就是后端 Result 结构体不用在几十个页面里写response.data.data。401 统一跳转登录页比在每个接口 catch 里重复判断强很多。4.3 路由守卫和角色控制router.beforeEach((to, from, next) { const token localStorage.getItem(token) if (to.meta.requiresAuth !token) { next({ path: /login, query: { redirect: to.fullPath } }) return } if (to.meta.roles) { const role localStorage.getItem(role) if (!to.meta.roles.includes(role)) { next({ path: /403 }) return } } next() })路由的 meta 里声明requiresAuth和roles数组比如后台管理路由写roles: [admin, doctor]前端就是靠这段守卫决定能不能进入页面。这里要注意的是路由守卫只控制页面显示真正的数据权限必须由后端接口校验否则直接请求接口还是能拿到数据。另一个常见坑是 localStorage 里存的角色信息不准确登录时后端返回什么 role 就原样保存但用户修改角色后不会重新刷新刷新页面时必须重新拉取用户信息覆盖一次。4.4 上传核酸报告页面的写法async handleUpload(file) { const formData new FormData() formData.append(file, file) formData.append(patientId, this.patientId) const res await request({ url: /nucleic/upload, method: post, data: formData, headers: { Content-Type: multipart/form-data } }) if (res.code 200) { this.$message.success(核酸报告已上传) this.loadReportList() } }FormData 是浏览器内置对象file 必须通过append放进表单数据集后端用RequestParam(file) MultipartFile file接收参数名要严格对上。patientId 也放在同一个 FormData 里比拼在 URL 上更安全也避免 URL 长度限制。上传成功后再调用 loadReportList 重新拉取列表页面展示的是包含 fileUrl 的报告记录前端用img或a标签预览时fileUrl 指向/upload/日期/UUID.jpg这种路径。5. 部署验证与答辩细节批处理脚本、MySQL 初始化与 Nginx 优化资源包里带1-install.bat、2-run.bat、3-build.bat三个脚本顺序一般是先初始化后端依赖再跑前端构建最后启动后端服务。5.1 三个 .bat 脚本的执行顺序# 1-install.bat 首次执行拉取依赖并跳过测试 mvn install -DskipTests -q # 3-build.bat 前端构建先装依赖再打包 npm install npm run build # 2-run.bat 启动后端使用 tomcat7 插件 mvn tomcat7:run -Dmaven.tomcat.port8080-DskipTests是跳过单元测试编译但会保留测试类编译结果正常情况下不写-Dmaven.test.skiptrue是因为后者连测试类都不编译项目里如果有测试引用的工具类就会直接报错。启动命令里的-Dmaven.tomcat.port指定后端口默认是 8080。遇到 Windows 提示命令找不到时检查 JAVA_HOME、MAVEN_HOME、NODE_HOME 三套环境变量是否都已配进 PATH。5.2 MySQL 导入和初始化的检查点SQL 文件导入后先打开 sys_user 表看有没有初始管理员账号没有的话要用 SQL 手动插入一条。注意数据库字符集要统一成 utf8mb4排序规则选 utf8mb4_general_ci否则前端传进来的中文在网页上显示乱码。时间字段尽量使用 DATETIME 而不是 timestampDATETIME 范围更大也没有 2038 年问题。5.3 答辩前值得加的三个加固点提示界面能跑、流程能走是合格线真正拉开差距的是异常处理和部署方式。第一把上传目录单独抽到application.properties配置项里用Value(${upload.path})注入而不是散落在 Controller 里写死绝对路径。第二给 Controller 统一加一个BaseController把所有异常用ExceptionHandler兜住返回 Result 结构而不是一长串堆栈。第三部署时把前端 dist 交给 Nginx后端单独挂在 TomcatNginx 配置/api/反向代理到http://127.0.0.1:8080同时把/upload/目录用 alias 指向服务器上的实际路径这样前端页面访问图片走 Nginx 静态文件服务不再挤占 Tomcat 线程接口响应时间会有明显改善。本文还有配套的精品资源点击获取
返回列表