【医院管理详细步骤】(内附源码)
页面预览
列表页
批量导入数据
为了方便测试,我们可以将更多的医院信息数据批量导入到系统中。将资料中的json数据和测试用例复制到项目中,然后执行测试用例即可
资料:资料>批量导入医院数据
第01章-医院列表信息
1、医院列表
1.1、Controller
在service-hosp中创建AdminHospitalController
package com.atguigu.syt.hosp.controller.admin;
@Api(tags = "医院管理")
@RestController
@RequestMapping("/admin/hosp/hospital")
public class AdminHospitalController {
//注入service
@Resource
private HospitalService hospitalService;
@ApiOperation(value = "获取分页列表")
@ApiImplicitParams({
@ApiImplicitParam(name = "page",value = "页码", required = true),
@ApiImplicitParam(name = "limit",value = "每页记录数", required = true),
@ApiImplicitParam(name = "hosname",value = "查询字符串")})
@GetMapping("/{page}/{limit}")
public Result<Page<Hospital>> pageList(
@PathVariable Integer page, //路径
@PathVariable Integer limit, //路径
String hosname /*查询字符串*/) {
//调用方法
Page<Hospital> pageModel = hospitalService.selectPage(page, limit, hosname);
return Result.ok(pageModel);
}
}
1.2、Service
接口:HospitalService
/**
* 根据医院名称分页查询医院列表
* @param page
* @param limit
* @param hosname
* @return
*/
Page<Hospital> selectPage(Integer page, Integer limit, String hosname);
实现:HospitalServiceImpl
@Override
public Page<Hospital> selectPage(Integer page, Integer limit, String hosname) {
//设置排序规则
Sort sort = Sort.by(Sort.Direction.ASC, "hoscode");
//设置分页参数
PageRequest pageRequest = PageRequest.of(page-1, limit, sort);
//执行查询
if(StringUtils.isEmpty(hosname)){
return hospitalRepository.findAll(pageRequest);
}else{
return hospitalRepository.findByHosnameLike(hosname, pageRequest);
}
}
1.3、Repository
/**
* 根据医院名称查询医院分页列表
* @param hosname
* @return
*/
Page<Hospital> findByHosnameLike(String hosname, PageRequest pageRequest);
2、获取数据字典名称
2.1、Controller
在service-cmn中创建InnerDictController
package com.atguigu.syt.cmn.controller.inner;
@Api(tags = "数据字典")
@RestController
@RequestMapping("/inner/cmn/dict")
public class InnerDictController {
@Resource
private DictService dictService;
@ApiOperation(value = "获取数据字典名称")
@ApiImplicitParams({
@ApiImplicitParam(name = "dictTypeId",value = "字典类型id", required = true),
@ApiImplicitParam(name = "value",value = "字典值", required = true)})
@GetMapping(value = "/getName/{dictTypeId}/{value}")
public String getName(
@PathVariable("dictTypeId") Long dictTypeId,
@PathVariable("value") String value) {
return dictService.getNameByDictTypeIdAndValue(dictTypeId, value);
}
}
2.2、Service
接口:DictService
/**
* 根据数据字典类别和字典值获取字典名称
* @param dictTypeId
* @param value
* @return
*/
String getNameByDictTypeIdAndValue(Long dictTypeId, String value);
实现:DictServiceImpl
@Override
public String getNameByDictTypeIdAndValue(Long dictTypeId, String value) {
LambdaQueryWrapper<Dict> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Dict::getDictTypeId, dictTypeId);
queryWrapper.eq(Dict::getValue, value);
Dict dict = baseMapper.selectOne(queryWrapper);
if (dict != null) {
return dict.getName();
}
return "";
}
2.3、配置Swagger分组
在service-util的Knife4jConfig类中添加如下@Bean配置:
@Bean
public Docket docketInner() {
//指定使用Swagger2规范
Docket docket = new Docket(DocumentationType.SWAGGER_2)
.apiInfo(new ApiInfoBuilder()
.description("尚医通 APIs")
.description("本文档描述了尚医通微服务内部调用系统接口")
.contact("admin@atguigu.com")
.version("1.0")
.build())
//分组名称
.groupName("微服务内部调用")
.select()
.paths(PathSelectors.regex("/inner/.*"))
.build();
return docket;
}
3、获取地区名称
3.1、Controller
在service-cmn中创建InnerRegionController
package com.atguigu.syt.cmn.controller.inner;
@Api(tags = "地区")
@RestController
@RequestMapping("/inner/cmn/region")
public class InnerRegionController {
@Resource
private RegionService regionService;
@ApiOperation(value = "根据地区编码获取地区名称")
@ApiImplicitParam(name = "code",value = "值", required = true)
@GetMapping(value = "/getName/{code}")
public String getName(@PathVariable("code") String code) {
return regionService.getNameByCode(code);
}
}
3.2、Service
接口:RegionService
/**
* 根据地区编码获取地区名称
* @param code
* @return
*/
String getNameByCode(String code);
实现:RegionServiceImpl
@Override
public String getNameByCode(String code) {
LambdaQueryWrapper<Region> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Region::getCode, code);
Region region = baseMapper.selectOne(queryWrapper);
if (region != null) {
return region.getName();
}
return "";
}
第02章-微服务远程调用
1、openfeign接口定义
1.1、创建service-client
在父工程guigu-syt-parent下面,选择 maven类型的模块,输入模块名称service-client
,完成创建。
删除src目录。
1.2、引入依赖
<dependencies>
<!-- 服务调用 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
1.3、创建service-cmn-client模块
在service-client下面,选择 maven类型的模块,输入模块名称service-cmn-client
,完成创建。
注意:parent选择service-client,删除Main.java
1.4、添加FeignClient接口
DictFeignClient
package com.atguigu.syt.cmn.client;
@FeignClient(value = "service-cmn")
public interface DictFeignClient {
/**
* 获取数据字典名称
* @param dictTypeId
* @param value
* @return
*/
@GetMapping(value = "/inner/cmn/dict/getName/{dictTypeId}/{value}")
String getName(
@PathVariable("dictTypeId") Long dictTypeId,
@PathVariable("value") String value
);
}
RegionFeignClient
package com.atguigu.syt.cmn.client;
@FeignClient(value = "service-cmn")
public interface RegionFeignClient {
/**
* 根据地区编码获取地区名称
* @param code
* @return
*/
@GetMapping(value = "/inner/cmn/region/getName/{code}")
String getName(@PathVariable("code") String code);
}
2、openfeign接口调用
2.1、service模块中引入依赖
<!-- 服务调用 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>service-cmn-client</artifactId>
<version>1.0</version>
</dependency>
2.2、service-hosp启动类添加注解
@EnableFeignClients("com.atguigu.syt")
2.3、修改HospitalServiceImpl
添加FeignClient
@Resource
private DictFeignClient dictFeignClient;
@Resource
private RegionFeignClient regionFeignClient;
封装Hospital数据
/**
* 封装Hospital数据
* @param hospital
* @return
*/
private Hospital packHospital(Hospital hospital) {
String hostypeString = dictFeignClient.getName(DictTypeEnum.HOSTYPE.getDictTypeId(), hospital.getHostype());
String provinceString = regionFeignClient.getName(hospital.getProvinceCode());
String cityString = regionFeignClient.getName(hospital.getCityCode());
if(provinceString.equals(cityString)) cityString = "";
String districtString = regionFeignClient.getName(hospital.getDistrictCode());
hospital.getParam().put("hostypeString", hostypeString);
hospital.getParam().put("fullAddress", provinceString + cityString + districtString + hospital.getAddress());
return hospital;
}
完善selectPage方法
@Override
public Page<Hospital> selectPage(Integer page, Integer limit, String hosname) {
//设置排序规则
Sort sort = Sort.by(Sort.Direction.ASC, "hoscode");
//设置分页参数
PageRequest pageRequest = PageRequest.of(page-1, limit, sort);
//执行查询
Page<Hospital> pages = null;
if(StringUtils.isEmpty(hosname)){
pages = hospitalRepository.findAll(pageRequest);
}else{
pages = hospitalRepository.findByHosnameLike(hosname, pageRequest);
}
pages.getContent().forEach(item -> {
this.packHospital(item);
});
return pages;
}
2.4、配置覆盖注册
问题:默认情况下,一个项目中不能同时存在两个相同value值的@FeignClient,否则微服务无法启动
解决方案:
方法一:配置允许覆盖注册
#当遇到同样名字的时候,是否允许覆盖注册
spring.main.allow-bean-definition-overriding=true
方法二:在@FeignClient中添加contextId属性,设置不同的值
DictFeignClient:
@FeignClient(
value = "service-cmn",
contextId = "dictFeignClient"
)
public interface DictFeignClient {
RegionFeignClient:
@FeignClient(
value = "service-cmn",
contextId = "regionFeignClient"
)
public interface RegionFeignClient {
2.5、测试
注意:测试前需要修改spring-security的WebSecurityConfig类,配置授权校验排除inner路径
/**
* 配置哪些请求不拦截
* 排除swagger相关请求
* @param web
* @throws Exception
*/
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/api/**","/inner/**","/favicon.ico","/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**", "/doc.html");
}
3、服务超时和服务降级
3.1、超时配置
如果微服务间的远程调用连接和响应时间过长,导致调用超时,会使整个业务流程选失败,我们可以在服务的消费者端配置如下内容,延长连接和响应的超时时间
feign:
client:
config:
default:
connect-timeout: 2000 #连接建立的超时时长,单位是ms,默认1s
read-timeout: 2000 #处理请求的超时时间,单位是ms,默认为1s
3.2、引入服务降级依赖
如果服务生产者长时间没有响应,可以启用服务降级,使下游服务能够正常运行
在service模块中添加依赖
<!-- 熔断和降级 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
3.3、添加配置
在service-hosp模块中添加配置
feign:
sentinel:
enabled: true #开启Feign对Sentinel的支持
3.4、降级实现
DictDegradeFeignClient:
package com.atguigu.syt.cmn.client.impl;
@Component
public class DictDegradeFeignClient implements DictFeignClient {
@Override
public String getName(Long dictTypeId, String value) {
return "数据获取失败";
}
}
RegionDegradeFeignClient:
package com.atguigu.syt.cmn.client.impl;
@Component
public class RegionDegradeFeignClient implements RegionFeignClient {
@Override
public String getName(String code) {
return "数据获取失败";
}
}
3.5、配置降级实现
DictFeignClient:
@FeignClient(
value = "service-cmn",
contextId = "dictFeignClient",
fallback = DictDegradeFeignClient.class
)
public interface DictFeignClient {
RegionFeignClient:
@FeignClient(
value = "service-cmn",
contextId = "regionFeignClient",
fallback = RegionDegradeFeignClient.class
)
public interface RegionFeignClient {
第03章-医院状态
1、Controller
在AdminHospitalController添加方法
@ApiOperation(value = "更新上线状态")
@ApiImplicitParams({
@ApiImplicitParam(name = "hoscode",value = "医院编码", required = true),
@ApiImplicitParam(name = "status",value = "状态(0:未上线 1:已上线)", required = true)})
@GetMapping("/updateStatus/{hoscode}/{status}")
public Result updateStatus(@PathVariable("hoscode") String hoscode, @PathVariable("status") Integer status){
hospitalService.updateStatus(hoscode, status);
return Result.ok();
}
2、Service
接口:HospitalService
/**
* 根据医院编码修改医院状态
* @param hoscode
* @param status
*/
void updateStatus(String hoscode, Integer status);
实现:HospitalServiceImpl
@Override
public void updateStatus(String hoscode, Integer status) {
if(status.intValue() == 0 || status.intValue() == 1) {
Hospital hospital = hospitalRepository.findByHoscode(hoscode);
hospital.setStatus(status);
hospitalRepository.save(hospital);
return;
}
throw new GuiguException(ResultCodeEnum.PARAM_ERROR);
}
第04章-前端整合
1、路由
静态路由:
src/router/index.js:在“医院管理”下添加子节点
{
path: 'hosp/list',
name: 'hospList',
component: () =>import('@/views/syt/hosp/list'),
meta: { title: '医院列表', icon: 'el-icon-s-unfold' }
}
动态路由:
2、api
在src/api/syt目录下创建hosp.js文件
import request from '@/utils/request'
const apiName = '/admin/hosp/hospital'
export default {
//医院列表
getPageList(page, limit, hosname) {
return request ({
url: `${apiName}/${page}/${limit}`,
method: 'get',
params: {hosname}
})
},
updateStatus(hoscode, status){
return request ({
url: `${apiName}/updateStatus/${hoscode}/${status}`,
method: 'get'
})
}
}
3、组件渲染
创建 src/views/syt/hosp/list.vue
<template>
<div class="app-container">
<el-form :inline="true" class="demo-form-inline">
<el-form-item>
<el-input v-model="hosname" placeholder="医院名称" />
</el-form-item>
<el-button type="primary" icon="el-icon-search" @click="fetchData()">
查询
</el-button>
<el-button type="default" @click="resetData()">清空</el-button>
</el-form>
<!-- banner列表 -->
<el-table
v-loading="listLoading"
:data="list"
element-loading-text="数据加载中"
border
highlight-current-row
>
<el-table-column label="序号" width="60" align="center">
<template slot-scope="scope">
{{ (page - 1) * limit + scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column label="LOGO" width="80">
<template slot-scope="scope">
<img
:src="'data:image/jpeg;base64,' + scope.row.logoData"
width="50"
/>
</template>
</el-table-column>
<el-table-column prop="hosname" label="医院名称" />
<el-table-column prop="param.hostypeString" label="等级" width="90" />
<el-table-column prop="param.fullAddress" label="详情地址" />
<el-table-column label="状态" width="80">
<template slot-scope="scope">
{{ scope.row.status === 1 ? '已上线' : '未上线' }}
</template>
</el-table-column>
<el-table-column label="操作" width="230" align="center">
<template slot-scope="scope">
<router-link
:to="'/syt/hospset/hosp/show/' + scope.row.hoscode"
style="margin-right: 5px"
>
<el-button type="primary" size="mini">查看</el-button>
</router-link>
<router-link
:to="'/syt/hospset/hosp/schedule/' + scope.row.hoscode"
style="margin-right: 5px"
>
<el-button type="success" size="mini">排班</el-button>
</router-link>
<el-button
v-if="scope.row.status == 1"
type="warning"
size="mini"
@click="updateStatus(scope.row.hoscode, 0)"
>下线</el-button
>
<el-button
v-else
type="info"
size="mini"
@click="updateStatus(scope.row.hoscode, 1)"
>上线</el-button
>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<el-pagination
:current-page="page"
:total="total"
:page-size="limit"
:page-sizes="[2, 5, 10]"
style="padding: 30px 0; text-align: center"
layout="total, sizes, prev, pager, next, jumper"
@size-change="changePageSize"
@current-change="changeCurrentPage"
/>
</div>
</template>
<script>
import hosp from '@/api/syt/hosp'
export default {
data() {
return {
listLoading: true, // 数据是否正在加载
list: null, // 医院列表数据集合
total: 0, // 数据库中的总记录数
page: 1, // 默认页码
limit: 10, // 每页记录数
hosname: '', //查询表单:医院名称
}
},
created() {
//调用医院列表
this.fetchData()
},
methods: {
//医院列表
fetchData() {
console.log('加载列表')
this.listLoading = true
hosp.getPageList(this.page, this.limit, this.hosname).then((response) => {
this.list = response.data.content
this.total = response.data.totalElements
this.listLoading = false
})
},
// 每页记录数改变,size:回调参数,表示当前选中的“每页条数”
changePageSize(size) {
this.limit = size
this.fetchData()
},
// 改变页码,page:回调参数,表示当前选中的“页码”
changeCurrentPage(page) {
this.page = page
this.fetchData()
},
//清空查询表单
resetData() {
this.hosname = ''
this.fetchData()
},
//修改状态
updateStatus(hoscode, status) {
hosp.updateStatus(hoscode, status).then((response ) => {
this.$message.success(response.message),
this.fetchData()
})
},
},
}
</script>
本文来自博客园,作者:自律即自由-,转载请注明原文链接:https://www.cnblogs.com/deyo/p/17475902.html