大漠知秋的加油站

  • 首页
大漠知秋的加油站
你就当我的烂笔头吧
  1. 首页
  2. Spring Cloud Finchley.RELEASE
  3. 正文

Feign GET 多参数传递

2019年1月3日 266点热度 0人点赞 0条评论

  Spring MVC 是支持 GET/POST 多参数传递的,但是 Feign 并没有实现所有的 Spring MVC 的功能,暂时是不支持 GET 的 POJO 传递方法。一般的解决办法有一下三种:

  • 把 POJO 拆散成一个一个单独的属性放在方法参数里。
  • 把方法参数变成 Map 传递。
  • 使用 GET 传递 @Requestbody,但此方式违反 RESTFul 规范。

  以上三种方法都是可以的,这里要使用的方法是 Feign 的 RequestInterceptor 进行统一的处理,当检测到请求方法为 GET 时,把请求体里面的内容重新拼装成请求参数的形式。

  1. 消费者的 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);
    }

}
  1. 消费者的 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);

}
  1. 提供者的 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 方式,会报如下错误:

报错

  1. 增加 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);
                }
            }
        }
    }

}
  1. 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;

}
  1. 结果:

GET 请求

POST 请求

源码:https://github.com/SlowSlicing/demo-spring-cloud-finchley/tree/FeignGETRequestMoreParameter

标签: Feign GET Parameter Spring Cloud
最后更新:2019年3月27日

大漠知秋

唯黄昏而思烛明,唯覆雪始念日暖,唯放手方知情真,今困苦而怀峥嵘,今飘零而涌乡愁,今孑然而徒唏嘘,唏嘘成愁。

点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

COPYRIGHT © 2022 大漠知秋的加油站. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang