一、预约下单
1 需求分析
1.1 订单表结构
1.2 下单分析
参考《尚医通API接口文档.docx》业务接口5.1预约下单
下单参数:就诊人id与排班id
- 下单我们要获取就诊人信息
- 获取排班下单信息与规则信息
- 获取医院签名信息,然后通过接口去医院预约下单
- 下单成功更新排班信息与发送短信
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 //保存订单 @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接口
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 获取下单引用签名信息接口
5.2.1 添加service接口与实现
1、在HospitalSetService类添加接口
_//获取医院签名信息_SignInfoVo getSignInfoVo(String hoscode); |
---|
2、在HospitalSetServiceImpl类添加实现
//获取医院签名信息@Overridepublic SignInfoVo getSignInfoVo(String hoscode) { 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 实现下单接口
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
Map
for (Map.Entry
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(**"|"**);<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
@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 /> || **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
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 封装短信接口
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 } |
---|
说明:已统一引入
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 封装更新排班数量
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 调整下单接口
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 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 |
---|
2、在OrderInfoServiceImpl类添加接口实现
//订单列表(条件查询带分页)@Overridepublic IPage //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 if(!StringUtils._isEmpty 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.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 IPage 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组件
type=”date” placeholder=”选择开始日期” value-format=”yyyy-MM-dd” /> type=”date” placeholder=”选择截止日期” value-format=”yyyy-MM-dd” /> type=”date” placeholder=”就诊日期” value-format=”yyyy-MM-dd” /> :key=”item.status” :label=”item.comment” :value=”item.status”> :data=”list” border fit highlight-current-row> width=”60” align=”center”> {{ (page - 1) * limit + scope.$index + 1 }} {{ scope.row.reserveDate }} {{ scope.row.reserveTime === 0 ? ‘上午’ : ‘下午’ }} :total=”total” :page-size=”limit” :page-sizes=”[5, 10, 20, 30, 40, 50, 100]” style=”padding: 30px 0; text-align: center;” layout=”sizes, prev, pager, next, jumper, ->, total, slot” @current-change=”fetchData” @size-change=”changeSize” /> |
---|
11 订单详情
2.1 api接口
2.1.1 添加service接口及实现类
1、在OrderInfoService类添加接口
/* 订单详情 * @param __orderId* @return_*/_Map |
---|
2、在OrderInfoServiceImpl类添加接口实现
@Overridepublic Map Map 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组件
订单信息
就诊人信息
|
||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|