[TOC]

一、预约下单

1 需求分析

1.1 订单表结构

预约下单 - 图1

1.2 下单分析

参考《尚医通API接口文档.docx》业务接口5.1预约下单
下单参数:就诊人id与排班id

  1. 下单我们要获取就诊人信息
  2. 获取排班下单信息与规则信息
  3. 获取医院签名信息,然后通过接口去医院预约下单
  4. 下单成功更新排班信息与发送短信

    2、搭建service-order模块

    2.1 搭建service-order模块

    搭建过程参考service-user模块

    2.2 修改配置

    1、修改pom.xml,引入依赖
<dependencies>
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>service_cmn_client</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>

2、添加配置文件application.properties

# 服务端口server.port=8206# 服务名spring.application.name=service-order# 环境设置:dev、test、prodspring.profiles.active=dev
# mysql数据库连接spring.datasource.driver-class-name=com.mysql.jdbc.Driverspring.datasource.url=jdbc:mysql://192.168.44.165:3306/yygh_hosp?characterEncoding=utf-8&useSSL=falsespring.datasource.username=rootspring.datasource.password=root123
#返回json的全局时间格式spring.jackson.date-format=yyyy-MM-dd HH:mm:ssspring.jackson.time-zone=GMT+8
spring.data.mongodb.uri
=mongodb://192.168.44.165:27017/yygh_hosp
# nacos服务地址spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
#rabbitmq地址spring.rabbitmq.host=192.168.44.165spring.rabbitmq.port=5672spring.rabbitmq.username=guestspring.rabbitmq.password=guest

2.3 启动类

@SpringBootApplication
@ComponentScan(basePackages = {“com.atguigu”})@EnableDiscoveryClient
@EnableFeignClients(basePackages = {“com.atguigu”})public class ServiceOrderApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceOrderApplication.class, args);
}
}

2.4配置网关

#设置路由idspring.cloud.gateway.routes[6].id=service-order#设置路由的urispring.cloud.gateway.routes[6].uri=lb://service-order#设置路由断言,代理servicerId为auth-service的/auth/路径spring.cloud.gateway.routes[6].predicates= Path=//order/*

3、添加订单基础类

3.1 添加model

说明:由于实体对象没有逻辑,我们已经统一导入
com.atguigu.yygh.model.order.OrderInfo

3.2 添加Mapper

添加com.atguigu.yygh.order.mapper.OrderInfoMapper

public interface OrderInfoMapper extends BaseMapper {
}

3.3 添加service接口及实现类

1、添加com.atguigu.yygh.order.service.OrderService接口

public interface OrderService extends IService {
_//保存订单
_Long saveOrder(String scheduleId, Long patientId);
}

2、添加com.atguigu.yygh.order.service.impl.OrderServiceImpl接口实现

@Servicepublic class OrderServiceImpl extends
ServiceImpl implements OrderService {
//保存订单
@Override
public Long saveOrder(String scheduleId, Long patientId) {
return null;
}
}

3.4 添加controller

添加com.atguigu.yygh.order.api.OrderApiController类

| @Api(tags = “订单接口”)@RestController
@RequestMapping(“/api/order/orderInfo”)public class OrderApiController {

@Autowired<br />    **private **OrderService **orderService**;

@ApiOperation(value = **"创建订单"**)<br />    @PostMapping(**"auth/submitOrder/{scheduleId}/{patientId}"**)<br />    **public **Result submitOrder(<br />            @ApiParam(name = **"scheduleId"**, value = **"排班id"**, required = **true**)<br />            @PathVariable String scheduleId,<br />            @ApiParam(name = **"patientId"**, value = **"就诊人id"**, required = **true**)<br />            @PathVariable Long patientId) {<br />        **return **Result._ok_(**orderService**.saveOrder(scheduleId, patientId));<br />    }<br />} |

| —- |

2 封装Feign调用获取就诊人接口

4.1 获取就诊人信息api接口

操作模块:service-user
在PatientApiController类添加方法

@ApiOperation(value = “获取就诊人”)@GetMapping(“inner/get/{id}”)public Patient getPatientOrder(
@ApiParam(name = “id”, value = “就诊人id”, required = true)
@PathVariable(“id”) Long id) {
return patientService.getById(id);
}

4.2 搭建service-user-client模块

4.2.1 搭建service-user-client模块

搭建过程如service-cmn-client模块

4.2.2添加Feign接口类

@FeignClient(value = “service-user”)@Repositorypublic interface PatientFeignClient {
//获取就诊人
@GetMapping(“/api/user/patient/inner/get/{id}”)
Patient getPatient(@PathVariable(“id”) Long id);
}

3 封装Feign调用获取排班下单信息接口

