Hello, I'm glacier~~
Recently, I'm using SpringBoot+K8S to develop a microservice system. Since I use K8S, I don't want to use SpringCloud. Why? Because K8S itself provides very 6 technologies for service registration and discovery, current limiting, fusing, load balancing and other micro services, why should I access spring cloud? Well, after all this, when I really use the SpringBoot+K8S technology stack, I will also encounter some problems. For example, when I don't need to use SpringCloud and call other services, I use the native OpenFegin. When I use OpenFegin to call other services, I encounter a big pit. An exception occurred in the return value LocalDateTime of the OpenFeign request. Today, let's talk about this pit!
All right, let's start~~
Project integration OpenFegin
Integrating OpenFegin dependencies
First of all, let me tell you about the project configuration. The SpringBoot version used in the overall project is 2.2.6, and the native OpenFegin uses 11.0. We use POM. Com in the following way OpenFegin is introduced into XML.
<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 omit some other configuration items.
Next, I started using OpenFegin to call remote services in my project. The specific steps are as follows.
Implement remote call
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 client. This class is also relatively simple. In essence, it caches all feginclients with a HashMap. This FeginClient is essentially our custom Fegin interface. The Key in the cache is the basic URL for requesting connection, and the cached Value is the FeginClient interface we define.
public class FeginClientFactory { /** * Cache all Fegin clients */ private volatile static Map<String, Object> feginClientCache = new HashMap<>(); /** * Get data from 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 will 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 a test class for SpringBoot.
@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 to run the test. Ma egg, something's wrong. The main problem is that an exception will occur in the LocalDateTime field of the return value of the OpenFeign request!!!
Note: in case of exception, the annotation we added on 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;
solve the problem
Problem description
SpringBoot calls the HTTP interface through the native OpenFeign client. If the return value contains the LocalDateTime type (including the time class of java.time package in other JSR-310), there may be an error of deserialization failure 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')
problem analysis
Calling fegin from the client is also equivalent to passing a URL parameter, which is equivalent to a JSON conversion. The database takes out the data of '2020-10-07T11:04:32'. At this time, it is a time type. After entering JSON, it becomes a String type, and T becomes a character. It is no longer a special character. Therefore, the deserialization of the String "2020-10-07T11:04:32" will fail.
Problem solving
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 SpringBoot is used and the SpringBoot version is explicitly specified, the version number may not be specified when jackson-datatype-jsr310 is introduced.
Next, add the following annotation in 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 point, call the remote interface again to solve the problem.
Write at the end
If you want to enter a big factory, want to be promoted and raised, or are confused about your existing work, you can communicate with me privately. I hope some of my experience can help you~~
Recommended reading:
- <Summary of the most complete performance optimization of the whole network!! (glacier hematemesis finishing, recommended Collection)>
- <After three days of rolling up MyBatis, please ask!! (glacier hematemesis finishing, recommended Collection)>
- <I advise those students who have just joined the work: if you want to enter the big factory, you must master these core skills! Complete learning route!! (recommended Collection)>
- <I advise those students who have just joined the work: the sooner they know the basic knowledge of computers and operating systems, the better! Ten thousand words long text is too top!! (recommended Collection)>
- <I developed a national game suitable for all ages in three days. It supports playing music. Now I open the complete source code and comments (recommended Collection)!!>
- <I am the author of high concurrency programming with the hardest core in the network and the most noteworthy blogger of CSDN. Do you agree? (recommended Collection)>
- <Five years after graduation, from a monthly salary of 3000 to an annual salary of one million, what core skills have I mastered? (recommended Collection)>
- <I invaded the Wifi of my sister next door and found... (actual dry goods in the whole process, collection recommended)>
- <Don't try "panda burning incense" easily. I regret it!>
- <On the Qingming Festival, I secretly trained "panda burning incense". As a result, my computer "died" for the panda!>
- <73000 words liver burst Java 8 new features, I don't believe you can read it! (recommended Collection)>
- <What kind of experience is it to unplug the server during peak business hours?>
- <Summary of the most complete Linux commands in the whole network!! (the most complete in history, recommended Collection)>
- <Write a tool in Python and crack MySQL perfectly!! (recommended Collection)>
Well, that's all for today. Let's praise, collect and comment. Let's walk up three times with one button. I'm glacier. I'll see you next time~~