天天看点

彤医通项目之微服务架构初入 @EnableDIscoveryClient注册与@FeignClient远程调用远程调用注册中心(中介)核心业务 思路总结

远程调用

不同模块之间的远程调用。service-hosp医院管理模块调用service-cmn数据字典内容模块。

注册中心(中介)

远程调用的实现前提是先将微服务模块在注册中心进行注册

彤医通项目之微服务架构初入 @EnableDIscoveryClient注册与@FeignClient远程调用远程调用注册中心(中介)核心业务 思路总结

尚医通使用nacos注册中心,启动nacos,账号密码nacos。

  1. 导入依赖spring-cloud-starter-alibaba-nacos-discovery
  2. 将hosp和cmn服务在nacos注册中心中注册,修改配置文件:

#nacos服务地址

spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848

#服务名

spring.application.name=service-cmn

  1. 在启动类上标明@EnableDiscoveryClient注解,对此服务进行注册。

远程调用场景:

通过value和dict_code获取对应id,再通过赋值id给parent_id属性作为条件查询另一条bean的getName(),从而得到医院等级旗下的级别信息。

这其中需要hosp模块远程调用cmn模块(的接口)中查询到的级别名。

彤医通项目之微服务架构初入 @EnableDIscoveryClient注册与@FeignClient远程调用远程调用注册中心(中介)核心业务 思路总结

Controller层:

/**
     * 在数据字典中根据dictcode和value查询,因为有value会重复
     * 返回医院等级名
     * @param dictCode
     * @param value
     * @return
     */
    @GetMapping("getName/{dictCode}/{value}")
    public String getName(@PathVariable String dictCode,
                          @PathVariable String value){
        String dictName = dictService.getDictName(dictCode,value);
        return dictName;
    }

    /**
     * 在数据字典中根据value查询
     * @param value
     * @return
     */
    @GetMapping("getName/{value}")
    public String getName(@PathVariable String value){
        String dictName = dictService.getDictName("",value);
        return dictName;
    }
           

Service层:

@Override
    public String getDictName(String dictCode, String value) {
        if (StringUtils.isEmpty(dictCode)) { // 如果dictCode为空,则只通过value查询
            QueryWrapper<Dict> wrapper = new QueryWrapper<>();
            wrapper.eq("value", value);
            Dict dict = baseMapper.selectOne(wrapper);
            return dict.getName();
        }else { // 如果dictCode不为空,可能会出现value有相同值的情况

            /*
            总结,一个对象,通过一个属性值查询出一条bean对象,再通过这条bean对象获取另一属性值
            可解决:某些情况下,不同bean对象有属性值重复的问题
             */
            Dict dictByDictCode = this.getDictByDictCode(dictCode);// 根据dictcode查询dict对象的id值,再通过parent_id
            Long id = dictByDictCode.getId();
            Dict finalDict = baseMapper.selectOne(new QueryWrapper<Dict>()
                    .eq("parent_id", id) // 医院等级id为10000,查找parent_id列值等于10000(id)的数据
                    .eq("value", value));
            return finalDict.getName();
        }
    }
    // 根据dictcode查询dict对象的id值,再通过parent_id
    private Dict getDictByDictCode(String dictCode){
        QueryWrapper<Dict> wrapper = new QueryWrapper<>();
        wrapper.eq("dict_code", dictCode);
        Dict codeDict = baseMapper.selectOne(wrapper);
        return codeDict;
    }
           

在父模块中新增封装性质的service-client模块,在其中再创建子模块(用被调用者service-cmn命名)

  1. 在service-client引入依赖和在service-hosp中引入依赖
<!--    打包方式为pom类型,因为其下仍有子模块-->
    <packaging>pom</packaging>
    <modules>
        <module>service-cmn-client</module>
    </modules>


    <dependencies>
        <dependency>
            <groupId>com.lwt</groupId>
            <artifactId>common_util</artifactId>
            <version>1.0</version>
        </dependency>
        <dependency>
            <groupId>com.lwt</groupId>
            <artifactId>model</artifactId>
            <version>1.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

    </dependencies>
           
  1. 创建接口DictFeignClient,其上标明@FeignClient(“被调用模块的服务名”),复制被调用模块的控制层方法。@Repository