5.1 获取排班下单信息api接口

操作模块:service-hosp

5.1.1 添加service接口与实现

1、在ScheduleService类添加接口

_//根据排班id获取预约下单数据_ScheduleOrderVo getScheduleOrderVo(String scheduleId);

2、在ScheduleServiceImpl类添加实现

| //根据排班id获取预约下单数据@Overridepublic ScheduleOrderVo getScheduleOrderVo(String scheduleId) {
ScheduleOrderVo scheduleOrderVo = new ScheduleOrderVo();
//排班信息
_Schedule schedule = baseMapper.selectById(scheduleId);
if(null == schedule) {
throw new YyghException(ResultCodeEnum.**_PARAM_ERROR
**);
}

_//获取预约规则信息<br />    _Hospital hospital = **hospitalService**.getByHoscode(schedule.getHoscode());<br />    **if**(**null **== hospital) {<br />        **throw new **YyghException(ResultCodeEnum.**_DATA_ERROR_**);<br />    }<br />    BookingRule bookingRule = hospital.getBookingRule();<br />    **if**(**null **== bookingRule) {<br />        **throw new **YyghException(ResultCodeEnum.**_PARAM_ERROR_**);<br />    }

scheduleOrderVo.setHoscode(schedule.getHoscode());<br />    scheduleOrderVo.setHosname(**hospitalService**.getHospName(schedule.getHoscode()));<br />    scheduleOrderVo.setDepcode(schedule.getDepcode());<br />    scheduleOrderVo.setDepname(**departmentService**.getDepName(schedule.getHoscode(), schedule.getDepcode()));<br />    scheduleOrderVo.setHosScheduleId(schedule.getHosScheduleId());<br />    scheduleOrderVo.setAvailableNumber(schedule.getAvailableNumber());<br />    scheduleOrderVo.setTitle(schedule.getTitle());<br />    scheduleOrderVo.setReserveDate(schedule.getWorkDate());<br />    scheduleOrderVo.setReserveTime(schedule.getWorkTime());<br />    scheduleOrderVo.setAmount(schedule.getAmount());

_//退号截止天数(如:就诊前一天为-1,当天为0)<br />    _**int **quitDay = bookingRule.getQuitDay();<br />    DateTime quitTime = **this**.getDateTime(**new **DateTime(schedule.getWorkDate()).plusDays(quitDay).toDate(), bookingRule.getQuitTime());<br />    scheduleOrderVo.setQuitTime(quitTime.toDate());

_//预约开始时间<br />    _DateTime startTime = **this**.getDateTime(**new **Date(), bookingRule.getReleaseTime());<br />    scheduleOrderVo.setStartTime(startTime.toDate());

_//预约截止时间<br />    _DateTime endTime = **this**.getDateTime(**new **DateTime().plusDays(bookingRule.getCycle()).toDate(), bookingRule.getStopTime());<br />    scheduleOrderVo.setEndTime(endTime.toDate());

_//当天停止挂号时间<br />    _DateTime stopTime = **this**.getDateTime(**new **Date(), bookingRule.getStopTime());<br />    scheduleOrderVo.setStartTime(startTime.toDate());<br />    **return **scheduleOrderVo;<br />} |

| —- |

5.1.2 添加controller方法

在HospitalApiController类添加方法

@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);
}

5.2 获取下单引用签名信息接口

操作模块:service-hosp

5.2.1 添加service接口与实现

1、在HospitalSetService类添加接口

_//获取医院签名信息_SignInfoVo getSignInfoVo(String hoscode);

2、在HospitalSetServiceImpl类添加实现

//获取医院签名信息@Overridepublic SignInfoVo getSignInfoVo(String hoscode) {
QueryWrapper wrapper = new QueryWrapper<>();
wrapper.eq(“hoscode”,hoscode);
HospitalSet hospitalSet = baseMapper.selectOne(wrapper);
if(null == hospitalSet) {
throw new YyghException(ResultCodeEnum.HOSPITAL_OPEN);
}
SignInfoVo signInfoVo = new SignInfoVo();
signInfoVo.setApiUrl(hospitalSet.getApiUrl());
signInfoVo.setSignKey(hospitalSet.getSignKey());
return signInfoVo;
}

5.2.2 添加controller方法

在HospitalApiController类添加方法

@ApiOperation(value = “获取医院签名信息”)@GetMapping(“inner/getSignInfoVo/{hoscode}”)public SignInfoVo getSignInfoVo(
@ApiParam(name = “hoscode”, value = “医院code”, required = true)
@PathVariable(“hoscode”) String hoscode) {
return hospitalSetService.getSignInfoVo(hoscode);
}

5.3 搭建service-hosp-client模块

