尚医通概览

尚医通概览

项目介绍

医院预约挂号项目,包含三个系统:

  1. 预约挂号系统前台
  2. 预约挂号系统管理员后台
  3. 外部医院管理后台(已经开发好)

如图所示:

项目功能

预约挂号系统前台

  • 登录
  • 首页信息展示
  • 预约挂号
  • 支付订单

预约挂号系统管理员后台

  • 数据字典
    • easy Excel 导入导出
  • 医院管理
  • 用户管理
  • 订单(预约)管理
  • 统计管理

医院接口模拟平台

相当于医院自己维护的系统,通过签名校验的方式调研我们提供的接口来管理医院数据。

技术栈

前端

  • Vue
  • vue-admin-template管理员模板
  • ueQriously二维码生成库
  • babel
  • webpack
  • nuxt服务端渲染
  • element ui

后端

微服务:

  • Spring Cloud Alibaba框架
  • Nacos注册中心
  • Spring Cloud Feign远程调用
  • Spring Cloud Gateway微服务网关
  • Maven子父多模块
  • Docker(部署项目、安装服务)

数据存储:

  • MongoDB:负责存医院基本信息(性更高)
  • mySQL:存储用户、订单、预约等关系信息

中间件:

  • Redis:缓存、存储验证码
  • RabbitMQ:应用解耦、消息通知
  • Nginx:部署项目

工具库:

  • easy excel:读写Excel文件
  • Json Web Token:生成jwt token
  • Joda Time:日期时间操作

架构中并没搭建集群,都是用的单机版

项目学习

本项目重点知识

  1. 微服务的思想、划分以及实现方式,以及相关技术的用法:
    • 注册中心
    • 客户端调用
    • 微服务网关
  2. 熟悉一个完整的业务流程(信息发布=>信息展示=>购买=>下单支付=>统计管理)
  3. 登录认证机制,包括手机号登录、微信扫码登绿、OAuth、JWT等知识
  4. 如何运用合适的数据库来解决问题?比如MySQL存储关系型数据、Redis用于缓存、MongoDB存储一些非关系型的数据(提高访问速度)、RāobitMQ来实现异步通知和应用解耦。
  5. 调用第三方API来解决实际问题,比如微信接口、OSS、SMS
  6. 学习项目的目录结构及编码规范,比如通用返回对象、全局异常处理器、ContextHolder等

项目启动流程

  1. 启动nacos

    startup.cmd -m standalone

  2. 启动docker上的rabbit,redis,MongoDB

  3. 启动后端
    spring一键启动

  4. 启动yygh_sit,用户前台
    选第二个dev nuxt

  5. 启动yygh_admin,管理员后台
    选第一个start

端口分析:

  • ​ 80是服务网关
  • ​ 8160是用户api接口服务
  • ​ 8201是医院api接口服务
  • ​ 8202是数据字典服务
  • ​ 8204是短信 api接口服务
  • ​ 8205是文件api接口服务
  • ​ 8206是订单api接口服务
  • ​ 8207是定时任务服务
  • ​ 8208是统计api接口服务
  • ​ 9998是接口模拟系统

测试前台vue_site可以只启动:80,8160,8201,8202,8204

管理后台vue_admin可以直接运行

后端微服务学习:

本项目的服务划分如下:

  • common项目公共代码
  • model项目数据模型层(只提供接口,便于公用)
  • service具体的业务逻辑(微服务)
  • service client服务调用客户端(只提供接口,便于公用)
  • service_.gateway(微服务网关)负责统一校验/拦截、跨域、请求转发
  • 公共服务:数据字典管理,导入导出(公共用的枚举值)
  • 医院服务:管理医院,医院信息、排版信息、医院设置信息的增删改查
  • 短信服务(SMS):负责发送短信验证码
  • 用户服务:管理用户、就诊人、用户登泉
  • 订单服务:支付订单,订单(预约)管理
  • 存储服务:上传文件(上传用户的图片)
  • 统计服务:分析下单情况
  • 定时任务服务:每天8点就医提醒

数据库设置:

  • yygh_cnm
    dict:组织架构表,数据字典的数据

  • yygh_hosp
    hospital_set,医院列表

  • yygh_manage
    hospital_set,医院设置表
    order_info,订单表
    schedule,医生排班表

  • yygh_order
    order_info,订单表
    payment_info,支付信息表
    refund_info,退款信息表

  • yygh_user
    patient,就诊人表
    user_info.用户表
    user_login_record,用户登录记录表

