拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

SpringBoot+Vue+MySQL社区医院管理系统开发全流程实战指南

SpringBoot+Vue+MySQL社区医院管理系统开发全流程实战指南

做这类系统,最怕的就是"看起来什么都做了,实际上每块都没做透"。SpringBoot + Vue + MySQL 做社区医院管理系统,是JavaWeb方向最经典的毕业设计组合,但它之所以经典,恰恰是因为它把前后端分离、权限控制、业务流转、数据建模这些核心面试题全包进去了。我拆过不少这种项目,也带过一些同学复现,今天就以这套系统为例,把从立项、技术选型、数据库设计,到前后端编码、部署、论文撰写、答辩准备的完整链路,一条龙讲清楚。

这篇文章适合下面三类人:一是正在做类似毕业设计、需要一套完整思路作为参照的同学;二是工作后想拿一个全栈型项目练手、补齐前后端衔接经验的初级开发;三是准备用这个项目做面试亮点、需要把"业务细节"讲明白的人。内容会尽量贴近真实开发里"踩过的坑"来写,能抄作业的地方直接抄。

1. 项目价值拆解与整体定位

1.1 为什么社区医院管理系统是毕业设计的好选题

社区医院这种业务场景,恰好卡在"复杂度够用"和"边界清晰"之间。它不像三甲医院那样有几十个复杂的子系统,也不像单纯的图书管理系统那样业务过于单薄。核心业务大致就这几条线:挂号、分诊、门诊开单、收费、药品库存、患者档案。

这几条线串起来以后,天然就有了"多角色"的需求——管理员、医生、收费员、药房、护士、患者,不同角色看到的东西、能操作的功能完全不同。这就逼着你去做登录鉴权、路由守卫、接口权限控制。要知道,毕设答辩的老师最常问的问题之一就是"你的系统安全性怎么体现的",如果只是一个登录页,没有任何角色层面的控制逻辑,这一问基本就挂了。

另外,这个场景能产生数据统计的需求。比如某段时间内各科室接诊量、某类疾病的开药趋势、药品消耗排名,这些既可以用MySQL的聚合查询来做,也可以顺便引入一个简单的ECharts图表展示。有了统计模块,项目的展示面就拉得很高,演示的时候能讲的东西也更多。

1.2 技术栈选型的真实考量

这里重点说下为什么是这三个东西组合,而不是别的。

SpringBoot提供了一个"约定优于配置"的开发骨架,内置Tomcat,不用再手动打war包扔外置容器里;和MySQL的整合也极其顺滑,起步依赖引入后,几十行配置就能把数据源跑起来。如果选传统的SSH(Struts2 + Spring + Hibernate)或SSM框架,光配置文件的折腾就能耗掉一半时间,而且答辩时还要被追问一堆XML配置的细节,属于自己给自己加难度。

Vue这边,用Vue 2.6 + Element UI属于最稳的组合。有同学问为什么不用Vue 3 + Element Plus,原因很直白:网上现成的管理系统模板、博客文档、报错解决方案,绝大多数都是Vue 2这套生态。你碰到一个编译报错,随手一搜基本都有答案,这就省了太多时间。Vue 3 + TypeScript的版本确实更"现代",但作为一个以业务为展示核心的毕业设计,稳定、文档全、易排查,优先级比前沿性高得多。

MySQL不用多说,开源、免费、装起来方便,Navicat之类的图形化工具一应俱全。做毕设完全够用,没有任何理由去选Oracle或SQL Server。

2. 系统功能架构与数据库设计思路

2.1 六类角色与核心业务闭环

这套系统里,我建议把用户角色拆成六类,分别是:系统管理员、医生、护士、收费员、药房管理员、患者。有人会觉得角色太多了,实现起来麻烦。但我的观点是:角色多不是负担,而是毕业设计最大的加分项。每多一个角色,就多一组接口、多一组菜单权限配置、多处一个可讲的业务点,论文里的功能描述也更有话可写。