5.3.1 搭建service-hosp-client模块

搭建过程如service-cmn-client模块

5.3.2添加Feign接口类

@FeignClient(value = “service-hosp”)@Repositorypublic 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);
}

4 实现下单接口

操作模块:service-order

6.1 引入依赖

| <dependencies>
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>service_cmn_client</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>

<**dependency**><br />        <**groupId**>com.atguigu</**groupId**><br />        <**artifactId**>service_hosp_client</**artifactId**><br />        <**version**>0.0.1-SNAPSHOT</**version**><br />    </**dependency**>

<**dependency**><br />        <**groupId**>com.atguigu</**groupId**><br />        <**artifactId**>service_user_client</**artifactId**><br />        <**version**>0.0.1-SNAPSHOT</**version**><br />    </**dependency**><br /></**dependencies**> |

| —- |

6.2 封装下单工具类

封装HttpRequestHelper类,添加签名请求方法

| public class HttpRequestHelper {
/*

*
@param paramMap
* @return
__
*/
public static Map switchMap(Map paramMap) {
Map resultMap = new HashMap<>();
for (Map.Entry param : paramMap.entrySet()) {
resultMap.put(param.getKey(), param.getValue()[0]);
}
return resultMap;
}

_/**<br />     * 请求数据获取签名<br />     * _**_@param __paramMap<br />__     _**_* _**_@param __signKey<br />__     _**_* _**_@return<br />__     _**_*/<br />    _**public static **String getSign(Map<String, Object> paramMap, String signKey) {<br />        **if**(paramMap.containsKey(**"sign"**)) {<br />            paramMap.remove(**"sign"**);<br />        }<br />        TreeMap<String, Object> sorted = **new **TreeMap<>(paramMap);<br />        StringBuilder str = **new **StringBuilder();<br />        **for **(Map.Entry<String, Object> param : sorted.entrySet()) {<br />            str.append(param.getValue()).append(**"&#124;"**);<br />        }<br />        str.append(signKey);<br />        **_log_**.info(**"加密前:" **+ str.toString());<br />        String md5Str = MD5._encrypt_(str.toString());<br />        **_log_**.info(**"加密后:" **+ md5Str);<br />        **return **md5Str;<br />    }

_/**<br />     * 签名校验<br />     * _**_@param __paramMap<br />__     _**_* _**_@param __signKey<br />__     _**_* _**_@return<br />__     _**_*/<br />    _**public static boolean **isSignEquals(Map<String, Object> paramMap, String signKey) {<br />        String sign = (String)paramMap.get(**"sign"**);<br />        String md5Str = _getSign_(paramMap, signKey);<br />        **if**(!sign.equals(md5Str)) {<br />            **return false**;<br />        }<br />        **return true**;<br />    }

_/**<br />     * 获取时间戳<br />     * _**_@return<br />__     _**_*/<br />    _**public static long **getTimestamp() {<br />        **return new **Date().getTime();<br />    }

