Spring MVC 是支持 GET/POST 多参数传递的,但是 Feign 并没有实现所有的 Spring MVC 的功能,暂时是不支持 GET 的 POJO 传递方法。一般的解决办法有一下三种:
- 把 POJO 拆散成一个一个单独的属性放在方法参数里。
- 把方法参数变成 Map 传递。
- 使用 GET 传递
@Requestbody
,但此方式违反 RESTFul 规范。
以上三种方法都是可以的,这里要使用的方法是 Feign 的 RequestInterceptor 进行统一的处理,当检测到请求方法为 GET 时,把请求体里面的内容重新拼装成请求参数的形式。
- 消费者的 Controller
/**
* @Author:大漠知秋
* @Description:测试 FeignGetInterceptor 的 Controller
* @CreateDate:2:38 PM 2018/10/25
*/
@RestController
@RequestMapping("/feignGet")
public class FeignGetInterceptorController {
@Resource
private FeignGetInterceptorFeign feignGetInterceptorFeign;
@RequestMapping(
value = "/addUser",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE
)
ResponseEntity<byte[]> addUser(User user) {
return feignGetInterceptorFeign.addUser(user);
}
@RequestMapping(
value = "/updateUser",
method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE
)
ResponseEntity<byte[]> updateUser(@RequestBody User user) {
return feignGetInterceptorFeign.updateUser(user);
}
}
- 消费者的 Feign
@FeignClient(name = "demo-goods")
public interface FeignGetInterceptorFeign {
@RequestMapping(
value = "/feignGet/addUser",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE
)
ResponseEntity<byte[]> addUser(User user);
@RequestMapping(
value = "/feignGet/updateUser",
method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE
)
ResponseEntity<byte[]> updateUser(@RequestBody User user);
}
- 提供者的 Controller
/**
* @Author:大漠知秋
* @Description:测试 FeignGetInterceptor 的 Controller
* @CreateDate:2:38 PM 2018/10/25
*/
@RestController
@RequestMapping("/feignGet")
public class FeignGetInterceptorController {
@RequestMapping(
value = "/addUser",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE
)
User addUser(User user) {
user.setAge(user.getAge() + 1);
user.setUsername(user.getUsername() + "1");
user.setBirthday(new Date());
return user;
}
@RequestMapping(
value = "/updateUser",
method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE
)
User updateUser(@RequestBody User user) {
user.setAge(user.getAge() + 1);
user.setUsername(user.getUsername() + "1");
user.setBirthday(new Date());
return user;
}
}
没有加拦截器之前,请求 GET 方式,会报如下错误:
- 增加 Feign 拦截器
/**
* 拦截使用 Get 请求,并且使用的时 POJO 请求方式的 Feign 请求
*
* @author 大漠知秋
* @date 2019-03-27 17:35
*/
@Component
@Slf4j
public class FeignRequestInterceptor implements RequestInterceptor {
@Resource
private ObjectMapper objectMapper;
/**
* 如果是 GET 方式并且 请求体 不为空,那么把请求体转换成请求参数,防止自动转换成 POST 方式
* * 并不推荐使用 GET 方式传输请求体内容,建议更改为 POST 方式
*
* @param template Feign 低层发送 Http 请求模板工具
*/
@Override
public void apply(RequestTemplate template) {
if (HttpMethod.GET.name().equals(template.method())
&& null != template.body()) {
try {
JsonNode jsonNode = objectMapper.readTree(template.body());
template.body(null);
Map<String, Collection<String>> queries = new HashMap<>(16);
buildQuery(jsonNode, "", queries);
template.queries(queries);
} catch (IOException e) {
log.error("【拦截 GET 请求 POJO 方式】-出错了:{}", ExceptionUtils.getStackFrames(e));
throw new RuntimeException();
}
}
}
/**
* 构建请求参数
*
* @param jsonNode 原始数据
* @param path json 节点
* @param queries 构建购的请求参数集合
*/
private void buildQuery(JsonNode jsonNode, String path, Map<String, Collection<String>> queries) {
// 叶子节点
if (!jsonNode.isContainerNode()) {
if (jsonNode.isNull()) {
return;
}
Collection<String> values = queries.get(path);
if (null == values) {
values = new ArrayList<>();
queries.put(path, values);
}
values.add(jsonNode.asText());
return;
}
// 数组节点
if (jsonNode.isArray()) {
Iterator<JsonNode> it = jsonNode.elements();
while (it.hasNext()) {
buildQuery(it.next(), path, queries);
}
} else {
Iterator<Map.Entry<String, JsonNode>> it = jsonNode.fields();
while (it.hasNext()) {
Map.Entry<String, JsonNode> entry = it.next();
if (StringUtils.hasText(path)) {
buildQuery(entry.getValue(), path + "." + entry.getKey(), queries);
} else { // 根节点
buildQuery(entry.getValue(), entry.getKey(), queries);
}
}
}
}
}
- Model
@Data
public class User {
private String username;
private Integer age;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date birthday;
}
- 结果:
源码:https://github.com/SlowSlicing/demo-spring-cloud-finchley/tree/FeignGETRequestMoreParameter
文章评论