FeignClient实现form表单提交Object

1,422 阅读1分钟

现在在Spring-Boot提供了Map<String,?> map的格式来提交form表单参数,但是Map<String,?> map不能体现request的含义,而且还多了object转换map的流程,期望能够在FeignClient中直接提交object为form表单参数

现在FeignClient支持的form表单参数提交的格式

@FeignClient(name = "jddefray", url = "${jd.defrayPay.url}")
public interface JdDefrayPayClient {   
     @PostMapping(value = "/npp10/defray_pay" ,
                consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)  
     String defrayPay(Map<String,?> entityBody);

}

在@FeignClient中是使用FormEncoder进行提交的, 观察FormEncoder#encode中的源码实现,可以看到Map<String,?>对应的Type是Type MAP_STRING_WILDCARD = Util.MAP_STRING_WILDCARD;, 那么对于自定义的PoJo那么是不是只要在自定义的Encoder中将其转换成Map, 然后委托给FormEncoder就可以实现想要的效果了.

@Override@SuppressWarnings("unchecked")
public void encode (Object object, Type bodyType, RequestTemplate template) 
            throws EncodeException {  
    String contentTypeValue = getContentTypeValue(template.headers()); 
    val contentType = ContentType.of(contentTypeValue); 
     if (!processors.containsKey(contentType)) { 
           delegate.encode(object, bodyType, template);  
              return;  
     }  
     Map<String, Object> data; 
     if (MAP_STRING_WILDCARD.equals(bodyType)) { 
           data = (Map<String, Object>) object; 
     } else if (isUserPojo(bodyType)) { 
           data = toMap(object);  
     } else {  
           delegate.encode(object, bodyType, template);   
            return;
     }  

     val charset = getCharset(contentTypeValue); 
     processors.get(contentType).process(template, charset, data);
}

下面是自定义的ObjectFormEncoder,将object转换为Map<String,?>交给FormEncoder以form表单格式提交

/** * 这里将object转换为@Feignclient中支持的 Map<String,?> 提交的表单格式 */
@Slf4j
class ObjectFormEncoder implements Encoder { 
   private final Encoder delegate;   

   public ObjectFormEncoder(Encoder delegate) {    
    this.delegate = delegate;   
   }  
  
   @Override   
   public void encode(Object object, Type bodyType, RequestTemplate template)
         throws EncodeException {        
        // object -> Map<String,?> map
        Map<String, ?> map = new ObjectMapper().convertValue(object, new TypeReference<Map<String, ?>>() {        });     
        log.info("request:{}" ,map );      
        delegate.encode(map, MAP_STRING_WILDCARD, template);     
        return;    
    }
}

然后在@FeignClient中换上自定义的feignEncoder即可

class JdAgreeConfiguration {  
     @Autowired   
     private ObjectFactory<HttpMessageConverters> messageConverters;   

     @Bean   
     public Encoder feignEncoder() {   
         return  new ObjectFormEncoder(new FormEncoder(new SpringEncoder(messageConverters)));  
      }     
}

经过测试,这样是可以实现以form表单格式提交object(自定义PoJo)的。

Question: 在观察FormEncoder#encode中的源码的时候,发现有判断isUserPojo(bodyType),然后转换为map的动作, 按说是应该是实现了上面所说的功能, 是需要哪里配置什么么?