首先搭建父工程模块yygh-parent,该模块不需要编写代码只需要一个POM文件即可。它的作用就是一个规范,将要使用的依赖引入并指定版本号,在后续的子模块中只需要引入依赖不需要指定版本号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<properties>
<java.version>1.8</java.version>
<cloud.version>Hoxton.RELEASE</cloud.version>
<alibaba.version>2.2.0.RELEASE</alibaba.version>
<mybatis-plus.version>3.3.1</mybatis-plus.version>
<mysql.version>5.1.46</mysql.version>
<swagger.version>2.7.0</swagger.version>
<jwt.version>0.7.0</jwt.version>
<fastjson.version>1.2.29</fastjson.version>
<httpclient.version>4.5.1</httpclient.version>
<easyexcel.version>2.2.0-beta2</easyexcel.version>
<aliyun.version>4.1.1</aliyun.version>
<oss.version>3.9.1</oss.version>
<jodatime.version>2.10.1</jodatime.version>
</properties>

整体结构

common模块:

将会重复使用的模块抽离出来形成一个单独模块,其他模块在使用的时候直接在POM中加入依赖即可

common目录结构:

common:公共模块父节点
common-util:工具类模块,所有模块都可以依赖于它
rabbit-util:rabbitmq业务封装
service-util:service服务的工具包,包含service服务的公共配置类,所有service模块依赖于它

common_util子模块:

设置项目编码中的统一规范

  • GlobalExceptionHandler:默认全局异常
  • YyghException:自定义全局异常
  • JwtHelper:设置JWT的登录验证
  • Result:自定义返回类型
  • ResultCodeEnum:返回状态码,例如200成功201失败
  • AuthContextHolder:获取当前用户信息

rabbit-util子模块:

进行rabbitmq的业务封装

  • MQConfig:mq的配置文件,例如设置消息转换器,将消息队列中的数据转换成指定类型
  • MqConst:设置消息的状态码
  • RabbitService:消息的发送

service-util子模块:

service服务的工具包

  • RedisConfig:Redis配置文件
  • Swagger2Config:Swagger配置文件
  • HttpRequestHelper:自定义service请求
  • HttpUtil:自定义Http请求
  • MD5:设置MD5加密

hospital-manage模块:

医院接口模拟端(已开发,直接使用)

hospital-manage目录结构:

application.yml:

1
2
3
4
5
spring:
application:
name: hospital-manage
profiles:
active: dev

设置项目环境为dev

相应的就会执行application-dev.yml中的配置

model模块:

根据数据库中的表创建对应的实体类

目录结构:

在实体类中添加注解

1
2
3
@Data
@ApiModel(description = "权限") 在swagger中设置方法注解
@TableName("acl_permission") 对应数据库中表的名称

在字段上添加注解

1
2
3
@ApiModelProperty(value = "所属上级")		对应数据库中的字段
@TableField("pid") 在swagger中设置字段
@TableField(exist = false) 如果该字段不存在数据库中

对于使用EasyExcel要进行导入导出的数据添加注解

1
@ExcelProperty(value = "id" ,index = 0)		设置导出列的名称和第几列

Service模块:

api接口服务父节点

目录结构:

service:api接口服务父节点

  • ​ service-hosp:医院api接口服务
  • ​ service-cmn:数据字典服务
  • ​ service-user:用户api接口服务
  • ​ service-order:订单api接口服务
  • ​ service-oss:文件api接口服务
  • ​ service-sms:短信 api接口服务
  • ​ service-task:定时任务服务
  • ​ service-statistics:统计api接口服务

service-cmn子模块:

公共api接口服务

目录结构:

关于Service模块大致都是这么一个结构

首先在mapper包中创建为当前模块使用的mapper接口继承Basemapper,使用mybatisplus包中封装好的增删改查方法如果需要写其他的sql语句再在该接口中增加抽象方法

1
public interface DictMapper extends BaseMapper<Dict> {}

在service包中编写业务接口并创建抽象方法、

1
2
3
4
public interface DictService extends IService<Dict> {
//根据数据id查询子数据列表
List<Dict> findChlidData(Long id);
}