@ApiModelProperty(value = "其他参数")
    @Transient //被该注解标注的,将不会被录入到数据库中。只作为普通的javaBean属性
    private Map<String,Object> param = new HashMap<>();
           
  1. 在调用者模块中的service层的实现类中注入DictFeignClient,我现在是想在简单的分页查询集合中 先调用后添加数据字典中的医院等级级别。但Hospital中并没有医院等级的属性,但在继承BaseEntity类中额外声明了不在数据库中的map属性,专门用来存储这种数据信息。也就是说,被调用者(cmn的医院等级信息)中的属性字段在调用者(hosp的hospital和BaseEntity有个map)的实体类中并不会出现,故BaseEntity存在的意义是,如下:

@ApiModelProperty(value = “其他参数”)

@Transient //被该注解标注的,将不会被录入到数据库中。只作为普通的javaBean属性

private Map<String,Object> param = new HashMap<>();

// 在param这个map中封装医院等级信息,以便在页面中显示

/**
     * 查询医院信息,分页显示
     * 后将简单分页重新注入其他模块查询出的医院等级信息 远程调用来的信息添加到分页数据中
     * @param page
     * @param limit
     * @param hospitalQueryVo
     * @return
     */
    @Override
    public Page<Hospital> selectHospPage(Integer page, Integer limit, HospitalQueryVo hospitalQueryVo) {
        Pageable pageable = PageRequest.of(page-1,limit); // 创建分页对象
        ExampleMatcher exampleMatcher = ExampleMatcher.matching()
                .withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING)
                .withIgnoreCase(true); // 创建条件匹配器
        Hospital hospital = new Hospital();
        BeanUtils.copyProperties(hospitalQueryVo, hospital);
        Example<Hospital> example = Example.of(hospital,exampleMatcher); // 创建查询对象
        Page<Hospital> pages = hospitalRepository.findAll(example, pageable);

//        List<Hospital> content = pages.getContent();
// 使用java8 Stream流 mongo中hostype
        pages.getContent().stream().forEach(item->{
            this.setHospitalHosType(item); // 向遍历出来的每条分页信息中再设置医院等级信息名
        });

        return pages;
    }
    // 调用数据字典中接口封装好的方法,传入dictCode和value值查询医院,放进map集合中欧冠
    private Hospital setHospitalHosType(Hospital hospital) {
        String hostypeString = dictFeignClient.getName("Hostype", hospital.getHostype());

        // 练习,查询省 市 地区
        String provinceString = dictFeignClient.getName(hospital.getProvinceCode());
        String cityString = dictFeignClient.getName(hospital.getCityCode());
        String districtString = dictFeignClient.getName(hospital.getDistrictCode());

        hospital.getParam().put("fullAddress",provinceString+cityString+districtString);
        hospital.getParam().put("hostypeString", hostypeString);
        return hospital;
    }
           
  1. 易忘操作

    (1)在service模块中引入依赖openfeign包

    (2)在service-hosp模块启动类中添加@EnableFeignClients注解保证可以找到DictFeignClient中指定的服务名,并指定扫描的基础包basePackage=com.lwt,因为在不同模块中,防止找不到

核心业务 思路总结

(1)数据字典模块

(2)医院模块

在数据字典中有许多属性 包括居民身份证 医院等级…等

但在医院模块中不可能将所有属性都直接声明创建getset方法

此时有必要在另一模块中查询出数据作为被调用者 被调用者调用。

而此时,我们在医院实体类中需要额外定义一个map集合去专门存放cmn中查询出的额外信息,比如医院的地理位置省试区、医院等级,使用远程调用技术feign实现具体复杂业务。(前提是在nacos注册中心将模块进行注册)