文章目录
前言
提示:既然用到了微服务就会有服务间调用的问题产生,我总结了通过feign和hystrix进行调用的方式,希望对大家有所帮助。
提示:以下是本篇文章正文内容,下面案例可供参考
介绍
服务提供者是sms短信发送服务,服务消费者是系统用户模块;
1. 服务提供者
1.1 jar包引入
<dependencies>
<!-- SpringCloud Openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- SpringBoot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- SpringCloud Ailibaba Nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--阿里大于-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-dysmsapi</artifactId>
</dependency>
<!--阿里大于-->
</dependencies>
1.2 配置文件
server.port=9300
spring.application.name=sms
# 注册中心地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
# 允许熔断机制
feign.hystrix.enabled=true
#消息:
sms.accessKeyId=
sms.accessKeySecret=
1.3 controller
/**
* 短息服务
*
* @author lixy
*/
@RestController
@RequestMapping("/sms")
public class SmsController extends BaseController {
@Autowired
private SmsService smsService;
@PostMapping("/send")
public R<Map<String, String>> sendSms(@RequestParam("phoneNumbers") String phoneNumbers, @RequestParam("signName") String signName, @RequestParam("templateCode") String templateCode, @RequestParam("param") String param) {
Map<String, String> map = smsService.sendSms(phoneNumbers, signName, templateCode, param);
return R.ok(map);
}
}
1.4 service
public interface SmsService {
Map<String,String> sendSms(String phoneNumbers, String signName, String templateCode, String param);
}
1.5 impl
/**
* @author lixy
*/
@Service
public class SmsServiceImpl implements SmsService {
private final Logger logger = LoggerFactory.getLogger(SmsServiceImpl.class);
@Autowired
private SmsUtil smsUtil;
public Map<String,String> sendSms(String phoneNumbers, String signName, String templateCode, String param){
//调用发送短息的方法 ;
try {
SendSmsResponse response = smsUtil.sendSms(phoneNumbers, signName, templateCode, param);
//封装返回值给map
Map<String ,String> resultMap = new HashMap<String ,String>();
resultMap.put("Code",response.getCode());
resultMap.put("Message",response.getMessage());
resultMap.put("RequestId",response.getRequestId());
resultMap.put("BizId",response.getBizId());
return resultMap;
} catch (ClientException e) {
logger.error("短信发送失败:{}" , e.getMessage());
throw new CustomException("短信发送失败:" + e.getErrMsg());
}
}
}
1.5 SmsUtil
@Component
public class SmsUtil {
//产品名称:云通信短信API产品,开发者无需替换
static final String product = "Dysmsapi";
//产品域名,开发者无需替换
static final String domain = "dysmsapi.aliyuncs.com";
//加载properties中的key
@Value("${sms.accessKeyId}")
private String accessKeyId ;
@Value("${sms.accessKeySecret}")
private String accessKeySecret;
public SendSmsResponse sendSms(String phoneNumbers,String signName,String templateCode,String param) throws ClientException {
//可自助调整超时时间
System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
System.setProperty("sun.net.client.defaultReadTimeout", "10000");
//初始化acsClient,暂不支持region化
IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
IAcsClient acsClient = new DefaultAcsClient(profile);
//组装请求对象-具体描述见控制台-文档部分内容
SendSmsRequest request = new SendSmsRequest();
//必填:待发送手机号
request.setPhoneNumbers(phoneNumbers);
//必填:短信签名-可在短信控制台中找到
request.setSignName(signName);
//必填:短信模板-可在短信控制台中找到
request.setTemplateCode(templateCode);
//可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
request.setTemplateParam(param);
//选填-上行短信扩展码(无特殊需求用户请忽略此字段)
//request.setSmsUpExtendCode("90997");
//可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
request.setOutId("yourOutId");
//hint 此处可能会抛出异常,注意catch
SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
return sendSmsResponse;
}
public QuerySendDetailsResponse querySendDetails(String bizId,String phoneNumber) throws ClientException {
//可自助调整超时时间
System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
System.setProperty("sun.net.client.defaultReadTimeout", "10000");
//初始化acsClient,暂不支持region化
IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
IAcsClient acsClient = new DefaultAcsClient(profile);
//组装请求对象
QuerySendDetailsRequest request = new QuerySendDetailsRequest();
//必填-号码
request.setPhoneNumber(phoneNumber);
//可选-流水号
request.setBizId(bizId);
//必填-发送日期 支持30天内记录查询,格式yyyyMMdd
SimpleDateFormat ft = new SimpleDateFormat("yyyyMMdd");
request.setSendDate(ft.format(new Date()));
//必填-页大小
request.setPageSize(10L);
//必填-当前页码从1开始计数
request.setCurrentPage(1L);
//hint 此处可能会抛出异常,注意catch
QuerySendDetailsResponse querySendDetailsResponse = acsClient.getAcsResponse(request);
return querySendDetailsResponse;
}
}
1.6 启动类
/**
* @author lixy
*/
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableDiscoveryClient
public class SmsApplication {
public static void main(String[] args) {
SpringApplication.run(SmsApplication.class);
}
}
2. api(Feign+Hystrix熔断降级接口)
2.1 service接口
/**
* Feign调用远程
* ServiceNameConstants.SMS_SERVICE = "sms",短信服务名
*/
@FeignClient(contextId = "remoteSmsService", value = ServiceNameConstants.SMS_SERVICE, fallbackFactory = RemoteSmsServiceFactory.class)
public interface RemoteSmsService {
// 一定要加@RequestParam 否则调用时候会报错: 参数太长
@PostMapping("/sms/send")
public R<Map<String, String>> sendSms(@RequestParam("phoneNumbers") String phoneNumbers, @RequestParam("signName") String signName, @RequestParam("templateCode") String templateCode, @RequestParam("param") String param);
}
2.2 服务熔断降级
/**
* 降级处理
* @author lixy
*/
@Component
public class RemoteSmsServiceFactory implements FallbackFactory<RemoteSmsService> {
private static final Logger log = LoggerFactory.getLogger(RemoteSmsServiceFactory.class);
@Override
public RemoteSmsService create(Throwable cause) {
log.error("短信服务调用失败:{}", cause.getMessage());
return new RemoteSmsService() {
@Override
public R<Map<String, String>> sendSms(String phoneNumbers, String signName, String templateCode, String param) {
return R.fail("短信发送失败:" + cause.getMessage());
}
};
}
}
2.3 将降级处理加载到spring容器
spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.guanwei.sms.api.factory.RemoteSmsServiceFactory
3.服务消费者
3.1 jar包引入
<!-- SpringBoot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- SpringCloud Openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- SpringCloud Ailibaba Nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--atlas-sms-api-->
<dependency>
<groupId>com.yan</groupId>
<artifactId>atlas-sms-api</artifactId>
</dependency>
3.2 配置文件
# 注册地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
# 开启熔断
feign.hystrix.enabled=true
3.3 服务启动类
/**
* 系统应用启动项
* author: lixy
*/
@SpringBootApplication
@MapperScan("com.guanwei.atlas.system.mapper")
@EnableFeignClients(basePackages = {"com.yan.sms.api"}) //解决消费者找不到feign接口
@EnableDiscoveryClient // 注册到nacos,使其他服务发现
@EnableCircuitBreaker // 熔断
public class AtlasSystemApplicaiton {
public static void main(String[] args) {
SpringApplication.run(AtlasSystemApplicaiton.class);
}
}
@EnableDiscoveryClient // 注册到nacos,使其他服务发现
@EnableCircuitBreaker // 熔断
@SpringBootApplication
这三个可以用
@SpringCloudApplication代替
3.4 SysUserController
/**
* 发送短信
* @param phone
* @return
*/
@RequestMapping("/sendSmsCode")
public R<?> sendSmsCode(String phone){
sysUserService.sendSmsCode(phone);
return R.ok(true,"短信发送成功");
}
3.5 SysUserServiceImpl
/**
* 用户信息Service业务层处理
*
* @author lixy
* @date 2021-01-06
*/
@Service
public class SysUserServiceImpl implements ISysUserService {
@Autowired
private RemoteSmsService smsService;
@Value("岩")
private String signName;
@Value("SMS_16*******")
private String templateCode;
@Autowired
private RedisTemplate redisTemplate;
//发送短信的方法:需要httpClient发送url,就是调用阿里云发送短信;
public void sendSmsCode(String phone) {
//1.生成动态的6位验证码:
int num = (int) (Math.random() + 1);
String smsCode = num + RandomStringUtils.randomNumeric(5);//因为当第一个数字是0的时候阿里云默认去掉0;
//2.将生成的验证码保存到redis中15分钟,
redisTemplate.boundValueOps(phone).set(smsCode, 15L, TimeUnit.MINUTES);
String param = "{\"code\":" + smsCode + "}";
R<Map<String, String>> result = smsService.sendSms(phone, signName, templateCode, param);
if(result.getCode() == 200){
Map<String, String> response = result.getData();
if (!response.get("Code").equals("200")) {
throw new CustomException(result.getMsg());
}
}else{
throw new CustomException(result.getMsg());
}
}
}
如果有其他消费者想调用sms,直接引入api的jar就好啦!!! 希望对大家有所帮助~~