在impl中实现该接口并在实现的抽象方法中编写具体的业务逻辑,添加@service注解交给spring管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Service
public class DictServiceImpl extends ServiceImpl<DictMapper, Dict> implements DictService {

//根据数据id查询子数据列表
@Override
//@Cacheable(value = "dict",keyGenerator = "keyGenerator")
public List<Dict> findChlidData(Long id) {
QueryWrapper<Dict> wrapper = new QueryWrapper<>();
wrapper.eq("parent_id",id);
List<Dict> dictList = baseMapper.selectList(wrapper);
//向list集合每个dict对象中设置hasChildren
for (Dict dict:dictList) {
Long dictId = dict.getId();
boolean isChild = this.isChildren(dictId);
dict.setHasChildren(isChild);
}
return dictList;
}
}

在controller包中注入sevice接口,调用service中的各种方法处理请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Api(description = "数据字典接口")
@RestController
@RequestMapping("/admin/cmn/dict")
public class DictController {

@Autowired
private DictService dictService;

//导入数据字典
@PostMapping("importData")
public Result importDict(MultipartFile file) {
dictService.importDictData(file);
return Result.ok();
}
}

@Autowired为什么注入接口就可以使用其实现类?

@Autowired默认按byType(自动装配)注入:寻找实现了interface的Bean(在实现类上添加注解@Service后就相当于在xml中编写了配置),这个注解适用于只有一个Bean实现了接口的情况。

能不能直接注入接口的实现类?

开发中往往会对实现类做增强,如事务,日志等,实现增强的AOP技术是通过动态代理实现的,而spring默认是JDK动态代理,对实现类对象做增强得到的增强类与实现类是兄弟关系,所以不能用实现类接收增强类对象,只能用接口接收。如果将对象注入给实现类而非接口的话,在代理时就会报错。

可以用Cglib代理强制实现,cglib代理类和实现类之间是父子关系,自然可以用父类(实现类)去接收子类对象(代理类对象即增强类对象)。

在config包中创建配置类:对当前模块进行配置,例如设置数据库的查询分页

1
2
3
4
5
6
7
8
9
10
11
//指定要变成实现类的接口所在的包,然后包下面的所有接口在编译之后都会生成相应的实现类
@MapperScan("com.atguigu.yygh.cmn.mapper")
public class CmnConfig {
/**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}

listener为EasyExcel的导入导出配置类

service-hosp子模块:

医院api接口服务

目录结构:

在mapper包中除了原来的mapper接口还有xml包用于对应mapper接口

当Basemapper中方法不能满足需求时在xml中编写自己的sql语句

1
2
3
4
5
6
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.yygh.hosp.mapper.HospitalSetMapper">

</mapper>

repository包和mapper包类似,创建接口继承 Mongodb调用对数据库的增删改查方法,根据业务需求增加抽象方法

HospitalReceiver:对rabbit消息队列进行设置

controller包:

将经常使用的控制类放到api包下,处理经常发出的请求

service-msm子模块:

短信 api接口服务

目录结构:

service-order子模块:

订单api接口服务

目录结构:

service-oss子模块:

文件api接口服务

目录结构:

service-statistics子模块:

统计api接口服务

目录结构:

service-task子模块:

定时任务服务

目录结构:

service-user子模块:

用户api接口服务

目录结构:

service-client模块:

feign服务调用父节点

目录结构:

  • service-cmn-client:公共api接口

  • service-hosp-client:医院api接口

  • service-order-client:订单api接口

  • service-user-client:用户api接口

  • Feign是声明式Web Service客户端它让微服务之间的调用变得更简单,类似controller调用service。SpringCloud集成了Ribbon和Eureka,可以使用Feigin提供负载均衡的http客户端

  • 只需要创建一个接口,然后添加注解即可使用Feign

1
@FeignClient(value = "service-cmn")

当声明FeignClient后其他微服务就可以直接注入使用该模块,使得微服务之间的调用更方便了

1
2
@Autowired
private DictFeignClient dictFeignClient;

server-gateway模块:

服务网关过滤请求设置访问路由

目录结构:


尚医通概览
https://yztldxdz.top/2022/10/01/尚医通-概览/
发布于
2022年10月1日
许可协议