尚医通即为网上预约挂号系统,网上预约挂号是近年来开展的一项便民就医服务,旨在缓解看病难、挂号难的就医难题,许多患者为看一次病要跑很多次医院,最终还不一定能保证看得上医生。网上预约挂号全面提供的预约挂号业务从根本上解决了这一就医难题。
包含后台管理系统和前台用户系统,采用前后端分离开发模式。项目技术应用广泛,涵盖微服务、全栈、分布式、高并发;技术应用场景合理,并非多技术的盲目堆叠;业务场景贴近实际,按照市场需求开发。
项目后端技术栈,采用主流的SpringBoot+SpringCloud微服务架构,全面使用了目前流行的NoSQL技术,使用Redis缓存数据,使用MongoDB实现高并发读写,整合消息中间件RabbitMQ提高订单的并发量,同时还整合了定时任务,实现就医提醒功能,综合应用了阿里云OSS,短信服务以及微信登录、微信支付,同时增加了微信退款功能。
项目前端技术栈,采用主流前端框架Vue,使用Nuxt和vue-admin-template模板搭建页面环境,采用Element-ui进行页面布局,Npm进行依赖管理,axios进行异步调用,使用ECharts进行图表显示,实现全栈开发。
2.1 架构图
2.2 业务流程图
3.1 后端技术栈
-
SpringBoot:简化新Spring应用的初始搭建以及开发过程
-
SpringCloud:基于Spring Boot实现的云原生应用开发工具,SpringCloud使用的技术:(SpringCloudGateway(网关)、Spring Cloud Alibaba Nacos(服务注册中心)、Spring Cloud Alibabasentinel(保护服务的稳定性)、SpringCloud Task()和SpringCloudFeig(远程过程调用)等)
-
MyBatis-Plus:持久层框架
-
Redis:内存缓存
-
RabbitMQ:消息中间件
-
HTTPClient: Http协议客户端
-
Swagger2:Api接口文档工具
-
Nginx:负载均衡
-
Lombok
-
Mysql:关系型数据库
-
MongoDB:面向文档的NoSQL数据库
3.2 前端技术栈
-
Vue.js:web 界面的渐进式框架
-
Node.js: Javascript 运行环境
-
Axios:Axios 是一个基于 promise 的 HTTP 库
-
NPM:包管理器
-
Babel:转码器
-
Webpack:打包工具
3.3 其他技术
-
Docker :容器技术
-
Git:代码管理工具
4.1 上传医院信息接口
首先实现的是医院基本信息,在后台管理网站上,可以由管理员管理和操作医院的一些信息,如医院名称、联系人、医院编号等
具体技术:
-
整合了swagger作为接口测试
-
封装结果集,使的返回的结果都遵循统一格式。(状态码+信息+数据)
-
@RequestBody注解,前端可以用Json格式传数据给后端
-
@RestController,采用Restfu风格传递路径和参数
-
@PostMapping、@GetMapping 和 @RequestMapping都一样,用来传递路径和参数(@RequestMapping(method = RequestMethod.GET)就是GetMapping,post同理)
4.2 数据字典
数据字典树形显示、导入、导出
-
@ComponentScan 的作用就是根据定义的扫描路径,把符合扫描规则的类装配到spring容器中
-
@Mapper:在接口类上添加了@Mapper,在编译之后会生成相应的接口实现类(Mapper层就是DAO层,是数据持久化层,写一些数据库语句什么的,在这个项目中因为是MybatisPlus,所以没有写多少sql语句)
-
@MapperScan:指定要变成实现类的接口所在的包,然后包下面的所有接口在编译之后都会生成相应的实现类
-
@TableField:MybatisPlus中的注解
关于exist,当model实体类中存在一个字段(因为elementUI中需要一个“hasChildren”字段),但是数据库表中没有,就可以在实体类中加注解:表示数据库中没有这个字段
4.3 利用EasyExcel导入和导出数据字典
easyExcel使用:
实体类注解:@ExcelProperty(“表头名称”)
读方法
实体类注解:@ExcelProperty(value=“表头名称”,index=0)标识从0开始读取
写一个监听器类继承AnalysisEventListener<>,里面有一个每行读取(从第二行开始,第一行是表头)方法,一个读取表头方法,一个读取结束后的方法
调用监听器方法实现读取
4.4 签名密钥校验
-
获取医院传过来的信息,获取签名,并且签名进行MD5加密
-
根据医院传过来的信息,获取医院编码,查询对应医院的签名,并且签名进行MD5加密
校验两个签名是否一致,一致才允许操作不一致直接抛出异常跳转页面即可
4.5 数据字典缓存
因为数据字典不经常修改,是一些省份和民族信息,所以可以放在缓存里,加快读取速度
-
@cacheable:只会执行一次,当标记在一个方法上时表示该方法是支持缓存的,Spring会在其被调用后将其返回值缓存起来,以保证下次利用同样的参数来执行该方法时可以直接从缓存中获取结果。
-
@cacheput:@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。,一般用在添加的方法上
-
@CacheEvict是用来标注在需要清除缓存元素的方法或类上的。当标记在一个类上时表示其中所有的方法的执行都会触发缓存的清除操作。
4.6 上传科室排班的接口
这个接口是对医院的工作人员开放的(本项目中模拟了一个医院的内部网站,医院的管理人员通过这个网站上的接口传递一些信息给我们的后台管理平台) 每个医院本身有自己的系统,通过调用我们给处的接口,可以上传医院信息、科室信息、排班信息到我们的平台上,方便患者查看挂号,同时医院当然也可以查询自己上传的以上信息。 此部分的数据库为mongodb。
4.7 MongoDB和MySQL的区别
MySQL与MongoDB都是开源的常用数据库,但是MySQL是传统的关系型数据库,MongoDB则是非关系型数据库,也叫文档型数据库,是一种NoSQL的数据库。它们各有各的优点,关键是看用在什么地方。所以我们所熟知的那些SQL语句就不适用于MongoDB了,因为SQL语句是关系型数据库的标准语言。
一、关系型数据库-MySQL
-
在不同的引擎上有不同的存储方式。
-
查询语句是使用传统的sql语句,拥有较为成熟的体系,成熟度很高。
-
开源数据库的份额在不断增加,mysql的份额页在持续增长。
-
缺点就是在海量数据处理的时候效率会显著变慢。
二、非关系型数据库-MongoDB
非关系型数据库(nosql ),属于文档型数据库。先解释一下文档的数据库,即可以存放xml、json、bson类型系那个的数据。这些数据具备自述性,呈现分层的树状数据结构。数据结构由键值(key=>value)对组成。
-
存储方式:虚拟内存+持久化。
-
查询语句:是独特的MongoDB的查询方式。
-
适合场景:事件的记录,内容管理或者博客平台等等。
-
架构特点:可以通过副本集,以及分片来实现高可用。
-
数据处理:数据是存储在硬盘上的,只不过需要经常读取的数据会被加载到内存中,将数据存储在物理内存中,从而达到高速读写。
-
成熟度与广泛度:新兴数据库,成熟度较低,Nosql数据库中最为接近关系型数据库,比较完善的DB之一,适用人群不断在增长。
三、MongoDB优势与劣势
优势:
-
在适量级的内存的MongoDB的性能是非常迅速的,它将热数据存储在物理内存中,使得热数据的读写变得十分快。
-
MongoDB的高可用和集群架构拥有十分高的扩展性。
-
在副本集中,当主库遇到问题,无法继续提供服务的时候,副本集将选举一个新的主库继续提供服务。
-
MongoDB的Bson和JSon格式的数据十分适合文档格式的存储与查询。
劣势:
-
不支持事务操作。MongoDB本身没有自带事务机制,若需要在MongoDB中实现事务机制,需通过一个额外的表,从逻辑上自行实现事务。
-
应用经验少,由于NoSQL兴起时间短,应用经验相比关系型数据库较少。
-
MongoDB占用空间过大。
4.8 管理医院信息
在这个模块中,由于要同时用到不同的service模块(按照现实来说可能是不同服务器上的微服务),需要用到远程调用,这里就用到注册中心,本项目用的是Nacos
@EnableDiscoveryClient:加在主启动类上,将本服务注册到注册中心中(Nacos、Zookeeper、Consul等),配合properties文件中设置当前服务的地址端口号,就完成了注册
要完成跨服务调用,还需要Feign。feign是声明式的web service客户端,它让微服务之间的调用变得更简单了,类似controller调用service。
SpringbootApplication启动类加上@FeignClient注解,以及@EnableDiscoveryClient。
创建一个借口,加上@FeignClient(value = “service-cmn”) 注解,value后面是已注册服务的名字。声明完为feign client后,其他spring管理的类,如service就可以直接注入使用了
4.9 管理排班信息
点击排班,会显示排班信息
4.10 服务网关
本项目用的是SpringCloud中的GateWay
4.11 用户审批用户管理
用户进行实名认证后,在后台可以管理用户和审批用户
参考北京市统一预约挂号平台 一些简单的功能:如搜索医院名称、点击医院选择科室排班等,就不再赘述。主要讲登陆注册相关的。
5.1 如何实现请求不同端口
-
可以用转发进行访问
-
使用Nginx,把各个端口封装,对外暴露一个统一端口,访问的时候进行转发访问实际端口
5.2 如何解决跨域问题
-
在controller上面添加@CrossOrigin注解
-
使用springcloud提供的gateway网关
5.3 登录功能
手机号登录和微信扫码登录,短信验证用到容联云
5.4 网关过滤器
既然有登录问题,就有权限问题,网站中有部分网址是内部人员才能访问,有些是用户登录后才能访问,还有些是可以直接访问。实现这个功能是用GateWay中的filter,继承GlobalFilter然后重写一些方法即可具体实现代码(在GateWay服务中)
5.5 JWT(JSON Web Token)
参考介绍
Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
本项目用JWT来生成token
5.6 OAuth2
官方指南
-
第三方发起微信授权登录请求,微信用户允许授权第三方应用后,微信会拉起应用或重定向到第三方网站,并且带上授权临时票据code参数;
-
通过code参数加上AppID和AppSecret等,通过API换取access_token;
-
通过access_token进行接口调用,获取用户基本数据资源或帮助用户实现基本操作。
5.7 手机号验证码登录
整合JWT,生成token。
总体流程:
-
用户输入手机号,点击获取验证码
-
阿里云短信服务,给用户发送生成的验证码,同时把验证码放到redis中,设置过期时间。
-
用户收到验证码并输入,服务器拿到并与redis中对应用户的验证码比对。如果不相同抛出异常,如果相同则登录成功
由于阿里云个人账户认证通过不了,我整合了容联云短信验证发送功能!
5.8 微信扫码登录
微信的开发指南
根据开发指南,填入相应信息传回前端,在前端就可以显示二维码给用户了。
微信扫码登录成功后,会重定向至手机号验证码登录界面。用户用手机号登录后,如果是第一次登录,会将用户的微信和手机号在数据库中绑定在一起。
6.1 实名认证与后台审核
如果没有进行过实名认证,要挂号需要先进行实名认证
6.2 管理就诊人(增删改查)
可以用自己的账号给家人挂号
6.3 预约挂号详情信息
点击一个科室,显示可预约的挂号信息,点击某个信息显示相关内容
6.4 选择科室,预约挂号
如果商品服务和订单服务是两个不同的微服务,在下单的过程中订单服务需要调用商品服务进行扣库存操作。按照传统的方式,下单过程要等到调用完毕之后才能返回下单成功,如果网络产生波动等原因使得商品服务扣库存延迟或失败,就会带来交叉的用户体验。如果在高并发的场景下,这样的处理显然是不合适的,那么如何优化呢?就要使用消息队列 消息队列提供一个异步通信机制,消息的发送者不必一直等到消息被成功处理才返回,而是立即就返回。消息中间件负责处理网络通信,如果网络连接不可用,消息可被暂存于队列之中,当网络畅通的时候将消息转发给相应的程序或服务,当然前提是这些服务订阅了该队列。
在服务之间使用消息中间件,既可以提高并发量,又可以降低服务之间的耦合度
6.5 微信扫码下单
这部分模块主要是调用微信的一些服务,不做赘述 值得一提的是,生成的微信二维码放在Redis中,两小时过期
7.1 后台管理系统
1、医院设置管理 (1)医院设置列表、添加、锁定、删除 (2)医院列表、详情、排班、下线 2、数据管理 (1)数据字典树形显示、导入、导出 (2)因为数据字典不经常修改,是一些省份和民族信息,所以可以放在缓存里,加快读取速度 3、用户管理 (1)用户列表、查看、锁定 (2)认证用户审批 4、订单管理 (1)订单列表、详情 5、统计管理 (1)预约统计
7.2 前台用户系统
1、首页数据显示 (1)医院列表 2、医院详情显示 (1)医院科室显示 3、用户登录功能 (1)手机号登录(短信验证码发送) (2)微信扫描登录 4、用户实名认证 5、就诊人管理 (1)列表、添加、详情、删除 6、预约挂号功能 (1)排班和挂号详情信息 (2)确认挂号信息 (3)生成预约挂号订单 (4)挂号订单支付(微信) (5)取消预约订单 7、就医提醒功能