FeignClient调用接口接收不到参数问题

FeignClient调用接口接收不到参数问题

  • 1. 问题描述
  • 2. 问题分析
  • 3. 测试验证
    • 3.1 环境依赖
    • 3.2 代码实现
  • 4. 结论总结
  • 5. 阿里开发手册

1. 问题描述

问题就是通过FeignClient调用某个接口的时候,请求参数明明有值,服务端拿到的请求对象却为null。

2. 问题分析

FeignClient接收不到参数可能会存在以下原因,
1.客户端没有传值。
2.客户端与服务端参数类型不一致导致服务端接收不到。
3.请求对象中含有以is开头的参数,FeignClient框架序列化会过滤掉。
4.FeignClient框架问题,考虑其他框架如httpclient,hutool的httpUtil等。

3. 测试验证

3.1 环境依赖

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>

3.2 代码实现

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);
    
}

4. 结论总结

通过Feign调用接口,请求参数接收不到值问题
1.使用Feign与hutool的httpUtil调用,且请求对象含有以is开头的命名的布尔类型参数,且请求基本类型,服务端包装类型,接收不到值。
2.客户端通过集合作为请求对象不存在这种问题,即使请求参数中含有以is开头的命名的参数。
3.客户端通过给以is开头的参数添加序列化注解@JsonProperty(“isDeletedJson”)
4.客户端对于除了布尔类型以外其他类型即使含有以is开头的参数也不会受影响

5. 阿里开发手册

阿里开发手册-泰山版,命名规范第8条。

8.【强制】POJO 类中的任何布尔类型的变量,都不要加 is 前缀,否则部分框架解析会引起序列化错误。
说明:在本文 MySQL 规约中的建表约定第一条,表达是与否的值采用 is_xxx 的命名方式,所以,需要在设置从 is_xxx 到 xxx 的映射关系。

反例:定义为基本数据类型 Boolean isDeleted 的属性,它的方法也是 isDeleted(),框架在反向解析的时候,“误以为”对应的属性名称是 deleted,导致属性获取不到,进而抛出异常。

你可能感兴趣的:(问题总结,Feign调用接口接收不到参数)