先说核心的业务闭环。患者通过系统注册账号并完善基本信息,按科室查看医生排班表,选择合理的时间段完成挂号。医生在待诊列表中看到已挂号的患者,接诊后填写诊断结果,开药品处方或检查项。检查项可以选择立刻做还是预约时间做,药品处方先传到药房,患者拿着处方单到收费窗口缴费,缴费后去药房取药。

这里有一个容易忽略但又很重要的点:收费模块一定要跟库存和处方状态联动。如果处方缴费后,药房没有减库存,也没有把处方标记为"已取药",那药房就只能看着处方单手动发药,整条链路就断了。所以数据库设计的时候,就要提前把状态字段想清楚。

以处方单为例,状态至少要有四个:待缴费、已缴费待取药、已取药、已退费。每个状态对应一条审批流,这样在演示的时候,就能把事情讲得很细——"医生开方后,处方状态为待缴费,患者到收费窗口结算,收费员操作后变成已缴费待取药,药房看到处方后发药并减库存,状态改为已取药"。

除了业务主链路,还有一些辅助模块也要分给合适的角色。系统管理员负责用户管理、角色分配、科室管理、基础字典数据的维护,比如性别、血型、药品分类、检查项目类型等。护士侧可以负责分诊台操作,比如为患者量体温血压并记录到就诊信息里。这类小功能不需要太多,但每个角色有一个专属功能,答辩的时候讲"多角色协作"就有具体的支撑。

2.2 数据库表设计的关键取舍

表怎么设计,能直接看出来你有没有真实做过项目经验。我见过很多毕设的数据库表就三五张,全是核心主表,业务主表和业务明细表完全分不开。比如一张"挂号表"里就塞了诊断、处方、费用、缴费状态,这种设计答辩时老师一眼就能看出来没经过正规训练。

我这里给一个经过实践筛选的表清单,大家可以直接照着建,这些表数量控制在十六到二十张之间,团队的规模也刚好是"有一定工作量但又不至于臃肿":

  • 系统管理类:sys_user(用户)、sys_role(角色)、sys_menu(菜单/权限)、sys_user_role(用户角色关联)、sys_role_menu(角色菜单关联)
  • 机构人员类:department(科室)、doctor_info(医生信息,包括职称、排班、所属科室)
  • 患者业务类:patient(患者档案,和sys_user可以分开,也可以合在sys_user里加patient_type字段)、appointment(挂号预约/挂号记录)
  • 诊疗业务类:medical_record(门诊病历/诊断记录)、prescription(处方单)、prescription_item(处方明细)
  • 收费与药品类:charge_order(收费单)、charge_item(收费明细)、drug_info(药品)、drug_stock(药品库存)
  • 扩展业务类:check_report(检查报告)、bed_info(病床)、hospitalization(住院记录)

这里单独说一个很多同学的误区:sys_user是一张统一的登录账号表。不要给医生、收费员、患者各自建一张用户表,然后登录的时候拿Type字段去区分查询哪张表。正确做法是一张sys_user表里放上用户类型字段,打比方说role_type为1、2、3……分别对应不同角色。用一张表做登录校验,逻辑最清晰,写JWT鉴权拦截器时也不用一段代码里写多次查询。

还有一点是外键的问题。我在实际开发里很少在数据库层面建真正的外键约束,都是逻辑外键,也就是用字段关联id,但不加FOREIGN KEY。原因有两个:一是MySQL里的物理外键在删除和更新时容易导致"倒不下数据"的问题,做毕设关键表中反而容易自缚手脚;二是实际项目里物理外键约束对性能影响不小,现在主流的互联网团队基本都用逻辑外键。这一点答辩时如果被问到,可以讲"从性能和维护性考虑,采用逻辑外键设计,由代码保证关联完整性",是加分的回答。

3. 环境准备与项目初始化实战

3.1 开发环境清单与版本选择

