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 key
        Constants.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> {

    @Autowired
    protected FeedbackDao userDao;

        /**
     * 查询满足指定条件的Feedback列表
     *
     * @param o 查询条件对象
     * @return 满足条件的Feedback列表
     */
    @Override
    public List<Feedback> query(Feedback o) {
        // 创建QueryWrapper对象
        QueryWrapper<Feedback> wrapper = new QueryWrapper();
        if (Assert.notEmpty(o)) {
            // 将对象转换为Map
            Map<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);
    }

    @Override
    public List<Feedback> all() {
        return query(null);
    }

    @Override
    public Feedback save(Feedback o) {
        if (Assert.isEmpty(o.getId())) {
            userDao.insert(o);
        } else {
            userDao.updateById(o);
        }
        return userDao.selectById(o.getId());
    }

    @Override
    public Feedback get(Serializable id) {
        return userDao.selectById(id);
    }

    @Override
    public 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> {

    @Autowired
    protected IllnessDao illnessDao;

    @Override
    public 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);
    }

    @Override
    public List<Illness> all() {
        return query(null);
    }

    @Override
    public Illness save(Illness o) {
        if (Assert.isEmpty(o.getId())) {
            illnessDao.insert(o);
        } else {
            illnessDao.updateById(o);
        }
        return illnessDao.selectById(o.getId());
    }

    @Override
    public Illness get(Serializable id) {
        return illnessDao.selectById(id);
    }

    @Override
    public 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条记录)被硬编码在查询中,可以作为常量提取出来。

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java多线程之线程池,volatile,悲观锁,乐观锁,并发工具类

目录 1.线程池核心原理1.创建线程池2.任务拒绝策略3.自定义线程池 2.线程池的大小1.最大并行数2.影响线程池大小的因素 3.多线程常见考点&#xff08;volatile&#xff0c;悲观锁&#xff0c;乐观锁&#xff09;4.并发工具类 1.线程池核心原理 ①创建一个空的池子 ②提交任务时…

c++写入数据到文件中

假设你想编写一个C程序&#xff1a;当你在调试控制台输入一些数据时&#xff0c;系统会自动存入到指定的文件中&#xff0c;该如何操作呢&#xff1f; 具体操作代码如下&#xff1a; #include<iostream> #include<string> #include<fstream> using namespa…

Spring Boot日志:从Logger到@Slf4j的探秘

写在前面 Hello大家好&#xff0c;今日是2024年的第一天&#xff0c;祝大家元旦快乐&#x1f389; 2024第一篇文章从SpringBoot日志开始 文章目录 一、前言二、日志有什么用&#xff1f;三、日志怎么用&#xff1f;四、自定义日志打印&#x1f4ac; 常见日志框架说明4.1 在程序…

【教3妹学编程-算法题】一年中的第几天

3妹&#xff1a;“太阳当空照&#xff0c;花儿对我笑&#xff0c;小鸟说早早早&#xff0c;你为什么背上炸药包” 2哥 :3妹&#xff0c;什么事呀这么开森。 3妹&#xff1a;2哥你看今天的天气多好啊&#xff0c;经过了一周多的寒潮&#xff0c;天气总算暖和些了。 2哥&#xff…

VUE——IDEA 启动前端工程VS文件启动前端工程

IDEA 启动前端 目录 前言一、打开控制台二、输入npm install三、依赖下载完之后&#xff0c;输入npm run dev&#xff0c;运行前端项目1、IDEA启动前端工程2、文件目录启动前端工程 四、点击http://localhost:8080后续敬请期待 前言 启动已有的vue前端项目 一、打开控制台 选…

服务器硬件及RAID配置实战

目录 1、RAID的概念 2、RAID的实现方式 3、标准的RAID 3.1 RAID 0 3.2 RAID 1 3.3 RAID 5 3.4 RAID 10 4、建立硬件 RAID的过程步骤 1、进入RAID 1.1 重启服务器 1.2 进入RAID界面 1.3 在RAID界面切换目录 2、创建RAID 2.1 移动到RAID卡 2.2 按F2&#xff0c;选择…

NullByte

信息收集 # nmap -sn 192.168.1.0/24 -oN live.nmap Starting Nmap 7.94 ( https://nmap.org ) at 2023-12-29 09:23 CST Nmap scan report for 192.168.1.1 Host is up (0.00038s latency). MAC Address: 00:50:56:C0:00:08 (VMware) Nmap scan report for …

Rust学习笔记006:代码组织

Crate 在Rust中&#xff0c;“crate” 是指 Rust 的代码单元&#xff0c;它可以包含一个或多个模块&#xff08;modules&#xff09;。Rust 的 crate 分类主要有两个方面&#xff1a;库&#xff08;Library Crates&#xff09;和二进制&#xff08;Binary Crates&#xff09;。…

