nacos 服务发现

  • 下载 略
  • 启动略

image.png

微服务端配置

依赖倒入

  • 未提供版本,根据自身项目去选用,或者交给spring自动进行版本仲裁 ```java
    1. <dependency>
    2. <groupId>com.alibaba.cloud</groupId>
    3. <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    4. </dependency>
<a name="rJEtC"></a>
## 配置

- 首先在要注册到服务发现,也就是nacos中的微服务下进行配置
```java
server:
  port: 8120

spring:
  application:
    name: service-sms # 服务名  注册到nacos 中会作为该微服务模块标示
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 # nacos 服务地址

logging:
  level:
    com.addicated.srb.sms.client.CoreUserInfoClient: DEBUG #以什么级别监控哪个接口

注解添加

package com.addicated.srb.core;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@EnableDiscoveryClient
@ComponentScan({"com.addicated.srb","com.addicated.common"})
public class ServiceCoreApplication {

    public static void main(String[] args) {
        SpringApplication.run(ServiceCoreApplication.class,args);
    }

}

检查结果

image.png

OpenFeign使用场景

  • 当微服务之间需要进行调用的时候进行使用,需要配合服务发现来进行使用,否则微服务之间无法发现彼此。

    openFegin简单使用

  • 需求背景:

    • 用户注册,需要走验证码服务,
  • image.png
    • 原始逻辑为点击下一步的时候才进行 查库请求,例如查询该用户是否已经注册。这样对用户体验不够友好,同时会造成验证码发送的使用浪费,要知道,这些都是钱

架构介绍

image.png

  • sms 为 发送验证码的单独模块
  • core 为 核心逻辑模块
  • 综上所述,设想逻辑为,在sms模块得到前端点击发送验证码的请求之后,直接请求 core 模块的服务,去查库进行校验, 如果已存在,则不去发送验证码,否则再进行发送。

    简单开发

  • 导入依赖 ```java

      <!--服务调用-->
      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-openfeign</artifactId>
      </dependency>
    

- 被调用目标接口开发
```java
 @ApiOperation("校验账号是否已经被注册")
    @GetMapping("/checkEmail/{email}")
    public  boolean checkEmail(@PathVariable("email") String email){
       return  userInfoService.checkMail(email);

    }
  • sms 模块下,即调用发起者
    • 启动类上添加 enableFeignClients注解 标示启用openfeign调用 ```java package com.addicated.srb.sms;

import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication @EnableFeignClients @ComponentScan({“com.addicated.srb”, “com.addicated.common”}) public class ServiceSmsApplication {

public static void main(String[] args) {
    SpringApplication.run(ServiceSmsApplication.class, args);
}

}


- 在 sms 模块下 创建接口类
```java
package com.addicated.srb.sms.client;


import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(value="service-core")   // 声明要调用哪个模块下的功能
public interface CoreUserInfoClient {

    @GetMapping("/api/core/userInfo/checkEmail/{email}")   // 声明要调用哪个接口路径 仅声明即可
    boolean checkEmail(@PathVariable String email);



}
  • 在 sms controller 层进行注入调用 ```java package com.addicated.srb.sms.controller.api;

import com.addicated.common.exception.Assert; import com.addicated.common.result.R; import com.addicated.common.result.ResponseEnum; import com.addicated.common.util.RandomUtils; import com.addicated.common.util.RegexValidateUtils; import com.addicated.srb.sms.client.CoreUserInfoClient; import com.addicated.srb.sms.service.SmsService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.web.bind.annotation.*;

import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit;

@RestController @RequestMapping(“/api/sms”) @Api(tags = “短信管理”) @CrossOrigin //跨域 @Slf4j public class ApiSmsController {

@Autowired
private SmsService smsService;

@Autowired
private RedisTemplate redisTemplate;


@Autowired
private CoreUserInfoClient coreUserInfoClient;

@Value("${mail.subject}")
private String SUBJECT;

@Value("${mail.content}")
private String CONTENT;



@ApiOperation("获取验证码,发送到填写邮箱")
@GetMapping("/send/{email}")
public R send(
        @ApiParam(value = "邮箱地址", required = true)
        @PathVariable(value="email") String email) {

    // 使用断言来进行异常处理
    Assert.notEmpty(email, ResponseEnum.MAIL_NULL_ERROR);
    // 邮箱格式校验
    Assert.isTrue(RegexValidateUtils.checkEmail(email),ResponseEnum.MAIL_ERROR);

    // FIXME 在发送之前对 账号是否已经注册进行判断 | 判断逻辑在另外一个core 微服务下, 需要跨微服务进行调用,引出openFeign
    // 对应的要在core 微服务下进行 接口定义
    boolean result = coreUserInfoClient.checkEmail(email);
    System.out.println("result = " + result);
    // 断言 如果为fasle 则抛出异常
    Assert.isTrue(result == false, ResponseEnum.MAIL_EXIST_ERROR);

    // 调用工具类生成验证码
    String code = RandomUtils.getFourBitRandom();
    // 进行短信模板组装
    Map<String,Object> param = new HashMap<>();
    param.put("code", code);

    // 发送验证码到目标邮箱
    smsService.sendMail(email,SUBJECT,String.format(CONTENT,code));
    // 验证码押入 redis
    redisTemplate.opsForValue().set("srb:sms:code:" + email, code, 5, TimeUnit.MINUTES);

    return R.ok().message("短信发送成功");

}

}

```

查看结果

image.png

  • 前端页面未修改,提示信息不用在意。
  • image.png
  • 已经注册,被拦截到了,同样邮箱也未收到验证码,调用成功,功能实现。