简介:这是一套面向计算机、软件工程等专业学生的智慧医疗HIS系统完整源码与数据库资源,采用springboot框架开发,适合用作毕业设计、期末大作业或课程设计。项目经本地编译可运行,评审得分达98分,难度适中,内容经助教老师审定,兼顾学习性与实用性。压缩包共1302个文件,约20.62MB,以972个java源码、129个xml配置、49个js脚本、37个html页面及16个vm模板为主,另含sql数据库脚本、yml配置、css样式与字体图标等,覆盖后端逻辑、前端页面与数据持久化各层。系统通常包含患者信息管理、预约挂号、电子病历、药品库存、医生排班与财务管理等模块,遵循模块化、服务化设计,并注重权限管理与数据安全。目前已有183人学习下载,可帮助读者理解现代医疗信息系统的架构与实现,为后续开发实践打下基础。
1. 智慧医疗HIS系统到底在解决什么问题
很多同学第一次接触智慧医疗HIS系统源码,是被“高分毕业设计”这几个字吸引进来的。但真正打开代码之后,第一个冒出来的问题往往是:这东西到底在解决什么业务问题?HIS,全称Hospital Information System,医院信息系统,核心目标只有一个——把挂号、就诊、开方、收费、发药这条主线上的数据串起来,让信息跟着病人走,而不是让病人追着单据跑。一个能跑通的HIS系统,至少要覆盖门诊挂号、医生站开处方、收费结算、药房发药这四个环节,并且每个环节的数据要能互相校验。
这套源码适合谁?适合正在做毕业设计、期末大作业、课程设计的同学,也适合想通过一个完整项目理解三层架构、权限控制、数据库设计的开发者。它的难度适中,意味着你不需要从零搭框架,但也不能只改个界面就交差。你需要理解表结构之间的关联、后端接口的鉴权逻辑、前端页面的数据流转。评审能拿到98分,说明它在功能完整度、代码规范、文档说明这几个维度上达到了较高水准。接下来我会从环境搭建、数据库设计、核心模块实现、避坑排查、进阶技巧五个层面,把这套系统拆开讲清楚,让你不仅能跑起来,还能讲明白为什么这么设计。
2. 把智慧医疗HIS系统在本地跑起来:环境、依赖与启动顺序
2.1 技术栈选型与版本确认
拿到一套HIS源码,第一件事不是急着点运行,而是先看技术栈。常见的智慧医疗HIS系统源码,后端多用Spring Boot + MyBatis + MySQL,前端用Vue + Element UI或者Thymeleaf模板,权限框架用Spring Security或Shiro。这套组合的好处是生态成熟,遇到问题搜索成本低,适合毕业设计场景。你需要确认的版本信息包括:JDK是1.8还是11,MySQL是5.7还是8.0,Node.js是14还是16,Maven是3.6还是3.8。版本不匹配是启动失败的第一大原因,比如MySQL 8.0的驱动类名是com.mysql.cj.jdbc.Driver,而5.7用的是com.mysql.jdbc.Driver,写错了直接报连接失败。
我一般会先打开pom.xml或build.gradle,把依赖版本抄到记事本里,然后逐个核对本地环境。如果本地JDK版本高于项目要求,比如项目用1.8而你装了17,Spring Boot 2.x在JDK 17上跑会遇到反射相关的警告甚至报错,最稳妥的做法是装一个JDK 1.8专门跑这套项目。前端部分,如果package.json里锁定了Node 14,你用Node 18去npm install可能会遇到node-sass编译失败,这时候要么降Node版本,要么把node-sass换成dart-sass。
2.2 数据库导入与连接配置
数据库是HIS系统的核心,导入之前先建库。常见做法是创建一个名为his_db的数据库,字符集用utf8mb4,排序规则用utf8mb4_general_ci。然后执行项目自带的.sql文件。这里有个细节:有些SQL文件里写了CREATE DATABASE语句,有些没有,如果没有就手动建库再导入。
-- 创建数据库,字符集必须支持中文和emoji CREATE DATABASE his_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; -- 切换到这个库 USE his_db; -- 导入表结构和初始数据(假设SQL文件已准备好) SOURCE /path/to/his_db.sql;导入完成后,用SHOW TABLES;确认表数量。一个完整的HIS系统通常有20到40张表,包括用户表、角色表、权限表、科室表、医生表、患者表、挂号表、处方表、药品表、收费记录表等。如果表数量明显偏少,可能是SQL文件不完整,需要检查是否只导入了结构没有导入数据。
接下来改配置文件。Spring Boot项目一般改application.yml或application.properties。重点改三个地方:数据库URL、用户名、密码。URL里要加上useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai,否则中文乱码和时间差8小时的问题会同时出现。
spring: datasource: url: jdbc:mysql://localhost:3306/his_db?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false username: root password: your_password driver-class-name: com.mysql.cj.jdbc.Driver注意:
serverTimezone参数在MySQL 8.0驱动里是必须的,不写会报The server time zone value '?D1ú±ê×?ê±??' is unrecognized。这个报错看起来吓人,其实就是时区没配。
2.3 后端启动与前端联调
后端启动用mvn spring-boot:run或者直接运行主启动类。启动过程中重点看控制台有没有Started Application in X seconds,如果有,说明后端起来了。如果卡在Initializing Spring root WebApplicationContext然后报错,大概率是数据库连不上或者MyBatis映射文件路径不对。
前端启动分两种情况。如果是前后端分离项目,进入前端目录执行npm install然后npm run serve,默认端口一般是8080或8081。如果是Thymeleaf模板项目,后端启动后直接访问http://localhost:8080即可。前后端分离项目要注意跨域问题,后端一般会配CorsConfig或者在Controller上加@CrossOrigin注解。如果前端请求报Access-Control-Allow-Origin错误,先检查后端有没有开启跨域配置。
# 前端安装依赖,建议用淘宝镜像加速 npm install --registry=https://registry.npmmirror.com # 启动开发服务器 npm run serve # 后端启动(在项目根目录) mvn spring-boot:run启动顺序建议是:先启动MySQL,再启动后端,最后启动前端。这样前端请求接口时后端已经就绪,不会出现登录页面能打开但点登录没反应的情况。登录账号一般在SQL文件里有初始数据,常见的是admin/123456或者doctor/123456,具体看sys_user表的插入语句。
3. 智慧医疗HIS系统数据库设计:表关系与核心字段
3.1 从挂号到发药的数据流转
理解HIS系统的数据库设计,最好的方式是跟着一个病人走一遍流程。病人先到挂号窗口,系统在register表插入一条记录,包含病人ID、科室ID、医生ID、挂号类型、挂号费、挂号时间。然后病人去诊室,医生在prescription表插入处方主记录,在prescription_detail表插入药品明细。接着病人去收费窗口,系统在charge表插入收费记录,同时更新挂号表的状态为“已收费”。最后病人去药房,药房工作人员在dispense表插入发药记录,处方状态变为“已发药”。
这条链路里,register表的patient_id关联patient表,doctor_id关联doctor表,department_id关联department表。prescription表的register_id关联挂号表,prescription_detail表的prescription_id关联处方主表,drug_id关联药品表。每一层关联都保证了数据不会孤立存在,删掉一个病人,他的挂号记录、处方记录、收费记录都能通过外键或者业务逻辑找到。
-- 挂号表核心字段示例 CREATE TABLE `register` ( `id` int NOT NULL AUTO_INCREMENT, `patient_id` int NOT NULL COMMENT '患者ID', `doctor_id` int NOT NULL COMMENT '医生ID', `department_id` int NOT NULL COMMENT '科室ID', `register_type` varchar(20) DEFAULT '普通号' COMMENT '挂号类型', `register_fee` decimal(10,2) DEFAULT '0.00' COMMENT '挂号费', `status` tinyint DEFAULT '0' COMMENT '0未就诊 1已就诊 2已收费', `create_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_patient` (`patient_id`), KEY `idx_doctor` (`doctor_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='挂号记录表';注意:
status字段用tinyint而不是varchar,是为了查询效率。但要在代码里定义枚举或者常量类,否则时间久了没人记得0、1、2分别代表什么。
3.2 权限表设计与登录鉴权逻辑
HIS系统的权限设计通常是RBAC模型,即用户-角色-权限三层。sys_user表存用户,sys_role表存角色,sys_user_role表存用户和角色的关联,sys_menu表存菜单和按钮权限,sys_role_menu表存角色和菜单的关联。登录时,后端根据用户名查用户,校验密码,然后查该用户的所有角色,再查角色对应的菜单权限,返回给前端生成动态路由。
密码存储不能用明文,常见做法是BCrypt加密。Spring Security提供了BCryptPasswordEncoder,每次加密结果不同但校验时能匹配。如果你在SQL文件里看到密码字段是$2a$10$...开头的长字符串,那就是BCrypt加密后的结果,初始密码通常是123456。
// 登录接口的核心逻辑 @PostMapping("/login") public Result login(@RequestBody LoginDTO loginDTO) { // 1. 根据用户名查用户 SysUser user = userService.getByUsername(loginDTO.getUsername()); if (user == null) { return Result.error("用户名不存在"); } // 2. 校验密码(BCrypt方式) if (!passwordEncoder.matches(loginDTO.getPassword(), user.getPassword())) { return Result.error("密码错误"); } // 3. 查询用户角色和权限 List<String> roles = roleService.getRoleCodesByUserId(user.getId()); List<String> permissions = menuService.getPermsByUserId(user.getId()); // 4. 生成Token返回 String token = jwtUtil.generateToken(user.getUsername(), roles, permissions); return Result.success(new LoginVO(token, user.getNickname())); }这段代码的关键点在于:密码校验用matches而不是equals,因为BCrypt每次加密结果不同;Token里要放角色和权限信息,前端根据权限控制按钮显示;返回的用户信息不要包含密码字段,否则是低级安全漏洞。
3.3 药品库存与收费的联动设计
药品表drug里有一个stock字段表示库存数量。医生开处方时,系统要检查库存是否充足;收费时,系统要扣减库存;如果病人退费,库存要加回来。这个联动逻辑如果写在Controller里,代码会非常臃肿,常见做法是抽一个DrugStockService,用@Transactional注解保证事务一致性。
@Service public class DrugStockService { @Autowired private DrugMapper drugMapper; // 扣减库存,使用乐观锁防止超卖 @Transactional(rollbackFor = Exception.class) public boolean reduceStock(Integer drugId, Integer quantity) { // 先查当前库存 Drug drug = drugMapper.selectById(drugId); if (drug.getStock() < quantity) { throw new BusinessException("药品库存不足"); } // 用版本号做乐观锁更新 int affected = drugMapper.reduceStockWithVersion(drugId, quantity, drug.getVersion()); if (affected == 0) { throw new BusinessException("库存更新失败,请重试"); } return true; } }对应的SQL要带上版本号条件:
UPDATE drug SET stock = stock - #{quantity}, version = version + 1 WHERE id = #{drugId} AND version = #{version} AND stock >= #{quantity}这样设计的好处是并发场景下不会出现库存扣成负数的情况。毕业设计答辩时,老师如果问“多人同时开同一个药怎么办”,你能答出乐观锁,就是一个加分项。
4. 核心模块实现:挂号、处方、收费的代码拆解
4.1 挂号模块的接口设计与参数校验
挂号接口看起来简单,但参数校验做不好会埋很多坑。前端传过来的参数包括患者ID、医生ID、科室ID、挂号类型。后端要校验:患者是否存在、医生是否属于该科室、该医生当天是否还有号源、患者是否已经挂过该科室的号。这些校验如果全写在Controller里,代码会超过100行,建议用自定义注解加AOP或者抽一个RegisterValidator类。
// 挂号请求参数 public class RegisterDTO { @NotNull(message = "患者ID不能为空") private Integer patientId; @NotNull(message = "医生ID不能为空") private Integer doctorId; @NotNull(message = "科室ID不能为空") private Integer departmentId; @NotBlank(message = "挂号类型不能为空") private String registerType; } // Controller层 @PostMapping("/register") public Result register(@RequestBody @Valid RegisterDTO dto) { // 校验医生和科室的关联关系 Doctor doctor = doctorService.getById(dto.getDoctorId()); if (doctor == null || !doctor.getDepartmentId().equals(dto.getDepartmentId())) { return Result.error("医生与科室不匹配"); } // 校验是否重复挂号 if (registerService.hasRegisteredToday(dto.getPatientId(), dto.getDepartmentId())) { return Result.error("今日已挂过该科室的号"); } // 执行挂号 RegisterVO vo = registerService.doRegister(dto); return Result.success(vo); }参数校验用@Valid加JSR-303注解,能省掉大量if-else。@NotNull和@NotBlank的区别是前者只管null,后者还管空字符串和纯空格。挂号类型这种字段用@NotBlank更合适。
4.2 处方开立与药品明细的批量插入
医生开处方时,一次可能开5种药,前端传过来的是一个药品列表。后端要做的操作是:插入处方主表,拿到主键,再批量插入处方明细表。这里的关键是useGeneratedKeys和keyProperty的配置,让MyBatis把自增主键回填到实体类里。
<!-- 处方主表插入,回填ID --> <insert id="insertPrescription" useGeneratedKeys="true" keyProperty="id"> INSERT INTO prescription (register_id, patient_id, doctor_id, diagnosis, create_time) VALUES (#{registerId}, #{patientId}, #{doctorId}, #{diagnosis}, NOW()) </insert> <!-- 处方明细批量插入 --> <insert id="batchInsertDetails"> INSERT INTO prescription_detail (prescription_id, drug_id, quantity, usage_method, dosage) VALUES <foreach collection="list" item="item" separator=","> (#{item.prescriptionId}, #{item.drugId}, #{item.quantity}, #{item.usageMethod}, #{item.dosage}) </foreach> </insert>Service层要加@Transactional,保证主表和明细表要么都成功,要么都回滚。如果明细插入失败但主表已经插入,数据库里就会出现一条没有药品的处方,这种脏数据在答辩时被老师查到会很尴尬。
@Transactional(rollbackFor = Exception.class) public void createPrescription(PrescriptionDTO dto) { // 1. 插入主表 Prescription prescription = new Prescription(); prescription.setRegisterId(dto.getRegisterId()); prescription.setPatientId(dto.getPatientId()); prescription.setDoctorId(dto.getDoctorId()); prescription.setDiagnosis(dto.getDiagnosis()); prescriptionMapper.insertPrescription(prescription); // 2. 组装明细并批量插入 List<PrescriptionDetail> details = dto.getDrugs().stream().map(drug -> { PrescriptionDetail detail = new PrescriptionDetail(); detail.setPrescriptionId(prescription.getId()); // 回填的主键 detail.setDrugId(drug.getDrugId()); detail.setQuantity(drug.getQuantity()); detail.setUsageMethod(drug.getUsageMethod()); detail.setDosage(drug.getDosage()); return detail; }).collect(Collectors.toList()); prescriptionDetailMapper.batchInsertDetails(details); }注意:批量插入的
foreach里不要忘记separator=",",否则生成的SQL语法错误。另外,如果药品列表为空,要先判断并抛出业务异常,避免生成INSERT INTO ... VALUES后面没有值的非法SQL。
4.3 收费结算与状态机流转
收费模块的核心是状态流转。挂号记录有状态:0未就诊、1已就诊、2已收费。处方有状态:0未收费、1已收费、2已发药。收费操作要同时更新挂号状态和处方状态,并且插入收费记录。这个流程用状态机来描述最清晰,代码里可以用枚举定义状态和允许的流转方向。
public enum RegisterStatus { NOT_VISITED(0, "未就诊"), VISITED(1, "已就诊"), CHARGED(2, "已收费"); private final int code; private final String desc; // 构造方法和getter省略 // 校验状态流转是否合法 public static boolean canTransfer(int from, int to) { if (from == NOT_VISITED.code && to == VISITED.code) return true; if (from == VISITED.code && to == CHARGED.code) return true; return false; } }收费Service里先查当前状态,判断能否流转,再执行更新。这样即使前端传了错误的参数,后端也能拦住。
@Transactional(rollbackFor = Exception.class) public void charge(Integer registerId, BigDecimal amount) { Register register = registerMapper.selectById(registerId); if (register == null) { throw new BusinessException("挂号记录不存在"); } // 只有已就诊状态才能收费 if (!RegisterStatus.canTransfer(register.getStatus(), RegisterStatus.CHARGED.getCode())) { throw new BusinessException("当前状态不允许收费"); } // 更新挂号状态 registerMapper.updateStatus(registerId, RegisterStatus.CHARGED.getCode()); // 更新处方状态 prescriptionMapper.updateStatusByRegisterId(registerId, 1); // 插入收费记录 Charge charge = new Charge(); charge.setRegisterId(registerId); charge.setAmount(amount); charge.setChargeTime(new Date()); chargeMapper.insert(charge); }状态机的好处是业务逻辑清晰,答辩时能画出一张状态流转图,比一堆if-else有说服力得多。
5. 避坑与排查:智慧医疗HIS系统跑不起来怎么办
5.1 启动报错“Table ‘his_db.xxx’ doesn‘t exist”
现象:后端启动时控制台报Table 'his_db.sys_user' doesn't exist,但你去数据库里查,表明明在。
原因:最常见的是数据库连接配置里指定的库名和实际导入的库名不一致。比如配置里写的是his_db,但你导入SQL时建的是his。另一个原因是MyBatis的mapper-locations配置路径不对,导致XML文件没加载,但这种情况通常报的是Invalid bound statement而不是表不存在。
解决:先执行SELECT DATABASE();确认当前连接的库,再检查application.yml里的URL。如果库名没错,检查MySQL的大小写敏感设置。Linux下MySQL默认区分大小写,Windows下不区分。如果SQL文件里建表用的大写Sys_User,而代码里查的是sys_user,在Linux上就会报错。统一用 snake_case 小写命名最稳妥。
5.2 登录后菜单空白或403错误
现象:输入账号密码能登录成功,但登录后页面空白,或者点任何菜单都提示403无权限。
原因:RBAC权限数据没有正确关联。sys_user_role表里没有给当前用户分配角色,或者sys_role_menu表里没有给角色分配菜单。另一个可能是前端路由守卫拿到的权限列表为空,导致所有动态路由都没注册。
解决:直接查数据库。先查sys_user_role里有没有当前用户的记录,再查sys_role_menu里有没有该角色的菜单记录。如果数据缺失,手动插入或者重新执行初始化SQL。前端部分,在路由守卫里打印一下从后端拿到的权限列表,确认数据是否正常返回。
-- 检查用户角色关联 SELECT * FROM sys_user_role WHERE user_id = 1; -- 检查角色菜单关联 SELECT * FROM sys_role_menu WHERE role_id = 1; -- 如果为空,手动补一条 INSERT INTO sys_user_role (user_id, role_id) VALUES (1, 1);5.3 中文乱码从数据库到页面全链路排查
现象:页面显示的中文变成问号或者乱码,比如“内科”显示成“???”。
原因:乱码可能出现在三个环节——数据库字符集、连接URL字符集、前端页面编码。数据库建库时如果用了latin1,存中文就会丢。连接URL里没加characterEncoding=utf-8,传输过程会乱。前端HTML的meta标签没声明UTF-8,浏览器解析会乱。
解决:按链路逐个排查。先执行SHOW VARIABLES LIKE 'character%';确认数据库字符集是utf8mb4。再检查JDBC URL里有没有characterEncoding=utf-8。最后检查前端index.html里有没有<meta charset="utf-8">。三个地方都对了,乱码问题基本就解决了。
注意:MySQL的
utf8和utf8mb4不一样,utf8最多存3字节,存不了emoji和部分生僻字。建库时直接用utf8mb4,省得后面改。
5.4 前端npm install卡住或报node-sass错误
现象:执行npm install时卡在node-sass的编译阶段,或者报Python not found、gyp ERR!之类的错误。
原因:node-sass是一个需要本地编译的包,依赖Python2和node-gyp。Node版本越高,编译越容易失败。很多老项目锁定的是Node 14,你用Node 18就会翻车。
解决:最省事的办法是用dart-sass替换node-sass。在package.json里把node-sass改成sass,然后把代码里@import的写法保持不变,dart-sass兼容大部分语法。如果不想改依赖,就装一个Node 14的环境,用nvm切换版本。
# 查看当前Node版本 node -v # 如果版本太高,用nvm切换到14 nvm install 14 nvm use 14 # 删除node_modules和package-lock.json后重新安装 rm -rf node_modules package-lock.json npm install5.5 接口返回时间差8小时
现象:前端显示的挂号时间是2024-01-01 08:00:00,但数据库里存的是2024-01-01 00:00:00,差了8小时。
原因:MySQL的时区是UTC,Java应用的时区是GMT+8,两边不一致。JDBC URL里没配serverTimezone,或者配成了UTC。
解决:在JDBC URL里明确指定serverTimezone=Asia/Shanghai。如果已经配了但还是差,检查MySQL的全局时区设置:SHOW VARIABLES LIKE '%time_zone%';。如果system_time_zone是UTC,可以在MySQL配置文件里加default-time-zone='+08:00',重启MySQL生效。
# 正确的JDBC URL示例 url: jdbc:mysql://localhost:3306/his_db?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false6. 让智慧医疗HIS系统在答辩中拿高分的三个进阶技巧
6.1 用AOP记录操作日志,答辩时能演示审计功能
HIS系统涉及处方、收费等敏感操作,操作日志是一个很好的加分项。用Spring AOP加自定义注解,可以在不侵入业务代码的前提下记录谁在什么时间做了什么操作。定义一个@Log注解,在Controller方法上标注,AOP切面里获取当前登录用户、请求参数、执行结果,写入sys_oper_log表。
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Log { String module() default ""; String operation() default ""; } @Aspect @Component public class LogAspect { @Around("@annotation(logAnnotation)") public Object around(ProceedingJoinPoint point, Log logAnnotation) throws Throwable { long start = System.currentTimeMillis(); Object result = point.proceed(); long cost = System.currentTimeMillis() - start; // 获取当前用户 String username = SecurityUtils.getCurrentUsername(); // 获取方法名和参数 String methodName = point.getSignature().getName(); String params = Arrays.toString(point.getArgs()); // 写入日志表 OperLog operLog = new OperLog(); operLog.setUsername(username); operLog.setModule(logAnnotation.module()); operLog.setOperation(logAnnotation.operation()); operLog.setMethod(methodName); operLog.setParams(params); operLog.setCostTime(cost); operLog.setCreateTime(new Date()); operLogMapper.insert(operLog); return result; } }答辩时你可以演示:用admin登录开一张处方,然后用另一个账号登录查看操作日志,能看到admin在几点几分开了什么处方。这个演示效果比单纯讲代码好得多。
6.2 用Swagger生成接口文档,省去手写文档的时间
毕业设计通常要求提交接口文档。手写文档费时费力还容易和代码不一致。集成Swagger或者Knife4j,启动后访问/doc.html就能看到所有接口的在线文档,还能直接测试。Spring Boot 2.x用springfox-swagger2,Spring Boot 3.x用springdoc-openapi。加依赖、加配置类、在Controller上加注解,三步搞定。
@Configuration @EnableSwagger2 public class SwaggerConfig { @Bean public Docket docket() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(new ApiInfoBuilder() .title("智慧医疗HIS系统接口文档") .version("1.0") .build()) .select() .apis(RequestHandlerSelectors.basePackage("com.his.controller")) .paths(PathSelectors.any()) .build(); } }注意:Swagger在生产环境要关闭,否则接口信息暴露有安全风险。在
application.yml里加一个swagger.enable开关,开发环境true,生产环境false。
6.3 用Redis缓存科室和药品字典,提升查询性能
HIS系统里科室列表、药品字典这类数据变动少、查询频繁。每次挂号都去查数据库,并发一高数据库压力就大。用Redis做缓存,第一次查数据库后写入Redis,后续请求直接读Redis。Spring Boot集成Redis只需要加spring-boot-starter-data-redis依赖,配好连接信息,用StringRedisTemplate或RedisTemplate操作。
@Service public class DepartmentService { @Autowired private StringRedisTemplate redisTemplate; @Autowired private DepartmentMapper departmentMapper; private static final String CACHE_KEY = "his:department:list"; public List<Department> listAll() { // 先查缓存 String cached = redisTemplate.opsForValue().get(CACHE_KEY); if (cached != null) { return JSON.parseArray(cached, Department.class); } // 缓存没有,查数据库 List<Department> list = departmentMapper.selectAll(); // 写入缓存,设置10分钟过期 redisTemplate.opsForValue().set(CACHE_KEY, JSON.toJSONString(list), 10, TimeUnit.MINUTES); return list; } }答辩时老师如果问“系统性能怎么优化”,你可以从缓存、索引、分页三个角度回答。缓存讲Redis,索引讲register表的patient_id和doctor_id加了普通索引,分页讲MyBatis的PageHelper插件。这三个点覆盖了大部分性能问题。
我自己做这类项目最大的教训是:不要一上来就改代码,先把项目跑通,把主流程走一遍,再动手改。很多同学拿到源码第一件事是改界面、加功能,结果改到一半发现数据库连不上,回头排查环境问题,时间全浪费了。先跑通、再理解、最后改造,这个顺序能帮你省下大量返工时间。希望帮到你。
本文还有配套的精品资源,点击获取