第01章-医院系统
1、业务功能描述
资料:资料>医院模拟系统>尚医通API接口文档.docx
1.1、平台方
参考《尚医通API接口文档.docx》
进行业务接口的开发,接收医院方的接口调用,将医院信息、科室信息、排班信息等数据存入MongoDB。
1.2、医院方
每个医院有自己的业务平台,需参考《尚医通API接口文档.docx》
进行接口调用与数据上传,将本院的医院信息、科室信息、排班信息等数据上传到统一挂号平台。
2、部署医院端程序
2.1、创建yygh_manage数据库
资料:资料>医院模拟系统>yygh_manage.sql
2.2、运行医院程序
资料:资料>医院模拟系统>hospital-manage.zip
用idea打开医院端程序,修改数据库配置和maven配置 ,运行启动类
访问http://localhost:9998
2. 3、添加医院设置信息
在平台端
数据库guigu_syt_hosp
中的hospital_set
表中为每个需要接入平台的医院配置医院设置信息,例如“北京协和医院”,并生成医院编号和signKey
在医院端
数据库guigu_yygh_manage
中的hospital_set
表配置医院设置信息,确保医院编号和signKey和平台端一致
。
医院编号:是平台为医院颁发的,每个医院唯一。
signKey:是平台为医院颁发的,用于生成签名,确保数据传输过程的不可篡改。
第02章-接口安全
1、数字签名
1.1、对称加密
1.2、非对称加密
1.3、摘要算法
实现完整性的手段主要是摘要算法(Digest Algorithm),也就是我们常说的哈希函数。假设一个任意长的数据 z,经过哈希运算后会得到固定长度的数据 h,h 就是z的哈希结果又称作“数据指纹“ 或 “摘要”。MD5就是一个摘要算法
。摘要算法必须具有下面的 4 种特性:
不可逆:只有算法,没有秘钥,只能加密,不能解密
难题友好性:想要破解,只能暴力枚举
发散性:只要对原文进行一点点改动,摘要就会发生剧烈变化
抗碰撞性:原文不同,计算后的摘要也要不同
常见摘要算法:MD5、SHA1、SHA2(SHA224、SHA256、SHA384)
1.4、数字签名的原理
信息完整性
- Bob有两把钥匙,一把公钥(public key),一把私钥(private key)
- Bob把公钥送给他的朋友们,每人一把。Bob的私钥自己保留。
Bob决定给Pat写一封信,要保证Pat收到信后,能够确认信的内容没有被篡改过,也就是需要保证信息的完整性。我们可以利用摘要运算,具体的流程是这样的:
- 第一步:Bob写完信后,先用摘要算法(MD5、SHA),生成信件原文的摘要(Digest)
- 第二步:Bob将摘要附在信件的原文下面,一起发给Pat
Pat收信后,也是两个步骤:
- 第一步:Pat使用和Bob一样的摘要算法加密信件的原文得到信件的摘要。
- 第二步:Pat将加密后的摘要,和Bob在原文中附加的摘要做对比,如果一致,说明信件没有篡改。
问题:这种方式看似解决了数据完整性的问题,但是有一个致命的漏洞,就是,如果信件原文不加密,并且被黑客截获,黑客直接修改了原文,并且根据原文直接生成了新的摘要,然后附加在原文的下面,伪装成Bob将信件发给Pat,那么Pat接收后,是完全察觉不出来信件其实已经被篡改了。所以说摘要算法不具有机密性,如果明文传输,那么黑客可以修改消息后把摘要也一起改了,还是鉴别不出信息的完整性。
解决方案:我们可以使用非对称加密中的私钥,将摘要进行加密处理。
具体的流程是:
- 第一步:Bob写完信后,先用摘要算法(MD5、SHA),生成信件的摘要(Digest)
- 第二步:Bob使用自己的私钥,将摘要加密。加密后的结果,我们称之为“数字签名”Signature
- 第三步:Bob将数字签名附在信的原文下面,一起发给Pat
Pat收信后,也是三个步骤:
第一步:Pat取下数字签名,用Bob的公钥解密,得到信件的摘要。
第二步:Pat使用和Bob一样的摘要算法加密信件的原文,得到信件的摘要。
第三步:将前面两部得到的摘要进行比对,如果一致,信件是就是Bob发的,并且没有经过篡改
。
这个过程叫做“验签”,也就是验证签名通过Bob的签名流程和Pat的验签流程,我们发现即使信件被黑客截获,即使黑客能够篡改信件原文,即使黑客能够通过摘要算法生成新的摘要,但是因为他没有Bob的私钥,因此无法对摘要进行加密,无法生成只有Bob才能生成的签名,所以信件也就无法被篡改了。微信支付中的签名和验签的过程就是这个原理。经过以上步骤,我们就可以取出信件原文了。
- 上面,我们讲解的数字签名的生成,这里使用了非对称加密+摘要算法的方式,在对安全性要求较高的系统中(如支付系统),会采用这种接口安全策略。
- 尚医通项目中医院和平台间接口的调用对安全性的要求没有那么高,因此没有使用非对称加密的方式,使用了对称加密+摘要算法的方式。
2、获取签名密钥
2.1、引入依赖
service-util中引入依赖
<!--fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
2.2、工具类
将工具类复制到service-util的utils包中
资料:资料>医院模拟系统>工具类
2.3、签名的过程
尚医通的签名算法:参考《尚医通API接口文档.docx》
3.1传参说明
2.4、签名密钥的获取
接口:HospitalSetService
/**
* 根据医院编码获取医院签名密钥
* @param hoscode
* @return
*/
String getSignKey(String hoscode);
/**
* 根据hoscode获取医院设置
* @param hoscode
* @return
*/
HospitalSet getByHoscode(String hoscode);
实现:HospitalSetServiceImpl
@Override
public String getSignKey(String hoscode) {
HospitalSet hospitalSet = this.getByHoscode(hoscode);
if(hospitalSet == null) {
throw new GuiguException(ResultCodeEnum.HOSPITAL_OPEN);
}
if(hospitalSet.getStatus().intValue() == 0) {
throw new GuiguException(ResultCodeEnum.HOSPITAL_LOCK);
}
return hospitalSet.getSignKey();
}
@Override
public HospitalSet getByHoscode(String hoscode) {
return baseMapper.selectOne(
new LambdaQueryWrapper<HospitalSet>().eq(HospitalSet::getHoscode, hoscode)
);
}
第03章-接口开发
1、上传医院信息接口
1.1、创建Repository
service-hosp中添加接口HospitalRepository
package com.atguigu.syt.hosp.repository;
public interface HospitalRepository extends MongoRepository<Hospital,ObjectId> {
/**
* 根据医院编号查询医院
* @param hoscode
* @return
*/
Hospital findByHoscode(String hoscode);
}
1.2、创建Service
接口:HospitalService
package com.atguigu.syt.hosp.service;
public interface HospitalService {
/**
* 保存医院信息
* @param paramMap
*/
void save(Map<String, Object> paramMap);
}
实现:HospitalServiceImpl
package com.atguigu.syt.hosp.service.impl;
@Service
public class HospitalServiceImpl implements HospitalService {
@Resource
private HospitalRepository hospitalRepository;
/**
* 添加医院信息
* @param paramMap
*/
@Override
public void save(Map<String, Object> paramMap) {
//把paramMap变成对象
Hospital hospital = JSONObject.parseObject(JSONObject.toJSONString(paramMap), Hospital.class);
//根据医院编号查询医院信息是否已经添加
Hospital existHospital = hospitalRepository.findByHoscode(hospital.getHoscode());
//如果已经添加过,则修改
if(existHospital != null) {
//设置id
hospital.setId(existHospital.getId());
hospital.setStatus(existHospital.getStatus());
hospitalRepository.save(hospital);
} else {
//如果没有添加,则添加
//0:未上线 1:已上线
hospital.setStatus(1);
hospitalRepository.save(hospital);
}
}
}
1.3、创建Controller
在controller包中创建api包,创建ApiController类
package com.atguigu.syt.hosp.controller.api;
@Api(tags = "医院管理API接口")
@RestController
@RequestMapping("/api/hosp")
public class ApiController {
@Resource
private HospitalService hospitalService;
@Resource
private HospitalSetService hospitalSetService;
@ApiOperation(value = "上传医院基本信息")
@PostMapping("/saveHospital")
public Result saveHospital(HttpServletRequest request) {
Map<String, Object> paramMap = HttpRequestHelper.switchMap(request.getParameterMap());
//签名验证
String hoscode = (String)paramMap.get("hoscode");
String signKey = hospitalSetService.getSignKey(hoscode);
HttpRequestHelper.checkSign(paramMap, signKey);
hospitalService.save(paramMap);
return Result.ok();
}
}
1.4、测试
运行医院端程序,测试医院信息的添加
医院端相关代码:hospital-manage:controller.ApiCOntroller.saveHospital
注意:在spring-security的AuthorizationWebSecurityConfig类中,我们配置了授权校验排除了api路径
/**
* 配置哪些请求不拦截
* 排除swagger相关请求
* @param web
* @throws Exception
*/
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/api/**", "/favicon.ico","/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**", "/doc.html");
}
2、查询医院信息接口
2.1、ApiController
@ApiOperation(value = "获取医院信息")
@PostMapping("/hospital/show")
public Result hospital(HttpServletRequest request) {
Map<String, Object> paramMap = HttpRequestHelper.switchMap(request.getParameterMap());
//签名验证
String hoscode = (String)paramMap.get("hoscode");
String signKey = hospitalSetService.getSignKey(hoscode);
HttpRequestHelper.checkSign(paramMap, signKey);
Hospital hospital = hospitalService.getByHoscode(hoscode);
return Result.ok(hospital);
}
2.2、Service
接口:HospitalService
/**
* 根据医院编码获取医院信息
* @param hoscode
* @return
*/
Hospital getByHoscode(String hoscode);
实现:HospitalServiceImpl
@Override
public Hospital getByHoscode(String hoscode) {
return hospitalRepository.findByHoscode(hoscode);
}
2.3、测试
测试查看医院信息:
医院端相关代码:hospital-manage:controller.ApiCOntroller.getHospital
3、上传科室接口
3.1、创建Repository
service-hosp中添加接口DepartmentRepository
package com.atguigu.syt.hosp.repository;
public interface DepartmentRepository extends MongoRepository<Department,ObjectId> {
//根据医院编号和科室编号查询科室
Department findByHoscodeAndDepcode(String hoscode, String depcode);
}
3.2、创建Service
接口:DepartmentService
package com.atguigu.syt.hosp.service;
public interface DepartmentService {
/**
* 保存科室信息
* @param paramMap
*/
void save(Map<String, Object> paramMap);
}
实现:DepartmentServiceImpl
package com.atguigu.syt.hosp.service.impl;
@Service
public class DepartmentServiceImpl implements DepartmentService {
@Resource
private DepartmentRepository departmentRepository;
@Override
public void save(Map<String, Object> paramMap) {
// 把paramMap变成对象
Department department = JSONObject.parseObject(JSONObject.toJSONString(paramMap), Department.class);
//查询科室是否存在 医院编号 + 科室编号
Department existsDepartment = departmentRepository.findByHoscodeAndDepcode(
department.getHoscode(),
department.getDepcode());
//判断
if(existsDepartment != null) { //修改
department.setId(existsDepartment.getId());
departmentRepository.save(department);
} else {
departmentRepository.save(department);
}
}
}
3.3、添加Controller方法
在ApiController中添加方法
@Resource
private DepartmentService departmentService;
@ApiOperation(value = "上传科室")
@PostMapping("/saveDepartment")
public Result saveDepartment(HttpServletRequest request) {
Map<String, Object> paramMap = HttpRequestHelper.switchMap(request.getParameterMap());
//签名验证
String hoscode = (String)paramMap.get("hoscode");
String signKey = hospitalSetService.getSignKey(hoscode);
HttpRequestHelper.checkSign(paramMap, signKey);
departmentService.save(paramMap);
return Result.ok();
}
3.4、测试
运行医院端程序,测试部门信息的添加
4、查询科室接口
4.1、添加Service方法
接口:DepartmentService
/**
* 分页查询
* @param page 当前页码
* @param limit 每页记录数
* @param hoscode 查询条件
* @return
*/
Page<Department> selectPage(int page, int limit, String hoscode);
实现:DepartmentServiceImpl
@Override
public Page<Department> selectPage(int page, int limit, String hoscode) {
//设置排序规则
Sort sort = Sort.by(Sort.Direction.ASC, "depcode");
//设置分页参数
Pageable pageable = PageRequest.of(page-1, limit, sort);
//创建查询对象
Department department = new Department();
department.setHoscode(hoscode);
Example<Department> example = Example.of(department);
//执行查询
Page<Department> pages = departmentRepository.findAll(example, pageable);
return pages;
}
4.2、添加Controller方法
在ApiController中添加方法
@ApiOperation(value = "获取分页列表")
@PostMapping("/department/list")
public Result department(HttpServletRequest request) {
Map<String, Object> paramMap = HttpRequestHelper.switchMap(request.getParameterMap());
//签名验证
String hoscode = (String)paramMap.get("hoscode");
String signKey = hospitalSetService.getSignKey(hoscode);
HttpRequestHelper.checkSign(paramMap, signKey);
int page = Integer.parseInt((String)paramMap.get("page"));
int limit = Integer.parseInt((String)paramMap.get("limit"));
Page<Department> pageModel = departmentService.selectPage(page, limit, hoscode);
return Result.ok(pageModel);
}
5、删除科室接口
5.1、添加Service方法
接口:DepartmentService
/**
* 根据医院编码和科室编码删除科室
* @param hoscode
* @param depcode
*/
void remove(String hoscode, String depcode);
实现:DepartmentServiceImpl
@Override
public void remove(String hoscode, String depcode) {
//根据医院编号、科室编号查询
Department department = departmentRepository.findByHoscodeAndDepcode(hoscode, depcode);
//判断查询出来数据,根据科室id删除
if(department != null) {
departmentRepository.deleteById(department.getId());
}
}
5.2、添加Controller方法
@ApiOperation(value = "删除科室")
@PostMapping("/department/remove")
public Result removeDepartment(HttpServletRequest request) {
Map<String, Object> paramMap = HttpRequestHelper.switchMap(request.getParameterMap());
//签名验证
String hoscode = (String)paramMap.get("hoscode");
String signKey = hospitalSetService.getSignKey(hoscode);
HttpRequestHelper.checkSign(paramMap, signKey);
String depcode = (String)paramMap.get("depcode");
departmentService.remove(hoscode, depcode);
return Result.ok();
}
6、上传排班接口
6.1、创建Repository
package com.atguigu.syt.hosp.repository;
public interface ScheduleRepository extends MongoRepository<Schedule,ObjectId> {
/**
* 根据医院编码和医院端排版id查询排班记录
* @param hoscode
* @param hosScheduleId
* @return
*/
Schedule findByHoscodeAndHosScheduleId(String hoscode, String hosScheduleId);
}
6.2、创建Service
接口:ScheduleService
package com.atguigu.syt.hosp.service;
public interface ScheduleService {
/**
* 保存排班信息
* @param paramMap
*/
void save(Map<String, Object> paramMap);
}
实现:ScheduleServiceImpl
package com.atguigu.syt.hosp.service.impl;
@Service
public class ScheduleServiceImpl implements ScheduleService {
@Resource
private ScheduleRepository scheduleRepository;
@Override
public void save(Map<String, Object> paramMap) {
//数据转换
Schedule schedule = JSONObject.parseObject(JSONObject.toJSONString(paramMap), Schedule.class);
//查询mongodb中数据是否存在
Schedule existSchedule = scheduleRepository.findByHoscodeAndHosScheduleId(
schedule.getHoscode(),
schedule.getHosScheduleId()
);
//如果不存在
if(existSchedule != null){//更新
schedule.setId(existSchedule.getId());
scheduleRepository.save(schedule);
}else{//新增
scheduleRepository.save(schedule);
}
}
}
6.3、添加Controller
ApiController
@Resource
private ScheduleService scheduleService;
@ApiOperation(value = "上传排班")
@PostMapping("/saveSchedule")
public Result saveSchedule(HttpServletRequest request) {
Map<String, Object> paramMap = HttpRequestHelper.switchMap(request.getParameterMap());
//签名验证
String hoscode = (String)paramMap.get("hoscode");
String signKey = hospitalSetService.getSignKey(hoscode);
HttpRequestHelper.checkSign(paramMap, signKey);
scheduleService.save(paramMap);
return Result.ok();
}
7、查询排班接口
7.1、添加Service方法
接口:ScheduleService
/**
* 分页查询
* @param page 当前页码
* @param limit 每页记录数
* @param hoscode 查询条件
* @return
*/
Page<Schedule> selectPage(int page, int limit, String hoscode);
实现:ScheduleServiceImpl
@Override
public Page<Schedule> selectPage(int page, int limit, String hoscode) {
//设置排序规则
Sort sort = Sort.by(Sort.Direction.ASC, "workDate");
//设置分页参数
Pageable pageable = PageRequest.of(page-1, limit, sort);
//创建查询对象
Schedule schedule = new Schedule();
schedule.setHoscode(hoscode);
Example<Schedule> example = Example.of(schedule);
Page<Schedule> pages = scheduleRepository.findAll(example, pageable);
return pages;
}
7.2、添加Controller方法
@ApiOperation(value = "获取排班分页列表")
@PostMapping("/schedule/list")
public Result schedule(HttpServletRequest request) {
Map<String, Object> paramMap = HttpRequestHelper.switchMap(request.getParameterMap());
//签名验证
String hoscode = (String)paramMap.get("hoscode");
String signKey = hospitalSetService.getSignKey(hoscode);
HttpRequestHelper.checkSign(paramMap, signKey);
int page = Integer.parseInt((String)paramMap.get("page"));
int limit = Integer.parseInt((String)paramMap.get("limit"));
Page<Schedule> pageModel = scheduleService.selectPage(page, limit, hoscode);
return Result.ok(pageModel);
}
8、删除排班接口
8.1、添加Service
接口:ScheduleService
/**
* 根据医院编码和排班id删除排班
* @param hoscode
* @param hosScheduleId
*/
void remove(String hoscode, String hosScheduleId);
实现:ScheduleServiceImpl
@Override
public void remove(String hoscode, String hosScheduleId) {
Schedule schedule = scheduleRepository.findByHoscodeAndHosScheduleId(hoscode, hosScheduleId);
if(null != schedule) {
scheduleRepository.deleteById(schedule.getId());
}
}
8.2、添加Controller接口
@ApiOperation(value = "删除排班")
@PostMapping("/schedule/remove")
public Result removeSchedule(HttpServletRequest request) {
Map<String, Object> paramMap = HttpRequestHelper.switchMap(request.getParameterMap());
//签名验证
String hoscode = (String)paramMap.get("hoscode");
String signKey = hospitalSetService.getSignKey(hoscode);
HttpRequestHelper.checkSign(paramMap, signKey);
String hosScheduleId = (String)paramMap.get("hosScheduleId");
scheduleService.remove(hoscode, hosScheduleId);
return Result.ok();
}
源码:https://gitee.com/dengyaojava/guigu-syt-parent
标签:hoscode,String,尚医通,day06,接口,医院,源码,paramMap,public From: https://www.cnblogs.com/deyo/p/17475901.html