_/**<br />     * 封装同步请求_**_     _**_*/<br />    _**public static **JSONObject sendRequest(Map<String, Object> paramMap, String url){<br />        String result = **""**;<br />        **try **{<br />            _//封装post参数<br />            _StringBuilder postdata = **new **StringBuilder();<br />            **for **(Map.Entry<String, Object> param : paramMap.entrySet()) {<br />                postdata.append(param.getKey()).append(**"="**)<br />                        .append(param.getValue()).append(**"&"**);<br />            }<br />            **_log_**.info(String._format_(**"--> 发送请求:post data %1s"**, postdata));<br />            **byte**[] reqData = postdata.toString().getBytes(**"utf-8"**);<br />            **byte**[] respdata = HttpUtil._doPost_(url,reqData);<br />            result = **new **String(respdata);<br />            **_log_**.info(String._format_(**"--> 应答结果:result data %1s"**, result));<br />        } **catch **(Exception ex) {<br />            ex.printStackTrace();<br />        }<br />        **return **JSONObject._parseObject_(result);<br />    }<br />} |

| —- |

6.3 实现下单接口

修改OrderServiceImpl类下单方法

| @Servicepublic class OrderServiceImpl extends
ServiceImpl implements OrderService {

@Autowired<br />    **private **PatientFeignClient **patientFeignClient**;<br />    @Autowired<br />    **private **HospitalFeignClient **hospitalFeignClient**;

_//保存订单<br />    _@Override<br />    **public **Long saveOrder(String scheduleId, Long patientId) {<br />        Patient patient = **patientFeignClient**.getPatient(patientId);<br />        **if**(**null **== patient) {<br />            **throw new **YyghException(ResultCodeEnum.**_PARAM_ERROR_**);<br />        }<br />        ScheduleOrderVo scheduleOrderVo = **hospitalFeignClient**.getScheduleOrderVo(scheduleId);<br />        **if**(**null **== scheduleOrderVo) {<br />            **throw new **YyghException(ResultCodeEnum.**_PARAM_ERROR_**);<br />        }<br />        _//当前时间不可以预约<br />        _**if**(**new **DateTime(scheduleOrderVo.getStartTime()).isAfterNow()<br />                &#124;&#124; **new **DateTime(scheduleOrderVo.getEndTime()).isBeforeNow()) {<br />            **throw new **YyghException(ResultCodeEnum.**_TIME_NO_**);<br />        }<br />        SignInfoVo signInfoVo = **hospitalFeignClient**.getSignInfoVo(scheduleOrderVo.getHoscode());<br />        **if**(**null **== scheduleOrderVo) {<br />            **throw new **YyghException(ResultCodeEnum.**_PARAM_ERROR_**);<br />        }<br />        **if**(scheduleOrderVo.getAvailableNumber() <= 0) {<br />            **throw new **YyghException(ResultCodeEnum.**_NUMBER_NO_**);<br />        }<br />        OrderInfo orderInfo = **new **OrderInfo();<br />        BeanUtils._copyProperties_(scheduleOrderVo, orderInfo);<br />        String outTradeNo = System._currentTimeMillis_() + **""**+ **new **Random().nextInt(100);<br />        orderInfo.setOutTradeNo(outTradeNo);<br />        orderInfo.setScheduleId(scheduleId);<br />        orderInfo.setUserId(patient.getUserId());<br />        orderInfo.setPatientId(patientId);<br />        orderInfo.setPatientName(patient.getName());<br />        orderInfo.setPatientPhone(patient.getPhone());<br />        orderInfo.setOrderStatus(OrderStatusEnum.**_UNPAID_**.getStatus());<br />        **this**.save(orderInfo);

    Map<String, Object> paramMap = **new **HashMap<>();<br />        paramMap.put(**"hoscode"**,orderInfo.getHoscode());<br />        paramMap.put(**"depcode"**,orderInfo.getDepcode());<br />        paramMap.put(**"hosScheduleId"**,orderInfo.getScheduleId());<br />        paramMap.put(**"reserveDate"**,**new **DateTime(orderInfo.getReserveDate()).toString(**"yyyy-MM-dd"**));<br />        paramMap.put(**"reserveTime"**, orderInfo.getReserveTime());<br />        paramMap.put(**"amount"**,orderInfo.getAmount());<br />        paramMap.put(**"name"**, patient.getName());<br />        paramMap.put(**"certificatesType"**,patient.getCertificatesType());<br />        paramMap.put(**"certificatesNo"**, patient.getCertificatesNo());<br />        paramMap.put(**"sex"**,patient.getSex());<br />        paramMap.put(**"birthdate"**, patient.getBirthdate());<br />        paramMap.put(**"phone"**,patient.getPhone());<br />        paramMap.put(**"isMarry"**, patient.getIsMarry());<br />        paramMap.put(**"provinceCode"**,patient.getProvinceCode());<br />        paramMap.put(**"cityCode"**, patient.getCityCode());<br />        paramMap.put(**"districtCode"**,patient.getDistrictCode());<br />        paramMap.put(**"address"**,patient.getAddress());<br />        _//联系人<br />        _paramMap.put(**"contactsName"**,patient.getContactsName());<br />        paramMap.put(**"contactsCertificatesType"**, patient.getContactsCertificatesType());<br />        paramMap.put(**"contactsCertificatesNo"**,patient.getContactsCertificatesNo());<br />        paramMap.put(**"contactsPhone"**,patient.getContactsPhone());<br />        paramMap.put(**"timestamp"**, HttpRequestHelper._getTimestamp_());<br />        String sign = HttpRequestHelper._getSign_(paramMap, signInfoVo.getSignKey());<br />        paramMap.put(**"sign"**, sign);<br />        JSONObject result = HttpRequestHelper._sendRequest_(paramMap, signInfoVo.getApiUrl()+**"/order/submitOrder"**);<br />        <br />        **if**(result.getInteger(**"code"**) == 200) {<br />            JSONObject jsonObject = result.getJSONObject(**"data"**);<br />            _//预约记录唯一标识(医院预约记录主键)<br />            _String hosRecordId = jsonObject.getString(**"hosRecordId"**);<br />            _//预约序号<br />            _Integer number = jsonObject.getInteger(**"number"**);;<br />            _//取号时间<br />            _String fetchTime = jsonObject.getString(**"fetchTime"**);;<br />            _//取号地址<br />            _String fetchAddress = jsonObject.getString(**"fetchAddress"**);;<br />            _//更新订单<br />            _orderInfo.setHosRecordId(hosRecordId);<br />            orderInfo.setNumber(number);<br />            orderInfo.setFetchTime(fetchTime);<br />            orderInfo.setFetchAddress(fetchAddress);<br />            **baseMapper**.updateById(orderInfo);<br />            _//排班可预约数<br />            _Integer reservedNumber = jsonObject.getInteger(**"reservedNumber"**);<br />            _//排班剩余预约数<br />            _Integer availableNumber = jsonObject.getInteger(**"availableNumber"**);<br />            _//发送mq信息更新号源和短信通知<br />        _} **else **{<br />            **throw new **YyghException(result.getString(**"message"**), ResultCodeEnum.**_FAIL_**.getCode());<br />        }<br />        **return **orderInfo.getId();<br />    }<br />} |

| —- |

5 预约成功后处理逻辑

预约成功后我们要更新预约数和短信提醒预约成功,为了提高下单的并发性,这部分逻辑我们就交给mq为我们完成,预约成功发送消息即可
(1)RabbitMQ简介
以商品订单场景为例,
如果商品服务和订单服务是两个不同的微服务,在下单的过程中订单服务需要调用商品服务进行扣库存操作。按照传统的方式,下单过程要等到调用完毕之后才能返回下单成功,如果网络产生波动等原因使得商品服务扣库存延迟或者失败,会带来较差的用户体验,如果在高并发的场景下,这样的处理显然是不合适的,那怎么进行优化呢?这就需要消息队列登场了。
消息队列提供一个异步通信机制,消息的发送者不必一直等待到消息被成功处理才返回,而是立即返回。消息中间件负责处理网络通信,如果网络连接不可用,消息被暂存于队列当中,当网络畅通的时候在将消息转发给相应的应用程序或者服务,当然前提是这些服务订阅了该队列。如果在商品服务和订单服务之间使用消息中间件,既可以提高并发量,又降低服务之间的耦合度。
RabbitMQ就是这样一款消息队列。RabbitMQ是一个开源的消息代理的队列服务器,用来通过普通协议在完全不同的应用之间共享数据。
(2)典型应用场景:
异步处理。把消息放入消息中间件中,等到需要的时候再去处理。
流量削峰。例如秒杀活动,在短时间内访问量急剧增加,使用消息队列,当消息队列满了就拒绝响应,跳转到错误页面,这样就可以使得系统不会因为超负载而崩溃。
日志处理
应用解耦
(2)安装RabbitMQ

docker pull rabbitmq:management
docker run -d -p 5672:5672 -p 15672:15672 —name rabbitmq rabbitmq:management

管理后台http://IP:15672
预约下单 - 图2
预约下单 - 图3

7.1 rabbit-util模块封装

由于后续可能多个模块都会使用mq,所以我们把它封装成一个模块,需要的地方直接引用即可

7.1.1 搭建rabbit-util模块

在common模块下搭建,搭建过程如:common-util

7.1.2 修改pom.xml

<dependencies>

<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>

7.1.3 封装service方法

@Servicepublic 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;
}
}

7.1.4 配置mq消息转换器

@Configurationpublic class MQConfig {
@Bean
public MessageConverter messageConverter(){
return new Jackson2JsonMessageConverter();
}
}

说明:默认是字符串转换器

7.2 封装短信接口

操作模块:service-msm

7.2.1 引入依赖

<dependency>
<groupId>com.atguigu</groupId>
<artifactId>rabbit_util</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>

7.2.2 添加配置

在resources/application.properties添加

#rabbitmq地址spring.rabbitmq.host=192.168.44.165spring.rabbitmq.port=5672spring.rabbitmq.username=guestspring.rabbitmq.password=guest

7.2.3 添加常量配置

在rabbit-util模块com.atguigu.yygh.common.constant.MqConst类添加

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”;
}

