如何自定义@FeignClient Expander 来转换param?
How to custom @FeignClient Expander to convert param?
Feign default expander to convert param:
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);
我能做什么?
首先,你必须写一个像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);
我不知道@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);
}
如open feign issue and spring doc所说:
The OpenFeign @QueryMap annotation provides support for POJOs to be used as GET parameter maps.
Spring Cloud OpenFeign provides an equivalent @SpringQueryMap annotation, which is used to annotate a POJO or Map parameter as a query parameter map since 2.1.0.
你可以这样使用它:
@GetMapping("user")
String getUser(@SpringQueryMap User user);
public class User {
private String name;
private int age;
...
}
Feign default expander to convert param:
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);
我能做什么?
首先,你必须写一个像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);
我不知道@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);
}
如open feign issue and spring doc所说:
The OpenFeign @QueryMap annotation provides support for POJOs to be used as GET parameter maps.
Spring Cloud OpenFeign provides an equivalent @SpringQueryMap annotation, which is used to annotate a POJO or Map parameter as a query parameter map since 2.1.0.
你可以这样使用它:
@GetMapping("user")
String getUser(@SpringQueryMap User user);
public class User {
private String name;
private int age;
...
}