码云看,内含源码
网上预约挂号系统,网上预约挂号是近年来开展的一项便民就医服务,旨在缓解看病难、挂号难的就医难题,许多患者为看一次病要跑很多次医院,最终还不一定能保证看得上医生。网上预约挂号全面提供的预约挂号业务从根本上解决了这一就医难题。随时随地轻松挂号!不用排长队!
项目描述
1.前后端分离开发
2.后端技术:
3.前端技术:
流程图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NWgxffrK-1632414532304)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002148.png)]
医院编号
医院与平台合作后,平台提供给医院的唯一标识ID号(hoscode)。
签名密钥
医院与平台合作后,平台提供给医院,用于接口调用的MD5数字签名算法的密码串(signKey)。
架构图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PjwsFC0L-1632414532307)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002205.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fBoZyNXh-1632414532309)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002213.png)]
医院系统:http://localhost:9998/
用户系统:http://localhost:3000/
管理员系统:http://localhost:9528/
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d9R8MePW-1632414532310)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002218.png)]
医院设置主要是用来保存开通医院的一些基本信息,每个医院一条信息,保存了医院编号(平台分配,全局唯一)和接口调用相关的签名key等信息,是整个流程的第一步,只有开通了医院设置信息,才可以上传医院相关信息。
我们所开发的功能就是基于单表的一个CRUD、锁定/解锁和发送签名信息这些基本功能。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xUjXP24o-1632414532312)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002225.png)]
测试数据:
南溪山医院
1000_1
http://localhost:9998
武则天
18376593173
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lWsM1ugd-1632414532313)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002232.png)]
成功添加
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OmgUH3lq-1632414532314)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002239.png)]
数据里增加记录,并且生成了签名key
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d5nFmRRP-1632414532314)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002244.png)]
此时,在平台开通了一家医院设置信息。
前后端分离开发,用其维护接口文档
什么是swagger2
编写和维护接口文档是每个程序员的职责,根据Swagger2可以快速帮助我们编写最新的API接口文档,再也不用担心开会前仍忙于整理各种资料了,间接提升了团队开发的沟通效率。
常用注解
swagger通过注解表明该接口会生成文档,包括接口名、请求方法、参数、返回信息的等等。
@Api:修饰整个类,描述Controller的作用
@ApiOperation:描述一个类的一个方法,或者说一个接口
@ApiParam:单个参数描述
@ApiModel:用对象来接收参数
@ApiModelProperty:用对象接收参数时,描述对象的一个字段
@ApiImplicitParam:一个请求参数
@ApiImplicitParams:多个请求参数
前端工程师“Front-End-Developer”源自于美国。大约从2005年开始正式的前端工程师角色被行业所认可,到了2010年,互联网开始全面进入移动时代,前端开发的工作越来越重要。
最初所有的开发工作都是由后端工程师完成的,随着业务越来越繁杂,工作量变大,于是我们将项目中的可视化部分和一部分交互功能的开发工作剥离出来,形成了前端开发。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0H0VlV3k-1632414532315)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002253.png)]
使用了vscode进行开发前端
ECMAScript 6.0(简称 ES6)是 JavaScript 语言的下一代标准, 2015 年 6 月正式发布。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
一个常见的问题是,ECMAScript 和 JavaScript 到底是什么关系?
要讲清楚这个问题,需要回顾历史。1996 年 11 月,JavaScript 的创造者 Netscape 公司,决定将 JavaScript 提交给标准化组织 ECMA,希望这种语言能够成为国际标准。次年,ECMA 发布 262 号标准文件(ECMA-262)的第一版,规定了浏览器脚本语言的标准,并将这种语言称为 ECMAScript,这个版本就是 1.0 版。
因此,ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现(另外的 ECMAScript 方言还有 Jscript 和 ActionScript)
==ES6相对之前的版本语法更严格,==新增了面向对象的很多特性以及一些高级特性。本部分只学习项目开发中涉及到ES6的最少必要知识,方便项目开发中对代码的理解。
在为 AngularJS 工作之后,Vue 的作者尤雨溪开发出了这一框架。他声称自己的思路是提取 Angular 中为自己所喜欢的部分,构建出一款相当轻量的框架。Vue 最早发布于 2014 年 2 月。作者在 Hacker News、Echo JS 与 Reddit 的 javascript 版块发布了最早的版本。一天之内,Vue 就登上了这三个网站的首页。Vue 是 Github 上最受欢迎的开源项目之一。同时,在 JavaScript 框架/函数库中,Vue 所获得的星标数已超过 React,并高于 Backbone.js、Angular 2、jQuery 等项目。
Vue.js 是一款流行的 JavaScript 前端框架,目的是简化 Web 开发。Vue 所关注的核心是 MVC 模式中的视图层,同时,它也能方便地获取数据更新,实现视图与模型的交互。
官方网站:https://cn.vuejs.org
axios是独立于vue的一个项目,可以用于浏览器和node.js中发送ajax请求
element-ui 是饿了么前端出品的基于 Vue.js的 后台组件库,方便程序员进行页面快速布局和构建
官网: http://element-cn.eleme.io/#/zh-CN
浏览器的内核包括两部分核心:
DOM渲染引擎
JavaScript解析引擎
Chrome浏览器内置V8引擎,V8引擎执行Javascript的速度非常快,性能非常好。
脱离浏览器环境也可以运行JavaScript,只要有JavaScript引擎就可以。
Node.js是一个基于Chrome V8引擎的JavaScript运行环境:即Node.js内置了Chrome的V8 引擎,可以在Node.js环境中直接运行JavaScript程序。
在Node.js中写JavaScript和在Chrome浏览器中写JavaScript基本没有什么不一样。哪里不一样呢?
Node.js没有浏览器API,即document,window的等。
加了许多Node.js 专属API,例如文件系统,进程,http功能。
如果想开发类似JavaWeb的简单的后端程序,那么学习Node.js是一个非常好的选择。
如果你想部署一些高性能的服务,那么学习Node.js也是一个非常好的选择。
通常他会被用来作一个BFF层,即 Backend For Frontend(服务于前端的后端),通俗的说是一个专门用于为前端业务提供数据的后端程序
一个前端页面向 Service A、Service B 以及 Service C发送请求,不同的微服务返回的值用于渲染页面中不同的组件。此时,每次访问该页面都需要发送 3 个请求。我们需要一个服务来聚合Service A、Service B 以及 Service C响应的数据,这个服务层叫做BFF。
手机、平板端、PC机等用户终端都需要向每个Service,例如Service A发送请求。对于同一个功能,不同的终端需要的数据格式和内容会有不同。此时 Service A 的一个接口,不能同时满足三个客户端的不同需求。我们可以在Service A中开发三个接口,也可以增加一个数据裁剪服务,将数据按照不同终端的不同要求进行裁剪,这个服务层叫做BFF。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E2GfPhGj-1632414532316)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002306.png)]
BFF层的作用是让前端有能力自由组装后台数据,减少大量的业务沟通成本,加快业务的迭代速度。
无论是数据聚合还是数据剪裁,这类程序的特点是不需要太强大的服务器运算能力,但是对程序的灵活性有较高的要求,这两个特点都正好和Node.js的优势相吻合。
用户体验适配器
什么是NPM
NPM全称Node Package Manager,是Node.js包管理工具,是全球最大的模块生态系统,里面所有的模块都是开源免费的;也是Node.js的包管理工具,相当于前端的Maven 。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DUhCPCv1-1632414532316)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002312.png)]
数据字典就是管理系统常用的分类数据或者一些固定数据,
例如:省市区三级联动数据、民族数据、行业数据、学历数据等,由于该系统大量使用这种数据,所以我们要做一个数据管理方便管理系统数据,一般系统基本都会做数据管理。
示例:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yUrlmZOW-1632414532317)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002316.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LiSqbzIr-1632414532317)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002322.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rwqbjUFE-1632414532318)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002325.png)]
parent_id
:
上级id,通过id与parent_id构建上下级关系,例如:要获取所有行业数据,那么只需要查询parent_id=20000的数据
name
:
名称,例如:填写用户信息,我们要select标签选择民族,“汉族”就是数据字典的名称
value
:
值,例如:填写用户信息,我们要select标签选择民族,“1”(汉族的标识)就是数据字典的值
dict_code
:
编码,编码是我们自定义的,全局唯一,例如:我们要获取行业数据,我们可以通过parent_id获取,但是parent_id是不确定的,所以我们可以根据编码来获取行业数据
说明:系统中会使用省市区三级联动数据,该数据来自“国家统计局”官方数据,地址:http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2019/index.html
数据字典是树形展示,由于数据众多,我们使用“树形数据与==懒加载”==的方式展现数据列表,其他就是对数据的新增、修改与删除操作,因此需要提供的接口如下:
1,根据上级id获取下级数据(构造树形数据)
2,导入接口
3,导出接口
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7PFXnyPR-1632414532319)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002333.png)]
Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,能够原本一个3M的excel用POI sax依然需要100M左右内存降低到几M,并且再大的excel不会出现内存溢出,03版依赖POI的sax模式。在上层做了模型转换的封装,让使用者更加简单方便。
EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel。
文档地址:https://alibaba-easyexcel.github.io/index.html
github地址:https://github.com/alibaba/easyexcel
Spring Cache 是一个非常优秀的缓存组件。自Spring 3.1起,提供了类似于@Transactional注解事务的注解Cache支持,且提供了Cache抽象,方便切换各种底层Cache(如:redis)
使用Spring Cache的好处:
1,提供基本的Cache抽象,方便切换各种底层Cache;
2,通过注解Cache可以实现类似于事务一样,缓存逻辑透明的应用到我们的业务代码上,且只需要更少的代码就可以完成;
3,提供事务回滚时也自动回滚缓存;
4,支持比较复杂的缓存逻辑;
因为缓存也是公共使用,所有的service模块都有可能使用缓存,所以我们把依赖与部分配置加在service-util模块,这样其他service模块都可以使用了
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jm128UqW-1632414532319)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002338.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6kyYHPIv-1632414532320)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002403.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9CcXvpiH-1632414532320)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002411.png)]
nginx服务地址:localhost:9001
后端模块的服务端口:
hosp:swagger:http://localhost:8201/swagger-ui.html,8201
cmn:swagger:http://localhost:8201/swagger-ui.html,8202
user:swagger:http://localhost:8203/swagger-ui.html,8160(微信原因)
sms: swagger:http://localhost:8204/swagger-ui.html,8204
oss: swagger:http://localhost:8204/swagger-ui.html,8205
order: swagger:http://localhost:8204/swagger-ui.html,8206
task: swagger:http://localhost:8204/swagger-ui.html,8207
statistics: swagger:http://localhost:8204/swagger-ui.html,8208,统计分析
在nginx中进行配置,使其能访问相应的服务。
server {
#表示nginx对外的端口号是9001
listen 9001;
#主机名称
server_name localhost;
#访问路径中包含/hosp/,转发到http://localhost:8201
#~:表示正则匹配
location ~ /hosp/
{
proxy_pass http://localhost:8201;
}
location ~ /cmn/ {
root html;
proxy_pass http://localhost:8202;
}
...
...
}
前端只需要访问nginx对外端口即可
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t6XiHgpR-1632414532321)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002429.png)]
说明:
后续我们将会使用Spring Cloud Gateway网关,替代nginx网关
NoSQL(NoSQL = Not Only SQL),意即反SQL运动,指的是非关系型的数据库,是一项全新的数据库革命性运动,早期就有人提出,发展至2009年趋势越发高涨。NoSQL的拥护者们提倡运用非关系型的数据存储,相对于目前铺天盖地的关系型数据库运用,这一概念无疑是一种全新的思维的注入
为什么使用NoSQL :
1、对数据库高并发读写。
2、对海量数据的高效率存储和访问。
3、对数据库的高可扩展性和高可用性。
弱点:
1、数据库事务一致性需求
2、数据库的写实时性和读实时性需求
3、对复杂的SQL查询,特别是多表关联查询的需求
用于对象及 JSON数据的存储:Mongo的BSON数据格式非常适合文档化格式的存储 及查询。
BSON有三个特点:轻量性、可遍历性、高效性。
MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。
在高负载的情况下,添加更多的节点,可以保证服务器性能。
MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。
MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1lRLiNOL-1632414532321)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002429.png)]
1、MongoDB 是一个面向文档存储的数据库,操作起来比较简单和容易。
2、你可以在MongoDB记录中设置任何属性的索引 (如:FirstName=“Sameer”,Address=“8 Gandhi Road”)来实现更快的排序。
3、你可以通过本地或者网络创建数据镜像,这使得MongoDB有更强的扩展性。
4、如果负载的增加(需要更多的存储空间和更强的处理能力) ,它可以分布在计算机网络中的其他节点上这就是所谓的分片。
5、Mongo支持丰富的查询表达式。查询指令使用JSON形式的标记,可轻易查询文档中内嵌的对象及数组。
6、MongoDb 使用update()命令可以实现替换完成的文档(数据)或者一些指定的数据字段 。
7、Mongodb中的Map/reduce主要是用来对数据进行批量处理和聚合操作。
8、Map和Reduce。Map函数调用emit(key,value)遍历集合中所有的记录,将key与value传给Reduce函数进行处理。
9、Map函数和Reduce函数是使用Javascript编写的,并可以通过db.runCommand或mapreduce命令来执行MapReduce操作。
10、GridFS是MongoDB中的一个内置功能,可以用于存放大量小文件。
11、MongoDB允许在服务端执行脚本,可以用Javascript编写某个函数,直接在服务端执行,也可以把函数的定义存储在服务端,下次直接调用即可。
12、MongoDB支持各种编程语言:RUBY,PYTHON,JAVA,C++,PHP,C#等多种语言。
13、MongoDB安装简单。
{
"hoscode": "1000_0",
"hosname": "北京协和医院",
"hostype": "1",
"provinceCode": "110000",
"cityCode": "110100",
"districtCode": "110102",
"address": "大望路",
"intro": "北京协和医院是集医疗、教学、科研于一体的大型三级甲等综合医院,是国家卫生计生委...目标而继续努力。",
"route": "东院区乘车路线:106、...更多乘车路线详见须知。",
"logoData": "iVBORw0KGgoAAAA...NSUhEUg==",
"bookingRule": {
"cycle": "1",
"releaseTime": "08:30",
"stopTime": "11:30",
"quitDay": "-1",
"quitTime": "15:30",
"rule": [
"西院区预约号取号地点:西院区门诊楼一层大厅挂号窗口取号",
"东院区预约号取号地点:东院区老门诊楼一层大厅挂号窗口或新门诊楼各楼层挂号/收费窗口取号"
]
}
}
说明:
1,数据分为医院基本信息与预约规则信息
2,医院logo转换为base64字符串
3,预约规则信息属于医院基本信息的一个属性
4,预约规则rule,以数组形式传递
5,数据传递过来我们还要验证签名,只允许平台开通的医院可以上传数据,保证数据安全性
医院code: 1000_1
key: 214833ed3a10cb6af5c61d5eda1ea90c
**统一预约挂号平台基础路径:**http://localhost:8201
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V7kPf0LM-1632414532322)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002434.png)]
测试数据:
上传医院
图片的base64编码就是可以将一张图片数据编码成一串字符串,使用该字符串代替图像地址url
在前端页面中常见的base64图片的引入方式
(1)base64格式的图片是文本格式,占用内存小,转换后的大小比例大概为1/3,降低了资源服务器的消耗;
(2)网页中使用base64格式的图片时,不用再请求服务器调用图片资源,减少了服务器访问次数。
(1)base64格式的文本内容较多,存储在数据库中增大了数据库服务器的压力;
(2)网页加载图片虽然不用访问服务器了,但因为base64格式的内容太多,所以加载网页的速度会降低,可能会影响用户的体验。
说明:医院logo图片小,因此上传医院logo是可以使用base64格式保存
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0HwgC2g5-1632414532322)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002536.png)]
上传科室
上传排班
查询排班,删除排班
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CtT0hJQQ-1632414532323)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002536.png)]
目前我们把医院、科室和排班都上传到了平台,那么管理平台就应该把他们管理起来,在我们的管理平台能够直观的查看这些信息。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PACRzDlR-1632414532323)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002457.png)]
查看详情功能
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MTcuYnxz-1632414532324)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002555.png)]
排班分成三部分显示:
1、科室信息(大科室与小科室树形展示)
2、排班日期,分页显示,根据上传排班数据聚合统计产生
3、排班日期对应的就诊医生信息
1,科室数据使用Element-ui el-tree组件渲染展示,需要将医院上传的科室数据封装成两层父子级数据;
2,聚合所有排班数据,按日期分页展示,并统计号源数据展示;
3,根据排班日期获取排班详情数据
虽然是一个页面展示所有内容,但是页面相对复杂,我们分步骤实现
1,先实现左侧科室树形展示;
2,其次排班日期分页展示
3,最后根据排班日期获取排班详情数据
目前在医院列表中需要医院的信息和等级信息,而两段信息属于不同的的模块,service-hosp和service-cmn,所以我们需要使用到远程调用。
Nacos 是阿里巴巴推出来的一个新开源项目,这是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。
Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。 Nacos 是构建以“服务”为中心的现代应用架构 (例如微服务范式、云原生范式) 的服务基础设施
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2Dxsjomu-1632414532325)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002609.png)]
通过 Nacos Server 和 spring-cloud-starter-alibaba-nacos-config 实现配置的动态变更。
通过 Nacos Server 和 spring-cloud-starter-alibaba-nacos-discovery 实现服务的注册与发现。
API网关出现的原因是微服务架构的出现,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题:
(1)客户端会多次请求不同的微服务,增加了客户端的复杂性。
(2)存在跨域请求,在一定场景下处理相对复杂。
(3)认证复杂,每个服务都需要独立认证。
(4)难以重构,随着项目的迭代,可能需要重新划分微服务。例如,可能将多个服务合并成一个或者将一个服务拆分成多个。如果客户端直接与微服务通信,那么重构将会很难实施。
(5)某些微服务可能使用了防火墙 / 浏览器不友好的协议,直接访问会有一定的困难。
以上这些问题可以借助 API 网关解决。API 网关是介于客户端和服务器端之间的中间层,所有的外部请求都会先经过API 网关这一层。也就是说,API 的实现方面更多的考虑业务逻辑,而安全、性能、监控可以交由 API 网关来做,这样既提高业务灵活性又不缺安全性
Spring cloud gateway是spring官方基于Spring 5.0、Spring Boot2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供简单、有效和统一的API路由管理方式,Spring Cloud Gateway作为Spring Cloud生态系统中的网关,目标是替代Netflix Zuul,其不仅提供统一的路由方式,并且还基于Filer链的方式提供了网关基本的功能,例如:安全、监控/埋点、限流等
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wrdlnUIO-1632414532326)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002617.png)]
跨域不一定都会有跨域问题。
因为跨域问题是浏览器对于ajax请求的一种安全限制:一个页面发起的ajax请求,只能是与当前页域名相同的路径,这能有效的阻止跨站攻击。
因此:跨域问题 是针对ajax的一种限制。
但是这却给我们的开发带来了不便,而且在实际生产环境中,肯定会有很多台服务器之间交互,地址和端口都可能不同,怎么办?
解决跨域问题
添加一个全局配置类实现
//处理跨域
@Configuration
public class CorsConfig {
@Bean
public CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedMethod("*");
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}
目前我们已经在网关做了跨域处理,那么service服务就不需要再做跨域处理了,将之前在controller类上添加过@CrossOrigin标签的去掉,防止程序异常
通过平台与管理平台前端测试
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RxWLVNfq-1632414532326)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002624.png)]
另外,使用服务器端渲染,我们可以获得更快的内容到达时间(time-to-content),无需等待所有的 JavaScript 都完成下载并执行,产生更好的用户体验,对于那些内容到达时间(time-to-content)与转化率直接相关的应用程序而言,服务器端渲染(SSR)至关重要。
Nuxt.js 是一个基于 Vue.js 的轻量级应用框架,可用来创建服务端渲染 (SSR) 应用,也可充当静态站点引擎生成静态站点应用,具有优雅的代码结构分层和热加载等特性。
官网网站:
https://zh.nuxtjs.org/
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PWove79o-1632414532327)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002648.png)]
1,登录采取弹出层的形式
2,登录方式:
(1)手机号码+手机验证码
(2)微信扫描
3,无注册界面,第一次登录根据手机号判断系统是否存在,如果不存在则自动注册
4,微信扫描登录成功必须绑定手机号码,即:第一次扫描成功后绑定手机号,以后登录扫描直接登录成功
5,网关统一判断登录状态,如何需要登录,页面弹出登录层
JWT工具
JWT(Json Web Token)是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准。
JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,便于从资源服务器获取资源。比如用在用户登录上
JWT最重要的作用就是对 token信息的防伪作用。
JWT的原理,
一个JWT由三个部分组成:公共部分、私有部分、签名部分。最后由这三者组合进行base64编码得到JWT。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bQtW0det-1632414532327)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924001537.png)]
1、 公共部分
主要是该JWT的相关配置参数,比如签名的加密算法、格式类型、过期时间等等。
Key=ATGUIGU
2、 私有部分
用户自定义的内容,根据实际需要真正要封装的信息。
userInfo{用户的Id,用户的昵称nickName}
3、 签名部分
SaltiP: 当前服务器的Ip地址!{linux 中配置代理服务器的ip}
主要用户对JWT生成字符串的时候,进行加密{盐值}
最终组成 key+salt+userInfo è token!
base64编码,并不是加密,只是把明文信息变成了不可见的字符串。但是其实只要用一些工具就可以把base64编码解成明文,所以不要在JWT中放入涉及私密的信息。
使用容联云,阿里云注册不到,需要企业认证
注册好之后,创建一个应用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pQ4xxvC6-1632414532328)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924001617.png)]
添加接收短信的手机号
添加maven依赖
<dependency>
<groupId>com.cloopengroupId>
<artifactId>java-sms-sdkartifactId>
<version>1.0.3version>
dependency>
运行即可发送
public static void main(String[] args) {
-
在yygh系统中创建一个模块 service_sms
配置类
# 服务端口
server.port=8204
# 服务名
spring.application.name=service-sms
#返回json的全局时间格式
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
spring.redis.host=120.76.245.154
spring.redis.port=6379
spring.redis.database= 0
spring.redis.timeout=1800000
spring.redis.lettuce.pool.max-active=20
spring.redis.lettuce.pool.max-wait=-1
#最大阻塞等待时间(负数表示没限制)
spring.redis.lettuce.pool.max-idle=5
spring.redis.lettuce.pool.min-idle=0
# nacos服务地址
spring.cloud.nacos.discovery.server-addr=120.76.245.154:8848
#aliyun.sms.regionId=default
#aliyun.sms.accessKeyId=LT6I0Y5633pX89qC
#aliyun.sms.secret=jX8D04Dm12I3gGKj345FYSzu0fq8mT
accountSId=8aaf07087bc82708017bdaa93f7d03c2
accountToken=fbcc0c9c000a471f8ffa9ff514b4d050
appId=8aaf07087bc82708017bdaad3fad03cb
在启动类上加上属性,表示不需要主动去加载数据源(数据库)配置,因为短信并不需要数据库。
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
添加配置类
传递了发送短信需要的三属性
accountSId=8aaf07087bc82708017bdaa93f7d03c2
accountToken=fbcc0c9c000a471f8ffa9ff514b4d050
appId=8aaf07087bc82708017bdaa940cb03c8
思路:
所有请求都会经过服务网关,服务网关对外暴露服务,在网关进行统一用户认证;
既然要在网关进行用户认证,网关得知道对哪些url进行认证,所以我们得对ur制定规则
Api接口异步请求的,我们采取url规则匹配,如:/api//auth/,如凡是满足该规则的都必须用户认证
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String path = request.getURI().getPath();
System.out.println("==="+path);
//内部服务接口,不允许外部访问
if(antPathMatcher.match("/**/inner/**", path)) {
ServerHttpResponse response = exchange.getResponse();
return out(response, ResultCodeEnum.PERMISSION);
}
Long userId = this.getUserId(request);
//api接口,异步请求,校验用户必须登录
if(antPathMatcher.match("/api/**/auth/**", path)) {
if(StringUtils.isEmpty(userId)) {
ServerHttpResponse response = exchange.getResponse();
return out(response, ResultCodeEnum.LOGIN_AUTH);
}
}
return chain.filter(exchange);
}
在网关中如何获取用户信息:
1,我们统一从header头信息中获取
如何判断用户信息合法:
登录时我们返回用户token,在服务网关中获取到token后,我在到redis中去查看用户id,如何用户id存在,则token合法,否则不合法
/**
* 获取当前登录用户id
* @param request
* @return
*/
private Long getUserId(ServerHttpRequest request) {
String token = "";
List<String> tokenList = request.getHeaders().get("token");
if(null != tokenList) {
token = tokenList.get(0);
}
if(!StringUtils.isEmpty(token)) {
return JwtHelper.getUserId(token);
}
return null;
}
调整前端
请求服务器端接口时我们默认带上token,需要登录的接口如果token没有或者token过期,服务器端会返回208状态,然后发送登录事件打开登录弹出层登录
照片拥有者想要在云冲印服务上打印照片,云冲印服务需要访问云存储服务上的资源
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NHiDteXW-1632414532329)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924001636.png)]
资源拥有者:照片拥有者
客户应用:云冲印
受保护的资源:照片
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lk57quHC-1632414532330)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924001644.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GfewpS6I-1632414532330)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924001709.png)]
用户将自己的"云存储"服务的用户名和密码,告诉"云冲印",后者就可以读取用户的照片了。这样的做法有以下几个严重的缺点。
(1)"云冲印"为了后续的服务,会保存用户的密码,这样很不安全。
(2)Google不得不部署密码登录,而我们知道,单纯的密码登录并不安全。
(3)"云冲印"拥有了获取用户储存在Google所有资料的权力,用户没法限制"云冲印"获得授权的范围和有效期。
(4)用户只有修改密码,才能收回赋予"云冲印"的权力。但是这样做,会使得其他所有获得用户授权的第三方应用程序全部失效。
(5)只要有一个第三方应用程序被破解,就会导致用户密码泄漏,以及所有被密码保护的数据泄漏。
总结:
将受保护的资源中的用户名和密码存储在客户应用的服务器上,使用时直接使用这个用户名和密码登录
适用于同一公司内部的多个系统,不适用于不受信的第三方应用
适用于合作商或者授信的不同业务部门之间
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XeAAUrQ4-1632414532331)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924001709.png)]
接近OAuth2方式,需要考虑如何管理令牌、颁发令牌、吊销令牌,需要统一的协议,因此就有了OAuth2协议
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uKxwnRAO-1632414532332)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924001720.png)]
令牌类比仆从钥匙
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OFOoDiJP-1632414532332)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924001740.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lKyP6RtD-1632414532333)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924001748.png)]
川崎高彦:OAuth2领域专家,开发了一个OAuth2 sass服务,OAuth2 as Service,并且做成了一个公司
在融资的过程中为了向投资人解释OAuth2是什么,于是写了一篇文章,《OAuth2最简向导》
现代微服务中系统微服务化以及应用的形态和设备类型增多,不能用传统的登录方式
核心的技术不是用户名和密码,而是token,由AuthServer颁发token,用户使用token进行登录
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jwDfJMHc-1632414532333)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924001755.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wAepCpZx-1632414532334)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924001802.png)]
1、注册
微信开放平台:https://open.weixin.qq.com
2、邮箱激活
3、完善开发者资料
4、开发者资质认证
准备营业执照,1-2个工作日审批、300元
5、创建网站应用
提交审核,7个工作日审批
参考文档:https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505&token=e547653f995d8f402704d5cb2945177dc8aa4e7e&lang=zh_CN
获取access_token时序图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iILqN8gW-1632414532335)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924001813.png)]
第一步:请求CODE(生成授权URL)
第二步:通过code获取access_token(开发回调URL)
操作模块:service-user
说明:微信登录二维码我们是以弹出层的形式打开,不是以页面形式,所以做法是不一样的,参考如下链接,上面有相关弹出层的方式
https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html
如图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y8YPMD4e-1632414532335)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924001824.png)]
因此我们的操作步骤为:
第一步通过接口把对应参数返回页面;
第二步在头部页面启动打开微信登录二维码;
第三步处理登录回调接口;
第四步回调返回页面通知微信登录层回调成功
第五步如果是第一次扫描登录,则绑定手机号码,登录成功
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CPxMAH8M-1632414532336)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924001833.png)]
用户登录成功后都要进行身份认证,认证通过后才可以预约挂号
认证过程:用户填写信息(姓名、证件类型、证件号码和证件照片)==> 平台审批
用户认证设计接口:
1、提交认证
2、上传证件图片
3、获取提交认证信息
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DP5CUAde-1632414532336)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924001838.png)]
用户认证需要上传证件图片、首页轮播也需要上传图片,因此我们要做文件服务,阿里云oss是一个很好的分布式文件服务系统,所以我们只需要集成阿里云oss即可
(1)申请阿里云账号
(2)实名认证
(3)开通“对象存储OSS”服务
(4)进入管理控制台
选择:标准存储、公共读、不开通
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2q2bNoCD-1632414532337)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924001844.png)]
创建文件夹avatar,上传默认的用户头像
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lYtH238Y-1632414532338)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924001857.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XrTBJsPG-1632414532338)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924001902.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-45hYcMCY-1632414532339)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924001906.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eX7nxzFf-1632414532339)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924001911.png)]
用户登录成功后都要进行身份认证,认证通过后才可以预约挂号
认证过程:用户填写信息(姓名、证件类型、证件号码和证件照片)==> 平台审批
用户认证设计接口:
1、提交认证
2、上传证件图片
3、获取提交认证信息
如果要预约挂号,我们必须要认证通过后才可以,所以我们在预约挂号前要做认证判断,如果没有认证通过,则跳转到认证页面
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZjiVaJ8Z-1632414532340)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924001918.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zHTWhhcj-1632414532340)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924001923.png)]
预约下单需要选择就诊人,因此我们要实现就诊人管理,前端就诊人管理其实就是要实现一个完整的增删改查
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rIEvECij-1632414532341)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924001931.png)]
我们做了用户登录、用户认证与就诊人,现在我们需要把这些信息在我们的平台管理系统做一个统一管理
详情里有他的就诊人信息
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZWfUx8uR-1632414532342)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924001954.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aD6HCEmO-1632414532342)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002004.png)]
1、接口分析
(1)根据预约周期,展示可预约日期数据,按分页展示
(2)选择日期展示当天可预约列表(该接口后台已经实现过)
2、页面展示分析
(1)分页展示可预约日期,根据有号、无号、约满等状态展示不同颜色,以示区分
(2)可预约最后一个日期为即将放号日期,根据放号时间页面展示倒计时
选择日期
选择就诊人
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JPI0B0sb-1632414532343)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002009.png)]
确认挂号
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ukZJ6lEl-1632414532343)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002017.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WlElC9y3-1632414532344)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002021.png)]
order
中引入依赖
<dependency>
<groupId>com.github.wxpaygroupId>
<artifactId>wxpay-sdkartifactId>
<version>0.0.3version>
dependency>
添加redis、微信支付的配置
#连接的redis地址,写虚拟机(服务器)的ip
spring.redis.host=120.76.245.154
#端口号
spring.redis.port=6379
spring.redis.database= 0
spring.redis.timeout=1800000
spring.redis.lettuce.pool.max-active=20
spring.redis.lettuce.pool.max-wait=-1
#最大阻塞等待时间(负数表示没限制)
spring.redis.lettuce.pool.max-idle=5
spring.redis.lettuce.pool.min-idle=0
引入工具类
创建mvc
微信生成二维码。
是去调用的一个地址,返回的数据不是二维码。而是很多数据,里面有一个二维码的下载地址,需要我们拿出来。所以返回值用一个map接收
实体类 ,PaymentInfo
public Map createNative(Long orderId) {
try {
//如果redis中有数据,从redis获取数据
Map payMap = (Map) redisTemplate.opsForValue().get(orderId.toString());
if (payMap != null) {
return payMap;
}
//1.根据orderid获取订单信息
OrderInfo order = orderService.getById(orderId);
//2.向支付记录表里边添加信息
paymentService.savePaymentInfo(order, PaymentTypeEnum.WEIXIN.getStatus());
//3、设置参数,调用微信生成二维码接口
//使用微信的sdk把参数转换成xml格式,使用商户key进行加密,不这么做,微信那边是识别不了了
Map paramMap = new HashMap();
paramMap.put("appid", ConstantPropertiesUtils.APPID);//商户id
paramMap.put("mch_id", ConstantPropertiesUtils.PARTNER);//商户号
paramMap.put("nonce_str", WXPayUtil.generateNonceStr());//唯一随机的字符串
String body = order.getReserveDate() + "就诊" + order.getDepname();
paramMap.put("body", body);//主体信息:就诊人,相关信息
paramMap.put("out_trade_no", order.getOutTradeNo());//订单编号,唯一
//paramMap.put("total_fee", order.getAmount().multiply(new BigDecimal("100")).longValue()+"");
paramMap.put("total_fee", "1");//订单金额,表示0.01元。上面这种是获取实际金额。为了测试使用
paramMap.put("spbill_create_ip", "127.0.0.1");//当前ip地址。
paramMap.put("notify_url", "http://guli.shop/api/order/weixinPay/weixinNotify");//回调地址
paramMap.put("trade_type", "NATIVE");
//HTTPClient来根据URL访问第三方接口并且传递参数,url为微信提供的固定值
HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");
//设置map参数,第二个参数,是申请的微信支付,微信下发的key,在配置文件中声明,将其转成xml格式,再进行加密
client.setXmlParam(WXPayUtil.generateSignedXml(paramMap, ConstantPropertiesUtils.PARTNERKEY));
//设置支持请求
client.setHttps(true);
client.post();//发送请求
//6.返回相关数据
String xml = client.getContent();
//xml->map
Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);
//4、封装返回结果集
Map map = new HashMap<>();
System.out.println("resultMap:" + resultMap);
map.put("orderId", orderId);
map.put("totalFee", order.getAmount());
map.put("resultCode", resultMap.get("result_code"));
//二维码地址
map.put("codeUrl", resultMap.get("code_url"));
//添加到redis中
if (resultMap.get("result_code") != null) {
//参数:key,value,时间,单位
redisTemplate.opsForValue().set(orderId.toString(),map,120, TimeUnit.MINUTES);
}
return map;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
增加redis代码完善在上面
1、安装vue-qriously
npm install vue-qriously
2、引入
在/plugins/myPlugin.js文件添加引入
import VueQriously from ‘vue-qriously’
Vue.use(VueQriously)
前端
设置,每隔3秒钟调用一次支付状态接口,使用定时器方法
如果是支付中,返回。如果不是,清除计时器。
支付成功后更新支付订单的信息
微信queryPayStatus
根据订单id调用微信接口 查询订单状态
如果支付成功,更新订单状态
paySuccess
更新支付记录、更新订单、远程调用医院接口,更新订单支付信息
支付成功
支付
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IQYRxatm-1632414532344)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002045.png)]
两种情况:
参考文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
该接口需要使用证书,详情参考文档并下载证书
请下载的证书放在service-order模块/resources/cert文件夹下
在application.properties文件配置证书路径
#相对路径
weixin.cert= weixin.cert=src\\main\\resources\\cert\\apiclient_cert.p12
表refund_info:退款信息
创建该表对应的类
保存退款记录 WeixinServiceImpl
的refund
public Boolean refund(Long orderId) {
try {
//获取支付记录信息
PaymentInfo paymentInfo = paymentService.getPaymentInfo(orderId, PaymentTypeEnum.WEIXIN.getStatus());
//添加信息到退款记录表
RefundInfo refundInfo = refundInfoService.saveRefundInfo(paymentInfo);
//判断当前订单数据是否已退款
if (refundInfo.getRefundStatus().intValue() == RefundStatusEnum.REFUND.getStatus().intValue()) {
return true;
}
//调用微信接口实现退款
//封装需要参数,和之前一样
Map<String, String> paramMap = new HashMap<>();
paramMap.put("appid", ConstantPropertiesUtils.APPID); //公众账号ID
paramMap.put("mch_id", ConstantPropertiesUtils.PARTNER); //商户编号
paramMap.put("nonce_str", WXPayUtil.generateNonceStr());
paramMap.put("transaction_id", paymentInfo.getTradeNo()); //微信订单号
paramMap.put("out_trade_no", paymentInfo.getOutTradeNo()); //商户订单编号
paramMap.put("out_refund_no", "tk" + paymentInfo.getOutTradeNo()); //商户退款单号
//实际金额
//paramMap.put("total_fee",paymentInfoQuery.getTotalAmount().multiply(new BigDecimal("100")).longValue()+"");
//paramMap.put("refund_fee",paymentInfoQuery.getTotalAmount().multiply(new BigDecimal("100")).longValue()+"");
//测试金额 1分钱
paramMap.put("total_fee", "1");
paramMap.put("refund_fee", "1");
String paramXml = WXPayUtil.generateSignedXml(paramMap, ConstantPropertiesUtils.PARTNERKEY);
//设置接口调用内容(路径为退款)
HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/secapi/pay/refund");
client.setXmlParam(paramXml);
client.setHttps(true);
//设置退款证书,进行退款操作的必要设置
client.setCert(true);
client.setCertPassword(ConstantPropertiesUtils.PARTNER);
client.post();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
完善工具类HttpClient的TODO
先读取配置文件中的证书路径。需要在配置类中添加方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x4v8xjO0-1632414532345)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002045.png)]
订单列表
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ml8SmBlh-1632414532346)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002045.png)]
我们通过定时任务,每天8点执行,提醒就诊
搭建方式如service-user
引入rabbit依赖
p配置文件
# 服务端口
server.port=8207
# 服务名
spring.application.name=service-task
# 环境设置:dev、test、prod
spring.profiles.active=dev
# nacos服务地址
spring.cloud.nacos.discovery.server-addr=120.76.245.154:8848
#rabbitmq地址
spring.rabbitmq.host=120.76.245.154
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
#连接的redis地址,写虚拟机(服务器)的ip
spring.redis.host=120.76.245.154
#端口号
spring.redis.port=6379
spring.redis.database= 0
spring.redis.timeout=1800000
spring.redis.lettuce.pool.max-active=20
spring.redis.lettuce.pool.max-wait=-1
#最大阻塞等待时间(负数表示没限制)
spring.redis.lettuce.pool.max-idle=5
spring.redis.lettuce.pool.min-idle=0
创建启动类
在rabbit
常量类MQ。。。中添加task的常量
创建定时任务类ScheduledTask
@EnableScheduling :表示开启定时任务操作
cron表达式,网络上有很多生成cron表达式的网站 在线Cron表达式生成器 (qqe2.com)
在模块order
中添加监听类OrderReceive
。来监听该定时任务,监听到后会执行类中的方法,模拟实现。
该方法功能:查询这一天有哪些就诊人的订单,然后对其进行通知
//就诊通知
@Override
public void patientTips() {
QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();
//日期为这一天,状态为不为-1:取消预约
wrapper.eq("reserve_date", new DateTime().toString("yyyy-MM-dd"));
wrapper.ne("order_status", OrderStatusEnum.CANCLE.getStatus());
List<OrderInfo> orderInfoList = baseMapper.selectList(wrapper);
//遍历集合发送信息,可以使用流
for(OrderInfo orderInfo : orderInfoList) {
//短信提示
MsmVo msmVo = new MsmVo();
msmVo.setPhone(orderInfo.getPatientPhone());
String reserveDate = new DateTime(orderInfo.getReserveDate()).toString("yyyy-MM-dd") + (orderInfo.getReserveTime()==0 ? "上午": "下午");
Map<String,Object> param = new HashMap<String,Object>(){{
put("title", orderInfo.getHosname()+"|"+orderInfo.getDepname()+"|"+orderInfo.getTitle());
put("reserveDate", reserveDate);
put("name", orderInfo.getPatientName());
}};
msmVo.setParam(param);
//调用raabit
rabbitService.sendMessage(MQConstant.EXCHANGE_DIRECT_MSM, MQConstant.ROUTING_MSM_ITEM, msmVo);
}
}
测试:
先启动order模块。
再启动Sms模块
最后启动task模块。因为已启动每个设置的时间就会执行上面的方法
异常:RedisConnectionException: Unable to connect to localhost:6379
因为没有配置redis
需要在配置文件中加上
#连接的redis地址,写虚拟机(服务器)的ip
spring.redis.host=120.76.245.154
#端口号
spring.redis.port=6379
spring.redis.database= 0
spring.redis.timeout=1800000
spring.redis.lettuce.pool.max-active=20
spring.redis.lettuce.pool.max-wait=-1
#最大阻塞等待时间(负数表示没限制)
spring.redis.lettuce.pool.max-idle=5
spring.redis.lettuce.pool.min-idle=0
使用Dubug的方式去查看功能是否能执行。
可以发现,成功监听到短信发送。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D46WjRyb-1632414532346)(C:/Users/PC/AppData/Roaming/Typora/typora-user-images/image-20210924002053440.png)]
没有数据是因为,数据库中确实没有这一天的数据
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-at5tNkA2-1632414532347)(D:\learningappDataSave\Typora\生产实习\操作说明.assets\image-20210921182759141.png)]
再控制面板中,也可以发现
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lYUJzsGq-1632414532347)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002057.png)]
需求分析:
为什么需要一个统计模块呢,因为在实际的生成环境中,有很多种各式统计,数据来源于各个服务模块,我们得有一个统计模块来专门管理。更加直观,更加方便的管擦效果
统计医院每天的预约情况,通过图表的形式展示,统计的数据都来自订单模块,因此在该模块封装好数据,在统计模块通过feign的形式获取数据。
使用条形统计图、折线图、或者扇形图
需要使用图标工具ECharts
安装依赖,管理员系统
npm install --save [email protected]
# 查询每天有多少个订单(挂号数量)
select count(*) as count ,reserve_date as reserveDate
from order_info GROUP BY reserve_date
ORDER BY reserve_date
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LAd25TmC-1632414532348)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002103.png)]
因为需要用到sql,所以需要使用xml文件,创建OrderMapper.xml
这里创建一个OrderCountVo实体类。
@Data
@ApiModel(description = "OrderCountVo")
public class OrderCountVo {
@ApiModelProperty(value = "安排日期")
private String reserveDate;
@ApiModelProperty(value = "预约单数")
private Integer count;
}
编写xml,再配置文件加上找到xml的配置
mybatis-plus.mapper-locations=classpath:com/atguigu/yygh/order/mapper/xml/*.xml
给项目的pom中加上打包xml的配置
<build>
<resources>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.xmlinclude>
includes>
<filtering>falsefiltering>
resource>
resources>
build>
因为这些图需要的是一个数组格式,而java中传list可以使json在前端呈现数组
orderApi中创建获取count的方法
创建order_client
,添加远程调用方法。
新建模块service_statistics
,用作统计分析
引入order_client
添加启动类、配置文件
# 服务端口
server.port=8208
# 服务名
spring.application.name=service-statistics
# 环境设置:dev、test、prod
spring.profiles.active=dev
# nacos服务地址
spring.cloud.nacos.discovery.server-addr=120.76.245.154:8848
配置网关。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vH1FGE1x-1632414532348)(https://raw.githubusercontent.com/YHcen/piggo/master/20210924002110.png)]