7.2.4 在model模块封装短信实体

@Data
@ApiModel(description = “短信实体”)public class MsmVo {
@ApiModelProperty(value = “phone”)
private String phone;
@ApiModelProperty(value = “短信模板code”)
private String templateCode;
@ApiModelProperty(value = “短信模板参数”)
private Map param;
}

说明:已统一引入

7.2.5 封装service接口

1、在MsmService类添加接口

boolean send(MsmVo msmVo);

2、在MsmServiceImpl类添加接口实现

@Overridepublic boolean send(MsmVo msmVo) {
if(!StringUtils.isEmpty(msmVo.getPhone())) {
String code = (String)msmVo.getParam().get(“code”);
return this.send(msmVo.getPhone(),code);
}
return false;
}

7.2.6 封装mq监听器

@Componentpublic 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);
}
}

7.3 封装更新排班数量

操作模块:service-hosp

7.3.1 引入依赖

<dependency>
<groupId>com.atguigu.yygh</groupId>
<artifactId>rabbit-util</artifactId>
<version>1.0</version>
</dependency>

7.3.2 添加配置

在resources/application.properties添加

#rabbitmq地址spring.rabbitmq.host=192.168.44.165spring.rabbitmq.port=5672spring.rabbitmq.username=guestspring.rabbitmq.password=guest

