1. 主函数中引入@EnableFeignClients, ruoyi版本3.8.6
@EnableFeignClients
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class RuoYiApplication {
public static void main(String[] args) {
SpringApplication.run(RuoYiApplication.class, args);
}
}
2. 在业务模块里面引入openfeign
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
<dependency>
<groupId>com.google.code.gsongroupId>
<artifactId>gsonartifactId>
<version>2.6version>
dependency>
dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>Hoxton.SR1version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
3. 在父pom中引入springboot依赖配置
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>2.2.2.RELEASEversion>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
4. 在yml中添加feign的相关配置
# 是否开启hystrix。true:开启,false:不开启, 不开启的话feign调用失败不回走到回调函数里面
# 详细解释(当设置为 true 时,如果Feign客户端调用远程服务失败,Hystrix回退逻辑将被触发。如果为 false,Feign将简单地抛出异常,不会触发回退逻辑。)
feign:
hystrix:
enabled: true
rpc:
wbOauth2Service: https://api.weibo.com/oauth2
# hystrix超时时间, 不设置feign调用会很快超时,设置 Hystrix 命令的默认超时时间。如果远程服务调用的响应时间超过这个设置的值,Hystrix将认为这个命令失败,并触发回退逻辑
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 10000
# 请求参数
wb:
appKey: 66386414
appSecret: f4f9b07509d4cdab57c45917d92081d
5. 在业务模块中添加config文件, 放到相关配置文件
package com.ruoyi.business.config;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Configuration;
import javax.servlet.http.HttpServletRequest;
@Configuration
public class FeignConfig implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
HttpServletRequest httpServletRequest = ServletUtils.getRequest();
if (StringUtils.isNotNull(httpServletRequest)) {
}
}
}
package com.ruoyi.business.config;
import com.netflix.hystrix.HystrixThreadPoolKey;
import com.netflix.hystrix.HystrixThreadPoolProperties;
import com.netflix.hystrix.strategy.HystrixPlugins;
import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestVariable;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestVariableLifecycle;
import com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifier;
import com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook;
import com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisher;
import com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;
import com.netflix.hystrix.strategy.properties.HystrixProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Component
public class FeignHystrixConcurrencyStrategyIntellif extends HystrixConcurrencyStrategy {
Logger log = LoggerFactory.getLogger(this.getClass());
private HystrixConcurrencyStrategy delegate;
public FeignHystrixConcurrencyStrategyIntellif() {
try {
this.delegate = HystrixPlugins.getInstance().getConcurrencyStrategy();
if (this.delegate instanceof FeignHystrixConcurrencyStrategyIntellif) {
return;
}
HystrixCommandExecutionHook commandExecutionHook =
HystrixPlugins.getInstance().getCommandExecutionHook();
HystrixEventNotifier eventNotifier = HystrixPlugins.getInstance().getEventNotifier();
HystrixMetricsPublisher metricsPublisher = HystrixPlugins.getInstance().getMetricsPublisher();
HystrixPropertiesStrategy propertiesStrategy =
HystrixPlugins.getInstance().getPropertiesStrategy();
this.logCurrentStateOfHystrixPlugins(eventNotifier, metricsPublisher, propertiesStrategy);
HystrixPlugins.reset();
HystrixPlugins instance = HystrixPlugins.getInstance();
instance.registerConcurrencyStrategy(this);
instance.registerCommandExecutionHook(commandExecutionHook);
instance.registerEventNotifier(eventNotifier);
instance.registerMetricsPublisher(metricsPublisher);
instance.registerPropertiesStrategy(propertiesStrategy);
} catch (Exception e) {
log.error("Failed to register Sleuth Hystrix Concurrency Strategy", e);
}
}
private void logCurrentStateOfHystrixPlugins(HystrixEventNotifier eventNotifier,
HystrixMetricsPublisher metricsPublisher,
HystrixPropertiesStrategy propertiesStrategy) {
if (log.isDebugEnabled()) {
log.debug("Current Hystrix plugins configuration is [" + "concurrencyStrategy ["
+ this.delegate + "]," + "eventNotifier [" + eventNotifier + "]," + "metricPublisher ["
+ metricsPublisher + "]," + "propertiesStrategy [" + propertiesStrategy + "]," + "]");
log.debug("Registering Sleuth Hystrix Concurrency Strategy.");
}
}
@Override
public <T> Callable<T> wrapCallable(Callable<T> callable) {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
return new WrappedCallable<>(callable, requestAttributes);
}
@Override
public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey,
HystrixProperty<Integer> corePoolSize,
HystrixProperty<Integer> maximumPoolSize,
HystrixProperty<Integer> keepAliveTime,
TimeUnit unit, BlockingQueue<Runnable> workQueue) {
return this.delegate.getThreadPool(threadPoolKey, corePoolSize, maximumPoolSize, keepAliveTime,
unit, workQueue);
}
@Override
public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey,
HystrixThreadPoolProperties threadPoolProperties) {
return this.delegate.getThreadPool(threadPoolKey, threadPoolProperties);
}
@Override
public BlockingQueue<Runnable> getBlockingQueue(int maxQueueSize) {
return this.delegate.getBlockingQueue(maxQueueSize);
}
@Override
public <T> HystrixRequestVariable<T> getRequestVariable(HystrixRequestVariableLifecycle<T> rv) {
return this.delegate.getRequestVariable(rv);
}
static class WrappedCallable<T> implements Callable<T> {
private final Callable<T> target;
private final RequestAttributes requestAttributes;
public WrappedCallable(Callable<T> target, RequestAttributes requestAttributes) {
this.target = target;
this.requestAttributes = requestAttributes;
}
@Override
public T call() throws Exception {
try {
RequestContextHolder.setRequestAttributes(requestAttributes);
return target.call();
} finally {
RequestContextHolder.resetRequestAttributes();
}
}
}
}
package com.ruoyi.business.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@Data
@ConfigurationProperties(prefix = "wb")
public class WbConfig {
private String appKey;
private String appSecret;
}
6. 新建factory和service文件夹, 放请求接口
package com.ruoyi.business.factory;
import com.ruoyi.business.domain.dto.WxOAuth2RequestDTO;
import com.ruoyi.business.rpc.RemoteWbOauth2Rpc;
import feign.hystrix.FallbackFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class RemoteEEapiRpcFallbackFactory implements FallbackFactory<RemoteWbOauth2Rpc> {
@Override
public RemoteWbOauth2Rpc create(Throwable throwable) {
log.error("调用微博oauth2接口出错:", throwable);
return new RemoteWbOauth2Rpc() {
@Override
public String authorize(String clientId, String redirectUri, String state) {
return "调用请求用户授权code接口出错:" + throwable.getMessage();
}
@Override
public String accessToken(String appKey, String appSecret, String authorizationCode, String redirectUri, String code) {
return "调用获取access_token接口出错:" + throwable.getMessage();
}
@Override
public String accessToken2(WxOAuth2RequestDTO dto) {
return "调用获取access_token接口出错:" + throwable.getMessage();
}
};
}
}
package com.ruoyi.business.rpc;
import com.ruoyi.business.config.FeignConfig;
import com.ruoyi.business.factory.RemoteEEapiRpcFallbackFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(name = "wbOauth2Service", url = "${feign.rpc.wbOauth2Service}", configuration = FeignConfig.class, fallbackFactory = RemoteEEapiRpcFallbackFactory.class)
public interface RemoteWbOauth2Rpc {
@GetMapping(value = "/authorize?client_id={clientId}&redirect_uri={redirectUri}&response_type=code&state={state}", consumes = MediaType.APPLICATION_JSON_VALUE)
String authorize(@PathVariable("clientId") String clientId, @PathVariable("redirectUri") String redirectUri,@PathVariable("state") String state);
@PostMapping(value = "/access_token", consumes = MediaType.APPLICATION_JSON_VALUE)
String accessToken(@RequestParam("client_id") String appKey, @RequestParam("client_secret") String appSecret,@RequestParam("grant_type") String authorizationCode, @RequestParam("redirect_uri") String redirectUri,@RequestParam("code") String code);
@PostMapping(value = "/access_token",consumes = MediaType.APPLICATION_JSON_VALUE)
String accessToken2(@RequestBody WxOAuth2RequestDTO dto);
}
7. 实际service调用, 解析返回值的两种方式
package com.ruoyi.business.service;
import com.google.gson.Gson;
import com.ruoyi.business.config.IpConfig;
import com.ruoyi.business.config.WbConfig;
import com.ruoyi.business.domain.dto.WbOAuth2UserInfoDTO;
import com.ruoyi.business.domain.vo.IpVO;
import com.ruoyi.business.rpc.RemoteIpRpc;
import com.ruoyi.business.rpc.RemoteWbOauth2Rpc;
import com.ruoyi.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
@Slf4j
public class FeignService {
@Resource
private RemoteWbOauth2Rpc remoteWbOauth2Rpc;
public WbOAuth2UserInfoDTO getAccessTokenWb(String code, String redirectUri) {
if (StringUtils.isEmpty(code)) {
throw new RuntimeException("code不能为空");
}
if (StringUtils.isEmpty(redirectUri)) {
throw new RuntimeException("redirectUri不能为空");
}
String responseStr = remoteWbOauth2Rpc.accessToken(wbConfig.getAppKey(), wbConfig.getAppSecret(), "authorization_code", redirectUri, code);
Gson gson = new Gson();
WbOAuth2UserInfoDTO response = null;
try {
response = gson.fromJson(responseStr, WbOAuth2UserInfoDTO.class);
} catch (Exception e) {
log.error("获取access_token后用户信息response:{}", responseStr);
throw new RuntimeException("授权失败, 请稍后尝试");
}
log.info("获取access_token后用户信息response:{}", response);
return response;
}
public String getAuthUrlWb(String url, String state) {
return remoteWbOauth2Rpc.authorize(wbConfig.getAppKey(), url, state);
}
}
8. 有时候springboot版本问题需要调整下跨越
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
config.setMaxAge(1800L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}