问题就是通过FeignClient调用某个接口的时候,请求参数明明有值,服务端拿到的请求对象却为null。
FeignClient接收不到参数可能会存在以下原因,
1.客户端没有传值。
2.客户端与服务端参数类型不一致导致服务端接收不到。
3.请求对象中含有以is开头的参数,FeignClient框架序列化会过滤掉。
4.FeignClient框架问题,考虑其他框架如httpclient,hutool的httpUtil等。
spring-boot是2.3.2.RELEASE版本,openfeign是2.2.5.RELEASE。
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.3.3.RELEASEversion>
<relativePath/>
parent>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
<version>2.2.5.RELEASEversion>
dependency>
FeignClientReqDTO
package com.jerry.market.entity;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.io.Serializable;
/**
* 客户端请求对象
*
* @author zrj
* @since 2022/4/24
**/
@Data
public class FeignClientReqDTO implements Serializable {
private static final long serialVersionUID = 4804236268827809329L;
private String tenantId;
private String bizId;
//布尔类型,不以is开头,可以
private boolean mark;
//布尔类型,以is开头,客户端包装类型,服务端包装,可以
private Boolean isFilterMark;
//布尔类型,以is开头,客户端基本类型,服务端包装,但是通过JsonProperty注解处理,可以
@JsonProperty("isFilterMarkJson")
private boolean isFilterMarkJson;
//布尔类型,以is开头,客户端基本类型,服务端包装,不可以
private boolean isFilterMarkSimple;
//String类型,不以is开头,客户端包装类型,服务端包装,可以
private String start;
//String类型,以is开头,客户端包装类型,服务端包装,可以
private String isDeleted;
//String类型,以is开头,客户端包装类型,服务端包装,但是通过JsonProperty注解处理,可以
@JsonProperty("isDeletedJson")
private String isDeletedJson;
//int类型,不以is开头,客户端包装类型,服务端包装,可以
private Integer tools;
//int类型,不以is开头,客户端基本类型,服务端包装,可以
private int toolCount;
//int类型,以is开头,客户端包装类型,服务端包装,可以
private int isToolNumber;
//int类型,以is开头,客户端基本类型,服务端包装,但是通过JsonProperty注解处理,可以
@JsonProperty("isToolNumberJson")
private int isToolNumberJson;
}
FeignClientServerDTO
package com.jerry.market.entity;
import lombok.Data;
import java.io.Serializable;
/**
* 服务端请求对象
*
* @author zrj
* @since 2022/4/24
**/
@Data
public class FeignClientServerDTO implements Serializable {
private static final long serialVersionUID = 4804236268827809329L;
private String tenantId;
private String bizId;
//布尔类型
private Boolean mark;
private Boolean isFilterMark;
private Boolean isFilterMarkJson;
private Boolean isFilterMarkSimple;
//String类型
private String start;
private String isDeleted;
private String isDeletedJson;
//int类型
private Integer tools;
private Integer toolCount;
private Integer isToolNumber;
private Integer isToolNumberJson;
}
FeignController
package com.jerry.market.controller;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jerry.market.entity.*;
import com.jerry.market.integration.FeignClientService;
import com.jerry.market.integration.TemplateClientService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
/**
* Feign控制器
*
* @author makejava
* @since 2022-04-22 15:31:00
*/
@RestController
@RequestMapping("/feign")
@Api(tags = "FeignController", description = "Feign控制器")
public class FeignController {
@Resource
private FeignClientService feignClientService;
/**
* FeignClient服务端
* 1.客户端请求 isFilterUsemark Boolean,服务端请求 isFilterUsemark boolean,通过Feign可以接收到值
* 2.客户端请求 isFilterUsemark Boolean,服务端请求 isFilterUsemark Boolean,通过Feign可以接收到值
* 3.客户端请求 isFilterUsemark boolean,服务端请求 isFilterUsemark boolean,通过Feign可以接收到值
* 4.客户端请求 isFilterUsemark boolean,服务端请求 isFilterUsemark Boolean,通过Feign不可以接收到值
*
* 通过Feign调用接口,请求参数接收不到值问题
* 1.使用Feign与hutool的httpUtil调用,且请求对象含有以is开头的命名的布尔类型参数,且请求基本类型,服务端包装类型,接收不到值。
* 2.通过集合不存在这种问题,即使请求参数中含有以is开头的命名的参数。
* 3.通过给以is开头的参数添加序列化注解@JsonProperty("isDeletedJson")
* 4.其他类型即使含有以is开头的参数也不会受影响
*/
@PostMapping("/getFeignServer")
@ApiOperation(value = "FeignClient服务端")
public Response getFeignServer(@RequestBody FeignClientServerDTO feignClientServerDTO) {
System.out.println("【FeignClient服务端】请求参数:" + feignClientServerDTO);
return Response.success(feignClientServerDTO);
}
/**
* FeignClient根据请求对象查询客户端
*/
@GetMapping("/getFeignClientByObject")
@ApiOperation(value = "FeignClient根据请求对象查询客户端")
public Response getFeignClientByObject() {
//构建请求对象
FeignClientReqDTO dto = buildFeignClientReqDTO();
System.out.println("【FeignClientObject客户端】请求参数:" + dto);
JSONObject ret = feignClientService.getFeignClientByObject(dto);
System.out.println("【FeignClientObject客户端】响应参数:" + ret);
return Response.success(ret);
}
/**
* FeignClient根据请求集合查询客户端
*/
@GetMapping("/getFeignClientByMap")
@ApiOperation(value = "FeignClient根据请求集合查询客户端")
public Response getFeignClientByMap() {
//构建请求对象
Map<String, Object> map = buildFeignClientReqMap();
System.out.println("【FeignClientMap客户端】请求参数:" + map);
JSONObject ret = feignClientService.getFeignClientByMap(map);
System.out.println("【FeignClientMap客户端】响应参数:" + ret);
return Response.success(ret);
}
/**
* HttpClient根据请求对象查询客户端
*/
@GetMapping("/getHttpClientByObject")
@ApiOperation("查询模板通过HttpClient")
public Response<JSONObject> getHttpClientByObject() {
//创建头信息
HttpRequest post = HttpUtil.createPost("http://localhost:8090/feign/getFeignServer");
//构建请求对象
FeignClientReqDTO dto = buildFeignClientReqDTO();
post.body(JSON.toJSONString(dto));
//集合参数,isFilterUsemark可以接收参数
//Map map = buildFeignClientReqMap();
//post.body(JSON.toJSONString(map));
System.out.println("【查询模板通过HttpClient】请求参数:" + dto);
HttpResponse response = post.execute();
System.out.println("【查询模板通过HttpClient】响应参数:" + response.body());
return Response.success(JSON.parseObject(response.body()));
}
/**
* 构建请求对象
*
* @return FeignClientReqDTO
*/
private FeignClientReqDTO buildFeignClientReqDTO() {
//构建请求对象
FeignClientReqDTO dto = new FeignClientReqDTO();
dto.setTenantId("123456789");
dto.setBizId("helloWorld");
//布尔类型
dto.setIsFilterMark(false);
dto.setFilterMarkJson(false);
dto.setFilterMarkSimple(false);
dto.setMark(false);
//String类型
dto.setStart("1");
dto.setIsDeleted("2");
dto.setIsDeletedJson("3");
//整数类型
dto.setTools(4);
dto.setToolCount(5);
dto.setIsToolNumber(6);
dto.setIsToolNumberJson(7);
return dto;
}
/**
* 构建请求Map
*
* @return Map
*/
private Map<String, Object> buildFeignClientReqMap() {
//构建请求对象
Map<String, Object> map = new HashMap<>(9);
map.put("tenantId", "123456789");
map.put("bizId", "helloWorld");
//布尔类型
map.put("isFilterMark", false);
map.put("isFilterMarkJson", false);
map.put("isFilterMarkSimple", false);
map.put("mark", false);
//String类型
map.put("start", "1");
map.put("isDeleted", "2");
map.put("isDeletedJson", "3");
//整数类型
map.put("tools", "4");
map.put("toolCount", "5");
map.put("isToolNumber", "6");
map.put("isToolNumberJson", "7");
return map;
}
}
FeignClientService
package com.jerry.market.integration;
import com.alibaba.fastjson.JSONObject;
import com.jerry.market.entity.FeignClientReqDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.Map;
/**
* FeignClientService
*
* @author zrj
* @since 2022/4/25
**/
@Component
@FeignClient(url = "http://localhost:8090/feign", name = "FeignClientService")
public interface FeignClientService {
/**
* 通过对象查询模板
*
* @param dto FeignClientReqDTO
* @return JSONObject
*/
@PostMapping(value = "/getFeignServer")
JSONObject getFeignClientByObject(@RequestBody FeignClientReqDTO dto);
/**
* 通过集合查询模板
*
* @param map
* @return JSONObject
*/
@PostMapping(value = "/getFeignServer")
JSONObject getFeignClientByMap(@RequestBody Map<String, Object> map);
}
通过Feign调用接口,请求参数接收不到值问题
1.使用Feign与hutool的httpUtil调用,且请求对象含有以is开头的命名的布尔类型参数,且请求基本类型,服务端包装类型,接收不到值。
2.客户端通过集合作为请求对象不存在这种问题,即使请求参数中含有以is开头的命名的参数。
3.客户端通过给以is开头的参数添加序列化注解@JsonProperty(“isDeletedJson”)
4.客户端对于除了布尔类型以外其他类型即使含有以is开头的参数也不会受影响
阿里开发手册-泰山版,命名规范第8条。
8.【强制】POJO 类中的任何布尔类型的变量,都不要加 is 前缀,否则部分框架解析会引起序列化错误。
说明:在本文 MySQL 规约中的建表约定第一条,表达是与否的值采用 is_xxx 的命名方式,所以,需要在设置从 is_xxx 到 xxx 的映射关系。
反例:定义为基本数据类型 Boolean isDeleted 的属性,它的方法也是 isDeleted(),框架在反向解析的时候,“误以为”对应的属性名称是 deleted,导致属性获取不到,进而抛出异常。