这一节是很多新手第一步就卡住的地方,所以我想把版本号和坑都写清楚。

  • JDK:1.8。别上来就装JDK 17或21。Spring Boot 2.x系列在JDK 8上运行最稳定,16以上版本会出现一些兼容性问题,还需额外处理。
  • Maven:3.6.3或3.8.x。装3.9也可以,但不要装最新的4.x。
  • IDE:IntelliJ IDEA,社区版就够用。注意用Ultimate版的话要新建Spring Initializr项目比较方便,社区版则直接新建Maven项目,pom里加依赖即可,一样的效果。
  • Node.js:14.x或16.x。这个版本很有讲究,Vue CLI 4对低版本Node兼容更好,我见过有人装了Node 20,执行npm install直接报错,看得头大。
  • MySQL:5.7或8.0。两个版本都行,但注意不同版本连接驱动和时区配置有细微差别,后面会专门说。
  • Navicat:建议选Navicat 16或免费的DBeaver。不推荐破解版的Navicat,容易下到带广告或者带木马的东西,DBeaver完全够用。

上面版本建议的理由其实就一条:把环境的不确定性降到最低。毕业设计最怕的从来不是业务写不出来,而是时间全耗在环境问题上。

3.2 后端项目骨架搭建

SpringBoot项目我习惯用手工建Maven工程的方式来做,这样pom文件里的每个依赖都能讲明白作用。

在pom.xml中加入以下核心依赖:

<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.14</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.3.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.19.2</version> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.18</version> </dependency> </dependencies>

补充说明一下为什么选MyBatis而不是MyBatis-Plus。有很多同学会直接用MyBatis-Plus,因为它自带BaseMapper,单表CRUD不用写SQL,非常省事。但我个人建议做毕设的时候用原生MyBatis,原因有两个方面。第一,MyBatis-Plus太方便了,方便到写代码的时候你基本不思考SQL,答辩时老师问"你这个关联查询怎么写的",你一下想不起来自己封装了什么,场面会很尴尬。第二,原生MyBatis的XML文件里,每一条SQL都是自己一条条写出来的,这恰恰是论文里可以做重点展示的部分,直接把核心SQL贴出来,配合业务逻辑讲解,比贴一堆方法名有说服力得多。

再看HashMap。MyBatis查询返回的resultType直接写成Map<String, Object>会偷懒很多。有些同学所有的查询都返回Map,结果service里到处是类型强转,代码看着脑袋都大。我建议所有核心业务表都建对应的实体类,比如Appointment、Prescription,Map只在统计报表之类的动态字段查询时使用。

项目包结构我这里直接给出一个可以照抄的版本,比很多博客里那种无意义的entity/dao/service/controller四层多了业务分组的语义:

com.hospital ├── config (跨域配置、拦截器配置、全局异常处理) ├── controller (接收请求,只做参数校验和结果封装,不写业务逻辑) ├── service (业务逻辑,事务控制在这里) ├── mapper (MyBatis的mapper接口) ├── entity (数据库表对应的实体类) ├── dto (前端传来的请求参数对象,避免直接用entity接收) ├── vo (返回给前端的数据对象,比如带分页结果的PageVO) ├── utils (通用工具类,比如JWT工具类、日期处理工具类) └── common (统一返回结果类Result、统一状态码枚举)

3.3 前端Vue项目搭建与联调准备

前端我建议直接用Vue CLI而不是Vite。原因跟前端框架选型的逻辑一样:Vue CLI生态成熟、配置直观、报错可搜。Vite的冷启动确实快,但现在回想一下,毕业设计的演示场景下,这种开发体验差异微乎其微,而Vite下碰到特殊插件兼容问题时排错要花的时间可不少。

创建项目用以下命令:

npm install -g @vue/cli vue create hospital-web

选的时候注意:Vue版本选2.x,不要选3,跟上面Element UI的道理一样。我建议在创建项目时不要勾选eslint。ESLint固然能规范代码,但新手经常出现"代码写得没问题但一直报错"的情况,里头的报错信息反而更让人抓狂,格式化风格还会影响项目启动。在毕设阶段,建议先把功能写对、把项目跑起来,后面再考虑规范的事。

装依赖:

npm install element-ui@2.15.14 axios vue-router@3.5.4 vuex@3.6.2

