生成订单分析
资料:资料>订单微服务>guigu_syt_order.sql
在service模块下创建service-order模块
在service-order中添加依赖:
<dependencies> <!--实体--> <dependency> <groupId>com.atguigu</groupId> <artifactId>model</artifactId> <version>1.0</version> </dependency> <!--服务通用配置--> <dependency> <groupId>com.atguigu</groupId> <artifactId>service-util</artifactId> <version>1.0</version> </dependency> <!--自定义安全模块--> <dependency> <groupId>com.atguigu</groupId> <artifactId>spring-security</artifactId> <version>1.0</version> </dependency> <!--mysql驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!--时间日期工具--> <dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> </dependency> <!-- 单元测试 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
找到service-util模块中的代码生成器,修改moduleName为order
,并执行,然后删除entity包,相关类中引入model模块中的类
在server-order模块中resources目录下创建文件
application.yml
:
spring: application: name: service-order profiles: active: dev,redis
application-dev.yml
:
mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl mapper-locations: classpath:com/atguigu/syt/order/mapper/xml/*.xml server: port: 8205 spring: cloud: nacos: discovery: server-addr: 127.0.0.1:8848 datasource: driver-class-name: com.mysql.cj.jdbc.Driver password: 123456 url: jdbc:mysql://localhost:3306/guigu_syt_order?characterEncoding=utf-8&serverTimezone=GMT%2B8&useSSL=false username: root jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8 logging: level: root: info file: path: order feign: client: config: default: connect-timeout: 2000 #连接建立的超时时长,单位是ms,默认1s read-timeout: 2000 #处理请求的超时时间,单位是ms,默认为1s sentinel: enabled: true #开启Feign对Sentinel的支持
在server-gateway中配置网关路由
- id: service-order predicates: Path=/*/order/** uri: lb://service-order
package com.atguigu.syt.order; @SpringBootApplication @ComponentScan(basePackages = {"com.atguigu"}) @EnableFeignClients("com.atguigu.syt") public class ServiceOrderApplication { public static void main(String[] args) { SpringApplication.run(ServiceOrderApplication.class, args); } }
在service-user模块创建controller.inner包,创建InnerPatientController类
package com.atguigu.syt.user.controller.inner; @Api(tags = "就诊人接口-供其他微服务远程调用") @RestController @RequestMapping("/inner/user/patient") public class InnerPatientController { @Resource private PatientService patientService; @ApiOperation("获取就诊人") @ApiImplicitParam(name = "id",value = "就诊人id", required = true) @GetMapping("/get/{id}") public Patient getPatient(@PathVariable("id") Long id) { return patientService.getById(id); } }
在service-client下创建service-user-client
在service-client
中添加依赖
<dependency> <groupId>com.atguigu</groupId> <artifactId>model</artifactId> <version>1.0</version> </dependency>
在service-user-client中创建接口
package com.atguigu.syt.user.client; @FeignClient( value = "service-user", contextId = "patientFeignClient", fallback = PatientDegradeFeignClient.class) public interface PatientFeignClient { /** * 获取就诊人 * @param id * @return */ @GetMapping("/inner/user/patient/get/{id}") Patient getPatient(@PathVariable Long id); }
降级:
package com.atguigu.syt.user.client.impl; @Component public class PatientDegradeFeignClient implements PatientFeignClient { @Override public Patient getPatient(Long id) { return null; } }
在service-hosp模块创建controller.inner包,创建InnerScheduleController类
package com.atguigu.syt.hosp.controller.inner; @Api(tags = "医院接口-供其他微服务远程调用") @RestController @RequestMapping("/inner/hosp/hospital") public class InnerScheduleController { @Resource private ScheduleService scheduleService; @ApiOperation("根据排班id获取预约下单数据") @ApiImplicitParam(name = "scheduleId",value = "排班id", required = true) @GetMapping("/getScheduleOrderVo/{scheduleId}") public ScheduleOrderVo getScheduleOrderVo(@PathVariable String scheduleId) { return scheduleService.getScheduleOrderVo(scheduleId); } }
接口:ServiceScheduleService
/** * 获取排班相关数据 * @param scheduleId * @return */ ScheduleOrderVo getScheduleOrderVo(String scheduleId);
实现:ScheduleServiceImpl
@Override public ScheduleOrderVo getScheduleOrderVo(String scheduleId) { Schedule schedule = this.getDetailById(scheduleId); String hosname = (String)schedule.getParam().get("hosname"); String depname = (String)schedule.getParam().get("depname"); ScheduleOrderVo scheduleOrderVo = new ScheduleOrderVo(); scheduleOrderVo.setHoscode(schedule.getHoscode()); //医院编号 scheduleOrderVo.setHosname(hosname); //医院名称 scheduleOrderVo.setDepcode(schedule.getDepcode()); //科室编号 scheduleOrderVo.setDepname(depname); //科室名称 scheduleOrderVo.setHosScheduleId(schedule.getHosScheduleId()); //医院端的排班主键 scheduleOrderVo.setAvailableNumber(schedule.getAvailableNumber()); //剩余预约数 scheduleOrderVo.setTitle(hosname + depname + "挂号费"); scheduleOrderVo.setReserveDate(schedule.getWorkDate()); //安排日期 scheduleOrderVo.setReserveTime(schedule.getWorkTime()); //安排时间(0:上午 1:下午) scheduleOrderVo.setAmount(schedule.getAmount());//挂号费用 //获取预约规则相关数据 Hospital hospital = hospitalRepository.findByHoscode(schedule.getHoscode()); BookingRule bookingRule = hospital.getBookingRule(); String quitTime = bookingRule.getQuitTime();//退号时间 //退号实际时间(如:就诊前一天为-1,当天为0) DateTime quitDay = new DateTime(schedule.getWorkDate()).plusDays(bookingRule.getQuitDay());//退号日期 DateTime quitDateTime = this.getDateTime(quitDay, quitTime);//可退号的具体的日期和时间 scheduleOrderVo.setQuitTime(quitDateTime.toDate()); return scheduleOrderVo; }
在service-client下创建service-hosp-client
在service-hosp-client中创建接口
package com.atguigu.syt.hosp.client; @FeignClient( value = "service-hosp", contextId = "scheduleFeignClient", fallback = ScheduleDegradeFeignClient.class ) public interface ScheduleFeignClient { /** * 根据排班id获取预约下单数据 * @param scheduleId * @return */ @GetMapping("/inner/hosp/hospital/getScheduleOrderVo/{scheduleId}") ScheduleOrderVo getScheduleOrderVo(@PathVariable("scheduleId") String scheduleId); }
降级:
package com.atguigu.syt.hosp.client.impl; @Component public class ScheduleDegradeFeignClient implements ScheduleFeignClient { @Override public ScheduleOrderVo getScheduleOrderVo(String scheduleId) { return null; } }
<dependency> <groupId>com.atguigu</groupId> <artifactId>service-user-client</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>com.atguigu</groupId> <artifactId>service-hosp-client</artifactId> <version>1.0</version> </dependency>
在service-order中创建controller.front包,创建FrontOrderInfoController类,定义创建订单接口
package com.atguigu.syt.order.controller.front; @Api(tags = "订单接口") @RestController @RequestMapping("/front/order/orderInfo") public class FrontOrderInfoController { @Resource private OrderInfoService orderInfoService; @Resource private AuthContextHolder authContextHolder; @ApiOperation("创建订单") @ApiImplicitParams({ @ApiImplicitParam(name = "scheduleId",value = "排班id", required = true), @ApiImplicitParam(name = "patientId",value = "就诊人id", required = true)}) @PostMapping("/auth/submitOrder/{scheduleId}/{patientId}") public Result<Long> submitOrder(@PathVariable String scheduleId, @PathVariable Long patientId, HttpServletRequest request, HttpServletResponse response) { authContextHolder.checkAuth(request, response); Long orderId = orderInfoService.submitOrder(scheduleId, patientId); return Result.ok(orderId); } }
接口:OrderInfoService
/** * 根据排班id和就诊人id创建订单 * @param scheduleId * @param patientId * @return 新订单id */ Long submitOrder(String scheduleId, Long patientId);
实现:OrderInfoServiceImpl
@Resource private PatientFeignClient patientFeignClient; @Resource private ScheduleFeignClient scheduleFeignClient; @Override public Long submitOrder(String scheduleId, Long patientId) { //就诊人数据:远程获取就诊人数据(openfeign) Patient patient = patientFeignClient.getPatient(patientId); if(patient == null) { throw new GuiguException(ResultCodeEnum.PARAM_ERROR); } //获取医院排班相关数据 ScheduleOrderVo scheduleOrderVo = scheduleFeignClient.getScheduleOrderVo(scheduleId); if(scheduleOrderVo == null) { throw new GuiguException(ResultCodeEnum.PARAM_ERROR); } //SignInfoVo signInfoVo = hospitalFeignClient.getSignInfoVo(scheduleOrderVo.getHoscode()); SignInfoVo signInfoVo = new SignInfoVo(); signInfoVo.setSignKey("8af52af00baf6aec434109fc17164aae"); signInfoVo.setApiUrl("http://localhost:9998"); if(signInfoVo == null) { throw new GuiguException(ResultCodeEnum.PARAM_ERROR); } if(scheduleOrderVo.getAvailableNumber() <= 0) { throw new GuiguException(ResultCodeEnum.NUMBER_NO); } //创建订单对象 OrderInfo orderInfo = new OrderInfo(); //基本信息 String outTradeNo = UUID.randomUUID().toString().replace("-", ""); orderInfo.setOutTradeNo(outTradeNo); //订单号 orderInfo.setOrderStatus(OrderStatusEnum.UNPAID.getStatus());//未支付 //就诊人数据 orderInfo.setPatientId(patientId); orderInfo.setPatientPhone(patient.getPhone()); orderInfo.setPatientName(patient.getName()); orderInfo.setUserId(patient.getUserId()); //医院排班相关数据 orderInfo.setScheduleId(scheduleId); BeanUtils.copyProperties(scheduleOrderVo, orderInfo);//拷贝相关属性 //step4:调用医院端接口获取相关数据 Map<String, Object> paramsMap = new HashMap<>(); paramsMap.put("hoscode", scheduleOrderVo.getHoscode()); paramsMap.put("depcode", scheduleOrderVo.getDepcode()); paramsMap.put("hosScheduleId", scheduleOrderVo.getHosScheduleId()); paramsMap.put( "reserveDate", new DateTime(scheduleOrderVo.getReserveDate()).toString("yyyy-MM-dd") ); paramsMap.put("reserveTime", scheduleOrderVo.getReserveTime()); paramsMap.put("amount", scheduleOrderVo.getAmount()); paramsMap.put("name", patient.getName()); paramsMap.put("certificatesType", patient.getCertificatesType()); paramsMap.put("certificatesNo", patient.getCertificatesNo()); paramsMap.put("sex", patient.getSex()); paramsMap.put("birthdate", patient.getBirthdate()); paramsMap.put("phone", patient.getPhone()); paramsMap.put("isMarry", patient.getIsMarry()); paramsMap.put("timestamp", HttpRequestHelper.getTimestamp()); paramsMap.put("sign", HttpRequestHelper.getSign(paramsMap, signInfoVo.getSignKey()));//标准签名 JSONObject jsonResult = HttpRequestHelper.sendRequest( paramsMap, signInfoVo.getApiUrl() + "/order/submitOrder" ); log.info("结果:" + jsonResult.toJSONString()); if(jsonResult.getInteger("code") != 200){//失败 log.error("预约失败," + "code:" + jsonResult.getInteger("code") + ",message:" + jsonResult.getString("message") ); throw new GuiguException(ResultCodeEnum.FAIL.getCode(), jsonResult.getString("message")); } JSONObject data = jsonResult.getJSONObject("data"); String hosOrderId = data.getString("hosOrderId"); Integer number = data.getInteger("number"); String fetchTime = data.getString("fetchTime"); String fetchAddress = data.getString("fetchAddress"); orderInfo.setHosOrderId(hosOrderId); orderInfo.setNumber(number); orderInfo.setFetchTime(fetchTime); orderInfo.setFetchAddress(fetchAddress); baseMapper.insert(orderInfo); //使用这两个数据更新平台端的最新的排班数量 Integer reservedNumber = data.getInteger("reservedNumber"); Integer availableNumber = data.getInteger("availableNumber"); //目的1:更新mongodb数据库中的排班数量 //TODO 中间件:MQ 异步解耦 //目的2:给就诊人发短信 TODO:MQ return orderInfo.getId(); //返回订单id }
创建api/orderInfo.js
import request from '@/utils/request' export default { //生成订单 submitOrder(scheduleId, patientId) { return request({ url: `/front/order/orderInfo/auth/submitOrder/${scheduleId}/${patientId}`, method: 'post' }) } }
在booking.vue组件中完善下单方法
<div class="v-button" @click="submitOrder()">{{orderText}}</div>
定义data
orderBtnDisabled: false, //防止重复提交 orderText: '确认挂号'
引入api
import orderInfoApi from '~/api/orderInfo'
完善方法
//确认挂号 submitOrder() { if (this.orderBtnDisabled) return this.orderBtnDisabled = true this.orderText = '预约挂号中...' orderInfoApi .submitOrder(this.scheduleId, this.patient.id) .then((response) => { window.location.href = '/order/show?orderId=' + response.data }) },
在FrontOrderInfoController中添加方法
@ApiOperation("根据订单id查询订单详情") @ApiImplicitParam(name = "orderId",value = "订单id", required = true) @GetMapping("/auth/getOrder/{orderId}") public Result<OrderInfo> getOrder(@PathVariable Long orderId, HttpServletRequest request, HttpServletResponse response) { authContextHolder.checkAuth(request, response); OrderInfo orderInfo = orderInfoService.getOrderInfo(orderId); return Result.ok(orderInfo); }
接口:OrderInfoService
/** * 根据订单id获取订单详情 * @param orderId * @return */ OrderInfo getOrderInfo(Long orderId);
实现:OrderInfoServiceImpl
@Override public OrderInfo getOrderInfo(Long orderId) { OrderInfo orderInfo = baseMapper.selectById(orderId); return this.packOrderInfo(orderInfo); }
辅助方法
/** * 封装订单数据 * @param orderInfo * @return */ private OrderInfo packOrderInfo(OrderInfo orderInfo) { orderInfo.getParam().put( "orderStatusString", OrderStatusEnum.getStatusNameByStatus(orderInfo.getOrderStatus()) ); return orderInfo; }
在orderInfo.js添加方法
//订单详情 getOrder(orderId) { return request({ url: `/front/order/orderInfo/auth/getOrder/${orderId}`, method: `get` }) },
资料:资料>订单微服务>order
pages/order/show.vue组件
在FrontOrderInfoController中添加方法
@ApiOperation("订单列表") @GetMapping("/auth/list") public Result<List<OrderInfo>> list(HttpServletRequest request, HttpServletResponse response) { Long userId = authContextHolder.checkAuth(request, response); List<OrderInfo> orderInfolist = orderInfoService.selectList(userId); return Result.ok(orderInfolist); }
接口:OrderInfoService
/** * 获取当前用户订单列表 * @param userId * @return */ List<OrderInfo> selectList(Long userId);
实现:OrderInfoServiceImpl
@Override public List<OrderInfo> selectList(Long userId) { LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(OrderInfo::getUserId, userId); List<OrderInfo> orderInfoList = baseMapper.selectList(queryWrapper); orderInfoList.stream().forEach(this::packOrderInfo); return orderInfoList; }
在orderInfo.js添加方法
//订单列表 getList() { return request({ url: `/front/order/orderInfo/auth/list`, method: `get` }) },
资料:资料>订单微服务>order
pages/order/index.vue组件
源码:https://gitee.com/dengyaojava/guigu-syt-parent