Как настроить расширитель @FeignClient для преобразования параметра?

Притворитесь расширителем по умолчанию для преобразования параметра:

final class ToStringExpander implements Expander {

    @Override
    public String expand(Object value) {
      return value.toString();
    }
  }

Я хочу, чтобы он преобразовывал пользователя в поддержку параметра GET, например

@FeignClient("xx")
interface UserService{

   @RequestMapping(value="/users",method=GET)
   public List<User> findBy(@ModelAttribute User user);
}

userService.findBy(user);

Что я могу сделать?


person Dreampie    schedule 25.02.2016    source источник
comment
Возможный дубликат Клиент Spring Cloud Feign не может использовать @ModelAttribute?   -  person spencergibb    schedule 25.02.2016
comment
Я знаю это, я думаю, что это расширитель Feign по умолчанию toString, если изменить его, чтобы расширить с помощью user.attr1=xx&user.attr2=xx, возможно, это поможет.   -  person Dreampie    schedule 26.02.2016


Ответы (3)


Во-первых, вы должны написать расширитель, например ToJsonExpander:

public class ToJsonExpander implements Param.Expander {

  private static ObjectMapper objectMapper = new ObjectMapper();

  public String expand(Object value) {
    try {
      return objectMapper.writeValueAsString(value);
    } catch (JsonProcessingException e) {
      throw new ExpanderException(e);
    }
  }
}

Во-вторых, напишите AnnotatedParameterProcessor как JsonArgumentParameterProcessor, чтобы добавить расширитель для вашего процессора.

public class JsonArgumentParameterProcessor implements AnnotatedParameterProcessor {

  private static final Class<JsonArgument> ANNOTATION = JsonArgument.class;

  public Class<? extends Annotation> getAnnotationType() {
    return ANNOTATION;
  }

  public boolean processArgument(AnnotatedParameterContext context, Annotation annotation) {
    MethodMetadata data = context.getMethodMetadata();
    String name = ANNOTATION.cast(annotation).value();
    String method = data.template().method();

    Util.checkState(Util.emptyToNull(name) != null,
        "JsonArgument.value() was empty on parameter %s", context.getParameterIndex());

    context.setParameterName(name);

    if (method != null && (HttpMethod.POST.matches(method) || HttpMethod.PUT.matches(method) || HttpMethod.DELETE.matches(method))) {
      data.formParams().add(name);
    } else {
      `data.indexToExpanderClass().put(context.getParameterIndex(), ToJsonExpander.class);`
      Collection<String> query = context.setTemplateParameter(name, data.template().queries().get(name));
      data.template().query(name, query);
    }

    return true;
  }
}

В-третьих, добавьте его в конфигурацию Feign.

  @Bean
  public Contract feignContract(){
    List<AnnotatedParameterProcessor> processors = new ArrayList<>();
    processors.add(new JsonArgumentParameterProcessor());
    processors.add(new PathVariableParameterProcessor());
    processors.add(new RequestHeaderParameterProcessor());
    processors.add(new RequestParamParameterProcessor());
    return new SpringMvcContract(processors);
  }

Теперь вы можете использовать @JsonArgument для отправки аргумента модели, например:

public void saveV10(@JsonArgument("session") Session session);
person Dreampie    schedule 07.03.2016
comment
JsonArgumentParameterProcessor должен содержать data.indexToExpander().put(context.getParameterIndex(), new ToJsonExpander()); - person talipkorkmaz; 20.04.2018
comment
Существуют ли какие-либо методы, которые не должны изменять исходный код? (как АОП) - person Frank.Chang; 30.04.2019

Я не знаю, что делает @ModelAttribute, но я искал способ конвертировать значения @RequestParam, поэтому я сделал это:

import com.google.i18n.phonenumbers.PhoneNumberUtil;
import com.google.i18n.phonenumbers.Phonenumber;
import org.springframework.cloud.netflix.feign.FeignFormatterRegistrar;
import org.springframework.format.FormatterRegistry;
import org.springframework.stereotype.Component;

import static com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat.E164;

@Component
public class PhoneNumberFeignFormatterRegistrar implements FeignFormatterRegistrar {
    private final PhoneNumberUtil phoneNumberUtil;

    public PhoneNumberFeignFormatterRegistrar(PhoneNumberUtil phoneNumberUtil) {
        this.phoneNumberUtil = phoneNumberUtil;
    }

    @Override
    public void registerFormatters(FormatterRegistry registry) {
        registry.addConverter(Phonenumber.PhoneNumber.class, String.class, source -> phoneNumberUtil.format(source, E164));
    }
}

Теперь такие вещи, как следующие работы

import com.google.i18n.phonenumbers.Phonenumber;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.hateoas.Resource;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

@FeignClient("data-service")
public interface DataClient {
    @RequestMapping(method = RequestMethod.GET, value = "/phoneNumbers/search/findByPhoneNumber")
    Resource<PhoneNumberRecord> getPhoneNumber(@RequestParam("phoneNumber") Phonenumber.PhoneNumber phoneNumber);
}
person user988346    schedule 22.12.2016

Как открытая проблема с симуляцией и весенний документ говорит:

Аннотация OpenFeign @QueryMap обеспечивает поддержку POJO для использования в качестве карт параметров GET.

Spring Cloud OpenFeign предоставляет эквивалентную аннотацию @SpringQueryMap, которая используется для аннотирования параметра POJO или Map в качестве карты параметров запроса, начиная с версии 2.1.0.

Вы можете использовать его следующим образом:

    @GetMapping("user")
    String getUser(@SpringQueryMap User user);
public class User {
    private String name;
    private int age;
    ...
}
person Frank.Chang    schedule 30.04.2019