UE4运用C++和框架开发坦克大战教程笔记(十三)(第40~42集)

UE4运用C和框架开发坦克大战教程笔记&#xff08;十三&#xff09;&#xff08;第40~42集&#xff09; 40. 多按键绑定41. 自动生成对象42. 资源模块数据结构测试自动生成对象按资源类型生成对象 40. 多按键绑定 上节课实现了按键绑定系统的 4 种基础绑定&#xff0c;这节课来…

【大数据面试知识点】Spark的DAGScheduler

Spark数据本地化是在哪个阶段计算首选位置的&#xff1f; 先看一下DAGScheduler的注释&#xff0c;可以看到DAGScheduler除了Stage和Task的划分外&#xff0c;还做了缓存的跟踪和首选运行位置的计算。 DAGScheduler注释&#xff1a; The high-level scheduling layer that i…

畅捷通的 Serverless 探索实践之路

作者&#xff1a;计缘&#xff0c;阿里云云原生架构师 畅捷通介绍 畅捷通是中国领先的小微企业财税及业务云服务提供商&#xff0c;成立于 2010 年。畅捷通在 2021 年中国小微企业云财税市场份额排名第一&#xff0c;在产品前瞻性及行业全覆盖方面领跑市场&#xff0c;位居中…

C:Huffman编码a

【问题描述】 给定一组字符的Huffman编码表&#xff08;从标准输入读取&#xff09;&#xff0c;以及一个用该编码表进行编码的Huffman编码文件&#xff08;存在当前目录下的in.txt中&#xff09;&#xff0c;编写程序实现对Huffman编码文件的解码&#xff0c;并按照后序遍历序…

【UE 截图】 自定义截图路径 文件名

目录 0 引言1 实践 &#x1f64b;‍♂️ 作者&#xff1a;海码007&#x1f4dc; 专栏&#xff1a;UE虚幻引擎专栏&#x1f4a5; 标题&#xff1a;【UE 截图】 自定义截图路径 文件名❣️ 寄语&#xff1a;书到用时方恨少&#xff0c;事非经过不知难&#xff01;&#x1f388; 最…

zlib.decompressFile报错 【Bug已解决-鸿蒙开发】

文章目录 项目场景:问题描述原因分析:解决方案:方案1方案2此Bug解决方案总结寄语项目场景: 最近也是遇到了这个问题,看到网上也有人在询问这个问题,本文总结了自己和其他人的解决经验,解决了zlib.decompressFile报错 的问题。 问题: zlib.decompressFile报错,怎么解…

基于ssm的房屋租赁管理系统

功能介绍 房源信息模块&#xff1a; 房源信息展示、房源信息更新、房源信息增加、房源信息删除 账户管理模块&#xff1a; 账户登录、账户绑定、账户管理 租金结算模块&#xff1a; 每月租金信息、租金交付功能、月租金收入总额统计 房屋租赁合同管理模块&#xff1a; 房屋租赁…

【C语言】函数

函数是什么&#xff1f; “函数”是我们早些年在学习数学的过程中常见的概念&#xff0c;简单回顾一下&#xff1a;比如下图中&#xff0c;你给函数 f(x)2*x3 一个具体的x,这个函数通过一系列的计算来返回给你一个结果(图示如下)。 这就是数学中函数的基本过程和作用。但是你…

1.4 FMEA概述

FMEA适用场景 FMEA在三种基本情形下使用&#xff0c;每种情形都有不同的范围或重点。 情形1&#xff1a;新设计、新技术或新过程 FMEA的范围包括完整的设计、技术或过程。 情形2&#xff1a;现有设计或过程的新应用 FMEA的范围包含新环境、新场地、新应用或使用概况&#…

Servlet见解3

13 Cookie和Session http协议是一个无状态的协议&#xff0c;你每一个跳转到下一个页面的时候都是需要先登录才能使用&#xff0c;这样就很麻烦比如淘宝&#xff0c;没有cookie和session的话&#xff0c;用户在首页已经登录上去了&#xff0c;但是需要再次登录才能选择商品&am…

买对好车省钱又防坑,高性价比的买车攻略

一、教程描述 正所谓隔行如隔山&#xff0c;买车这件事情并不简单&#xff0c;买车的内幕还是有不少的&#xff0c;本套教程讲述买车攻略&#xff0c;非常适合准备买车的朋友&#xff0c;可以帮助大家买车少入坑&#xff0c;高性价比买到自己心仪的车。本套买车教程&#xff0…

Android 13 动态启用或禁用IPV6

介绍 客户想要通过APK来控制IPV6的启用和禁用&#xff0c;这里我们通过广播的方式来让客户控制IPV6。 效果展示 adb shell ifconfig 这里我们用debug软件&#xff0c;将下面节点置为1 如图ipv6已被禁用了 echo 1 > /proc/sys/net/ipv6/conf/all/disable_ipv6 修改 接下来…