7.3.3 添加常量配置

在rabbit-util模块com.atguigu.yygh.common.constant.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”;

7.3.4 在model模块封装更新排班实体

| @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;
} | | —- |

说明:已统一引入,该对象放一个短信实体,预约下单成功后,我们发送一条消息,让mq来保证两个消息都发送成功

7.3.5 封装service接口

1、在ScheduleService类添加接口

/*
修改排班
*/void **update(Schedule schedule);

2、在ScheduleServiceImpl类添加接口实现

@Overridepublic void update(Schedule schedule) {
schedule.setUpdateTime(new Date());
//主键一致就是更新
scheduleRepository.save(schedule);
}

7.3.6 封装mq监听器

| @Componentpublic class HospitalReceiver {

@Autowired<br />    **private **ScheduleService **scheduleService**;

@Autowired<br />    **private **RabbitService **rabbitService**;

@RabbitListener(bindings = @QueueBinding(<br />            value = @Queue(value = MqConst.**_QUEUE_ORDER_**, durable = **"true"**),<br />            exchange = @Exchange(value = MqConst.**_EXCHANGE_DIRECT_ORDER_**),<br />            key = {MqConst.**_ROUTING_ORDER_**}<br />    ))<br />    **public void **receiver(OrderMqVo orderMqVo, Message message, Channel channel) **throws **IOException {<br />        _//下单成功更新预约数<br />        _Schedule schedule = **scheduleService**.getScheduleId(orderMqVo.getScheduleId());<br />        schedule.setReservedNumber(orderMqVo.getReservedNumber());<br />        schedule.setAvailableNumber(orderMqVo.getAvailableNumber());<br />        **scheduleService**.update(schedule);<br />        _//发送短信<br />        _MsmVo msmVo = orderMqVo.getMsmVo();<br />        **if**(**null **!= msmVo) {<br />            **rabbitService**.sendMessage(MqConst.**_EXCHANGE_DIRECT_MSM_**, MqConst.**_ROUTING_MSM_ITEM_**, msmVo);<br />        }<br />    }<br />} |

| —- |

7.4 调整下单接口

操作模块:service-order

7.4.1 引入依赖

<dependency>
<groupId>com.atguigu</groupId>
<artifactId>rabbit_util</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>

7.4.2 添加配置

在resources/application.properties添加

#rabbitmq地址spring.rabbitmq.host=192.168.44.165spring.rabbitmq.port=5672spring.rabbitmq.username=guestspring.rabbitmq.password=guest

7.4.3 修改下单接口

修改OrderServiceImpl类下单方法

@Autowiredprivate RabbitService rabbitService;
@Transactional(rollbackFor = Exception.class)@Overridepublic Long saveOrder(String scheduleId, Long patientId) {
…….
//排班可预约数
_Integer reservedNumber = jsonObject.getInteger(“reservedNumber”);
//排班剩余预约数
_Integer availableNumber = jsonObject.getInteger(“availableNumber”);
//发送mq信息更新号源和短信通知
//发送mq信息更新号源
OrderMqVo orderMqVo = new OrderMqVo();
orderMqVo.setScheduleId(scheduleId);
orderMqVo.setReservedNumber(reservedNumber);
orderMqVo.setAvailableNumber(availableNumber);

//短信提示
MsmVo msmVo = new MsmVo();
msmVo.setPhone(orderInfo.getPatientPhone());
msmVo.setTemplateCode(“SMS_194640721”);
String reserveDate =
new DateTime(orderInfo.getReserveDate()).toString(“yyyy-MM-dd”)
+ (orderInfo.getReserveTime()==0 ? “上午”: “下午”);
Map param = new HashMap(){{
put(“title”, orderInfo.getHosname()+”|”+orderInfo.getDepname()+”|”+orderInfo.getTitle());
put(“amount”, orderInfo.getAmount());
put(“reserveDate”, reserveDate);
put(“name”, orderInfo.getPatientName());
put(“quitTime”, new DateTime(orderInfo.getQuitTime()).toString(“yyyy-MM-dd HH:mm”));
}};
msmVo.setParam(param);
    orderMqVo.setMsmVo(msmVo);<br />        rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_ORDER, MqConst.ROUTING_ORDER, orderMqVo);**    } **else **{<br />        **throw new **YyghException(result.getString(**"message"**), ResultCodeEnum.**_FAIL_**.getCode());<br />    }<br />    **return **orderInfo.getId();<br />} |

