没接触过feign之前,调用第三方接口都是通过httpclient,通过编写工具类实现,这种方式代码量很多,相比较feign调用来说特别繁琐,而feign简化底层http调用方式,通过feign.builder.target传入调用接口和地址即可完成调用吗,代码量相当少。
httpClient方式
httpclient工具类:
package com.fh.oa.apply.util;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.log4j.Log4j2;
import org.apache.http.StatusLine;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.util.Map;
/**
* @author wangzewei
* @ClassName HttpClientUtils
* @Description 调用工具类,目前只提供get和post,其他请求方式,有需要在添加
* @Date 2021/7/27 9:43
*/
@Log4j2
public class HttpClientUtils {
/**
* 发送get请求,无参
* @param url 请求地址
* @return
*/
public static String get(String url){
return getWithParam(url,null);
}
/**
* 发送get请求,有参
* @param url 请求地址
* @param map 携带参数
* @return 返回json串
*/
public static String getWithParam(String url, Map<String,Object> map){
//返回的json结果
String jsonResponse="";
//client对象
CloseableHttpClient client = HttpClientBuilder.create().build();
//get请求对象
HttpGet hGet=null;
String uri="";
// 配置连接参数
RequestConfig requestConfig = RequestConfig.custom()
// 设置连接超时时间
.setConnectTimeout(5000)
// 设置请求超时时间
.setConnectionRequestTimeout(5000)
// socket读写超时时间
.setSocketTimeout(5000)
// 设置是否允许重定向
.setRedirectsEnabled(true).build();
//解析参数 key=xxx
StringBuilder sb=new StringBuilder();
if(null!=map){
map.keySet().forEach(s -> sb.append(s).append("=").append(map.get(s)).append("&"));
//去掉多于的&
sb.deleteCharAt(sb.length() - 1);
uri=url+"?"+sb.toString();
hGet=new HttpGet(uri);
}else{
uri=url;
hGet=new HttpGet(uri);
}
log.info("本次Get调用地址:"+uri);
hGet.setConfig(requestConfig);
//响应
CloseableHttpResponse response=null;
try {
response = client.execute(hGet);
StatusLine statusLine = response.getStatusLine();
if(null!=response.getEntity()&&200==statusLine.getStatusCode()){
jsonResponse = EntityUtils.toString(response.getEntity());
}else{
log.error("Get请求返回异常");
}
} catch (IOException e) {
e.printStackTrace();
log.error("Get请求执行失败");
}finally {
try {
if(null!=client){
client.close();
}
if(null!=response){
response.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return jsonResponse;
}
/**
* 发送post请求,无参
* @param url 请求地址
* @return
*/
public static String post(String url){
return postWithParam(url,null);
}
/**
* 发送post请求,map参数转json格式传递
* @param url 请求地址
* @param map 请求参数
* @return json字符串
*/
public static String postWithParam(String url, Map<String,Object> map){
//返回的json结果
String jsonResponse="";
//client对象
CloseableHttpClient client = HttpClientBuilder.create().build();
//post请求对象
HttpPost hPost=new HttpPost(url);
if(null!=map){
//map对象转json字符串
String jsonString = new JSONObject(map).toJSONString();
StringEntity stringEntity=new StringEntity(jsonString,"UTF-8");
//将参数放在post请求体中
hPost.setEntity(stringEntity);
}
//设置请求头
hPost.setHeader("Content-Type", "application/json;charset=utf-8");
//响应
CloseableHttpResponse response=null;
try {
response = client.execute(hPost);
StatusLine statusLine = response.getStatusLine();
if(null!=response.getEntity()&&200==statusLine.getStatusCode()){
jsonResponse = EntityUtils.toString(response.getEntity());
}else{
log.error("Post请求执行异常");
}
} catch (IOException e) {
e.printStackTrace();
log.error("Post请求执行失败");
}finally {
try {
if(null!=client){
client.close();
}
if(null!=response){
response.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return jsonResponse;
}
}
/** * @author wangzewei * @ClassName Common * @Description 接口调用时通用参数 * @Date 2021/7/27 15:29 */ public class Common { public static Map<String,Object> getCommon(){ Map<String ,Object> map=new HashMap<>(); map.put("isEncrypt", false); map.put("random", UUID.randomUUID()); map.put("timestamp", new Date().getTime()); return map; } }
调用方式:
public String getToken(){ //common参数 Map<String, Object> map = Common.getCommon(); //登录认证 AuthInfo info=new AuthInfo(){{ setAccount("ab8d181174a942088616381525e078a7"); setPassword("SHOCvfyYtjL5xFU5JAM4"); }}; map.put("param",info); String response = HttpClientUtils.postWithParam(tokenUrl, map); String accessToken=""; // TODO: 2021/7/27 感觉这块不用存redis,获取的token有过期时间,而且在监听中可以直接取到token的值 if(null!=response){ //json转成map Map map1 = JSON.parseObject(response, Map.class); JSONObject data = (JSONObject)map1.get("data"); accessToken= (String)data.get("accessToken"); //存redis redisService.setKey("accessToken",accessToken); } //返回token串 return accessToken; }
feign简化调用方式
feign绑定接口:
参数对象:
返回值对象:
调用方式:
TongChengService t = Feign.builder().target(TongChengService.class, "http://api.qa.dttrip.cn/openapi/api");
这么调用会报异常
翻译过来就是带feign的调用方式是个mvc的调用方式不共通,可以采用编写service类,导入feign的配置解决
feign的实现类:
package com.fh.oa.feign; import java.io.BufferedReader; import java.io.IOException; import java.util.Enumeration; import javax.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.openfeign.FeignClientsConfiguration; import org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient; import org.springframework.context.annotation.Import; import org.springframework.stereotype.Service; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import com.alibaba.fastjson.JSONObject; import com.codingapi.txlcn.tracing.Tracings; import feign.Client; import feign.Contract; import feign.Feign; import feign.RequestInterceptor; import feign.Response; import feign.codec.Decoder; import feign.codec.Encoder; import feign.codec.ErrorDecoder; import lombok.extern.log4j.Log4j2; @Service @Import(FeignClientsConfiguration.class) @Log4j2 public class FeignServiceImpl implements FeignService { private final Feign.Builder urlBuilder; private final Feign.Builder nameBuilder; private HttpServletRequest cacheRequest; @Autowired public FeignServiceImpl(Decoder decoder, Encoder encoder, Client client, Contract contract) { // nameBuilder直接使用client,它会使用负载均衡 nameBuilder = Feign.builder().client(client).encoder(encoder).decoder(decoder).contract(contract) .requestInterceptor(requestInterceptor()).errorDecoder(errorDecoder()); if (client instanceof LoadBalancerFeignClient) { // 均衡负载 client = ((LoadBalancerFeignClient) client).getDelegate(); } urlBuilder = Feign.builder().client(client).encoder(encoder).decoder(decoder).contract(contract) .requestInterceptor(requestInterceptor()).errorDecoder(errorDecoder()); } @Override public <T> T newInstanceByUrl(Class<T> apiType, String url) { return urlBuilder.target(apiType, url); } @Override public <T> T newInstanceByName(Class<T> apiType, String name) { return nameBuilder.target(apiType, name); } @Override public <T> T newInstanceByUrl(Class<T> apiType, String url, HttpServletRequest request) { this.cacheRequest = request; return urlBuilder.target(apiType, url); } @Override public <T> T newInstanceByName(Class<T> apiType, String name, HttpServletRequest request) { this.cacheRequest = request; return nameBuilder.target(apiType, name); } }
调用:
对比更简单