31.前台系统-预约下单
# 需求分析
# 数据库表结构
查看yygh_order
库中的order_info
表信息查看订单表字段
- 包含医院信息,科室信息,排班信息
- 包含就诊人信息
- 包含预约序号等信息
-- auto-generated definition
create table order_info
(
id bigint auto_increment comment '编号' primary key,
user_id bigint null,
out_trade_no varchar(300) null comment '订单交易号',
hoscode varchar(30) null comment '医院编号',
hosname varchar(100) null comment '医院名称',
depcode varchar(30) null comment '科室编号',
depname varchar(20) null comment '科室名称',
title varchar(20) null comment '医生职称',
hos_schedule_id varchar(50) null comment '排班编号(医院自己的排班主键)',
reserve_date date null comment '安排日期',
reserve_time tinyint default 0 null comment '安排时间(0:上午 1:下午)',
patient_id bigint null comment '就诊人id',
patient_name varchar(20) null comment '就诊人名称',
patient_phone varchar(11) null comment '就诊人手机',
hos_record_id varchar(30) null comment '预约记录唯一标识(医院预约记录主键)',
number int null comment '预约号序',
fetch_time varchar(50) null comment '建议取号时间',
fetch_address varchar(255) null comment '取号地点',
amount decimal null comment '医事服务费',
quit_time datetime null comment '退号时间',
order_status tinyint null comment '订单状态',
create_time timestamp default CURRENT_TIMESTAMP not null comment '创建时间',
update_time timestamp default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
is_deleted tinyint default 0 not null comment '逻辑删除(1:已删除,0:未删除)',
constraint uk_out_trade_no unique (out_trade_no)
) comment '订单表';
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 预约下单接口定义
医院的基本信息与规则信息
参考 【附录:在线预约挂号API接口文档】 业务接口-预约下单
# 提交地址
${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 | 是 | 取号地址 |
# 设计流程
下单参数:就诊人id与排班id
下单要获取就诊人信息
- 通过feign调用 service-user模块,查询得到
获取排班下单信息与规则信息
- 通过feign调用service-hosp模块,查询得到
获取医院签名信息,然后通过调用医院模拟系统接口预约下单
下单成功更新排班信息与发送短信
# 搭建service-order模块
搭建过程参考service-user模块
# 修改pom
添加 service-cmn-client
依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>service</artifactId>
<groupId>com.stt.yygh</groupId>
<version>0.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<version>1.0</version>
<artifactId>service-order</artifactId>
<packaging>jar</packaging>
<name>service-order</name>
<description>service-order</description>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.stt.yygh</groupId>
<artifactId>service-cmn-client</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</project>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 添加配置文件
创建application.properties
文件并添加如下内容
- 添加mysql配置
- 添加mongodb配置
- 添加nacos配置
- 添加rabbitmq配置
# 服务端口
server.port=8206
# 服务名
spring.application.name=service-order
# 环境设置:dev、test、prod
spring.profiles.active=dev
# mysql数据库连接
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/yygh_order?characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
#返回json的全局时间格式
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
spring.data.mongodb.uri=mongodb://localhost:27017/yygh_hosp
# nacos服务地址
spring.cloud.nacos.discovery.server-addr=localhost:8848
#rabbitmq地址
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 编写启动类
创建 com.stt.yygh.order.ServiceOrderApplication
类,并添加如下内容
package com.stt.yygh.order;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@EnableDiscoveryClient
@ComponentScan(basePackages = {"com.stt"})
@EnableFeignClients(basePackages = {"com.stt"})
public class ServiceOrderApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceOrderApplication.class, args);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 配置网关 service-gateway
在网关服务的application.properties
中配置order相关路径,注意重启gateway服务
#设置路由id
spring.cloud.gateway.routes[6].id=service-order
spring.cloud.gateway.routes[6].uri=lb://service-order
spring.cloud.gateway.routes[6].predicates= Path=/*/order/**
2
3
4
# 添加订单基础类
# 添加model
在 model
模块中添加 com.stt.yygh.model.order.OrderInfo
类,如果已经添加可以忽略
package com.stt.yygh.model.order;
import com.stt.yygh.model.base.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
@Data
@ApiModel(description = "Order")
@TableName("order_info")
public class OrderInfo extends BaseEntity {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "userId")
@TableField("user_id")
private Long userId;
@ApiModelProperty(value = "订单交易号")
@TableField("out_trade_no")
private String outTradeNo;
@ApiModelProperty(value = "医院编号")
@TableField("hoscode")
private String hoscode;
@ApiModelProperty(value = "医院名称")
@TableField("hosname")
private String hosname;
@ApiModelProperty(value = "科室编号")
@TableField("depcode")
private String depcode;
@ApiModelProperty(value = "科室名称")
@TableField("depname")
private String depname;
@ApiModelProperty(value = "排班id")
@TableField("hos_schedule_id")
private String scheduleId;
@ApiModelProperty(value = "医生职称")
@TableField("title")
private String title;
@ApiModelProperty(value = "安排日期")
@JsonFormat(pattern = "yyyy-MM-dd")
@TableField("reserve_date")
private Date reserveDate;
@ApiModelProperty(value = "安排时间(0:上午 1:下午)")
@TableField("reserve_time")
private Integer reserveTime;
@ApiModelProperty(value = "就诊人id")
@TableField("patient_id")
private Long patientId;
@ApiModelProperty(value = "就诊人名称")
@TableField("patient_name")
private String patientName;
@ApiModelProperty(value = "就诊人手机")
@TableField("patient_phone")
private String patientPhone;
@ApiModelProperty(value = "预约记录唯一标识(医院预约记录主键)")
@TableField("hos_record_id")
private String hosRecordId;
@ApiModelProperty(value = "预约号序")
@TableField("number")
private Integer number;
@ApiModelProperty(value = "建议取号时间")
@TableField("fetch_time")
private String fetchTime;
@ApiModelProperty(value = "取号地点")
@TableField("fetch_address")
private String fetchAddress;
@ApiModelProperty(value = "医事服务费")
@TableField("amount")
private BigDecimal amount;
@ApiModelProperty(value = "退号时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm")
@TableField("quit_time")
private Date quitTime;
@ApiModelProperty(value = "订单状态")
@TableField("order_status")
private Integer orderStatus;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
添加订单枚举类com.stt.yygh.enums.order.OrderStatusEnum
,用于枚举订单的状态
package com.stt.yygh.enums;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public enum OrderStatusEnum {
UNPAID(0,"预约成功,待支付"),
PAID(1,"已支付" ),
GET_NUMBER(2,"已取号" ),
CANCLE(-1,"取消预约"),
;
private Integer status;
private String comment ;
public static String getStatusNameByStatus(Integer status) {
OrderStatusEnum arrObj[] = OrderStatusEnum.values();
for (OrderStatusEnum obj : arrObj) {
if (status.intValue() == obj.getStatus().intValue()) {
return obj.getComment();
}
}
return "";
}
public static List<Map<String,Object>> getStatusList() {
List<Map<String,Object>> list = new ArrayList<>();
OrderStatusEnum arrObj[] = OrderStatusEnum.values();
for (OrderStatusEnum obj : arrObj) {
Map<String,Object> map = new HashMap<>();
map.put("status", obj.getStatus());
map.put("comment", obj.getComment());
list.add(map);
}
return list;
}
OrderStatusEnum(Integer status, String comment ){
this.comment=comment;
this.status = status;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# 添加mapper
在 service-order
模块中创建com.stt.yygh.order.mapper.OrderInfoMapper
类
package com.stt.yygh.order.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.stt.yygh.model.order.OrderInfo;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface OrderInfoMapper extends BaseMapper<OrderInfo> {
}
2
3
4
5
6
7
8
9
# 添加service以及实现类
在 service-order
模块中创建com.stt.yygh.order.service.OrderService
类
package com.stt.yygh.order.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.stt.yygh.model.order.OrderInfo;
public interface OrderService extends IService<OrderInfo> {
//保存订单
Long saveOrder(String scheduleId, Long patientId);
}
2
3
4
5
6
7
8
9
实现该接口
package com.stt.yygh.order.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.stt.yygh.model.order.OrderInfo;
import com.stt.yygh.order.mapper.OrderInfoMapper;
import com.stt.yygh.order.service.OrderService;
import org.springframework.stereotype.Service;
@Service
public class OrderServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderService {
@Override
public Long saveOrder(String scheduleId, Long patientId) {
return null;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 添加controller
在 service-order
模块中创建com.stt.yygh.order.controller.OrderApiController
类
package com.stt.yygh.order.controller;
import com.stt.yygh.common.result.Result;
import com.stt.yygh.order.service.OrderService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Api(tags = "订单接口")
@RestController
@RequestMapping("/api/order/orderInfo")
public class OrderApiController {
@Autowired
private OrderService service;
@ApiOperation(value = "创建订单")
@PostMapping("auth/submitOrder/{scheduleId}/{patientId}")
public Result submitOrder(@ApiParam(name = "scheduleId", value = "排班id", required = true)
@PathVariable String scheduleId,
@ApiParam(name = "patientId", value = "就诊人id", required = true)
@PathVariable Long patientId) {
return Result.ok(service.saveOrder(scheduleId, patientId));
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 封装feign获取就诊人信息
# 添加获取就诊人信息接口 service-user
在 service-user
中的PatientApiController
类添加方法 getPatientOrder
注意:返回值类型是 Patient
,同时接口的path包含 inner
,在service-gateway
中针对该path路径做了屏蔽,不允许从gateway服务访问
package com.stt.yygh.user.controller;
import com.stt.yygh.common.result.Result;
import com.stt.yygh.common.utils.AuthContextHolder;
import com.stt.yygh.model.user.Patient;
import com.stt.yygh.user.service.PatientService;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
//就诊人管理接口
@RestController
@RequestMapping("/api/user/patient")
public class PatientApiController {
@Autowired
private PatientService service;
...
@ApiOperation(value = "获取就诊人")
@GetMapping("inner/get/{id}")
public Patient getPatientInfo(@ApiParam(name = "id", value = "就诊人id", required = true)
@PathVariable("id") Long id) {
return service.getById(id);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 搭建service-user-client模块
通过feign调用service-user模块,获取就诊人信息,调用上面的接口
搭建过程如service-cmn-client模块
# 修改pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>service-client</artifactId>
<groupId>com.stt.yygh</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>service-user-client</artifactId>
<packaging>jar</packaging>
<version>1.0</version>
<name>service-user-client</name>
<description>service-user-client</description>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 添加feign接口类
创建 com.stt.yygh.user.client.PatientFeignClient
类,并添加如下path
package com.stt.yygh.user.client;
import com.stt.yygh.model.user.Patient;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(value = "service-user")
@Component
public interface PatientFeignClient {
//获取就诊人信息
@GetMapping("/api/user/patient/inner/get/{id}")
Patient getPatientInfo(@PathVariable("id") Long id);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 封装feign获取排班下单信息
# 添加排班下单信息 model
在model
模块中添加com.stt.yygh.vo.hosp.ScheduleOrderVo
类
package com.stt.yygh.vo.hosp;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
@Data
@ApiModel(description = "Schedule")
public class ScheduleOrderVo {
@ApiModelProperty(value = "医院编号")
private String hoscode;
@ApiModelProperty(value = "医院名称")
private String hosname;
@ApiModelProperty(value = "科室编号")
private String depcode;
@ApiModelProperty(value = "科室名称")
private String depname;
@ApiModelProperty(value = "排班编号(医院自己的排班主键)")
private String hosScheduleId;
@ApiModelProperty(value = "医生职称")
private String title;
@ApiModelProperty(value = "安排日期")
private Date reserveDate;
@ApiModelProperty(value = "剩余预约数")
private Integer availableNumber;
@ApiModelProperty(value = "安排时间(0:上午 1:下午)")
private Integer reserveTime;
@ApiModelProperty(value = "医事服务费")
private BigDecimal amount;
@ApiModelProperty(value = "退号时间")
private Date quitTime;
@ApiModelProperty(value = "挂号开始时间")
private Date startTime;
@ApiModelProperty(value = "挂号结束时间")
private Date endTime;
@ApiModelProperty(value = "当天停止挂号时间")
private Date stopTime;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# 添加获取排班下单信息接口 service-hosp
在service-hosp
模块中添加如下操作
# 添加service接口与实现
在ScheduleService类添加接口
package com.stt.yygh.hosp.service;
...
import com.stt.yygh.vo.hosp.ScheduleOrderVo;
...
public interface ScheduleService {
...
//根据排班id获取预约下单数据
ScheduleOrderVo getScheduleOrderVo(String scheduleId);
}
2
3
4
5
6
7
8
9
添加对应的实现
package com.stt.yygh.hosp.service.impl;
...
@Service
public class ScheduleServiceImpl implements ScheduleService {
...
//根据排班id获取预约下单数据
@Override
public ScheduleOrderVo getScheduleOrderVo(String scheduleId) {
//排班信息
Schedule schedule = this.getById(scheduleId);
if (Objects.isNull(schedule)) {
throw new YyghException(ResultCodeEnum.DATA_ERROR);
}
//获取预约规则信息
Hospital hospital = hospitalService.getByHoscode(schedule.getHoscode());
if (Objects.isNull(hospital) || Objects.isNull(hospital.getBookingRule())) {
throw new YyghException(ResultCodeEnum.DATA_ERROR);
}
return parseScheduleOrderVo(schedule, hospital.getBookingRule());
}
private ScheduleOrderVo parseScheduleOrderVo(Schedule schedule, BookingRule rule) {
ScheduleOrderVo re = new ScheduleOrderVo();
re.setHoscode(schedule.getHoscode());
re.setDepcode(schedule.getDepcode());
re.setHosname(hospitalService.getHospName(schedule.getHoscode()));
re.setDepname(departmentService.getDepName(schedule.getHoscode(), schedule.getDepcode()));
re.setHosScheduleId(schedule.getHosScheduleId());
re.setAvailableNumber(schedule.getAvailableNumber());
re.setTitle(schedule.getTitle());
re.setReserveDate(schedule.getWorkDate());
re.setReserveTime(schedule.getWorkTime());
re.setAmount(schedule.getAmount());
//退号截止天数(如:就诊前一天为-1,当天为0)
re.setQuitTime(this.getDateTime(new DateTime(schedule.getWorkDate()).plusDays(rule.getQuitDay()).toDate(), rule.getQuitTime()).toDate());
//预约开始时间
re.setStartTime(this.getDateTime(new Date(), rule.getReleaseTime()).toDate());
//预约截止时间
re.setEndTime(this.getDateTime(new DateTime().plusDays(rule.getCycle()).toDate(), rule.getStopTime()).toDate());
//当天停止挂号时间
re.setStopTime(this.getDateTime(new Date(), rule.getStopTime()).toDate());
return re;
}
...
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# 添加controller方法
package com.stt.yygh.hosp.controller;
...
import java.util.List;
@Api(tags = "医院管理接口")
@RestController
@RequestMapping("/api/hosp/hospital")
public class HospitalApiController {
...
@Autowired
private ScheduleService scheduleService;
...
@ApiOperation(value = "根据排班id获取预约下单数据")
@GetMapping("inner/getScheduleOrderVo/{scheduleId}")
public ScheduleOrderVo getScheduleOrderVo(@ApiParam(name = "scheduleId", value = "排班id", required = true)
@PathVariable("scheduleId") String scheduleId) {
return scheduleService.getScheduleOrderVo(scheduleId);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 添加签名信息 model
在model
模块中添加com.stt.yygh.vo.hosp.SignInfoVo
类
返回医院设置的部分信息
package com.stt.yygh.vo.hosp;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
@Data
@ApiModel(description = "签名信息")
public class SignInfoVo implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "api基础路径")
private String apiUrl;
@ApiModelProperty(value = "签名秘钥")
private String signKey;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 获取下单签名引用信息接口 service-hosp
获取医院的签名信息,用于调用医院模拟系统时,给传输的数据添加数字签名,以及应该访问哪个医院系统,进行订单的创建
# 添加service接口与实现
在com.stt.yygh.hosp.service.HospitalSetService
类添加接口
package com.stt.yygh.hosp.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.stt.yygh.model.hosp.HospitalSet;
import com.stt.yygh.vo.hosp.SignInfoVo;
public interface HospitalSetService extends IService<HospitalSet> {
...
SignInfoVo getSignInfoVo(String hoscode);
}
2
3
4
5
6
7
8
9
10
对应实现
package com.stt.yygh.hosp.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.stt.yygh.common.exception.YyghException;
import com.stt.yygh.common.result.ResultCodeEnum;
import com.stt.yygh.hosp.mapper.HospitalSetMapper;
import com.stt.yygh.hosp.service.HospitalSetService;
import com.stt.yygh.model.hosp.HospitalSet;
import com.stt.yygh.vo.hosp.SignInfoVo;
import org.springframework.stereotype.Service;
import java.util.Objects;
@Service
public class HospitalSetServiceImpl extends ServiceImpl<HospitalSetMapper, HospitalSet> implements HospitalSetService {
...
//获取医院签名信息
@Override
public SignInfoVo getSignInfoVo(String hoscode) {
QueryWrapper<HospitalSet> wrapper = new QueryWrapper<>();
wrapper.eq("hoscode",hoscode);
HospitalSet hospitalSet = baseMapper.selectOne(wrapper);
if(Objects.isNull(hospitalSet)) {
throw new YyghException(ResultCodeEnum.HOSPITAL_OPEN);
}
SignInfoVo signInfoVo = new SignInfoVo();
signInfoVo.setApiUrl(hospitalSet.getApiUrl());
signInfoVo.setSignKey(hospitalSet.getSignKey());
return signInfoVo;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 添加controller方法
package com.stt.yygh.hosp.controller;
...
@Api(tags = "医院管理接口")
@RestController
@RequestMapping("/api/hosp/hospital")
public class HospitalApiController {
...
@Autowired
private HospitalSetService hospitalSetService;
...
@ApiOperation(value = "获取医院签名信息")
@GetMapping("inner/getSignInfoVo/{hoscode}")
public SignInfoVo getSignInfoVo(@ApiParam(name = "hoscode", value = "医院code", required = true)
@PathVariable("hoscode") String hoscode) {
return hospitalSetService.getSignInfoVo(hoscode);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 搭建service-hosp-client模块
通过feign调用service-hosp模块,获取排班下单信息,调用上面的接口
搭建过程如service-cmn-client模块
# 修改pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>service-client</artifactId>
<groupId>com.stt.yygh</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>service-hosp-client</artifactId>
<packaging>jar</packaging>
<version>1.0</version>
<name>service-hosp-client</name>
<description>service-hosp-client</description>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 添加feign接口类
创建 com.stt.yygh.hosp.client.HospitalFeignClient
类,并添加如下path
package com.stt.yygh.hosp.client;
import com.stt.yygh.vo.hosp.ScheduleOrderVo;
import com.stt.yygh.vo.hosp.SignInfoVo;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(value = "service-hosp")
@Component
public interface HospitalFeignClient {
/**
* 根据排班id获取预约下单数据
*/
@GetMapping("/api/hosp/hospital/inner/getScheduleOrderVo/{scheduleId}")
ScheduleOrderVo getScheduleOrderVo(@PathVariable("scheduleId") String scheduleId);
/**
* 获取医院签名信息
*/
@GetMapping("/api/hosp/hospital/inner/getSignInfoVo/{hoscode}")
SignInfoVo getSignInfoVo(@PathVariable("hoscode") String hoscode);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 实现下单接口 service-order
# 添加feign模块依赖
修改service-order
模块的pom文件,添加如下依赖
<dependencies>
<dependency>
<groupId>com.stt.yygh</groupId>
<artifactId>service-cmn-client</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>com.stt.yygh</groupId>
<artifactId>service-user-client</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>com.stt.yygh</groupId>
<artifactId>service-hosp-client</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 封装下单工具类
在common-util中添加如下工具类,如果之前已经添加可以忽略,该工具类用于给医院模拟系统发送http请求以及signKey的部分操作
package com.stt.yygh.common.helper;
import com.alibaba.fastjson.JSONObject;
import com.stt.yygh.common.utils.HttpUtil;
import com.stt.yygh.common.utils.MD5;
import lombok.extern.slf4j.Slf4j;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
@Slf4j
public class HttpRequestHelper {
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;
}
/**
* 请求数据获取签名
*
* @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();
}
/**
* 封装同步请求
*
* @param paramMap
* @param url
* @return
*/
public static JSONObject sendRequest(Map<String, Object> paramMap, String url) {
String result = "";
try {
//封装post参数
StringBuilder postdata = new StringBuilder();
for (Map.Entry<String, Object> param : paramMap.entrySet()) {
postdata.append(param.getKey()).append("=")
.append(param.getValue()).append("&");
}
log.info(String.format("--> 发送请求:post data %1s", postdata));
byte[] reqData = postdata.toString().getBytes("utf-8");
byte[] respdata = HttpUtil.doPost(url, reqData);
result = new String(respdata);
log.info(String.format("--> 应答结果:result data %1s", result));
} catch (Exception ex) {
ex.printStackTrace();
}
return JSONObject.parseObject(result);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# 实现保存订单方法
通过feign调用就诊人信息,调用排班信息,生成订单信息,发送给远端医院模拟系统,返回订单信息并更新,最后发送一个异步mq消息更新排班和可预约数目,以及发送短信通知就诊人
package com.stt.yygh.order.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.stt.yygh.common.exception.YyghException;
import com.stt.yygh.common.helper.HttpRequestHelper;
import com.stt.yygh.common.result.ResultCodeEnum;
import com.stt.yygh.enums.OrderStatusEnum;
import com.stt.yygh.hosp.client.HospitalFeignClient;
import com.stt.yygh.model.order.OrderInfo;
import com.stt.yygh.model.user.Patient;
import com.stt.yygh.order.mapper.OrderInfoMapper;
import com.stt.yygh.order.service.OrderService;
import com.stt.yygh.user.client.PatientFeignClient;
import com.stt.yygh.vo.hosp.ScheduleOrderVo;
import com.stt.yygh.vo.hosp.SignInfoVo;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
@Service
public class OrderServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderService {
@Autowired
private PatientFeignClient patientFeignClient;
@Autowired
private HospitalFeignClient hospitalFeignClient;
//保存订单
@Override
public Long saveOrder(String scheduleId, Long patientId) {
Patient patient = patientFeignClient.getPatientInfo(patientId);
if (Objects.isNull(patient)) {
throw new YyghException(ResultCodeEnum.DATA_ERROR);
}
OrderInfo order = createAndSaveOrder(scheduleId, patient);
JSONObject resp = accessRemoteHospAndCreateOrder(order, patient);
order.setHosRecordId(resp.getString("hosRecordId")); //预约记录唯一标识(医院预约记录主键)
order.setNumber(resp.getInteger("number")); //预约序号
order.setFetchTime(resp.getString("fetchTime")); //取号时间
order.setFetchAddress(resp.getString("fetchAddress")); //取号地址
baseMapper.updateById(order); //更新订单
//排班可预约数
Integer reservedNumber = resp.getInteger("reservedNumber");
//排班剩余预约数
Integer availableNumber = resp.getInteger("availableNumber");
// todo 发送mq信息更新号源和短信通知
return order.getId();
}
// 访问远端医院模拟系统,并创建订单,返回对应的参数并存储
private JSONObject accessRemoteHospAndCreateOrder(OrderInfo order, Patient patient) {
SignInfoVo signInfo = hospitalFeignClient.getSignInfoVo(order.getHoscode());
if (Objects.isNull(signInfo)) {
throw new YyghException(ResultCodeEnum.DATA_ERROR);
}
Map<String, Object> param = createHospParam(order, patient, signInfo);
JSONObject re = HttpRequestHelper.sendRequest(param, signInfo.getApiUrl() + "/order/submitOrder");
if (re.getInteger("code") != 200) {
throw new YyghException(re.getString("message"), ResultCodeEnum.FAIL.getCode());
}
return re.getJSONObject("data");
}
private OrderInfo createAndSaveOrder(String scheduleId, Patient patient) {
ScheduleOrderVo scheduleOrder = hospitalFeignClient.getScheduleOrderVo(scheduleId);
if (Objects.isNull(scheduleOrder)) {
throw new YyghException(ResultCodeEnum.DATA_ERROR);
}
//当前时间不可以预约
if (new DateTime(scheduleOrder.getStartTime()).isAfterNow() || new DateTime(scheduleOrder.getEndTime()).isBeforeNow()) {
throw new YyghException(ResultCodeEnum.TIME_NO);
}
if (scheduleOrder.getAvailableNumber() <= 0) {
throw new YyghException(ResultCodeEnum.NUMBER_NO);
}
OrderInfo re = new OrderInfo();
BeanUtils.copyProperties(scheduleOrder, re);
// 注意:这里是hosScheduleId字段,需要包含医院的模拟id 以及 mongodb 预约记录的id 合并在一起
re.setScheduleId(scheduleOrder.getHosScheduleId() + "@" + scheduleId);
re.setOutTradeNo(System.currentTimeMillis() + "" + new Random().nextInt(100));
re.setUserId(patient.getUserId());
re.setPatientId(patient.getId());
re.setPatientName(patient.getName());
re.setPatientPhone(patient.getPhone());
re.setOrderStatus(OrderStatusEnum.UNPAID.getStatus());
this.save(re);
return re;
}
// 调用医院模拟系统接口时传递的参数
private Map<String, Object> createHospParam(OrderInfo order, Patient patient, SignInfoVo signInfo) {
Map<String, Object> re = new HashMap<>();
re.put("hoscode", order.getHoscode());
re.put("depcode", order.getDepcode());
re.put("hosScheduleId", order.getScheduleId().split("@")[0]);
re.put("reserveDate", new DateTime(order.getReserveDate()).toString("yyyy-MM-dd"));
re.put("reserveTime", order.getReserveTime());
re.put("amount", order.getAmount());
re.put("name", order.getPatientName());
re.put("certificatesType", patient.getCertificatesType());
re.put("certificatesNo", patient.getCertificatesNo());
re.put("sex", patient.getSex());
re.put("birthdate", patient.getBirthdate());
re.put("phone", patient.getPhone());
re.put("isMarry", patient.getIsMarry());
re.put("provinceCode", patient.getProvinceCode());
re.put("cityCode", patient.getCityCode());
re.put("districtCode", patient.getDistrictCode());
re.put("address", patient.getAddress());
//联系人
re.put("contactsName", patient.getContactsName());
re.put("contactsCertificatesType", patient.getContactsCertificatesType());
re.put("contactsCertificatesNo", patient.getContactsCertificatesNo());
re.put("contactsPhone", patient.getContactsPhone());
re.put("timestamp", HttpRequestHelper.getTimestamp());
re.put("sign", HttpRequestHelper.getSign(re, signInfo.getSignKey()));
return re;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# 预约成功后处理
预约成功后要更新预约数和短信提醒预约成功,为了提高下单的并发性,这部分逻辑交给mq为我们完成,预约成功发送消息即可
提示
使用RabbitMQ作为消息中间件,注意当前使用版本 3.9.11
- name: 快速访问 🚀 RabbitMQ
desc: 使用RabbitMQ作为消息中间件
link: /pages/b0911c/
bgColor: '#DFEEE7'
textColor: '#2A3344'
2
3
4
5
# 创建rabbitmq-util模块
由于后续可能多个模块都会使用mq,把它封装成一个模块,需要的地方直接引用即可
在common模块下搭建,搭建过程如:common-util
# 修改pom
引入rabbitmq消息队列依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>common</artifactId>
<groupId>com.stt.yygh</groupId>
<version>0.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>rabbitmq-util</artifactId>
<version>0.0.1</version>
<packaging>jar</packaging>
<name>rabbitmq-util</name>
<description>rabbitmq-util</description>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--rabbitmq消息队列-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
</dependencies>
</project>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 封装service方法
创建RabbitService
类,添加发送消息的方法
package com.stt.yygh.rabbitmq;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class RabbitService {
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* 发送消息
* @param exchange 交换机
* @param routingKey 路由键
* @param message 消息
*/
public boolean sendMessage(String exchange, String routingKey, Object message) {
rabbitTemplate.convertAndSend(exchange, routingKey, message);
return true;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 配置mq消息转换器
创建MqConfig
类并添加转换bean,将传递的消息转换为json
- 注:默认是字符串转换器
package com.stt.yygh.rabbitmq;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MqConfig {
@Bean
public MessageConverter messageConverter() {
return new Jackson2JsonMessageConverter();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 添加常量配置
用于业务中发送消息使用的常量定义
package com.stt.yygh.rabbitmq;
public class MqConst {
//预约下单
public static final String EXCHANGE_DIRECT_ORDER = "exchange.direct.order";
public static final String ROUTING_ORDER = "order";
//队列
public static final String QUEUE_ORDER = "queue.order";
//短信
public static final String EXCHANGE_DIRECT_MSM = "exchange.direct.msm";
public static final String ROUTING_MSM_ITEM = "msm.item";
//短信队列
public static final String QUEUE_MSM_ITEM = "queue.msm.item";
//定时任务
public static final String EXCHANGE_DIRECT_TASK = "exchange.direct.task";
public static final String ROUTING_TASK_8 = "task.8";
//队列
public static final String QUEUE_TASK_8 = "queue.task.8";
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 封装短信接口 service-msm
在service-msm
中接受mq消息,并发送短信
# 修改pom添加依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>service</artifactId>
<groupId>com.stt.yygh</groupId>
<version>0.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<version>1.0</version>
<artifactId>service-msm</artifactId>
<packaging>jar</packaging>
<name>service-msm</name>
<description>service-msm</description>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>dysmsapi20170525</artifactId>
<version>2.0.8</version>
</dependency>
<dependency>
<groupId>com.stt.yygh</groupId>
<artifactId>rabbitmq-util</artifactId>
<version>0.0.1</version>
</dependency>
</dependencies>
</project>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 添加配置
修改application.properties
添加rabbitmq依赖
#rabbitmq地址
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
2
3
4
5
# 在module中添加短信实体
在module
中新建com.stt.yygh.vo.msm.MsmVo
类,如果已经创建可以忽略
package com.stt.yygh.vo.msm;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Map;
@Data
@ApiModel(description = "短信实体")
public class MsmVo {
@ApiModelProperty(value = "phone")
private String phone;
@ApiModelProperty(value = "短信模板code")
private String templateCode;
@ApiModelProperty(value = "短信模板参数")
private Map<String,Object> param;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 添加service方法与实现
在MsmService
中添加发送消息实体接口
package com.stt.yygh.msm.service;
import com.stt.yygh.vo.msm.MsmVo;
public interface MsmService {
...
boolean send(MsmVo msmVo);
}
2
3
4
5
6
7
8
实现该接口
package com.stt.yygh.msm.service.impl;
...
@Service
public class MsmServiceImpl implements MsmService {
...
// 由于使用的是同一个短信测试模板,实际开发中需要申请不同的短信模板
@Override
public boolean send(MsmVo msmVo) {
if(!StringUtils.isEmpty(msmVo.getPhone())) {
String code = (String)msmVo.getParam().get("code");
return this.send(msmVo.getPhone(),code);
}
return false;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 添加mq监听器
创建 com.stt.yygh.msm.receiver.MsmReceiver
类,监听key为 ROUTING_MSM_ITEM
消息
package com.stt.yygh.msm.receiver;
import com.stt.yygh.msm.service.MsmService;
import com.stt.yygh.rabbitmq.MqConst;
import com.stt.yygh.vo.msm.MsmVo;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class SmsReceiver {
@Autowired
private MsmService msmService;
@RabbitListener(bindings = @QueueBinding(
value = @Queue(value = MqConst.QUEUE_MSM_ITEM, durable = "true"),
exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_MSM),
key = {MqConst.ROUTING_MSM_ITEM}
))
public void send(MsmVo msmVo, Message message, Channel channel) {
msmService.send(msmVo);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 封装更新排班数量 service-hosp
# 修改pom添加依赖
<!--rabbitmq消息队列-->
<dependency>
<groupId>com.stt.yygh</groupId>
<artifactId>rabbitmq-util</artifactId>
<version>0.0.1</version>
</dependency>
2
3
4
5
6
# 添加配置
修改application.properties
添加rabbitmq配置
#rabbitmq地址
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
2
3
4
5
# 在module中添加排班信息实体
创建com.stt.yygh.vo.order.OrderMqVo
类
该对象放一个短信实体,预约下单成功后,发送一条消息,让mq来保证两个消息都发送成功
package com.stt.yygh.vo.order;
import com.stt.yygh.vo.msm.MsmVo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(description = "OrderMqVo")
public class OrderMqVo {
@ApiModelProperty(value = "可预约数")
private Integer reservedNumber;
@ApiModelProperty(value = "剩余预约数")
private Integer availableNumber;
@ApiModelProperty(value = "排班id")
private String scheduleId;
@ApiModelProperty(value = "短信实体")
private MsmVo msmVo;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 添加service方法与实现
在 ScheduleService
类添加接口
package com.stt.yygh.hosp.service;
import com.stt.yygh.model.hosp.Schedule;
import com.stt.yygh.vo.hosp.ScheduleOrderVo;
import com.stt.yygh.vo.hosp.ScheduleQueryVo;
import org.springframework.data.domain.Page;
import java.util.List;
import java.util.Map;
public interface ScheduleService {
...
// 修改排班
void update(Schedule schedule);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
在ScheduleServiceImpl类添加接口实现
package com.stt.yygh.hosp.service.impl;
...
@Service
public class ScheduleServiceImpl implements ScheduleService {
@Autowired
private ScheduleRepository repository;
...
@Override
public void update(Schedule schedule) {
schedule.setUpdateTime(new Date());
//主键一致就是更新
repository.save(schedule);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 添加mq监听器
创建com.stt.yygh.hosp.receiver.HospitalReceiver
类,接受更新排班数量mq,更新成功后发送短信mq给msm服务
package com.stt.yygh.hosp.receiver;
import com.rabbitmq.client.Channel;
import com.stt.yygh.hosp.service.ScheduleService;
import com.stt.yygh.model.hosp.Schedule;
import com.stt.yygh.rabbitmq.MqConst;
import com.stt.yygh.rabbitmq.RabbitService;
import com.stt.yygh.vo.order.OrderMqVo;
import com.stt.yygh.vo.msm.MsmVo;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.Objects;
@Component
public class HospitalReceiver {
@Autowired
private ScheduleService scheduleService;
@Autowired
private RabbitService rabbitService;
@RabbitListener(bindings = @QueueBinding(
value = @Queue(value = MqConst.QUEUE_ORDER, durable = "true"),
exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_ORDER),
key = {MqConst.ROUTING_ORDER}))
public void receiver(OrderMqVo orderMqVo, Message message, Channel channel) throws IOException {
//下单成功更新预约数
Schedule schedule = scheduleService.getById(orderMqVo.getScheduleId());
schedule.setReservedNumber(orderMqVo.getReservedNumber());
schedule.setAvailableNumber(orderMqVo.getAvailableNumber());
scheduleService.update(schedule);
//订单更新成功后发送短信mq
MsmVo msmVo = orderMqVo.getMsmVo();
if (!Objects.isNull(msmVo)) {
rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_MSM, MqConst.ROUTING_MSM_ITEM, msmVo);
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# 调整下单接口 service-order
实现了更新订单以及发送短信的mq接收功能,下面更改原先的下单接口,添加发送消息功能
# 修改pom添加依赖
<!--rabbitmq消息队列-->
<dependency>
<groupId>com.stt.yygh</groupId>
<artifactId>rabbitmq-util</artifactId>
<version>0.0.1</version>
</dependency>
2
3
4
5
6
# 添加配置
修改application.properties
添加rabbitmq配置
#rabbitmq地址
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
2
3
4
5
# 修改下单接口
package com.stt.yygh.order.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.stt.yygh.common.exception.YyghException;
import com.stt.yygh.common.helper.HttpRequestHelper;
import com.stt.yygh.common.result.ResultCodeEnum;
import com.stt.yygh.enums.OrderStatusEnum;
import com.stt.yygh.hosp.client.HospitalFeignClient;
import com.stt.yygh.model.order.OrderInfo;
import com.stt.yygh.model.user.Patient;
import com.stt.yygh.order.mapper.OrderInfoMapper;
import com.stt.yygh.order.service.OrderService;
import com.stt.yygh.rabbitmq.MqConst;
import com.stt.yygh.rabbitmq.RabbitService;
import com.stt.yygh.user.client.PatientFeignClient;
import com.stt.yygh.vo.o.OrderMqVo;
import com.stt.yygh.vo.hosp.ScheduleOrderVo;
import com.stt.yygh.vo.hosp.SignInfoVo;
import com.stt.yygh.vo.msm.MsmVo;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
@Service
public class OrderServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderService {
...
@Autowired
private RabbitService rabbitService;
//保存订单
@Override
@Transactional(rollbackFor = Exception.class)
public Long saveOrder(String scheduleId, Long patientId) {
Patient patient = patientFeignClient.getPatientInfo(patientId);
if (Objects.isNull(patient)) {
throw new YyghException(ResultCodeEnum.DATA_ERROR);
}
OrderInfo order = createAndSaveOrder(scheduleId, patient);
JSONObject resp = accessRemoteHospAndCreateOrder(order, patient);
order.setHosRecordId(resp.getString("hosRecordId")); //预约记录唯一标识(医院预约记录主键)
order.setNumber(resp.getInteger("number")); //预约序号
order.setFetchTime(resp.getString("fetchTime")); //取号时间
order.setFetchAddress(resp.getString("fetchAddress")); //取号地址
baseMapper.updateById(order); //更新订单
//排班可预约数
Integer reservedNumber = resp.getInteger("reservedNumber");
//排班剩余预约数
Integer availableNumber = resp.getInteger("availableNumber");
// 发送更新排班信息并发送短信通知
sendUpdateMq(order, reservedNumber, availableNumber);
return order.getId();
}
//发送mq信息更新号源和短信通知
private void sendUpdateMq(String scheduleId, OrderInfo order, Integer reservedNumber, Integer availableNumber) {
OrderMqVo orderMqVo = new OrderMqVo();
orderMqVo.setScheduleId(order.getScheduleId().split("@")[1]);
orderMqVo.setReservedNumber(reservedNumber);
orderMqVo.setAvailableNumber(availableNumber);
//短信提示
MsmVo msmVo = new MsmVo();
msmVo.setPhone(order.getPatientPhone());
String reserveDate = new DateTime(order.getReserveDate()).toString("yyyy-MM-dd") + (order.getReserveTime() == 0 ? "上午" : "下午");
Map<String, Object> param = new HashMap<String, Object>() {{
put("title", order.getHosname() + "|" + order.getDepname() + "|" + order.getTitle());
put("amount", order.getAmount());
put("reserveDate", reserveDate);
put("name", order.getPatientName());
put("quitTime", new DateTime(order.getQuitTime()).toString("yyyy-MM-dd HH:mm"));
// 注意:由于短信测试模板的原因,只有一个code字段可以被读取,其他参数如果短信模板支持可以添加
// 11111 在测试时表示创建成功
put("code", "11111");
}};
msmVo.setParam(param);
orderMqVo.setMsmVo(msmVo);
rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_ORDER, MqConst.ROUTING_ORDER, orderMqVo);
}
...
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# 前端实现 yygh-site
# 封装api请求
添加/api/order/orderInfo.js文件,定义下单接口
import request from '@/utils/request'
const api_name = `/api/order/orderInfo`
export function submitOrder(scheduleId, patientId) {
return request({
url: `${api_name}/auth/submitOrder/${scheduleId}/${patientId}`,
method: 'post'
})
}
2
3
4
5
6
7
8
9
10
# 修改页面
在/pages/hospital/booking.vue组件完善下单方法
<template>
...
</template>
<script>
...
import { submitOrder } from '@/api/order/orderInfo'
export default {
...
methods: {
...
submitOrder() {
if (this.patient.id == null) return this.$message.error('请选择就诊人')
// 防止重复提交
if (this.submitBnt === '正在提交...') return this.$message.error('重复提交')
this.submitBnt = '正在提交...'
submitOrder(this.scheduleId, this.patient.id).then(res => {
let orderId = res.data
window.location.href = '/order/show?orderId=' + orderId
}).catch(e => {
this.submitBnt = '确认挂号'
})
}
}
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 测试
重新启动service-order,service-hosp,service-user,service-cmn,service-gateway等服务,以及nacos和rabbitmq
注意:需要启动医院模拟系统,本次启用后的端口号是9998,用于接收创建的订单请求
选择医院->选择科室->选择一个预约日期->选择一个医生->进入->点击确认挂号按键
确认完成后,会收到短信,以及在数据库中会有订单记录,以及预约号会减少