Spring Cloud Alibaba Nacos 实战
前言
最近在做预约挂号系统时候有这样一个业务场景
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Pjxdi05W-1647410460729)(C:\Users\86157\AppData\Local\Temp\1647408580680.png)]
我们有这两个义务模块
cmn是一个数据字典模块,他负责数据字典的存储,他的数据存储在mysql
hosp是一个医院模块,他负责显示数据库中医院的属性,他的数据存储在mongodb
同时,mongodb中存放的数据是一个code,我们需要根据这个code去获取他对应的字符串.
这里我们想用Spring Cloud Alibaba Nacos来帮助我们完成这个业务
Nacos配置
1.1 什么是Nacos
Nacos 是阿里巴巴推出来的一个新开源项目,这是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。
Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。 Nacos 是构建以“服务”为中心的现代应用架构 (例如微服务范式、云原生范式) 的服务基础设施
1.2 常见的注册中心
\1. Eureka(原生,2.0遇到瓶颈,停止维护)
\2. Zookeeper(支持,专业的独立产品。例如:dubbo)
\3. Consul(原生,GO语言开发)
\4. Nacos
相对于 Spring Cloud Eureka 来说,Nacos 更强大。
Nacos = Spring Cloud Eureka + Spring Cloud Config
Nacos 可以与 Spring, Spring Boot, Spring Cloud 集成,并能代替 Spring Cloud Eureka, Spring Cloud Config。
- 通过 Nacos Server 和 spring-cloud-starter-alibaba-nacos-config 实现配置的动态变更。
- 通过 Nacos Server 和 spring-cloud-starter-alibaba-nacos-discovery 实现服务的注册与发现。
1.3 Nacos结构图
1.4 Nacos下载和安装
下载地址:https://github.com/alibaba/nacos/releases
下载版本:nacos-server-1.1.4.tar.gz或nacos-server-1.1.4.zip,解压任意目录即可
启动Nacos服务
Linux/Unix/Mac
启动命令(standalone代表着单机模式运行,非集群模式)
启动命令:sh startup.sh -m standalone
Windows
启动命令:cmd startup.cmd 或者双击startup.cmd运行文件。
访问:http://localhost:8848/nacos
用户名密码:nacos/nacos
服务注册
第一步:在service模块pom文件引入依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
第二步:在service-hosp的配置文件添加nacos服务地址
# nacos服务地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
第三步:在service-hosp的启动类添加注解
@EnableDiscoveryClient
@SpringBootApplication
@ComponentScan(basePackages = "com.example")
public class ServiceHospApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceHospApplication.class, args);
}
}
启动service-hosp服务,在Nacos管理界面的服务列表中可以看到注册的服务
service-cmn注册过程和service-hosp相同(省略)
业务实现
1.编写cmn中的业务代码
Controller类
@GetMapping("getName/{dictCode}/{value}")
public String getName(@PathVariable String dictCode,
@PathVariable String value){
String dictName = dictService.getDictName(dictCode,value);
return dictName;
}
@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)){
QueryWrapper<Dict> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("value",value);
Dict dict = baseMapper.selectOne(queryWrapper);
return dict.getName();
}else {
QueryWrapper<Dict> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("dict_code",dictCode);
Dict CodeDict = baseMapper.selectOne(queryWrapper);
Long parent_id = CodeDict.getId();
Dict dict = baseMapper.selectOne(new QueryWrapper<Dict>()
.eq("parent_id", parent_id)
.eq("value", value));
return dict.getName();
}
}
2.编写hosp中的业务代码
Controller类
@RestController
@RequestMapping("/admin/hosp/hospital")
@CrossOrigin
public class HospitalController {
@Autowired
private HospitalService hospitalService;
@GetMapping("list/{page}/{limit}")
public Result listHosp(@PathVariable("page") Integer page,
@PathVariable("limit") Integer limit,
HospitalQueryVo hospitalQueryVo) {
Page<Hospital> pageModel = hospitalService.selectHospPage(page, limit, hospitalQueryVo);
return Result.ok(pageModel);
}
}
service类
@Autowired
private DictFeignClient dictFeignClient;
@Override
public Page<Hospital> selectHospPage(Integer page, Integer limit, HospitalQueryVo hospitalQueryVo) {
Pageable pageable = PageRequest.of(page - 1, limit);
ExampleMatcher matcher = ExampleMatcher.matching()
.withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING)
.withIgnoreCase(true);
Hospital hospital = new Hospital();
BeanUtils.copyProperties(hospitalQueryVo, hospital);
Example<Hospital> example = Example.of(hospital, matcher);
Page<Hospital> all = hospitalRepository.findAll(example, pageable);
all.getContent().stream().forEach(item -> {
this.setHospitalHosType(item);
});
return all;
}
private Hospital setHospitalHosType(Hospital item) {
String hostypeString = dictFeignClient.getName("Hostype", item.getHostype());
String province = dictFeignClient.getName(item.getProvinceCode());
String client = dictFeignClient.getName(item.getCityCode());
String district = dictFeignClient.getName(item.getDistrictCode());
item.getParam().put("fullAddress", province + client + district);
item.getParam().put("hostypeString", hostypeString);
return item;
}
setHospitalHosType这个方法是将带有code的类转化为带有字典数据的类,在Hospital中有一个Param的Map<String,Object> param = new HashMap<>();帮助补充数据。dictFeignClient是我们为了方便在注册中心调度数据而建立的
3.DictFeignClient代码
@FeignClient("service-cmn")
public interface DictFeignClient {
@GetMapping("/admin/cmn/dict/getName/{value}")
public String getName(@PathVariable("value") String value);
@GetMapping("/admin/cmn/dict/getName/{dictCode}/{value}")
public String getName(@PathVariable("dictCode") String dictCode,
@PathVariable("value") String value);
}
最后在要调用注册中心的方法的启动类添加这个注解
发现服务
配置文件
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
@EnableFeignClients(basePackages = "com.example")
注意事项
启动HospService的时候报错
Description:
Field dictFeignClient in com.example.yygh.hosp.service.impl.HospitalServiceImpl required a bean of type 'com.example.yygh.cmn.clent.DictFeignClient' that could not be found.
The injection point has the following annotations:
- @org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com.example.yygh.cmn.clent.DictFeignClient' in your configuration.
服务调用需要这个配置项
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
需要这个注解
@EnableFeignClients
of type ‘com.example.yygh.cmn.clent.DictFeignClient’ in your configuration.
服务调用需要这个配置项
```xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
需要这个注解
@EnableFeignClients
要不然无法发现任务
|