目录
- 一、医院系统模拟接口
- 1. 服务部署
- 2. 操作说明
- 3. 上传接口与回调接口
- ① 业务术语
- ② 安全控制
- ③ 业务接口
- ④ 平台接口
- ⑤ 医院接口
- 二、集成 MongoDB
- 三、添加医院基础类
- 四、上传医院
- 五、参数签名
- 六、图片 Base64 编码
- 七、查询医院接口
一、医院系统模拟接口
1. 服务部署
① 找到资源文件夹下面的 hospital-manage 项目,导入 idea
② 导入sql,路径:hospital-manage/资源文件/sql/表结构.sql
③ 修改 application-dev.yml 文件数据库连接
④ 启动项目
2. 操作说明
① 访问项目
浏览器:http://localhost:9998/,如图
② 医院设置
我们在尚医通管理后台设置的医院信息配置到医院接口模拟系统,如图:
配置参数:
- 医院 code:尚医通分配的医院 code
- 签名 key:尚医通分配的签名 key
- 统一预约挂号平台基础路径:尚医通接口基础路径
3. 上传接口与回调接口
上传接口包括的相关操作有医院、科室与排班等。
对应的测试数据在:hospital-manage/资源文件/示例数据。
回调接口包括预约下单、更新支付状态和取消预约等。
① 业务术语
医院编号:医院与尚医通合作后,尚医通合提供给医院的唯一标识ID号(hoscode)。
签名密钥:医院与尚医通合作后,尚医通提供给医院,用于接口调用的 MD5 数字签名算法的密码串 (signKey)。
② 安全控制
接口采用数据签名的方式来保证医院与尚医通系统间的身份验证、中间信息传递的完整性,以便进行电子商务安全当中非常重要的交易身份辨识、不可抵赖、防止篡改等功能。
③ 业务接口
传参说明:
所有参数递交的方式必须为 POST,参数值编码为 gb2312。如果采用拼接(如http://localhost?a=1&b=李四) 的形式提交,传参时要对参数值进行 url 编码,尤其是汉字、网址等。采用 Form 表单形式提交则不需要。参数值不要带空格。
验签参数sign生成:
a、组成加密串。所有变量值按照参数名 (不包含sign参数) 升序用 | 连接,最后连接 signKey。
b、加密。采用 32 位 MD5 小写 (编码utf-8) 加密。
c、例:假设接口参数 a=1,b=张三,c=13012345678,指派给商户的签名密钥signKey=1234567890,则加密串如下:1|张三|13012345678|1234567890
。
d、MD5(32位小写) 加密值核对。
Md5("123456")=e10adc3949ba59abbe56e057f20f883e
所有的字段都使用驼峰形式,如:agent_id 改为 agentId
返回/通知结果:所有接口同步返回
④ 平台接口
A、上传医院
医院的基本信息与规则信息
提交地址:http://localhost/api/hosp/saveHospital
请求参数:变量定义
字段名 | 类型 | 长度 | 必输 | 说明 |
---|---|---|---|---|
hoscode | string | 30 | 是 | 给医院分配的唯一标识 |
hosname | string | 50 | 是 | 医院名称 |
hostype | string | 1 | 是 | 医院类型(1:三级甲等,2:三级乙等,3:二级甲等,4:二级乙等,5:一级) |
provinceCode | string | 18 | 是 | 省code (国家统计局对应省的code) |
cityCode | string | 50 | 是 | 市code (国家统计局对应市的code) |
districtCode | string | 10 | 是 | 区code(国家统计局对应区的code) |
address | string | 20 | 是 | 详情地址 |
logoData | string | 11 | 是 | 医院logo(转换为base64字符串) |
intro | string | 是 | 医院简介 | |
route | string | 255 | 是 | 坐车路线 |
bookingRule | string | 8000 | 是 | 预约规则,json数据 |
timestamp | long | 是 | 时间戳,从1970-01-01 00:00:00算起的毫秒数 | |
sign | string | 32 | 是 | 验签参数 |
bookingRule 例子:
{
"cycle": "1",
"releaseTime": "08:30",
"stopTime": "11:30",
"quitDay": "-1",
"quitTime": "15:30",
"rule": [
"西院区预约号取号地点:西院区门诊楼一层大厅挂号窗口取号", "东院区预约号取号地点:东院区老门诊楼一层大厅挂号窗口或新门诊楼各楼层挂号/收费窗口取号"
]
}
bookingRule 说明:属性说明
- cycle:预约周期
- releaseTime:放号时间
- stopTime:停挂时间
- quitDay:退号截止天数(如:就诊前一天为-1,当天为0)
- quitTime:退号时间
- rule:预约规则,以数组形式传递
同步返回:
结果参数含义:
字段名 | 类型 | 长度 | 必输 | 说明 |
---|---|---|---|---|
code | string | 是 | 结果编码。200:请求成功。不等于200:请求失败(message:失败原因) | |
message | string | 100 | 是 | 结果描述 |
data | string | 5000 | 是 | 业务数据 |
B、上传科室
科室信息:
提交地址:http://localhost/api/hosp/saveDepartment
请求参数:
变量定义
字段名 | 类型 | 长度 | 必输 | 说明 |
---|---|---|---|---|
hoscode | string | 30 | 是 | 给医院分配的唯一标识 |
depcode | string | 50 | 是 | 科室编号 |
depname | string | 1 | 是 | 科室名称 |
intro | string | 18 | 是 | 科室描述 |
bigcode | string | 50 | 是 | 大科室编号 |
bigname | string | 10 | 是 | 大科室名称 |
address | string | 20 | 是 | 详情地址 |
timestamp | long | 是 | 时间戳。从1970-01-01 00:00:00算起的毫秒数 | |
sign | string | 32 | 是 | 验签参数 |
同步返回:
结果参数含义
字段名 | 类型 | 长度 | 必输 | 说明 |
---|---|---|---|---|
code | string | 是 | 结果编码。200:请求成功;不等于200:请求失败(message:失败原因) | |
message | string | 100 | 是 | 结果描述 |
data | string | 5000 | 是 | 业务数据 |
C、上传排班
排班信息
提交地址:http://localhost/api/hosp/saveSchedule
请求参数:
变量定义
字段名 | 类型 | 长度 | 必输 | 说明 |
---|---|---|---|---|
hoscode | string | 30 | 是 | 给医院分配的唯一标识 |
depcode | string | 20 | 是 | 科室编号 |
title | string | 30 | 是 | 职称 |
docname | string | 30 | 是 | 医生名称 |
skill | string | 300 | 是 | 擅长技能 |
workDate | string | 10 | 是 | 安排日期(yyyy-MM-dd) |
workTime | int | 是 | 安排时间 (0:上午 1:下午) | |
reservedNumber | int | 可预约数 | ||
availableNumber | int | 剩余预约数 | ||
amount | string | 5 | 挂号费 | |
status | int | 排班状态 (-1:停诊 0:停约 1:可约) | ||
hosScheduleId | string | 30 | 排班编号 (医院自己的排班主键) | |
timestamp | long | 是 | 时间戳,从1970-01-01 00:00:00算起的毫秒数 | |
sign | string | 32 | 是 |
同步返回 :
结果参数含义
字段名 | 类型 | 长度 | 必输 | 说明 |
---|---|---|---|---|
code | string | 是 | 结果编码。200:请求成功,不等于200:请求失败 (message:失败原因) | |
message | string | 100 | 是 | 结果描述 |
data | string | 5000 | 是 | 业务数据 |
D、查询医院
医院信息
提交地址:http://localhost/api/hosp/hospital/show
请求参数:
变量定义
字段名 | 类型 | 长度 | 必输 | 说明 |
---|---|---|---|---|
hoscode | string | 30 | 是 | 给医院分配的唯一标识 |
timestamp | long | 是 | 时间戳,从1970-01-01 00:00:00算起的毫秒数 | |
sign | string | 32 | 是 | 验签参数。 |
同步返回:
结果参数含义
字段名 | 类型 | 长度 | 必输 | 说明 |
---|---|---|---|---|
code | string | 是 | 结果编码,200:请求成功。不等于200:请求失败 (message:失败原因) | |
message | string | 100 | 是 | 结果描述 |
data | string | 5000 | 是 | 业务数据 |
E、查询科室
科室信息
提交地址:http://localhost/api/hosp/department/list
请求参数
变量定义
字段名 | 类型 | 长度 | 必输 | 说明 |
---|---|---|---|---|
hoscode | string | 30 | 是 | 给医院分配的唯一标识 |
pageNum | Int | 是 | 第几页 | |
pageSize | Int | 是 | 每页个数 | |
timestamp | long | 是 | 时间戳。从1970-01-01 00:00:00算起的毫秒数 | |
sign | string | 32 | 是 | 验签参数。 |
同步返回
结果参数含义
字段名 | 类型 | 长度 | 必输 | 说明 |
---|---|---|---|---|
code | string | 是 | 结果编码,200:请求成功。不等于200:请求失败 (message:失败原因) | |
message | string | 100 | 是 | 结果描述 |
data | string | 5000 | 是 | 业务数据 |
F、查询排班
医院信息
提交地址:http://localhost/api/hosp/schedule/list
请求参数
变量定义:
字段名 | 类型 | 长度 | 必输 | 说明 |
---|---|---|---|---|
hoscode | string | 30 | 是 | 给医院分配的唯一标识 |
pageNum | Int | 是 | 第几页 | |
pageSize | Int | 是 | 每页个数 | |
timestamp | long | 是 | 时间戳,从 1970-01-01 00:00:00 算起的毫秒数 | |
sign | string | 32 | 是 | 验签参数 |
同步返回
结果参数含义:
字段名 | 类型 | 长度 | 必输 | 说明 |
---|---|---|---|---|
code | string | 是 | 结果编码,200:请求成功,不等于200:请求失败 (message:失败原因) | |
message | string | 100 | 是 | 结果描述 |
data | string | 5000 | 是 | 业务数据 |
G、删除科室
删除科室信息
提交地址:http://localhost/api/hosp/department/remove
请求参数
变量定义:
字段名 | 类型 | 长度 | 必输 | 说明 |
---|---|---|---|---|
hoscode | string | 30 | 是 | 给医院分配的唯一标识 |
depcode | string | 30 | 是 | 科室编号 |
timestamp | long | 是 | 时间戳,从1970-01-01 00:00:00算起的毫秒数 | |
sign | string | 32 | 是 | 验签参数 |
同步返回
结果参数含义:
字段名 | 类型 | 长度 | 必输 | 说明 |
---|---|---|---|---|
code | string | 是 | 结果编码 200:请求成功。不等于200:请求失败 (message:失败原因) | |
messag | string | 100 | 是 | 结果描述 |
data | string | 5000 | 是 | 业务数据 |
H、删除排班
删除排班信息
提交地址:http://localhost/api/hosp/schedule/remove
请求参数:
变量定义
字段名 | 类型 | 长度 | 必输 | 说明 |
---|---|---|---|---|
hoscode | string | 30 | 是 | 给医院分配的唯一标识 |
hosScheduleId | strin | 30 | 排班编号 (医院自己的排班主键) | |
timestamp | long | 是 | 时间戳,从1970-01-01 00:00:00算起的毫秒数 | |
sign | string | 32 | 是 | 验签参数 |
同步返回
结果参数含义
字段名 | 类型 | 长度 | 必输 | 说明 |
---|---|---|---|---|
code | string | 是 | 结果编码。200:请求成功,不等于200:请求失败 (message:失败原因) | |
message | string | 100 | 是 | 结果描述 |
data | string | 5000 | 是 | 业务数据 |
⑤ 医院接口
A、预约下单
医院的基本信息与规则信息
提交地址:${basePath}/order/submitOrder
请求参数:
变量定义
字段名 | 类型 | 长度 | 必输 | 说明 |
---|---|---|---|---|
hoscode | string | 30 | 是 | 给医院分配的唯一标识 |
depcode | string | 20 | 是 | 科室编号 |
hosScheduleId | string | 30 | 排班编号 (医院自己的排班主键) | |
reserveDate | string | 10 | 是 | 安排日期 (yyyy-MM-dd) |
reserveTime | int | 是 | 安排时间(0:上午 1:下午) | |
amount | string | 5 | 挂号费 | |
name | string | 20 | 就诊人姓名 | |
sex | int | 就诊人性别 | ||
birthdate | string | 20 | 就诊人出生年月 | |
phone | string | 11 | 就诊人手机 | |
isMarry | int | 就诊人是否结婚 | ||
provinceCode | string | 50 | ||
cityCode | string | 50 | 是 | 市code (国家统计局对应市的code) |
districtCode | string | 10 | 是 | 区code (国家统计局对应区的code) |
address | string | 20 | 是 | 就诊人详情地址 |
contactsName | string | 11 | 是 | 联系人姓名 |
contactsCertificatesType | int | 否 | 联系人证件类型 | |
contactsCertificatesNo | string | 30 | 是 | 联系人证件号 |
contactsPhone | string | 11 | 是 | 联系人手机 |
isInsure | int | 是否有医保 | ||
timestamp | long | 是 | 时间戳,从 1970-01-01 00:00:00 算起的毫秒数 | |
sign | string | 32 | 是 | 验签参数 |
同步返回
结果参数含义:
字段名 | 类型 | 长度 | 必输 | 说明 |
---|---|---|---|---|
code | string | 是 | 结果编码:200:请求成功,不等于200:请求失败(message:失败原因) | |
message | string | 100 | 是 | 结果描述 |
data | string | 5000 | 是 | 业务数据 |
data业务数据字段:
字段名 | 类型 | 长度 | 必输 | 说明 |
---|---|---|---|---|
hosRecordId | string | 是 | 预约记录唯一标识 (医院预约记录主键) | |
number | int | 是 | 预约序号 | |
reservedNumber | int | 是 | 排班可预约数 | |
availableNumber | int | 是 | 排班剩余预约数 | |
fetchTime | string | 50 | 是 | 取号时间 |
fetchAddress | string | 200 | 是 | 取号地址 |
B、更新支付状态
平台支付成功,通过该接口更新医院支付状态
提交地址 :${basePath}/order/updatePayStatus
请求参数 :
变量定义
字段名 | 类型 | 长度 | 必输 | 说明 |
---|---|---|---|---|
hoscode | string | 30 | 是 | 给医院分配的唯一标识 |
hosRecordId | string | 是 | 预约记录唯一标识 (医院预约记录主键) | |
timestamp | long | 是 | 时间戳,从1970-01-01 00:00:00算起的毫秒数 | |
sign | string | 32 | 是 | 验签参数 |
同步返回:
结果参数含义
字段名 | 类型 | 长度 | 必输 | 说明 |
---|---|---|---|---|
code | string | 是 | 结果编码,200:请求成功。不等于200:请求失败 (message:失败原因) | |
message | string | 100 | 是 | 结果描述 |
data | string | 5000 | 是 | 业务数据 |
C、取消预约
平台通过该接口取消预约
提交地址:${basePath}/order/updateCancelStatus
请求参数
变量定义
字段名 | 类型 | 长度 | 必输 | 说明 |
---|---|---|---|---|
hoscode | string | 30 | 是 | 给医院分配的唯一标识 |
hosRecordId | string | 是 | 预约记录唯一标识 (医院预约记录主键) | |
timestamp | long | 是 | 时间戳,从 1970-01-01 00:00:00 算起的毫秒数 | |
sign | string | 32 | 是 | 验签参数 |
同步返回
结果参数含义
字段名 | 类型 | 长度 | 必输 | 说明 |
---|---|---|---|---|
code | string | 是 | 结果编码,200:请求成功,不等于200:请求失败 (message:失败原因) | |
message | string | 100 | 是 | 结果描述 |
data | string | 5000 | 是 | 业务数据 |
二、集成 MongoDB
A、添加依赖
service-hosp 模块 pom.xml 添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
B、添加配置
在 application.properties 文件添加配置
spring.data.mongodb.uri=mongodb://192.168.38.130:27017/yygh_hosp
说明:改为自己安装 MongoDB 的 IP 地址
这样写也可以:
三、添加医院基础类
A、添加 model
说明:由于实体对象没有逻辑,我们已经统一导入com.fancy.yygh.model.hosp.Hospital
B、添加 Repository
@Repository
public interface HospitalRepository extends MongoRepository<Hospital,String> {
}
C、添加 service 接口及实现类
添加 com.fancy.yygh.hosp.service.HospitalService 接口
public interface HospitalService {
}
添加com.fancy.yygh.hosp.service.impl.HospitalServiceImpl接口实现
package com.fancy.yygh.hosp.service.impl;
@Service
public class HospitalServiceImpl implements HospitalService {
@Autowired
private HospitalRepository hospitalRepository;
}
D、添加 controller
添加 com.fancy.yygh.hosp.api.ApiController
package com.fancy.yygh.hosp.api;
@Api(tags = "医院管理API接口")
@RestController
@RequestMapping("/api/hosp")
public class ApiController {
@Autowired
private HospitalService hospitalService;
}
说明:平台对外开发的接口都写在该 Controller 类
四、上传医院
医院编号是平台分配的,全局唯一,上传医院接口可以多次调用,如果存在相同编号的为更新操作
A、接口数据分析
{
"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": [
"西院区预约号取号地点:西院区门诊楼一层大厅挂号窗口取号",
"东院区预约号取号地点:东院区老门诊楼一层大厅挂号窗口或新门诊楼各楼层挂号/收费窗口取号"
]
}
}
说明:
- 数据分为医院基本信息与预约规则信息
- 医院logo转换为base64字符串
- 预约规则信息属于医院基本信息的一个属性
- 预约规则rule,以数组形式传递
- 数据传递过来我们还要验证签名,只允许平台开通的医院可以上传数据,保证数据安全性
B、添加 service 接口
在 HospitalService 类添加接口
/**
* 上传医院信息
* @param paramMap
*/
void save(Map<String, Object> paramMap);
说明:参数使用Map,减少对象封装,有利于签名校验,后续会体验到
在 HospitalServiceImpl 类添加实现
@Override
public void save(Map<String, Object> paramMap) {
log.info(JSONObject.toJSONString(paramMap));
Hospital hospital = JSONObject.parseObject(JSONObject.toJSONString(paramMap),Hospital.class);
//判断是否存在
Hospital targetHospital = hospitalRepository.getHospitalByHoscode(hospital.getHoscode());
if(null != targetHospital) {
hospital.setStatus(targetHospital.getStatus());
hospital.setCreateTime(targetHospital.getCreateTime());
hospital.setUpdateTime(new Date());
hospital.setIsDeleted(0);
hospitalRepository.save(hospital);
} else {
//0:未上线 1:已上线
hospital.setStatus(0);
hospital.setCreateTime(new Date());
hospital.setUpdateTime(new Date());
hospital.setIsDeleted(0);
hospitalRepository.save(hospital);
}
}
说明:
Hospital hospital = JSONObject.parseObject(JSONObject.toJSONString(paramMap),Hospital.class);
Map 转换为 Hospital 对象时,预约规则 bookingRule 为一个对象属性,rule 为一个数组属性,因此在转换时我们要重新对应的 set 方法,不然转换不会成功
public class Hospital extends BaseMongoEntity {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "医院编号")
private String hoscode;
...
//预约规则
@ApiModelProperty(value = "预约规则")
private BookingRule bookingRule;
public void setBookingRule(String bookingRule) {
this.bookingRule = JSONObject.parseObject(bookingRule, BookingRule.class);
}
}
public class BookingRule {
@ApiModelProperty(value = "预约周期")
private Integer cycle;
...
@ApiModelProperty(value = "预约规则")
private List<String>rule;
/**
*
* @param rule
*/
public void setRule(String rule) {
if(!StringUtils.isEmpty(rule)) {
this.rule = JSONArray.parseArray(rule, String.class);
}
}
}
C、添加repository接口
在 HospitalRepository 类添加接口
Hospital getHospitalByHoscode(String hoscode);
D、添加 controller 接口
在 ApiController 类添加接口
@ApiOperation(value = "上传医院")
@PostMapping("saveHospital")
public Result saveHospital(HttpServletRequest request) {
Map<String, Object> paramMap = HttpRequestHelper.switchMap(request.getParameterMap());
hospitalService.save(paramMap);
return Result.ok();
}
E、添加帮助类
在 service-util 模块添加 HttpRequestHelper 帮助类
package com.fancy.yygh.common.helper;
@Slf4j
public class HttpRequestHelper {
/**
*
* @param paramMap
* @return
*/
public static Map<String, Object> switchMap(Map<String, String[]> paramMap) {
Map<String, Object> resultMap = new HashMap<>();
for (Map.Entry<String, String[]> param : paramMap.entrySet()) {
resultMap.put(param.getKey(), param.getValue()[0]);
}
return resultMap;
}
}
五、参数签名
A、封装签名方法
在 service-util 模块 HttpRequestHelper 类添加方法
public static void main(String[] args) {
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("d", "4");
paramMap.put("b", "2");
paramMap.put("c", "3");
paramMap.put("a", "1");
paramMap.put("timestamp", getTimestamp());
log.info(getSign(paramMap, "111111111"));
}
/**
* 请求数据获取签名
* @param paramMap
* @param signKey
* @return
*/
public static String getSign(Map<String, Object> paramMap, String signKey) {
if(paramMap.containsKey("sign")) {
paramMap.remove("sign");
}
TreeMap<String, Object> sorted = new TreeMap<>(paramMap);
StringBuilder str = new StringBuilder();
for (Map.Entry<String, Object> param : sorted.entrySet()) {
str.append(param.getValue()).append("|");
}
str.append(signKey);
log.info("加密前:"+ str.toString());
String md5Str = MD5.encrypt(str.toString());
log.info("加密后:"+ md5Str);
return md5Str;
}
/**
* 签名校验
* @param paramMap
* @param signKey
* @return
*/
public static boolean isSignEquals(Map<String, Object> paramMap, String signKey) {
String sign = (String)paramMap.get("sign");
String md5Str = getSign(paramMap, signKey);
if(!sign.equals(md5Str)) {
return false;
}
return true;
}
/**
* 获取时间戳
* @return
*/
public static long getTimestamp() {
return new Date().getTime();
}
B、上传医院添加签名校验
我们在医院设置的时候,为每个医院生成了医院编码与签名key,因此我在验证签名时要根据医院编码去动态获取签名key,然后再做签名校验
添加获取签名key接口
1,在 HospitalSetService 类添加接口
/**
* 获取签名key
* @param hoscode
* @return
*/
String getSignKey(String hoscode);
2,在 HospitalSetServiceImpl 类实现接口
@Override
public String getSignKey(String hoscode) {
HospitalSet hospitalSet = this.getByHoscode(hoscode);
if(null == hospitalSet) {
throw new YyghException(ResultCodeEnum.HOSPITAL_OPEN);
}
if(hospitalSet.getStatus().intValue() == 0) {
throw new YyghException(ResultCodeEnum.HOSPITAL_LOCK);
}
return hospitalSet.getSignKey();
}
/**
* 根据hoscode获取医院设置
* @param hoscode
* @return
*/
private HospitalSet getByHoscode(String hoscode) {
return hospitalSetMapper.selectOne(new QueryWrapper<HospitalSet>().eq("hoscode", hoscode));
}
修改 ApiController 类上传医院接口:
修改 ApiController 类上传医院接口
@ApiOperation(value = "上传医院")
@PostMapping("saveHospital")
public Result saveHospital(HttpServletRequest request) {
Map<String, Object> paramMap = HttpRequestHelper.switchMap(request.getParameterMap());
//必须参数校验 略
String hoscode = (String)paramMap.get("hoscode");
if(StringUtils.isEmpty(hoscode)) {
throw new YyghException(ResultCodeEnum.PARAM_ERROR);
}
//签名校验
if(!HttpRequestHelper.isSignEquals(paramMap, hospitalSetService.getSignKey(hoscode))) {
throw new YyghException(ResultCodeEnum.SIGN_ERROR);
}
hospitalService.save(paramMap);
return Result.ok();
}
六、图片 Base64 编码
A、图片 base64 说明
图片的 Base64 编码就是可以将一张图片数据编码成一串字符串,使用该字符串代替图像地址 url
在前端页面中常见的 Base64 图片的引入方式:
<img src="data:image/png;base64,iVBORw0..>
优点
- Base64 格式的图片是文本格式,占用内存小,转换后的大小比例大概为 1/3,降低了资源服务器的消耗;
- 网页中使用 Base64 格式的图片时,不用再请求服务器调用图片资源,减少了服务器访问次数。
缺点
- Base64 格式的文本内容较多,存储在数据库中增大了数据库服务器的压力
- 网页加载图片虽然不用访问服务器了,但因为 Base64 格式的内容太多,所以加载网页的速度会降低,可能会影响用户的体验。
说明:医院 logo 图片小,因此上传医院 logo 是可以使用Base64 格式保存
B、图片 Base64 工具类
在 common-util 模块添加工具类
添加 com.fancy.yygh.common.util.ImageBase64Util 类
package com.fancy.yygh.common.util;
import org.apache.commons.codec.binary.Base64;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class ImageBase64Util {
public static void main(String[] args) {
String imageFile= "D:\\yygh_work\\xh.png";// 待处理的图片
System.out.println(getImageString(imageFile));
}
public static String getImageString(String imageFile){
InputStream is = null;
try {
byte[] data = null;
is = new FileInputStream(new File(imageFile));
data = new byte[is.available()];
is.read(data);
return new String(Base64.encodeBase64(data));
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != is) {
try {
is.close();
is = null;
} catch (Exception e) {
e.printStackTrace();
}
}
}
return "";
}
}
C、上传医院接口修正
图片转换为 Base64 字符串时,该字符串中包含大量的加号“+”,服务器在解析数据时会把加号当成连接符,转换为空格,因此我们要做一下特殊处理
修改 ApiController 类上传接口
@ApiOperation(value = "上传医院")
@PostMapping("saveHospital")
public Result saveHospital(HttpServletRequest request) {
Map<String, Object> paramMap = HttpRequestHelper.switchMap(request.getParameterMap());
//必须参数校验 略
String hoscode = (String)paramMap.get("hoscode");
if(StringUtils.isEmpty(hoscode)) {
throw new YyghException(ResultCodeEnum.PARAM_ERROR);
}
//传输过程中“+”转换为了“ ”,因此我们要转换回来
String logoDataString = (String)paramMap.get("logoData");
if(!StringUtils.isEmpty(logoDataString)) {
String logoData = logoDataString.replaceAll("", "+");
paramMap.put("logoData", logoData);
}
//签名校验
if(!HttpRequestHelper.isSignEquals(paramMap, hospitalSetService.getSignKey(hoscode))) {
throw new YyghException(ResultCodeEnum.SIGN_ERROR);
}
hospitalService.save(paramMap);
return Result.ok();
}
七、查询医院接口
A、添加 service 接口
在 HospitalService 类添加接口
/**
* 查询医院
* @param hoscode
* @return
*/
Hospital getByHoscode(String hoscode);
在 HospitalServiceImpl 类添加实现
@Override
public Hospital getByHoscode(String hoscode) {
return hospitalRepository.getHospitalByHoscode(hoscode);
}
B、添加 controller 接口
在 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");
if(StringUtils.isEmpty(hoscode)) {
throw new YyghException(ResultCodeEnum.PARAM_ERROR);
}
//签名校验
if(!HttpRequestHelper.isSignEquals(paramMap, hospitalSetService.getSignKey(hoscode))) {
throw new YyghException(ResultCodeEnum.SIGN_ERROR);
}
return Result.ok(hospitalService.getByHoscode((String)paramMap.get("hoscode")));
}