注意版本号,Vue 2项目的vue-router要装3.x,不能装Vue 3专用的4.x。这是前端最经典、最迷惑的版本问题之一。

axios请求封装这里,最核心的一点是响应拦截器。要在后端返回结果里约定一个统一格式,前端拦截器里判断状态码。后端Result的结构可以这样设计:

public class Result<T> { private Integer code; // 200成功,401未登录,500失败 private String msg; private T data; }

axios请求封装示例:

import axios from 'axios' import { Message } from 'element-ui' import router from '@/router' const service = axios.create({ baseURL: '/api', // 后面配代理 timeout: 10000 }) service.interceptors.request.use(config => { const token = sessionStorage.getItem('token') if (token) { config.headers['Token'] = token } return config }) service.interceptors.response.use(response => { const res = response.data if (res.code === 401) { sessionStorage.clear() router.push('/login') Message.error('登录已过期') return Promise.reject(new Error('未登录')) } return res }) export default service

这里有个容易忽视的细节:Token放在请求头里的键名要跟后端拦截器里读取的键名保持一致。有的同学前端请求头里面写Authorization,后端签发的却是个自定义header,比如X-Token,两边对不上,登录后任何请求都会被拦截器干掉——这种小问题排查起来经常就是半小时起步。

4. 核心功能模块实现详解

4.1 JWT登录鉴权与拦截器配置

登录鉴权到底用Session还是JWT?之前有些同学用Session方式实现,就是登录后往HttpSession塞一个user对象,后面每个请求用request.getSession().getAttribute()去取。这个方案写起来确实简单,但有两个明显的问题:第一个问题是前后端分离部署时,Session跨域很麻烦,就算能通过配置解决,也属于不攻自破的隐藏坑;第二个问题是会话数据在服务端内存里,分布式部署时第一个机器上没有session就废了。所以用JWT是更符合行业主流方式的方案。

JWT的使用逻辑就是这样:用户在登录接口提供用户名密码,校验通过后,后端用私钥生成一个token,token里塞userId、userName、roleType之类的核心信息,然后返回给前端。前端存到sessionStorage里,之后每次请求都在请求头带上token。后端写一个拦截器统一拦截请求,登录之外的所有接口都校验token存在且合法。

生成token的工具方法示例:

private static final String SECRET = "hospital-secret-key"; public static String generateToken(Long userId, String userName, Integer roleType) { Algorithm algorithm = Algorithm.HMAC256(SECRET); return JWT.create() .withClaim("userId", userId) .withClaim("userName", userName) .withClaim("roleType", roleType) .withExpiresAt(new Date(System.currentTimeMillis() + 2 * 60 * 60 * 1000)) .sign(algorithm); }

校验token的核心逻辑:

public static Long getUserIdFromToken(String token) { DecodedJWT jwt = JWT.require(Algorithm.HMAC256(SECRET)).build().verify(token); return jwt.getClaim("userId").asLong(); }

拦截器配置时,要注意开放路径的问题。比如:/api/auth/login、/api/auth/register这两个接口必须是放行的,否则用户还没登录就进不来。另外前端项目的静态资源路径、错误页面路径也需要放行。我见过很多同学拦截器配得比较严格,导致登录页自己都无法访问,这个在配置映射的时候要多检查一遍。

还有一个面试常考的点:把密码以明文方式存进数据库。不管是不是毕业设计,这一点都应避免。建议密码使用MD5加盐的方式存储,原理是MD5(原始密码 + 固定盐值)后入库。加盐是为了防止彩虹表反查,这个点可以在论文和答辩中专门提出来说。

4.2 科室与排班模块

科室模块看起来是简单的增删改查,但里面藏着两个常见的设计问题。

第一个是科室和医生的关系。正确设计:先在department表里维护科室,再在doctor_info表里存储doctor_id和department_id关联。一个医生有且仅属于一个科室,但可以通过排班灵活调配出诊时间。有的同学会把科室列表字段直接存成医生表的一个字符串字段,比如"内科、外科",这样后端的科室统计几乎没法做,排班也没有任何扩展性可言。

第二个是排班的设计。排班表我建议单独建一张表,不要硬塞在医生表里。排班表可以设计成schedule表,大致字段有:id(主键)、doctor_id(医生id)、department_id(科室id)、schedule_date(出诊日期)、period_type(上午1/下午2/晚上3)、total_count(总号源)、booked_count(已挂号数量)、status(排班状态)。这样挂号的时候,才能按"科室+日期+时间段"组合查到排班,然后判断booked_count是否小于total_count。

如果排班槽位已经挂满,挂号接口要返回"号源已约满",不能无脑往appointment表里插入。这是体现业务完整性的一个小细节,答辩时值得主动提一句。

4.3 挂号与门诊收费闭环

挂号流程的前端交互不复杂,但后端要处理好三个联动问题。

首先,挂号的时候要检查患者是否已经存在在patient表里。如果患者是通过注册入口进入系统的,挂号时可以直接读取当前用户的patient档案;但患者填写的信息发生变更时,也要能更新档案。比较好的做法是不让患者自己维护病历,而是由挂号处核对处写入。

其次,挂号操作应该做成事务:第1步插入appointment记录,第2步更新schedule表的booked_count + 1。这两步不能只做其中一步,否则要么号源超卖、要么挂号记录缺失。给service方法加上@Transactional注解就能解决:

@Transactional(rollbackFor = Exception.class) public int registerAppointment(AppointmentDTO dto) { scheduleMapper.increaseBookedCount(dto.getScheduleId()); return appointmentMapper.insert(dto); }

再说收费模块。收费单我建议从挂号记录和处方单两个来源产生。挂号时直接生成一张挂号费收费单,就诊后医生开的处方产生一张处方收费单。收费员界面有两块:未缴费列表、已缴费列表。未缴费列表只展示状态为"待缴费"的记录,收费员点击"收款"按钮后,后台做两件事:把收费单状态改为已缴费,同时把关联的处方单状态改为"已缴费待取药"。这里的状态流转,一定要更新到关联单据,我见过不少系统只更新了收费单,药房那边的处方状态没有任何变化,等于药房模块白做。

药品库存扣减的时机很容易踩坑。我建议药品库存不扣在收费时,而扣在药房发药时。比如患者虽然缴费了但一直不去取药,如果收费时已经减了库存,药房过了两天盘点才发现账实不符。正确的做法是:药房发药事务里同时执行两条更新,者检查库存足够后做发货,外加库存数量减减和处方状态改改。

5. 部署上线流程与完整交付清单

5.1 前后端打包与Nginx部署

毕设答辩不能只在自己电脑上跑,那样老师是无法给部署的分数。这里给一套能够在单台云服务器或本机完成的前后端分离部署流程。

后端打包:

mvn clean package -DskipTests

这条命令会生成一个target目录下的jar包,比如hospital-server.jar。然后直接:

java -jar hospital-server.jar

就能启动后端。需要注意配置文件里MySQL地址、用户名、密码的配置方式。如果说你用的是云服务器数据库,要将jdbc的url改成公网数据库地址;本地则是jdbc:mysql://localhost:3306/hospital?useSSL=false&serverTimezone=Asia/Shanghai。

serverTimezone这个参数很关键。MySQL 8默认时区可能是UTC,会导致时间数据查出来差8小时。加了serverTimezone=Asia/Shanghai之后就能避开。另外useSSL=false也有用,不然数据库连接会报SSL连接错误。

前端打包:

npm run build

打包完成后会在dist目录生成静态文件。把这些dist文件放到Nginx的html目录里。Nginx配置目录建议这样写:

server { listen 80; server_name localhost; # 前端静态资源 location / { root /usr/share/nginx/html/hospital; index index.html index.htm; try_files $uri $uri/ /index.html; # Vue Router的history模式要加这句 } # 后端接口反向代理 location /api/ { proxy_pass http://127.0.0.1:8080/api/; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }

try_files $uri $uri/ /index.html这行一定要写。Vue Router如果用的是history模式,刷新某个非根路径(比如/medical-record)时会404,加上这一行就把请求都先引到index.html,再由前端路由器接管。

前后端端口的问题也要注意:如果后端接口是/api开头,后端Controller里所有接口要做统一前缀,在application.yml里可以配:

server: port: 8080 servlet: context-path: /api

后端有自己的统一跨域配置。但一旦走后端部署的反向代理,同源情况下就不需要跨域配置了。开发环境调试的时候,前端可以配一个proxy代理来解决跨域:

devServer: { port: 3000, proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } } }

5.2 数据库脚本与初始化数据

交付清单里数据库这块有两个东西是必须的:一个是建库建表脚本,一个是初始化数据脚本。

建表脚本要保证新环境上可以一键导入。如果你在Navicat里手动建的表,执行"转储SQL文件",导出时注意勾上"包含建库语句"和"包含数据"两个选项。我遇到过一个同学的交付包里没有数据库脚本,部署文档里写着"请按照ER图手动建表",这种交付直接会被降级评价。

初始化数据也很重要。管理员账号必须内置一个,不然他部署完连初始账号都没有,就没法登录后台。另外药品分类、科室列表这些基础数据,不要放空表,直接插入几条示例数据进去,演示的时候就有画面了。还应生成几十条模拟的挂号记录,因为如果你库里一张挂号单也没有,统计图表页面根本看不出效果。

6. 论文写作与答辩要点

6.1 论文结构安排与核心章节怎么写

论文模板学校通常会发,但内容架构基本都逃不开下面这几章:绪论、相关技术介绍、需求分析、系统设计、系统实现、系统测试、总结与展望。

这里有一个比较划算的安排方式:如果工作量集中在系统设计,那论文就把系统设计拆成两大章——总体设计和详细设计。总体设计里写总体架构图、功能模块划分、数据库概念模型(ER图);详细设计里按模块分别讲类设计、接口设计、业务流程时序图和关键表结构。

需要把关键代码贴进论文里,比如JWT拦截器的核心代码、挂号事务的代码、MyBatis关联查询的SQL。代码不要全部代码,只贴核心部分,并在代码前后写上设计思想。答辩老师看论文主要是扫图、扫标题、扫代码块。有一个图论是:系统架构图、功能模块图、数据库ER图、业务时序图。这四张图画好,论文整体基调也就稳了。

需求分析部分,一定要有"用例图配用例描述"。比如患者挂号这个用例:前置条件(患者已登录且存在有效排班)、主流程(选择科室、选择医生、选择排班时段、确认挂号)、异常流程(号源已满、未登录)。这类描述在网上可以搜到很多模板,但最好自己结合代码里的实际业务改写,更贴近真实。

6.2 答辩时的高频问题与应答思路

答辩场上老师提问,一般都围绕这几个角度:技术细节、业务设计、代码有没有你自己写的、解决方案的取舍。

举个例子,老师可能会问:"SpringBoot的自动配置原理是什么?"这道题是经典中的经典。答复思路大致这样说:SpringBoot是通过启动类上的@SpringBootApplication注解,该注解组合了@EnableAutoConfiguration,它会引入AutoConfigurationImportSelector,通过SpringFactoriesLoader读取META-INF/spring.factories文件里的自动配置类,再按照条件注解@ConditionalOnClass、@ConditionalOnMissingBean等判断是否生效。

再比如:"为什么数据库表不用物理外键?"这个问题前文已经埋过答案了,重点从性能和可维护性两个角度去答。

还有:"Vue的v-if和v-show有什么区别?"这个很常被问到。v-if是真正的条件渲染,触发重新创建或销毁组件;v-show是设置display为none。建议高频切换用v-show,初始化高频的用v-if。

教师可能会截取系统里的一段核心代码进行提问,所以答辩前要把自己最核心的模块——登录模块、挂号模块、收费模块——代码从头到尾过一遍,保证每个方法的作用、每条SQL的意图都能说得清。不管你实际是不是从别人的代码改的,都要像自己亲自写一样熟练,这个很关键。

7. 常见问题与避坑实录

7.1 数据库连接与版本问题

先说MySQL 8的连接问题。用com.mysql.jdbc.Driver会在启动时报错,"Loading class is not registered",正确driver是com.mysql.cj.jdbc.Driver。Spring Boot 2.x的mysql-connector-java 8.0.x版本已经自动管理这个驱动,但如果你在pom里乱指定旧版本就麻烦了。

SSL连接错误的处理:报错文本通常类似"SSL connection error"或"Public Key Retrieval is not allowed"。解决方法就是在url后加useSSL=false&allowPublicKeyRetrieval=true。千万不要只加useSSL=false,因为MySQL 8的caching_sha2_password认证模式下,allowPublicKeyRetrieval默认false时还是会报错。

时区问题表现是数据库里存的时间正常,但Java查询出来多了8小时,或者前端显示的时间不对。解决就是在url后加上serverTimezone=Asia/Shanghai。

7.2 前端跨域与Token失效类问题

开发模式下跨域报错,这个场景特别多。如果前端端口是3000,后端端口是8080,浏览器里会出现CORS错误。处理方案在5.1已经写过了。这里补充一个排查要点:加了代理后,即使浏览器地址还是localhost:3000,但接口请求已经由Node代理转发到8080了,所以浏览器不会再报跨域。如果你的项目不是通过devServer代理,而是直接在axios里写http://localhost:8080,那就要考虑后端统一加CORS配置了。

Token失效的典型症状是:登录状态过了一段时间后操作都报401,需要重新登录。这就是token过期时间到了,符合逻辑。但两个更隐蔽的问题需要排查:一是在拦截器中异常没处理,导致任何非200状态码都没有返回给前端;二是前端没有在拦截器里对401做跳转处理,导致用户看着页面,所有请求都在401。

7.3 后端启动失败与接口报错排查

端口占用的问题很常见:后端启动时报"Port 8080 was already in use"。Windows上可以通过netstat -ano | findstr 8080查看占用进程,然后taskkill /PID xxx /F结束。开发机上有其他服务占用8080时,也可以直接改application.yml里的端口。

MyBatis中特别常见的两种报错:

绑定异常,明明写了Mapper接口,还在接口上标了@Mapper,运行却报Invalid bound statement。绝大多数原因都是XML里的namespace写错了,或者mapper.xml文件没有放到resources目录下、没匹配到接口名。检查顺序应该是:namespace完全等于接口全限定名,XML里的id等于方法名,SQL里所用的参数名与接口方法参数对应。这三条逐一对照。

"Only java.lang.String and primitive types are supported"这种报错也很常见,通常是MyBatis传参时没用@Param注解,采用多个参数没有用map包装。解决办法:方法的参数上加@Param("xxx")注解,或者封装成一个DTO对象。

7.4 从零到答辩的时间规划建议

如果按照上面的方案来推进,结合我实际带项目的经验,一个正常的节奏大约是四周:

第一周:需求分析和数据库设计。写清楚有哪些角色、哪些核心流程;表格建好,初始化数据基本跑通。 第二周:后端核心接口。先做登录和鉴权,再做挂号、医生、收费等主体接口。 第三周:前端页面。先把登录和后台布局搭好,再实现每个模块的列表、表单和路由。开发时可以后端的接口尽量早设计,前后端并行推进。 第四周:部署和答辩材料准备。打包部署,整理论文,做PPT,复盘接口细节,模拟答辩问题。

这套系统最终的呈现形态是四个交付物:可运行源码、SQL脚本、完整论文、部署文档。这四样如果都做扎实,这个毕业设计不仅是一个项目,更是你面试时可以拿出来讲的完整全栈案例。

最后分享一个我自己体会很深的点:做完这个项目以后,把每个模块的"状态流转"画成一张图,比如挂号状态的流转、处方状态的流转、收费单状态的流转。答辩的时候,这张图比任何一百页PPT都管用。因为老师能看出来你是真的梳理过业务,而不是单纯背了几个框架。就讲到这里,接下来把环境装好,照着上面的步骤干就行。

返回列表