SpringBoot 医药咨询系统

在这里插入图片描述

概述

智慧医药系统(smart-medicine)是一个基于 SpringBoot 开发的Web 项目。整体页面简约大气,增加了AI医生问诊功能,功能设计的较为简单。

开源地址

https://gitcode.net/NVG_Haru/Java_04

界面预览

在这里插入图片描述

在这里插入图片描述

功能介绍

游客功能介绍

功能模块功能描述
登录注册方面注册成为系统用户
系统主页浏览系统主页、疾病、药品信息搜索、详情的查看(统计浏览量)

用户功能介绍

功能模块功能描述
登录注册方面填写用户信息进行账号注册(邮件接收验证码)、使用账号密码进行登录
个人资料方面修改个人资料(姓名、年龄、手机号、头像等)、修改登录密码
系统反馈方面提交系统反馈意见
智能医生方面与智能医生进行交流聊天

管理员功能介绍

功能模块功能描述
登录注册方面填写用户信息进行账号注册(邮件接收验证码)、使用账号密码进行登录
个人资料方面修改个人资料(姓名、年龄、手机号、头像等)、修改登录密码
系统反馈方面提交系统反馈意见
智能医生方面与智能医生进行交流聊天
疾病管理方面发布疾病、编辑(名称、原因、症状、分类等)、删除药品等
药品管理方面发布药品、编辑(名称、搜索关键词、功效、用法用量、类型等)、关联疾病、删除药品等
反馈管理方面管理用户提交的反馈信息

数据库设计

在这里插入图片描述

代码讲解

AI 问诊功能

