1.
思路1:拦截器
feign.RequestInterceptor
发送http 请求之前,会有拦截器将当前请求的 请求头信息都拦截并封装,请求下一个微服务的时候就会携带这些请求头信息,代码如下:
package com.pay.config;
import feign.RequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
/**
*
* tongyi peizhi
* @author feign diaoyong gei xia ge fuwu chuan di qingqiu tou xinxi
* @description $
* @date 2021/12/24$
*/
@Configuration
public class FeignConfig {
@Bean
public RequestInterceptor headerInterceptor() {
return template -> {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (null != attributes) {
HttpServletRequest request = attributes.getRequest();
Enumeration<String> headerNames = request.getHeaderNames();
if (headerNames != null) {
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
String values = request.getHeader(name);
template.header(name, values);
}
}
}
};
}
}
核心代码如下:
①添加依赖 ②启动类添加开启feign调用的 注解 ③ 实现业务的 feign
①
<!--openFeign start -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
<!--openFeign call server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign-core</artifactId>
</dependency>
<!--feign gei xia ge wu fa chuandi qingqiu tou de -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
</dependency>
<!--openFeign end -->
② 启动类开启 feign 调用的注解
@SpringBootApplication
@EnableDiscoveryClient
//excludeFilters这里的意思是,只要标有ExcludeFromComponetScan注解的类都不会去扫描
//@ComponentScan(value = "com", excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value= ExcludeFromComponetScan.class)})
@MapperScan(basePackages = "com.pay.mapper")
// bukaiqi feign diaoyong shibai
@EnableFeignClients
public class PayServiceApplication {
public static void main(String[] args) {
SpringApplication.run(PayServiceApplication.class, args);
}
}
③业务feign
package com.pay.api;
import com.pay.config.FeignConfig;
import com.pay.feignFailback.OrderFeignFailback;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
*
*/
@FeignClient(
// order-service target micro service name
name = "order-service",
fallback = OrderFeignFailback.class,
// package headers to next micro service request
configuration = FeignConfig.class)
public interface OrderFeignApi {
/**
* jia @RequestParam de yuanyin :Method has too many Body parameters
*
* update order status
**/
@RequestMapping(value = "/order/updateOrderStatus")
String updateOrderStatus(@RequestParam("orderNo") String orderNo, @RequestParam("status") String status);
}
代码结构如下:
配置文件:
server.port=8094
# meiyou yingyong mingcheng hui baocuo No service to register for nacos client...
# 这个微服务名称必须有否则注册不到nacos 上
spring.application.name=pay-service
#appID
#wx1a299b41e85d4b6d
#appsecret
#34b1d847bf6eb5f7ab58e7ea6a6171b4
#应用ID
payconfig.weixin.appId=wx9f1fa58451efa9b2
#商户ID号
payconfig.weixin.mchID=daishenqing
#秘钥
payconfig.weixin.key=QS8rrOI出于安全考虑,请自行申请TQCfI1
#默认回调地址
payconfig.weixin.notifyUrl = http://2cw4969042.wicp.vip:50381/wx/result
#证书存储路径
payconfig.weixin.certPath= D:/myproject/project2021/weifuwujiagou/weifuwujiagou/springcloud/pay-service/src/main/resources/apiclient_cert.p12
#支付安全校验(验签)
#AES加密秘钥
payconfig.aes.skey=ab2cc473d3334c39
#验签盐
payconfig.aes.salt=XPYQZb1kMES8HNaJWW8+TDu/4JdBK4owsU9eXCXZDOI=
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/read_data?useUnicode=true&characterEncoding=UTF-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
#nacos服务发现中心
#spring.application.name=pay-service meiyou yingyong mingcheng hui zhuce bushang o
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
#spring.cloud.nacos.config.server-addr=127.0.0.1:8848
management.endpoints.web.exposure.include=*
#spring.cloud.nacos.config.file-extension=properties
# true为注册服务到nacos上,false为不注册
spring.cloud.service-registry.auto-registration.enabled=true
调用错后 的 回调 method:
package com.pay.feignFailback;
import com.pay.api.OrderFeignApi;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* bu chang
*/
@Component
@Slf4j
public class OrderFeignFailback implements OrderFeignApi {
@Override
public String updateOrderStatus(String orderNo, String status) {
log.error("diao yong order-service failed!!");
return null;
}
}
测试代码:
service
package com.pay.service;
public interface OrderService {
/**
* 功能描述 call order-service to updateOrderStatus
* @author guoyiguang
* @date 2021/12/24
* @param
* @return
*/
String updateOrderStatus(String orderNo,String status);
}
实现类:
package com.pay.service.impl;
import com.pay.api.OrderFeignApi;
import com.pay.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author guoyiguang
* @description $
* @date 2021/12/24$
*/
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
@Autowired
OrderFeignApi orderFeignApi ;
@Override
public String updateOrderStatus(String orderNo, String status) {
try {
log.info("to call order-service ' updateOrderStatus params : orderNo {} ,status {}",orderNo,status);
String result = orderFeignApi.updateOrderStatus(orderNo, status);
log.info(" called order-service ' updateOrderStatus result : {} ",result);
return result;
} catch (Exception e) {
log.error("call order-service ' updateOrderStatus failed, cause : {}",e.getMessage());
}
return StringUtils.EMPTY;
}
}
controller:
package com.pay.controller;
import com.pay.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/*****
* @Author:
* @Description:
****/
@RestController
@RequestMapping(value = "/pay-order")
@CrossOrigin
@Slf4j
public class PayOrderController {
@Autowired
OrderService orderService ;
/**
*
* update order status
**/
@RequestMapping(value = "/updateOrderStatus")
public String updateOrderStatus(String orderNo,String status) throws Exception {
log.info("enter in updateOrderStatus params : orderNo {} ,status {} ",orderNo,status);
String result = orderService.updateOrderStatus(orderNo, status);
return result;
}
}
接下来 用上面的 pay-service 去调用 order-service 的方法
order-serivce 的测试方法:
package com.order.controller;
import com.alibaba.fastjson.JSON;
import com.order.service.ContractService;
import com.order.utils.WebUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
/*****
* @Author:
* @Description:
****/
@RestController
@RequestMapping(value = "/order")
@CrossOrigin
@Slf4j
public class OrderController {
@Autowired
private ContractService contractService;
@GetMapping(value = "/hello")
public String pay() throws Exception {
return "hello!I am order-service!!";
}
/**
*
* localhost:8092/order/contractService?orderNo=VIP20211215000001
**/
@RequestMapping(value = "/contractService")
public String contractService(String orderNo) throws Exception {
String url = "http://" + "localhost:" + 8094 + "/pay-service/callBack/updateOrderStatus";
contractService.sendContractRetry(url,orderNo);
return "contractService retry test!";
}
/**
*
* update order status
**/
@RequestMapping(value = "/updateOrderStatus")
public String updateOrderStatus(String orderNo,String status) throws Exception {
log.info("enter in updateOrderStatus params : orderNo {} ,status {} ",orderNo,status);
HttpServletRequest request = WebUtil.getRequest();
Enumeration<String> headerNames = request.getHeaderNames();
Map<String,String> result = new HashMap<>();
result.put("orderNo",orderNo);
result.put("status",status);
if (headerNames != null) {
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
String values = request.getHeader(name);
result.put(name, values);
}
// return
return JSON.toJSONString(result);
}
return " call updateOrderStatus success !";
}
}
说明:上面 用到一个工具类,在代码的任何地方获取 request 对象和 Response对象?
package com.order.utils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author guoyiguang
* @description houqu Request duixiang he Response duixiang
* @date 2021/12/24$
*/
public class WebUtil {
/** 获取request对象 **/
public static HttpServletRequest getRequest(){
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (requestAttributes == null){
return null;
}
return ((ServletRequestAttributes)requestAttributes).getRequest();
}
/** 获取response对象 **/
public static HttpServletResponse getResponse(){
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (requestAttributes == null){
return null;
}
return ((ServletRequestAttributes)requestAttributes).getResponse();
}
}
原理:
postMan测试:
响应结果格式化后:(说明 pay-serivce 将请求头信息传给了 order-service)
{
"orderNo": "OrderNo_123",
"user-agent": "PostmanRuntime/7.28.4",
"postman-token": "a30ba86d-8208-4a10-8380-b0ec6e1420bb",
"host": "192.168.60.84:8092",
"connection": "keep-alive",
"accept-encoding": "gzip, deflate, br",
"status": "0",
"accept": "*/*",
"user-id": "user-id-value",
"user-name": "user-name-value",
"token": "token_value"
}
测试的前提: