First of all, let me tell you about the configuration of the project. The SpringBoot version used by the overall project is 2.2.6. The native OpenFegin uses 11.0. We introduce OpenFegin in pom.xml as follows.
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <skip_maven_deploy>false</skip_maven_deploy> <java.version>1.8</java.version> <openfegin.version>11.0</openfegin.version> </properties> <dependencies> <dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-core</artifactId> <version>${openfegin.version}</version> </dependency> <dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-jackson</artifactId> <version>${openfegin.version}</version> </dependency> </dependencies>
Here, I have omitted some other configuration items.
Next, I started using OpenFegin to call remote services in my project. Specific steps are as follows.
First, create the OpenFeignConfig class and configure the Contract used by OpenFegin by default.
@Configuration public class OpenFeignConfig { @Bean public Contract useFeignAnnotations() { return new Contract.Default(); } }
Next, we write a general factory class for obtaining OpenFeign clients. This class is also relatively simple. It essentially uses a HashMap to cache all FeginClients. This FeginClient is essentially our custom one. Fegin interface, the Key in the cache is the base URL of the requested connection, and the cached Value is the FeginClient interface we defined.
public class FeginClientFactory { /** * 缓存所有的Fegin客户端 */ private volatile static Map<String, Object> feginClientCache = new HashMap<>(); /** * 从Map中获取数据 * @return */ @SuppressWarnings("unchecked") public static <T> T getFeginClient(Class<T> clazz, String baseUrl){ if(!feginClientCache.containsKey(baseUrl)) { synchronized (FeginClientFactory.class) { if(!feginClientCache.containsKey(baseUrl)) { T feginClient = Feign.builder().decoder(new JacksonDecoder()).encoder(new JacksonEncoder()).target(clazz, baseUrl); feginClientCache.put(baseUrl, feginClient); } } } return (T)feginClientCache.get(baseUrl); } }
Next, we define a FeginClient interface.
public interface FeginClientProxy { @Headers("Content-Type:application/json;charset=UTF-8") @RequestLine("POST /user/login") UserLoginVo login(UserLoginVo loginVo); }
Next, we create the SpringBoot test class.
@RunWith(SpringRunner.class) @SpringBootTest public class IcpsWeightStarterTest { @Test public void testUserLogin() { ResponseMessage result = FeginClientFactory.getFeginClient(FeginClientProxy.class, "http://127.0.0.1").login(new UserLoginVo("zhangsan", "123456", 1)); System.out.println(JsonUtils.bean2Json(result)); } }
Everything is ready, run the test. Damn it, something went wrong. The main problem is that an exception occurs when the LocalDateTime field returns the value through the OpenFeign request! ! !
Note: When an exception occurs at this time, the annotation we add to the LocalDateTime field is as follows.
import java.time.LocalDateTime; import com.baomidou.mybatisplus.annotation.FieldFill; import com.baomidou.mybatisplus.annotation.TableField; import com.fasterxml.jackson.annotation.JsonFormat; @TableField(value = "CREATE_TIME", fill = FieldFill.INSERT) @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", locale = "zh", timezone = "GMT+8") private LocalDateTime createTime;
SpringBoot calls the HTTP interface through the native OpenFeign client. If the return value contains the LocalDateTime type (including other JSR -Time class of the java.time package in -310), a deserialization failure error may occur on the client. The error message is as follows:
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `java.time.LocalDateTime` (no Creators, like default construct, exist): no String-argument constructor/factory method to deserialize from String value ("2020-10-07T11:04:32")
From When the client calls fegin, it is equivalent to passing parameters in the URL, which is equivalent to a JSON conversion. The database takes out the '2020-10-07T11:04:32' data. This is the time type. After entering the JSON, it becomes the String type. T becomes a character and is no longer a special character, so the deserialization of the String string "2020-10-07T11:04:32" will fail.
Add dependencies to the project.
<dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> <version>2.9.9</version> </dependency>
Note: If you are using SpringBoot and the SpringBoot version is explicitly specified, you do not need to specify the version number when introducing jackson-datatype-jsr310.
Next, add the following annotation to the LocalDateTime type field of the POJO class.
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
The effect after adding is as follows.
import java.time.LocalDateTime; import com.baomidou.mybatisplus.annotation.FieldFill; import com.baomidou.mybatisplus.annotation.TableField; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; @TableField(value = "CREATE_TIME", fill = FieldFill.INSERT) @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", locale = "zh", timezone = "GMT+8") @JsonDeserialize(using = LocalDateTimeDeserializer.class) private LocalDateTime createTime;
At this time, call the remote interface again and the problem is solved.
The above is the detailed content of How to solve the pitfalls of integrating OpenFeign with SpringBoot. For more information, please follow other related articles on the PHP Chinese website!