6 订单管理

7 订单列表

7.1 api接口

1.1.1 添加service接口及实现类

1、在OrderInfoService类添加接口

/*
分页列表
*_/_IPage selectPage(Page pageParam, OrderQueryVo orderQueryVo);

2、在OrderInfoServiceImpl类添加接口实现

//订单列表(条件查询带分页)@Overridepublic IPage selectPage(Page pageParam, OrderQueryVo orderQueryVo) {
//orderQueryVo获取条件值
_String name = orderQueryVo.getKeyword();
//医院名称
Long patientId = orderQueryVo.getPatientId(); //就诊人名称
String orderStatus = orderQueryVo.getOrderStatus(); //订单状态
String reserveDate = orderQueryVo.getReserveDate();//安排时间
String createTimeBegin = orderQueryVo.getCreateTimeBegin();
String createTimeEnd = orderQueryVo.getCreateTimeEnd();
//对条件值进行非空判断
QueryWrapper wrapper = new QueryWrapper<>();
if(!StringUtils._isEmpty
(name)) {
wrapper.like(“hosname”,name);
}
if(!StringUtils.isEmpty(patientId)) {
wrapper.eq(“patient_id”,patientId);
}
if(!StringUtils.isEmpty(orderStatus)) {
wrapper.eq(“order_status”,orderStatus);
}
if(!StringUtils.isEmpty(reserveDate)) {
wrapper.ge(“reserve_date”,reserveDate);
}
if(!StringUtils.isEmpty(createTimeBegin)) {
wrapper.ge(“create_time”,createTimeBegin);
}
if(!StringUtils.isEmpty(createTimeEnd)) {
wrapper.le(“create_time”,createTimeEnd);
}
//调用mapper的方法
_IPage pages = baseMapper.selectPage(pageParam, wrapper);
//编号变成对应值封装
pages.getRecords().stream().forEach(item -> {
this.packOrderInfo(item);
});
return pages;
}private OrderInfo packOrderInfo(OrderInfo orderInfo) {
orderInfo.getParam().put(“orderStatusString”, OrderStatusEnum._getStatusNameByStatus
(orderInfo.getOrderStatus()));
return orderInfo;
}

1.1.2 添加controller

在OrderApiController类添加方法

//订单列表(条件查询带分页)@GetMapping(“auth/{page}/{limit}”)public Result list(@PathVariable Long page,
@PathVariable Long limit,
OrderQueryVo orderQueryVo, HttpServletRequest request) {
//设置当前用户id
_orderQueryVo.setUserId(AuthContextHolder._getUserId
(request));
Page pageParam = new Page<>(page,limit);
IPage pageModel =
orderService.selectPage(pageParam,orderQueryVo);
return Result.ok(pageModel);
}
@ApiOperation(value = “获取订单状态”)@GetMapping(“auth/getStatusList”)public Result getStatusList() {
return Result.ok(OrderStatusEnum.getStatusList());
}

说明:订单状态我们是封装到枚举中的,页面搜索需要一个下拉列表展示,所以我们通过接口返回页面

7.2 前端

1.2.1封装api请求

在/api/orderInfo.js添加方法

//订单列表
getPageList(page, limit, searchObj) {
return request({
url: ${api_name}/auth/${page}/${limit},
method: get,
params: searchObj
})
},
//订单状态
getStatusList() {
return request({
url: ${api_name}/auth/getStatusList,
method: ‘get’
})
},

1.2.2 页面展示

创建/pages/order/index.vue组件


8 订单详情

2.1 api接口

2.1.1 添加service接口及实现类

1、在OrderInfoService类添加接口

/*
获取订单详情
*_/_OrderInfo getOrderInfo(Long id);

2、在OrderInfoServiceImpl类添加接口实现

//根据订单id查询订单详情@Overridepublic OrderInfo getOrder(String orderId) {
OrderInfo orderInfo = baseMapper.selectById(orderId);
return this.packOrderInfo(orderInfo);
}

2.1.2 添加controller

在OrderApiController类添加方法

//根据订单id查询订单详情@GetMapping(“auth/getOrders/{orderId}”)public Result getOrders(@PathVariable String orderId) {
OrderInfo orderInfo = orderService.getOrder(orderId);
return Result.ok(orderInfo);
}

2.2前端

2.2.1封装api请求

在/api/order/orderInfo.js添加方法

//订单详情
getOrders(orderId) {
return request({
url: ${api_name}/auth/getOrders/${orderId},
method: get
})
},

2.2.2 页面展示

创建/pages/order/show.vue组件



9 平台订单管理

10 订单列表

10.1 api接口

10.1.1 添加controller方法

添加com.atguigu.yygh.order.controller.OrderController类

| @Api(tags = “订单接口”)@RestController
@RequestMapping(“/admin/order/orderInfo”)public class OrderController {

@Autowired<br />    **private **OrderService **orderService**;

@ApiOperation(value = **"获取分页列表"**)<br />    @GetMapping(**"{page}/{limit}"**)<br />    **public **Result index(<br />            @ApiParam(name = **"page"**, value = **"当前页码"**, required = **true**)<br />            @PathVariable Long page,<br />            @ApiParam(name = **"limit"**, value = **"每页记录数"**, required = **true**)<br />            @PathVariable Long limit,<br />            @ApiParam(name = **"orderCountQueryVo"**, value = **"查询对象"**, required = **false**) OrderQueryVo orderQueryVo) {<br />        Page<OrderInfo> pageParam = **new **Page<>(page, limit);<br />        IPage<OrderInfo> pageModel = **orderService**.selectPage(pageParam, orderQueryVo);<br />        **return **Result._ok_(pageModel);<br />    }

@ApiOperation(value = **"获取订单状态"**)<br />    @GetMapping(**"getStatusList"**)<br />    **public **Result getStatusList() {<br />        **return **Result._ok_(OrderStatusEnum._getStatusList_());<br />    }<br />} |

| —- |

1.2前端

1.2.1添加路由

在 src/router/index.js 文件添加路由

{
path: ‘/order’,
component: Layout,
redirect: ‘/order/orderInfo/list’,
name: ‘BasesInfo’,
meta: { title: ‘订单管理’, icon: ‘table’ },
alwaysShow: true,
children: [
{
path: ‘orderInfo/list’,
name: ‘订单列表’,
component: () =>import(‘@/views/order/orderInfo/list’),
meta: { title: ‘订单列表’ }
}
]
}

1.2.2封装api请求

添加/api/order/orderInfo.js文件

import request from ‘@/utils/request’
const api_name = ‘/admin/order/orderInfo’
export default {
getPageList(page, limit, searchObj) {
return request({
url: ${api_name}/${page}/${limit},
method: ‘get’,
params: searchObj
})
},
getStatusList() {
return request({
url: ${api_name}/getStatusList,
method: ‘get’
})
}
}

1.2.3 添加组件

创建/views/order/orderInfo/list.vue组件


11 订单详情

2.1 api接口

2.1.1 添加service接口及实现类

1、在OrderInfoService类添加接口

/*
订单详情
*
@param __orderId* @return_*/_Map show(Long orderId);

