• 9.java项目-尚医通(9)


    前端代码:https://github.com/wyj41/yygh_html.git
    后端代码:https://github.com/wyj41/yygh_parent.git

    1.预约挂号详情

    需求分析
    1、接口分析
    (1)根据预约周期,展示可预约日期数据,按分页展示
    (2)选择日期展示当天可预约列表(该接口后台已经实现过)

    2、页面展示分析
    (1)分页展示可预约日期,根据有号、无号、约满等状态展示不同颜色,以示区分
    (2)可预约最后一个日期为即将放号日期,根据放号时间页面展示倒计时

    1.1 api接口

    操作模块service_hosp

    1.1.1 添加service接口

    在ScheduleService类添加接口

    //获取可预约排班数据
    Map<String,Object> getBookingScheduleRule(Integer page, Integer limit, String hoscode, String depcode);
    
    • 1
    • 2

    在ScheduleServiceImpl类实现接口

    //获取可预约排班数据
    @Override
    public Map<String,Object> getBookingScheduleRule(Integer page, Integer limit, String hoscode, String depcode) {
        Map<String,Object> result = new HashMap<>();
        //获取预约规则
        //根据医院编号获取预约规则
        Hospital hospital = hospitalService.getByHoscode(hoscode);
        if(hospital == null){
            throw new YyghException(ResultCodeEnum.DATA_ERROR);
        }
        BookingRule bookingRule = hospital.getBookingRule();
    
        //获取可预约日期的数据(分页)
        IPage iPage = this.getListDate(page,limit,bookingRule);
        //当前可预约日期
        List<Date> dateList = iPage.getRecords();
    
        //获取可预约日期里面科室的剩余预约数
        Criteria criteria = Criteria.where("hoscode").is(hoscode).and("depcode").is(depcode)
                .and("workDate").in(dateList);
        Aggregation agg = Aggregation.newAggregation(
                Aggregation.match(criteria),
                Aggregation.group("workDate").first("workDate").as("workDate")
                        .count().as("docCount")
                        .sum("availableNumber").as("availableNumber")
                        .sum("reservedNumber").as("reservedNumber")
        );
        AggregationResults<BookingScheduleRuleVo> aggregateResult =
                mongoTemplate.aggregate(agg, Schedule.class, BookingScheduleRuleVo.class);
        List<BookingScheduleRuleVo> scheduleVoList = aggregateResult.getMappedResults();
        //合并数据 map集合 key日期 value预约规则和剩余数量等
        Map<Date, BookingScheduleRuleVo> scheduleVoMap = new HashMap<>();
        if(!CollectionUtils.isEmpty(scheduleVoList)) {
            scheduleVoMap = scheduleVoList.stream()
                    .collect(Collectors.toMap(BookingScheduleRuleVo::getWorkDate, BookingScheduleRuleVo -> BookingScheduleRuleVo));
        }
    
        //获取可预约排班规则
        List<BookingScheduleRuleVo> bookingScheduleRuleVoList = new ArrayList<>();
        for(int i = 0,len = dateList.size();i < len;i++){
            Date date = dateList.get(i);
            //从map集合根据key日期获取value值
            BookingScheduleRuleVo bookingScheduleRuleVo = scheduleVoMap.get(date);
            //如果当天没有排班医生
            if(bookingScheduleRuleVo == null){
                bookingScheduleRuleVo = new BookingScheduleRuleVo();
                //就诊医生人数
                bookingScheduleRuleVo.setDocCount(0);
                //科室剩余预约数 -1表示无号
                bookingScheduleRuleVo.setAvailableNumber(-1);
            }
            bookingScheduleRuleVo.setWorkDate(date);
            bookingScheduleRuleVo.setWorkDateMd(date);
            //计算当前预约日期对应星期
            String dayOfWeek = this.getDayOfWeek(new DateTime(date));
            bookingScheduleRuleVo.setDayOfWeek(dayOfWeek);
    
            //最后一页最后一条记录为即将预约 状态0:正常 1:即将放号 -1:当天已停止挂号
            if(i == len-1 && page == iPage.getPages()){
                bookingScheduleRuleVo.setStatus(1);
            }else {
                bookingScheduleRuleVo.setStatus(0);
            }
            //当天预约如果过了停号时间,不能预约
            if(i == 0 && page == 1){
                DateTime stopTime = this.getDateTime(new Date(),bookingRule.getStopTime());
                if(stopTime.isBeforeNow()){
                    //停止预约
                    bookingScheduleRuleVo.setStatus(-1);
                }
            }
            bookingScheduleRuleVoList.add(bookingScheduleRuleVo);
        }
        //可预约日期规则数据
        result.put("bookingScheduleList", bookingScheduleRuleVoList);
        result.put("total", iPage.getTotal());
        //其他基础数据
        Map<String, String> baseMap = new HashMap<>();
        //医院名称
        baseMap.put("hosname", hospitalService.getByHoscode(hoscode).getHosname());
        //科室
        Department department =departmentService.getDepartment(hoscode, depcode);
        //大科室名称
        baseMap.put("bigname", department.getBigname());
        //科室名称
        baseMap.put("depname", department.getDepname());
        //月
        baseMap.put("workDateString", new DateTime().toString("yyyy年MM月"));
        //放号时间
        baseMap.put("releaseTime", bookingRule.getReleaseTime());
        //停号时间
        baseMap.put("stopTime", bookingRule.getStopTime());
        result.put("baseMap", baseMap);
        return result;
    
    }
    
    //获取可预约日志分页数据
    private IPage getListDate(Integer page, Integer limit, BookingRule bookingRule) {
        //获取当天放号时间 年 月 日 时 分
        DateTime releaseTime = this.getDateTime(new Date(), bookingRule.getReleaseTime());
        //获取预约周期
        Integer cycle = bookingRule.getCycle();
        //如果当天放号时间已经过去,预约周期从后一天开始计算,周期+1
        if(releaseTime.isBeforeNow()){
            cycle += 1;
        }
        //获取可预约所有日期,最后一天显示即将放号
        List<Date> dateList = new ArrayList<>();
        for(int i = 0;i < cycle;i++){
            DateTime curDateTime = new DateTime().plusDays(i);
            String dateString = curDateTime.toString("yyyy-MM-dd");
            dateList.add(new DateTime(dateString).toDate());
        }
        //因为预约周期不同,每页显示日期最多7天数据,超过7天分页
        List<Date> pageDateList = new ArrayList<>();
        int start = (page-1) * limit;
        int end = page * limit;
        //如果可以显式数据小于7,直接显示
        if(end > dateList.size()){
            end = dateList.size();
        }
        for(int i = start;i < end;i++){
            pageDateList.add(dateList.get(i));
        }
        //如果可以显式数据大于7,进行分页
        IPage<Date> iPage = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(page,7,dateList.size());
        iPage.setRecords(pageDateList);
        return iPage;
    }
    
    /**
     * 将Date日期(yyyy-MM-dd HH:mm)转换为DateTime
     */
    private DateTime getDateTime(Date date, String timeString) {
        String dateTimeString = new DateTime(date).toString("yyyy-MM-dd") + " "+ timeString;
        DateTime dateTime = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm").parseDateTime(dateTimeString);
        return dateTime;
    }
    
    • 1
    • 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
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139

    1.1.2 获取科室信息

    在DepartmentService类添加接口

    //根据科室编号和医院编号,查询科室
    Department getDepartment(String hoscode, String depcode);
    
    • 1
    • 2

    在DepartmentImpl类实现接口

    //根据科室编号和医院编号,查询科室
    @Override
    public Department getDepartment(String hoscode, String depcode) {
        return departmentRepository.getDepartmentByHoscodeAndDepcode(hoscode,depcode);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    1.1.3 添加controller方法

    在HospApiController类添加方法

    @Autowired
    private ScheduleService scheduleService;
    
    //获取可预约排班数据
    @ApiOperation(value = "获取可预约排班数据")
    @GetMapping("auth/getBookingScheduleRule/{page}/{limit}/{hoscode}/{depcode}")
    public Result getBookingSchedule(
            @ApiParam(name = "page", value = "当前页码", required = true)
            @PathVariable Integer page,
            @ApiParam(name = "limit", value = "每页记录数", required = true)
            @PathVariable Integer limit,
            @ApiParam(name = "hoscode", value = "医院code", required = true)
            @PathVariable String hoscode,
            @ApiParam(name = "depcode", value = "科室code", required = true)
            @PathVariable String depcode) {
        return Result.ok(scheduleService.getBookingScheduleRule(page, limit, hoscode, depcode));
    }
    
    //获取排班的具体数据
    @ApiOperation(value = "获取排班数据")
    @GetMapping("auth/findScheduleList/{hoscode}/{depcode}/{workDate}")
    public Result findScheduleList(
            @ApiParam(name = "hoscode", value = "医院code", required = true)
            @PathVariable String hoscode,
            @ApiParam(name = "depcode", value = "科室code", required = true)
            @PathVariable String depcode,
            @ApiParam(name = "workDate", value = "排班日期", required = true)
            @PathVariable String workDate) {
        return Result.ok(scheduleService.getDetailSchedule(hoscode, depcode, workDate));
    }
    
    • 1
    • 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

    1.2 前端

    操作:yygh_site

    1.2.1 封装api请求

    在/api/hosp.js添加方法

    //获取可预约信息(分页)
    getBookingScheduleRule(page, limit, hoscode, depcode) {
        return request({
          url: `${api_name}/auth/getBookingScheduleRule/${page}/${limit}/${hoscode}/${depcode}`,
          method: 'get'
        })
    },
    //获取排班信息
    findScheduleList(hoscode, depcode, workDate) {
        return request({
          url: `${api_name}/auth/findScheduleList/${hoscode}/${depcode}/${workDate}`,
          method: 'get'
        })
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    1.2.2 页面展示

    修改路由跳转
    修改/page/hosp/_hoscode.vue第155行

     window.location.href = '/hosp/schedule?hoscode=' + this.hospital.hoscode + "&depcode="+ depcode
    
    • 1

    创建/pages/hosp/schedule.vue组件

    
    
    
    • 1
    • 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
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302

    测试
    http://localhost:3000/hosp/schedule?hoscode=1000_0&depcode=200040878

    问题:没有当前时间的排班数据
    解决方案:添加部分数据
    1.修改workDate为你当前时间及后面几天的时间
    2.启动hospital-manage项目
    访问:http://localhost:9998/
    在排班列表中将下面修改好的排班信息添加

    [
    {"hoscode":"1000_0","depcode":"200040878","title":"医师","docname":"邵迎红","skill":"内分泌科常见病。","workDate":"2022-08-04","workTime":0,"reservedNumber":33,"availableNumber":22,"amount":"100","status":1,"hosScheduleId":"115"},
    {"hoscode":"1000_0","depcode":"200040878","title":"副主任医师","docname":"裴育","skill":"骨质疏松和骨代谢疾病、糖尿病、甲状腺疾病。","workDate":"2022-08-04","workTime":0,"reservedNumber":40,"availableNumber":6,"amount":"100","status":1,"hosScheduleId":"116"},
    {"hoscode":"1000_0","depcode":"200040878","title":"副主任医师","docname":"邵迎红","skill":"内分泌与代谢性疾病。","workDate":"2022-08-04","workTime":1,"reservedNumber":27,"availableNumber":10,"amount":"100","status":1,"hosScheduleId":"117"},
    {"hoscode":"1000_0","depcode":"200040878","title":"医师","docname":"邵迎红","skill":"内分泌科常见病。","workDate":"2022-08-05","workTime":0,"reservedNumber":33,"availableNumber":22,"amount":"100","status":1,"hosScheduleId":"118"},
    {"hoscode":"1000_0","depcode":"200040878","title":"副主任医师","docname":"裴育","skill":"骨质疏松和骨代谢疾病、糖尿病、甲状腺疾病。","workDate":"2022-08-05","workTime":0,"reservedNumber":40,"availableNumber":6,"amount":"100","status":1,"hosScheduleId":"118"},
    {"hoscode":"1000_0","depcode":"200040878","title":"副主任医师","docname":"邵迎红","skill":"内分泌与代谢性疾病。","workDate":"2022-08-05","workTime":1,"reservedNumber":27,"availableNumber":10,"amount":"100","status":1,"hosScheduleId":"120"},
    {"hoscode":"1000_0","depcode":"200040878","title":"医师","docname":"邵迎红","skill":"内分泌科常见病。","workDate":"2022-08-06","workTime":0,"reservedNumber":33,"availableNumber":22,"amount":"100","status":1,"hosScheduleId":"115"},
    {"hoscode":"1000_0","depcode":"200040878","title":"副主任医师","docname":"裴育","skill":"骨质疏松和骨代谢疾病、糖尿病、甲状腺疾病。","workDate":"2022-08-06","workTime":0,"reservedNumber":40,"availableNumber":6,"amount":"100","status":1,"hosScheduleId":"121"},
    {"hoscode":"1000_0","depcode":"200040878","title":"副主任医师","docname":"邵迎红","skill":"内分泌与代谢性疾病。","workDate":"2022-08-06","workTime":1,"reservedNumber":27,"availableNumber":10,"amount":"100","status":1,"hosScheduleId":"122"},
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2.预约确认

    1、根据排班id获取排班信息,在页面展示
    2、选择就诊人
    3、预约下单

    2.1 api接口

    操作模块:service_hosp

    2.1.1 添加service接口

    在ScheduleService类添加接口

    //根据排班id获取排班数据
    Schedule getScheduleById(String scheduleId);
    
    • 1
    • 2

    在ScheduleServiceImpl类添加实现

    //根据排班id获取排班数据
    @Override
    public Schedule getScheduleById(String scheduleId) {
        Schedule schedule = scheduleRepository.findById(scheduleId).get();
        this.packageSchedule(schedule);
        return schedule;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2.1.2 添加controller方法

    在HospApiController类添加方法

    @ApiOperation(value = "根据排班id获取排班数据")
    @GetMapping("getSchedule/{scheduleId}")
    public Result getSchedule(@PathVariable String scheduleId){
            Schedule schedule = scheduleService.getScheduleById(scheduleId);
        return Result.ok(schedule);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.2 前端

    操作模块:yygh-site

    1.在/api/hosp.js添加方法

    //根据排班id获取排班信息
    getScheduleById(id) {
        return request({
          url: `${api_name}/getSchedule/${id}`,
          method: 'get'
        })
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2.修改路由跳转路径
    修改/pages/hosp/schedule.vue的第297行

    window.location.href = '/hosp/booking?scheduleId=' + scheduleId
    
    • 1

    3.创建/pages/hospital/booking.vue组件

    
    
    
    
    
    • 1
    • 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
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237

    4.测试
    选择一个有号的,有剩余号的点击,查看是否显示信息

    3.预约下单

    需求分析
    参考《尚医通API接口文档.docx》业务接口5.1预约下单
    下单参数:就诊人id与排班id
    1、下单我们要获取就诊人信息
    2、获取排班下单信息与规则信息
    3、获取医院签名信息,然后通过接口去医院预约下单
    4、下单成功更新排班信息与发送短信

    3.1 的搭建service_order模块

    在service模块下创建service_order子模块

    3.1.1 修改配置

    修改pom.xml,引入依赖

    <dependencies>
        <dependency>
            <groupId>com.myprojectgroupId>
            <artifactId>service_cmn_clientartifactId>
            <version>1.0version>
        dependency>
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    添加配置文件application.yml

    server:
      port: 8206
    spring:
      application:
        name: service-order
      profiles:
        active: dev
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://192.168.50.224:3306/yygh_order?characterEncoding=utf-8&useSSL=false
        username: root
        password: 123456
    
      jackson:
        date-format: yyyy-MM-dd HH:mm:ss
        time-zone: GMT+8
      data:
        mongodb:
          uri: mongodb://192.168.50.224:27017/yygh_hosp
      cloud:
        nacos:
          server-addr: 127.0.0.1:8848
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    3.1.2 启动类

    com.myproject.yygh.order.ServiceOrderApplication

    package com.myproject.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
    @ComponentScan(basePackages = {"com.myproject"})
    @EnableDiscoveryClient
    @EnableFeignClients(basePackages = {"com.myproject"})
    public class ServiceOrderApplication {
        public static void main(String[] args) {
            SpringApplication.run(ServiceOrderApplication.class, args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    3.1.3 配置网关

    - id: service-order
      uri: lb://service-order
      predicates:
        - name: Path
          args:
            - /*/order/**
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.2 添加订单基础类

    1.添加model
    说明:由于实体对象没有逻辑,我们已经统一导入
    model模块中的com.myproject.yygh.model.order.OrderInfo

    2.添加Mapper
    com.myproject.yygh.order.mapper.OrderMapper

    package com.myproject.yygh.order.mapper;
    
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import com.myproject.yygh.model.order.OrderInfo;
    import org.apache.ibatis.annotations.Mapper;
    
    @Mapper
    public interface OrderMapper extends BaseMapper<OrderInfo> {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3.添加service接口及实现类
    添加com.myproject.yygh.order.service.OrderService接口

    package com.myproject.yygh.order.service;
    
    import com.baomidou.mybatisplus.extension.service.IService;
    import com.myproject.yygh.model.order.OrderInfo;
    
    public interface OrderService extends IService<OrderInfo> {
        //生成挂号订单
        Long saveOrder(String scheduleId, Long patientId);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    添加com.myproject.yygh.order.service.impl.OrderServiceImpl实现类

    package com.myproject.yygh.order.service.impl;
    
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import com.myproject.yygh.model.order.OrderInfo;
    import com.myproject.yygh.order.mapper.OrderMapper;
    import com.myproject.yygh.order.service.OrderService;
    import org.springframework.stereotype.Service;
    
    @Service
    public class OrderServiceImpl extends ServiceImpl<OrderMapper, OrderInfo> implements OrderService {
        //生成挂号订单
        @Override
        public Long saveOrder(String scheduleId, Long patientId) {
            return null;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    4.添加controller
    com.myproject.yygh.order.api.OrderApiController

    package com.myproject.yygh.order.api;
    
    import com.myproject.yygh.common.result.Result;
    import com.myproject.yygh.order.service.OrderService;
    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;
    
    @RestController
    @RequestMapping("/api/order/orderInfo")
    public class OrderApiController {
        @Autowired
        private OrderService orderService;
    
        //生成挂号订单
        @PostMapping("auth/submitOrder/{scheduleId}/{patientId}")
        public Result saveOrder(@PathVariable String scheduleId,
                                @PathVariable Long patientId){
            Long orderId = orderService.saveOrder(scheduleId,patientId);
            return Result.ok(orderId);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

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

    3.3.1 获取就诊人信息api接口

    操作模块:service_user

    在PatientApiController类添加方法

    //根据就诊人id获取就诊人信息
    @GetMapping("inner/get/{id}")
    public Patient getPatientOrder(@PathVariable Long id){
        Patient patient = patientService.getPatientById(id);
        return patient;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.3.2 搭建service_user_client模块

    在service_client模块下创建service-user_client子模块

    1.添加依赖
    在pom.xml中添加

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-openfeign-coreartifactId>
        dependency>
        <dependency>
            <groupId>com.myprojectgroupId>
            <artifactId>modelartifactId>
            <version>1.0version>
            <scope>compilescope>
        dependency>
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2.添加Feign接口类

    package com.myproject.yygh.user.client;
    
    import com.myproject.yygh.model.user.Patient;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.stereotype.Repository;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    
    @FeignClient(value = "service-user")
    @Repository
    public interface PatientFeignClient {
        //获取就诊人信息
        @GetMapping("/api/user/patient/inner/get/{id}")
        public Patient getPatientOrder(@PathVariable("id") Long id);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

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

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

    操作模块:service-hosp

    1.添加service接口与实现
    在ScheduleService类添加接口

    //根据排班id获取预约下单数据
    ScheduleOrderVo getScheduleOrderVo(String scheduleId);
    
    • 1
    • 2

    在ScheduleServiceImpl类添加实现

    //根据排班id获取预约下单数据
    @Override
    public ScheduleOrderVo getScheduleOrderVo(String scheduleId) {
        ScheduleOrderVo scheduleOrderVo = new ScheduleOrderVo();
        //获取排班信息
        Schedule schedule = scheduleRepository.findById(scheduleId).get();
        if(schedule == null){
            throw new YyghException(ResultCodeEnum.PARAM_ERROR);
        }
        //获取预约规则信息
        Hospital hospital = hospitalService.getByHoscode(schedule.getHoscode());
        if(hospital == null){
            throw new YyghException(ResultCodeEnum.PARAM_ERROR);
        }
        BookingRule bookingRule = hospital.getBookingRule();
        if(bookingRule == null){
            throw new YyghException(ResultCodeEnum.PARAM_ERROR);
        }
        //把获取数据设置到scheduleOrderVo中
        scheduleOrderVo.setHoscode(schedule.getHoscode());
        scheduleOrderVo.setHosname(hospital.getHosname());
        scheduleOrderVo.setDepcode(schedule.getDepcode());
        scheduleOrderVo.setDepname((String) departmentService.getDepName(schedule.getHoscode(),schedule.getDepcode()));
        scheduleOrderVo.setHosScheduleId(schedule.getHosScheduleId());
        scheduleOrderVo.setAvailableNumber(schedule.getAvailableNumber());
        scheduleOrderVo.setTitle(schedule.getTitle());
        scheduleOrderVo.setReserveDate(schedule.getWorkDate());
        scheduleOrderVo.setReserveTime(schedule.getWorkTime());
        scheduleOrderVo.setAmount(schedule.getAmount());
    
        //退号截止天数(如:就诊前一天为-1,当天为0)
        int quitDay = bookingRule.getQuitDay();
        DateTime quitTime = this.getDateTime(new DateTime(schedule.getWorkDate()).plusDays(quitDay).toDate(), bookingRule.getQuitTime());
        scheduleOrderVo.setQuitTime(quitTime.toDate());
    
        //预约开始时间
        DateTime startTime = this.getDateTime(new Date(), bookingRule.getReleaseTime());
        scheduleOrderVo.setStartTime(startTime.toDate());
    
        //预约截止时间
        DateTime endTime = this.getDateTime(new DateTime().plusDays(bookingRule.getCycle()).toDate(), bookingRule.getStopTime());
        scheduleOrderVo.setEndTime(endTime.toDate());
    
        //当天停止挂号时间
        DateTime stopTime = this.getDateTime(new Date(), bookingRule.getStopTime());
        scheduleOrderVo.setStartTime(stopTime.toDate());
        return scheduleOrderVo;
    }
    
    • 1
    • 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

    2.添加controller方法
    在HospApiController类添加方法

    @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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

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

    操作模块:service-hosp

    1.添加service接口与实现
    在HospitalSetService类添加接口

    //获取医院签名信息
    SignInfoVo getSignInfoVo(String hoscode);
    
    • 1
    • 2

    在HospitalSetServiceImpl类添加实现

    //获取医院签名信息
    @Override
    public SignInfoVo getSignInfoVo(String hoscode) {
        QueryWrapper<HospitalSet> 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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2.添加controller方法

    @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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    3.4.3 搭建service_hosp_client模块

    在service_client模块中创建service_hosp_client子模块

    1.添加依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-openfeign-core</artifactId>
        </dependency>
        <dependency>
            <groupId>com.myproject</groupId>
            <artifactId>model</artifactId>
            <version>1.0</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2.添加Feign接口类
    com.myproject.yygh.hosp.client.HospitalFeignClient

    package com.myproject.yygh.hosp.client;
    
    import com.myproject.yygh.vo.hosp.ScheduleOrderVo;
    import com.myproject.yygh.vo.order.SignInfoVo;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.stereotype.Repository;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    
    @FeignClient(value = "service-hosp")
    @Repository
    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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    3.5 实现下单接口

    操作模块:service_order

    1.引入依赖

    <dependency>
        <groupId>com.myprojectgroupId>
        <artifactId>service_user_clientartifactId>
        <version>1.0version>
    dependency>
    <dependency>
        <groupId>com.myprojectgroupId>
        <artifactId>service_hosp_clientartifactId>
        <version>1.0version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2.实现下单接口
    修改OrderServiceImpl类下单方法

    @Autowired
    private PatientFeignClient patientFeignClient;
    
    @Autowired
    private HospitalFeignClient hospitalFeignClient;
    
    //生成挂号订单
    @Override
    public Long saveOrder(String scheduleId, Long patientId) {
        //获取就诊人信息
        Patient patient = patientFeignClient.getPatientOrder(patientId);
        //获取排班相关信息
        ScheduleOrderVo scheduleOrderVo = hospitalFeignClient.getScheduleOrderVo(scheduleId);
    
        //判断当前时间是否还可以预约
        if(new DateTime(scheduleOrderVo.getStartTime()).isAfterNow()
                || new DateTime(scheduleOrderVo.getEndTime()).isBeforeNow()){
            throw new YyghException(ResultCodeEnum.TIME_NO);
        }
    
        //获取签名信息
        SignInfoVo signInfoVo = hospitalFeignClient.getSignInfoVo(scheduleOrderVo.getHoscode());
    
        //添加到订单表
        OrderInfo orderInfo = new OrderInfo();
        //scheduleOrderVo 数据复制到 orderInfo
        BeanUtils.copyProperties(scheduleOrderVo,orderInfo);
        //向orderInfo设置其他数据
        String outTradeNo = System.currentTimeMillis() + ""+ new Random().nextInt(100);
        orderInfo.setOutTradeNo(outTradeNo);
        orderInfo.setScheduleId(scheduleOrderVo.getHosScheduleId());
        orderInfo.setUserId(patient.getUserId());
        orderInfo.setPatientId(patientId);
        orderInfo.setPatientName(patient.getName());
        orderInfo.setPatientPhone(patient.getPhone());
        orderInfo.setOrderStatus(OrderStatusEnum.UNPAID.getStatus());
        baseMapper.insert(orderInfo);
    
        //调用医院接口,实现预约挂号操作
        //设置调用医院接口需要参数,参数放到map集合
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("hoscode",orderInfo.getHoscode());
        paramMap.put("depcode",orderInfo.getDepcode());
        paramMap.put("hosScheduleId",orderInfo.getScheduleId());
        paramMap.put("reserveDate",new DateTime(orderInfo.getReserveDate()).toString("yyyy-MM-dd"));
        paramMap.put("reserveTime", orderInfo.getReserveTime());
        paramMap.put("amount",orderInfo.getAmount());
        paramMap.put("name", patient.getName());
        paramMap.put("certificatesType",patient.getCertificatesType());
        paramMap.put("certificatesNo", patient.getCertificatesNo());
        paramMap.put("sex",patient.getSex());
        paramMap.put("birthdate", patient.getBirthdate());
        paramMap.put("phone",patient.getPhone());
        paramMap.put("isMarry", patient.getIsMarry());
        paramMap.put("provinceCode",patient.getProvinceCode());
        paramMap.put("cityCode", patient.getCityCode());
        paramMap.put("districtCode",patient.getDistrictCode());
        paramMap.put("address",patient.getAddress());
        //联系人
        paramMap.put("contactsName",patient.getContactsName());
        paramMap.put("contactsCertificatesType", patient.getContactsCertificatesType());
        paramMap.put("contactsCertificatesNo",patient.getContactsCertificatesNo());
        paramMap.put("contactsPhone",patient.getContactsPhone());
        paramMap.put("timestamp", HttpRequestHelper.getTimestamp());
        String sign = HttpRequestHelper.getSign(paramMap, signInfoVo.getSignKey());
        paramMap.put("sign", sign);
    
        //请求医院系统接口
        JSONObject result = HttpRequestHelper.sendRequest(paramMap, signInfoVo.getApiUrl() + "/order/submitOrder");
        if(result.getInteger("code") == 200){
            JSONObject jsonObject = result.getJSONObject("data");
            //预约记录唯一标识(医院预约记录主键)
            String hosRecordId = jsonObject.getString("hosRecordId");
            //预约序号
            Integer number = jsonObject.getInteger("number");;
            //取号时间
            String fetchTime = jsonObject.getString("fetchTime");;
            //取号地址
            String fetchAddress = jsonObject.getString("fetchAddress");;
            //更新订单
            orderInfo.setHosRecordId(hosRecordId);
            orderInfo.setNumber(number);
            orderInfo.setFetchTime(fetchTime);
            orderInfo.setFetchAddress(fetchAddress);
            baseMapper.updateById(orderInfo);
            //排班可预约数
            Integer reservedNumber = jsonObject.getInteger("reservedNumber");
            //排班剩余预约数
            Integer availableNumber = jsonObject.getInteger("availableNumber");
            //发送mq信息,更新号源和短信通知
        }else {
            throw new YyghException(result.getString("message"), ResultCodeEnum.FAIL.getCode());
        }
    
        return orderInfo.getId();
    }
    
    • 1
    • 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

    3.6 预约成功后处理逻辑

    预约成功后我们要更新预约数和短信提醒预约成功,为了提高下单的并发性,这部分逻辑我们就交给mq为我们完成,预约成功发送消息即可

    3.6.1 RabbitMQ

    RabbitMQ简介
    以商品订单场景为例,
    如果商品服务和订单服务是两个不同的微服务,在下单的过程中订单服务需要调用商品服务进行扣库存操作。按照传统的方式,下单过程要等到调用完毕之后才能返回下单成功,如果网络产生波动等原因使得商品服务扣库存延迟或者失败,会带来较差的用户体验,如果在高并发的场景下,这样的处理显然是不合适的,那怎么进行优化呢?这就需要消息队列登场了。
    消息队列提供一个异步通信机制,消息的发送者不必一直等待到消息被成功处理才返回,而是立即返回。消息中间件负责处理网络通信,如果网络连接不可用,消息被暂存于队列当中,当网络畅通的时候在将消息转发给相应的应用程序或者服务,当然前提是这些服务订阅了该队列。如果在商品服务和订单服务之间使用消息中间件,既可以提高并发量,又降低服务之间的耦合度。
    RabbitMQ就是这样一款消息队列。RabbitMQ是一个开源的消息代理的队列服务器,用来通过普通协议在完全不同的应用之间共享数据。

    典型应用场景
    1.异步处理。把消息放入消息中间件中,等到需要的时候再去处理。

    2.流量削峰。例如秒杀活动,在短时间内访问量急剧增加,使用消息队列,当消息队列满了就拒绝响应,跳转到错误页面,这样就可以使得系统不会因为超负载而崩溃。

    3.日志处理

    4.应用解耦

    Debian安装RabbitMQ

    官网参考:https://rabbitmq.com/install-debian.html#apt-packagecloud
    rabbitmq安装脚本(不是国内镜像,因此安装有点慢,而且容易报错,多试几次)

    #!/usr/bin/sh
    
    sudo apt-get install curl gnupg apt-transport-https -y
    
    ## Team RabbitMQ's main signing key
    curl -1sLf "https://keys.openpgp.org/vks/v1/by-fingerprint/0A9AF2115F4687BD29803A206B73A36E6026DFCA" | sudo gpg --dearmor | sudo tee /usr/share/keyrings/com.rabbitmq.team.gpg > /dev/null
    ## Launchpad PPA that provides modern Erlang releases
    curl -1sLf "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0xf77f1eda57ebb1cc" | sudo gpg --dearmor | sudo tee /usr/share/keyrings/net.launchpad.ppa.rabbitmq.erlang.gpg > /dev/null
    ## PackageCloud RabbitMQ repository
    curl -1sLf "https://packagecloud.io/rabbitmq/rabbitmq-server/gpgkey" | sudo gpg --dearmor | sudo tee /usr/share/keyrings/io.packagecloud.rabbitmq.gpg > /dev/null
    
    ## Add apt repositories maintained by Team RabbitMQ
    sudo tee /etc/apt/sources.list.d/rabbitmq.list <
    • 1
    • 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
    #启动rabbitmq-server
    systemctl start rabbitmq-server.service
    
    #查看rabbitmq-server状态
    systemctl status rabbitmq-server.service
    
    #安装管理插件
    rabbitmq-plugins enable rabbitmq_management
    
    # 为RabbitMQ添加用户并授权
    #sudo rabbitmqctl add_user [username] [password] 
    #sudo rabbitmqctl set_user_tags [username] administrator
    #sudo rabbitmqctl  set_permissions -p / [username] '.*' '.*' '.*'
    rabbitmqctl add_user admin admin 
    rabbitmqctl set_user_tags admin administrator
    rabbitmqctl  set_permissions -p / admin '.*' '.*' '.*'
    
    # 启用stomp和management插件
    sudo rabbitmq-plugins enable rabbitmq_management
    sudo rabbitmq-plugins enable rabbitmq_web_stomp
    sudo rabbitmq-plugins enable rabbitmq_web_stomp_examples
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    管理后台(IP为安装rabbitmq的服务器IP):http://IP:15672

    3.6.2 rabbit-util模块封装

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

    在common模块中创建rabbit_util子模块

    1.修改pom.xml
    添加依赖

    <dependencies>
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-actuatorartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-bus-amqpartifactId>
        dependency>
        <dependency>
            <groupId>com.alibabagroupId>
            <artifactId>fastjsonartifactId>
        dependency>
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2.封装service方法

    package com.myproject.common.rabbit.service;
    
    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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    3.配置mq消息转换器

    package com.myproject.common.rabbit.config;
    
    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();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    3.6.3 封装短信接口

    操作模块:service-msm
    1.引入依赖

    <dependency>
        <groupId>com.myprojectgroupId>
        <artifactId>rabbit_utilartifactId>
        <version>1.0version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.添加配置

    spring:
      rabbitmq:
        host: 192.168.50.224
        port: 5672
        username: admin
        password: admin
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.添加常量配置
    在rabbit-util模块com.myproject.common.rabbit.constant.MqConst类添加

    package com.myproject.common.rabbit.constant;
    
    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";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    4.在model模块封装短信实体
    model模块中:已统一导入
    com.myproject.yygh.vo.msm.MsmVo

    5.封装service接口
    在MsmService类添加接口

    //mq发送短信
    boolean send(MsmVo msmVo);
    
    • 1
    • 2

    在MsmServiceImpl类添加接口实现

    //mq发送短信
    @Override
    public boolean send(MsmVo msmVo) {
        if(!StringUtils.isEmpty(msmVo.getPhone())){
            String code = (String) msmVo.getParam().get("code");
            boolean issend = this.send(msmVo.getPhone(),code);
            return issend;
        }
        return false;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    6.封装mq监听器
    com.myproject.yygh.msm.receiver.MsmReceiver

    package com.myproject.yygh.msm.receiver;
    
    import com.myproject.common.rabbit.constant.MqConst;
    import com.myproject.yygh.msm.service.MsmService;
    import com.myproject.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 MsmReceiver {
        @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);
        }
    
    }
    
    • 1
    • 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

    3.6.4 封装更新排班数量

    操作模块:service-hosp
    1.引入依赖

    <dependency>
        <groupId>com.myprojectgroupId>
        <artifactId>rabbit_utilartifactId>
        <version>1.0version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.添加配置

    spring:
      rabbitmq:
        host: 192.168.50.224
        port: 5672
        username: admin
        password: admin
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.在model模块封装更新排班实体
    com.myproject.yygh.vo.order.OrderMqVo
    说明:已统一引入,该对象放一个短信实体,预约下单成功后,我们发送一条消息,让mq来保证两个消息都发送成功

    4.封装service接口
    在ScheduleService类添加接口

    //更新排班数据,用于mq
    void update(Schedule schedule);
    
    • 1
    • 2

    在ScheduleServiceImpl类添加接口实现

    //更新排班数据,用于mq
    @Override
    public void update(Schedule schedule) {
        schedule.setUpdateTime(new Date());
        scheduleRepository.save(schedule);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    5.封装mq监听器
    com.myproject.yygh.hosp.receiver.HospitalReceiver

    package com.myproject.yygh.hosp.receiver;
    
    import com.myproject.common.rabbit.constant.MqConst;
    import com.myproject.common.rabbit.service.RabbitService;
    import com.myproject.yygh.hosp.service.ScheduleService;
    import com.myproject.yygh.model.hosp.Schedule;
    import com.myproject.yygh.vo.msm.MsmVo;
    import com.myproject.yygh.vo.order.OrderMqVo;
    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;
    
    import java.io.IOException;
    
    @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.getScheduleById(orderMqVo.getScheduleId());
            schedule.setReservedNumber(orderMqVo.getReservedNumber());
            schedule.setAvailableNumber(orderMqVo.getAvailableNumber());
            scheduleService.update(schedule);
            //发送短信
            MsmVo msmVo = orderMqVo.getMsmVo();
            if(null != msmVo) {
                rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_MSM, MqConst.ROUTING_MSM_ITEM, msmVo);
            }
        }
    }
    
    • 1
    • 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

    3.6.5 调整下单接口

    操作模块:service-order

    1.引入依赖

    <dependency>
        <groupId>com.myprojectgroupId>
        <artifactId>rabbit_utilartifactId>
        <version>1.0version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.添加配置

    spring:
      rabbitmq:
        host: 192.168.50.224
        port: 5672
        username: admin
        password: admin
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.修改下单接口

        @Autowired
        private RabbitService rabbitService;
    
        //生成挂号订单
        @Override
        public Long saveOrder(String scheduleId, Long patientId) {
            ...
    
            //请求医院系统接口
            JSONObject result = HttpRequestHelper.sendRequest(paramMap, signInfoVo.getApiUrl() + "/order/submitOrder");
            if(result.getInteger("code") == 200){
                JSONObject jsonObject = result.getJSONObject("data");
                //预约记录唯一标识(医院预约记录主键)
                String hosRecordId = jsonObject.getString("hosRecordId");
                //预约序号
                Integer number = jsonObject.getInteger("number");;
                //取号时间
                String fetchTime = jsonObject.getString("fetchTime");;
                //取号地址
                String fetchAddress = jsonObject.getString("fetchAddress");;
                //更新订单
                orderInfo.setHosRecordId(hosRecordId);
                orderInfo.setNumber(number);
                orderInfo.setFetchTime(fetchTime);
                orderInfo.setFetchAddress(fetchAddress);
                baseMapper.updateById(orderInfo);
                //排班可预约数
                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());
                String reserveDate =
                        new DateTime(orderInfo.getReserveDate()).toString("yyyy-MM-dd")
                                + (orderInfo.getReserveTime()==0 ? "上午": "下午");
                Map<String,Object> param = new HashMap<String,Object>(){{
                    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);
                //发送
                rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_ORDER, MqConst.ROUTING_ORDER, orderMqVo);
    
            }else {
                throw new YyghException(result.getString("message"), ResultCodeEnum.FAIL.getCode());
            }
    
            return orderInfo.getId();
        }
    
    • 1
    • 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

    4.修改MsmServiceImpl的send方法

    //mq发送短信
    @Override
    public boolean send(MsmVo msmVo) {
        if(!StringUtils.isEmpty(msmVo.getPhone())){
            boolean isdend = this.send(msmVo.getPhone(),msmVo.getParam());
            return isdend;
        }
        return false;
    }
    
    //mq发送短信封装
    private boolean send(String phone, Map<String,Object> param) {
        //判断手机号是否为空
        if(StringUtils.isEmpty(phone)){
            return false;
        }
        //整合阿里云短信服务
        //设置相关参数
        DefaultProfile profile = DefaultProfile.
                getProfile(ConstantPropertiesUtils.REGION_Id,
                        ConstantPropertiesUtils.ACCESS_KEY_ID,
                        ConstantPropertiesUtils.SECRECT);
        IAcsClient client = new DefaultAcsClient(profile);
        CommonRequest request = new CommonRequest();
        //request.setProtocol(ProtocolType.HTTPS);
        request.setMethod(MethodType.POST);
        request.setDomain("dysmsapi.aliyuncs.com");
        request.setVersion("2017-05-25");
        request.setAction("SendSms");
    
        //手机号
        request.putQueryParameter("PhoneNumbers", phone);
        //签名名称
        request.putQueryParameter("SignName", "阿里云短信测试");
        //模板code
        request.putQueryParameter("TemplateCode", "SMS_154950909");
        //验证码  使用json格式   {"code":"123456"}
        request.putQueryParameter("TemplateParam", JSONObject.toJSONString(param));
    
        //调用方法进行短信发送
        try {
            CommonResponse response = client.getCommonResponse(request);
            System.out.println(response.getData());
            return response.getHttpResponse().isSuccess();
        } catch (ServerException e) {
            e.printStackTrace();
        } catch (ClientException e) {
            e.printStackTrace();
        }
        return false;
    }
    
    • 1
    • 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

    3.7 前端整合

    操作:yygh-site

    1.封装api请求
    添加/api/orderInfo.js文件,定义下单接口

    import request from '@/utils/request'
    
    const api_name = `/api/order/orderInfo`
    
    export default {
      saveOrders(scheduleId, patientId) {
        return request({
          url: `${api_name}/auth/submitOrder/${scheduleId}/${patientId}`,
          method: 'post'
        })
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2.页面修改
    在/pages/hosp/booking.vue组件完善下单方法
    引入接口

    import orderApi from '@/api/orderInfo'
    
    • 1

    修改submitOrder方法

    //生成订单
    submitOrder() {
      if(this.submitBnt == "正在提交"){
        this.$message.error("不能重复提交")
        return
      }
      this.submitBnt = "正在提交"
      orderApi.saveOrders(this.scheduleId,this.patient.id)
        .then(response => {
          let orderId = response.data //订单id
          window.location.href='/order/show?orderId='+orderId
        }).catch(e => {
          this.submitBnt = "确认挂号"
      })
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    修改bug
    1.修改model模块中的com.myproject.yygh.model.order.OrderInfo
    命名错误,数据库的表中字段名为“hos_schedule_id”

    @ApiModelProperty(value = "排班id")
    @TableField("hos_schedule_id")
    private String scheduleId;
    
    • 1
    • 2
    • 3

    2.修改加密方式
    service_util模块中
    com.myproject.yygh.common.helper.HttpRequestHelper
    修改getSign方法

    public static String getSign(Map<String, Object> paramMap, String signKey) {
        if(paramMap.containsKey("sign")) {
            paramMap.remove("sign");
        }
        log.info("加密前:" + signKey.toString());
        String md5Str = MD5.encrypt(signKey.toString());
        log.info("加密后:" + md5Str);
        return md5Str;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3.修改数据库的数据
    将mysql中yygh_hosp数据库的hospital_set表的“北京协和医院的apu_url”改为“http://localhost:9998”

    4.修改hospital_manage的配置文件,将IP修改为自己服务器的IP

    测试提交订单功能
    测试提交功能是否报错,若不报错并跳转到空白页面则成功
    并且可以在http://IP:15672/#/queues中看到记录
    注:使用阿里短信测试服务是不能发验证码以外内容的

  • 相关阅读:
    关于MySQL数据库中的索引
    电子学:第010课——实验 8:继电振荡器
    qt工程文件中根据编译环境进行不同操作
    利用mAP计算yolo精确度
    [PyTorch][chapter 57][WGAN-GP 代码实现]
    Asp .Net Core 系列:集成 Ocelot+Consul+Swagger+Cors实现网关、服务注册、服务发现
    STM32物联网项目-单极性步进电机28BYJ-48
    LeetCode70-爬楼梯
    unity之制作二维码扫描
    Pytorch框架学习记录4——数据集的使用(torchvision.dataset)
  • 原文地址:https://blog.csdn.net/hutc_Alan/article/details/126220350