这个功能借助阿里通义千问大模型实现,调用了com.alibaba.dashscope.*sdk提供的接口,主要流程如下:

  1. 创建Generation对象
  2. 创建MessageManager对象
  3. 创建系统消息
  4. 将系统消息和用户消息添加到MessageManager中
  5. 创建QwenParam对象
  6. 调用Generation的call方法,获取GenerationResult对象
  7. 获取GenerationResult对象的输出部分
  8. 获取输出中的第一个消息并返回
    public String query(String queryMessage) {// 设置API keyConstants.apiKey = apiKey;try {// 创建Generation对象Generation gen = new Generation();// 创建MessageManager对象MessageManager msgManager = new MessageManager(10);// 创建系统消息Message systemMsg = Message.builder().role(Role.SYSTEM.getValue()).content("你是智能医生,你只回答与医疗相关的问题,不要回答其他问题!").build();// 创建用户消息Message userMsg = Message.builder().role(Role.USER.getValue()).content(queryMessage).build();// 将系统消息和用户消息添加到MessageManager中msgManager.add(systemMsg);msgManager.add(userMsg);// 创建QwenParam对象QwenParam param = QwenParam.builder().model(Generation.Models.QWEN_TURBO).messages(msgManager.get()).resultFormat(QwenParam.ResultFormat.MESSAGE).build();// 调用Generation的call方法,获取GenerationResult对象GenerationResult result = gen.call(param);// 获取GenerationResult对象的输出部分GenerationOutput output = result.getOutput();// 获取输出中的第一个消息Message message = output.getChoices().get(0).getMessage();// 返回消息的内容return message.getContent();} catch (Exception e) {return "智能医生现在不在线,请稍后再试~";}}

反馈功能

主要讲解一下query这个查询函数,该函数接受一个Feedback实体函数,实际上这是一种偷懒的做法,最佳方案还是确定好哪些参数可以进入函数。

package world.xuewei.service;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import world.xuewei.dao.FeedbackDao;
import world.xuewei.entity.Feedback;
import world.xuewei.utils.Assert;
import world.xuewei.utils.BeanUtil;
import world.xuewei.utils.VariableNameUtils;import java.io.Serializable;
import java.util.List;
import java.util.Map;/*** 反馈服务类**/
@Service
public class FeedbackService extends BaseService<Feedback> {@Autowiredprotected FeedbackDao userDao;/*** 查询满足指定条件的Feedback列表** @param o 查询条件对象* @return 满足条件的Feedback列表*/@Overridepublic List<Feedback> query(Feedback o) {// 创建QueryWrapper对象QueryWrapper<Feedback> wrapper = new QueryWrapper();if (Assert.notEmpty(o)) {// 将对象转换为MapMap<String, Object> bean2Map = BeanUtil.bean2Map(o);// 遍历Map中的键值对for (String key : bean2Map.keySet()) {if (Assert.isEmpty(bean2Map.get(key))) {continue;}// 根据键值对创建查询条件wrapper.eq(VariableNameUtils.humpToLine(key), bean2Map.get(key));}}// 执行查询操作return userDao.selectList(wrapper);}@Overridepublic List<Feedback> all() {return query(null);}@Overridepublic Feedback save(Feedback o) {if (Assert.isEmpty(o.getId())) {userDao.insert(o);} else {userDao.updateById(o);}return userDao.selectById(o.getId());}@Overridepublic Feedback get(Serializable id) {return userDao.selectById(id);}@Overridepublic int delete(Serializable id) {return userDao.deleteById(id);}
}

疾病功能

package world.xuewei.service;import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import world.xuewei.dao.IllnessDao;
import world.xuewei.entity.*;
import world.xuewei.utils.Assert;
import world.xuewei.utils.BeanUtil;
import world.xuewei.utils.VariableNameUtils;import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** 疾病服务类** @author XUEW*/
@Service
public class IllnessService extends BaseService<Illness> {@Autowiredprotected IllnessDao illnessDao;@Overridepublic List<Illness> query(Illness o) {QueryWrapper<Illness> wrapper = new QueryWrapper();if (Assert.notEmpty(o)) {Map<String, Object> bean2Map = BeanUtil.bean2Map(o);for (String key : bean2Map.keySet()) {if (Assert.isEmpty(bean2Map.get(key))) {continue;}wrapper.eq(VariableNameUtils.humpToLine(key), bean2Map.get(key));}}return illnessDao.selectList(wrapper);}@Overridepublic List<Illness> all() {return query(null);}@Overridepublic Illness save(Illness o) {if (Assert.isEmpty(o.getId())) {illnessDao.insert(o);} else {illnessDao.updateById(o);}return illnessDao.selectById(o.getId());}@Overridepublic Illness get(Serializable id) {return illnessDao.selectById(id);}@Overridepublic int delete(Serializable id) {return illnessDao.deleteById(id);}public Map<String, Object> findIllness(Integer kind, String illnessName, Integer page) {Map<String, Object> map = new HashMap<>(4);QueryWrapper<Illness> illnessQueryWrapper = new QueryWrapper<>();if (Assert.notEmpty(illnessName)) {illnessQueryWrapper.like("illness_name", illnessName).or().like("include_reason", illnessName).or().like("illness_symptom", illnessName).or().like("special_symptom", illnessName);}if (kind != null) {if (Assert.notEmpty(illnessName)) {illnessQueryWrapper.last("and (kind_id = " + kind + ") ORDER BY create_time DESC limit " + (page - 1) * 9 + "," + page * 9);} else {illnessQueryWrapper.eq("kind_id", kind);illnessQueryWrapper.orderByDesc("create_time");illnessQueryWrapper.last("limit " + (page - 1) * 9 + "," + page * 9);}} else {illnessQueryWrapper.orderByDesc("create_time");illnessQueryWrapper.last("limit " + (page - 1) * 9 + "," + page * 9);}int size = illnessDao.selectMaps(illnessQueryWrapper).size();List<Map<String, Object>> list = illnessDao.selectMaps(illnessQueryWrapper);list.forEach(l -> {Integer id = MapUtil.getInt(l, "id");Pageview pageInfo = pageviewDao.selectOne(new QueryWrapper<Pageview>().eq("illness_id", id));l.put("kindName", "暂无归属类");l.put("create_time", MapUtil.getDate(l, "create_time"));l.put("pageview", pageInfo == null ? 0 : pageInfo.getPageviews());Integer kindId = MapUtil.getInt(l, "kind_id");if (Assert.notEmpty(kindId)) {IllnessKind illnessKind = illnessKindDao.selectById(kindId);if (Assert.notEmpty(illnessKind)) {l.put("kindName", illnessKind.getName());}}});map.put("illness", list);map.put("size", size < 9 ? 1 : size / 9 + 1);return map;}public Map<String, Object> findIllnessOne(Integer id) {Illness illness = illnessDao.selectOne(new QueryWrapper<Illness>().eq("id", id));List<IllnessMedicine> illnessMedicines = illnessMedicineDao.selectList(new QueryWrapper<IllnessMedicine>().eq("illness_id", id));List<Medicine> list = new ArrayList<>(4);Map<String, Object> map = new HashMap<>(4);Pageview illness_id = pageviewDao.selectOne(new QueryWrapper<Pageview>().eq("illness_id", id));if (Assert.isEmpty(illness_id)) {illness_id = new Pageview();illness_id.setIllnessId(id);illness_id.setPageviews(1);pageviewDao.insert(illness_id);} else {illness_id.setPageviews(illness_id.getPageviews() + 1);pageviewDao.updateById(illness_id);}map.put("illness", illness);if (CollUtil.isNotEmpty(illnessMedicines)) {illnessMedicines.forEach(illnessMedicine -> {Medicine medicine = medicineDao.selectOne(new QueryWrapper<Medicine>().eq("id", illnessMedicine.getMedicineId()));if (ObjectUtil.isNotNull(medicine)) {list.add(medicine);}});map.put("medicine", list);}return map;}public Illness getOne(QueryWrapper<Illness> queryWrapper) {return illnessDao.selectOne(queryWrapper);}
}

讲一讲findIllnessOne,这个函数是一个用于查找疾病信息的方法。它接受三个参数:kind表示疾病类型,illnessName表示疾病名称,page表示页码。函数首先创建一个HashMap用于存储结果。然后创建一个QueryWrapper对象用于构建查询条件。如果illnessName不为空,则通过like操作符模糊匹配illness_name、include_reason、illness_symptom和special_symptom字段中的任意一个包含illnessName的内容。接下来根据kind和illnessName的值,构建查询条件,包括对kind_id和create_time的筛选和排序。然后通过调用illnessDao.selectMaps方法获取查询结果的列表。接着遍历列表,对每个疾病对象获取id,并通过pageviewDao.selectOne方法查询对应的pageview信息。然后将一些字段放入疾病对象的HashMap中,包括kindName(默认值为"暂无归属类")、create_time、pageview(如果查询失败则为0)和kindName(如果有)。接下来根据疾病列表的大小计算总页数,并将疾病列表和总页数放入HashMap中。最后将HashMap作为结果返回。

主要问题有:

  • 重复代码:在kind !=
    null和else部分,关于orderByDesc和last的查询条件重复了分页逻辑。可以简化这两个部分的代码。

  • 查询条件构造:like操作的字段和值应该使用占位符,这样可以避免SQL注入。

  • 断言Assert.notEmpty的使用:代码中使用了Assert.notEmpty,这通常用于校验条件,但在这个上下文中,这个校验似乎是多余的,因为如果illnessName为空,之前的like条件就无法匹配任何结果。

  • 使用更合适的数据容器:List和Map已经足够表达结果,可以考虑直接返回一个Page对象,而不是Map,其中包含数据列表和分页信息。

  • 代码可读性:一些变量的命名可以更加清晰,例如map变量可以命名为pageResult,以更清楚地表示它包含的是分页结果。

  • 避免硬编码:分页大小(即每页9条记录)被硬编码在查询中,可以作为常量提取出来。

  • 异常处理:在查询过程中,应该有适当的异常处理机制,以处理潜在的数据库访问错误。

  • 数据映射:数据映射和处理逻辑可以封装到单独的方法中,以提高代码的可读性和可维护性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/311557.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AIGC重塑基础设施,高密数据中心为何众望所归?

凯文凯利在《必然》中认为&#xff0c;科技在本质上有所偏好&#xff0c;使得它朝往某种特定方向。 毫无疑问&#xff0c;进入到数字经济时代&#xff0c;人工智能技术飞速发展与加速应用之际&#xff0c;这个特定方向逐渐明朗&#xff1a;即算力科技&#xff0c;算力已经成为…

Linux shell编程学习笔记38:history命令

目录 0 前言 1 history命令的功能、格式和退出状态1.1 history命令的功能1.2 history命令的格式1.3退出状态2 命令应用实例2.1 history&#xff1a;显示命令历史列表2.2 history -a&#xff1a;将当前会话的命令行历史追加到历史文件~/.bash_history中2.3 history -c&#xf…

训狗技术从初级到高级,专业有效的训狗训犬教程

一、教程描述 现在大部分人家里都会养些宠物&#xff0c;比如狗狗&#xff0c;虽然狗狗的一些行为习惯跟遗传有关&#xff0c;但是主人后天的影响也会给狗狗带来改变&#xff0c;本套教程教你纠正狗狗的不良行为&#xff0c;可以让你与狗愉快地玩耍。本套训狗教程&#xff0c;…

程序员必备IDEA插件,什么是是IDE?

IDEA是一款功能强大的集成开发环境&#xff08;IDE&#xff09;插件&#xff0c;它可以帮助开发人员更加高效地编写、调试和部署软件应用程序。 我们在编写完接口代码后需要进行接口调试等操作&#xff0c;一般需要打开额外的调试工具。今天就给大家介绍一款IDEA插件&#xff…

2023年成都市中等职业学校学生技能大赛“网络搭建及应用”赛项竞赛样卷

2023年成都市中等职业学校学生技能大赛 “网络搭建及应用”赛项竞赛样卷 &#xff08;总分1000分&#xff09; 目录 2023年成都市中等职业学校学生技能大赛 “网络搭建及应用”赛项竞赛样卷 网络建设与调试项目&#xff08;500分&#xff09; 服务器搭建与运维项目&#xff08;…

Rust学习笔记002: 猜字游戏

version0.1 // 导入标准库中的 io 模块&#xff0c;它包含了输入输出相关的功能 use std::io;// 程序的入口点 fn main() {println!("Guess the number!");println!("Please input your guess.");// 创建一个可变的字符串变量 guess&#xff0c;用于存储用…

【2023年终总结】谈谈一个新人眼里的阿里方法论

写在开头 2023年转眼就过去了&#xff0c;今年我从一名大学生转变某阿里系大厂的“搬砖打工人”&#xff0c;这一转变真的是给我“涉世未深的纯洁心灵”带来了大大的“震撼”。 角色的转变是需要时间进行“内部消化”的。无论是对于个人的价值认知或者是行为方式来说&#xf…

液晶时钟设计

#include<reg51.h> //包含单片机寄存器的头文件 #include<stdlib.h> //包含随机函数rand()的定义文件 #include<intrins.h> //包含_nop_()函数定义的头文件 sbit RSP2^0; //寄存器选择位&#xff0c;将RS位定义为P2.0引脚 sbit RWP2^1; //读写选…

ros2 run传递参数的格式

ros2 run teleop_twist_keyboard teleop_twist_keyboard --ros-args -r /cmd_vel:/model/vehicle_blue/cmd_vel #这个只能用于重命名节点名称可以用以下语法直接从命令行中设置参数&#xff1a; 这里很清楚看出来ros2 run name exec --ros-args -p param:value中的parma指的是…

“C语言与人生:手把手教你玩转C语言数组,从此编程无难题“

各位少年&#xff0c;我是博主那一脸阳光&#xff0c;由我来给大家介绍C语言的数组的详解。 在C语言中&#xff0c;数组是一种极其重要的数据结构&#xff0c;它允许我们存储和管理相同类型的一系列相关数据。通过理解并熟练掌握数组的使用&#xff0c;开发者能够高效地处理大量…

分布式文件系统的介绍

什么是分布式文件系统 跨越多个服务器或者多个位置的文件系统。其中涉及的技术包括数据的复制、数据的分片和路由,由于用户可能存储大文件、图片或者其他类似的需求性文件,因此需要设计不同的系统方便用户访问的存取。 任何设备通过任何网络位置访问文件,就像访问到自己的文…

VSCode使用Remote SSH远程连接Windows 7

结论 VSCode Server不能启动&#xff0c;无法建立连接。 原因 .vscode-server 目录中的 node.exe 无法运行。 原因是Node.js仅在Windows 8.1、Windows Server 2012 R2或更高版本上受支持。 由于vscode基于node.js v14&#xff0c;不支持Windows 7操作系统。 另&#xff…