2、在OrderInfoServiceImpl类添加接口实现

@Overridepublic Map show(Long orderId) {
Map map = new HashMap<>();
OrderInfo orderInfo = this.packOrderInfo(this.getById(orderId));
map.put(“orderInfo”, orderInfo);
Patient patient
= patientFeignClient.getPatient(orderInfo.getPatientId());
map.put(“patient”, patient); return map;
}

2.1.2 添加controller

在OrderController类添加方法

@ApiOperation(value = “获取订单”)@GetMapping(“show/{id}”)public Result get(@ApiParam(name = “orderId”, value = “订单id”, required = true)@PathVariable Long id) { return Result.ok(orderService.show(id));
}

2.2前端

2.2.1添加路由

在 src/router/index.js 文件添加路由

{
path: ‘/order’,
component: Layout,
redirect: ‘/order/orderInfo/list’,
name: ‘BasesInfo’,
meta: { title: ‘订单管理’, icon: ‘table’ },
alwaysShow: true,
children: [
{
path: ‘orderInfo/list’,
name: ‘订单列表’,
component: () =>import(‘@/views/order/orderInfo/list’),
meta: { title: ‘订单列表’ }
},
{
path: ‘orderInfo/show/:id’,
name: ‘查看’,
component: () =>import(‘@/views/order/orderInfo/show’),
meta: { title: ‘查看’, noCache: true },
hidden: true
}
]
}

2.2.2封装api请求

在/api/order/orderInfo.js文件添加方法

getById(id) {
return request({
url: ${api_name}/show/${id},
method: ‘get’
})
}

2.2.3 修改列表组件

修改/views/order/orderInfo/list.vue组件

<el-table-column label=”操作”width=”100”align=”center”><template slot-scope=”scope”>
<router-link :to=”‘/order/orderInfo/show/‘+scope.row.id”>
<el-button type=”primary” size=”mini” icon=”el-icon-edit”>查看</el-button>
</router-link>
</template>
</el-table-column>

2.2.4 添加组件

创建/views/order/orderInfo/show.vue组件