1. What is responsive programming? Why do we now think this is the trend of micro service?
Let's dig a hole and give a simple formula.
Responsive programming = data stream + change transfer + declarative
2. Following nonsense, don't talk much about code directly
The Implementing Thought and Introduction of the Core Reactor of WebFlux
Because it is a preliminary study, so as far as possible to give the whole code, the lesson to understand in detail what kind of category or domain is quoted, because it is a simple experiment, so it is inevitable that there are mistakes.
First, the project startup class, similar to Spring Boot
package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.reactive.config.EnableWebFlux; @SpringBootApplication @EnableWebFlux public class WebfluxDemoApplication { public static void main(String[] args) { SpringApplication.run(WebfluxDemoApplication.class, args); } }
Then I have some configuration for web interaction.
Mainly in Codec, the configuration of serialization and deserialization for LocalDateTime related classes and two kinds of enumeration interfaces I defined are added.
package com.example.demo.config; import static com.example.demo.utils.LocalDateTimeUtils.DATE_FORMATTER; import static com.example.demo.utils.LocalDateTimeUtils.DATE_TIME_FORMATTER; import static com.example.demo.utils.LocalDateTimeUtils.TIME_FORMATTER; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import org.springframework.context.annotation.Configuration; import org.springframework.format.FormatterRegistry; import org.springframework.http.codec.ServerCodecConfigurer; import org.springframework.http.codec.json.Jackson2JsonDecoder; import org.springframework.http.codec.json.Jackson2JsonEncoder; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.web.reactive.config.WebFluxConfigurer; import com.example.demo.config.message.formatter.IntegerToIntegerBaseEnumFactory; import com.example.demo.config.message.formatter.StringToIntegerBaseEnumFactory; import com.example.demo.config.message.formatter.StringToLocalDate; import com.example.demo.config.message.formatter.StringToLocalDateTime; import com.example.demo.config.message.formatter.StringToLocalTime; import com.example.demo.config.message.formatter.StringToStringBaseEnumFactory; import com.example.demo.type.IntegerBaseEnum; import com.example.demo.type.StringBaseEnum; import com.example.demo.type.zt.TaskStatus; import com.example.demo.utils.json.jackson.IntegerBaseEnumDeserializer; import com.example.demo.utils.json.jackson.IntegerBaseEnumSerializer; import com.example.demo.utils.json.jackson.StringBaseEnumDeserializer; import com.example.demo.utils.json.jackson.StringBaseEnumSerializer; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer; @Configuration public class WebConfig implements WebFluxConfigurer { @Override public void addFormatters(FormatterRegistry registry) { registry.addConverter(new StringToLocalDateTime()); registry.addConverter(new StringToLocalDate()); registry.addConverter(new StringToLocalTime()); registry.addConverterFactory(new IntegerToIntegerBaseEnumFactory()); registry.addConverterFactory(new StringToIntegerBaseEnumFactory()); registry.addConverterFactory(new StringToStringBaseEnumFactory()); // registry.addFormatter(new LocalDatetimeFormatter()); } @Override public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) { var objectMapper = initObjectMapper(); configurer.defaultCodecs().jackson2JsonEncoder(new Jackson2JsonEncoder(objectMapper)); configurer.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(objectMapper)); } private ObjectMapper initObjectMapper() { var objectMapper = new ObjectMapper(); // var objectMapper = Jackson2ObjectMapperBuilder.json().build(); // Ignore empty properties objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); // objectMapper.enable(SerializationConfig.Feature.INDENT_OUTPUT); //Formatting objectMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY); objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); objectMapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT); JavaTimeModule timeModule = new JavaTimeModule(); timeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DATE_TIME_FORMATTER)); timeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DATE_FORMATTER)); timeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(TIME_FORMATTER)); timeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DATE_TIME_FORMATTER)); timeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DATE_FORMATTER)); timeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(TIME_FORMATTER)); objectMapper.registerModule(timeModule); addStringBaseEnumSerializers(TaskStatus.class); addIntegerBaseEnumSerializers(); objectMapper.registerModule(simpleModule); return objectMapper; } SimpleModule simpleModule = new SimpleModule(); @SafeVarargs private <T extends StringBaseEnum> void addStringBaseEnumSerializers(Class<T>... clazzes) { for (Class<T> s : clazzes) { simpleModule.addSerializer(s, new StringBaseEnumSerializer<>()); simpleModule.addDeserializer(s, new StringBaseEnumDeserializer<>()); } } @SafeVarargs private <T extends IntegerBaseEnum> void addIntegerBaseEnumSerializers(Class<T>... clazzes) { for (Class<T> i : clazzes) { simpleModule.addSerializer(i, new IntegerBaseEnumSerializer<>()); simpleModule.addDeserializer(i, new IntegerBaseEnumDeserializer<>()); } } }
Here are two enumeration interfaces I customized
For String type
(2) For int/number type
package com.example.demo.type; import java.io.Serializable; public interface IntegerBaseEnum extends Serializable { /** * Get value * @return */ int getValue(); /** * Getting tag information * @return */ String getLabel(); public static <T extends IntegerBaseEnum> T valEnum(Class<T> type, Integer value) { if (value == null) { throw new IllegalArgumentException("IntegerBaseEnum value should not be null"); } if (type.isAssignableFrom(Enum.class)) { throw new IllegalArgumentException("illegal IntegerBaseEnum type"); } T[] enums = type.getEnumConstants(); for (T t : enums) { if (t.getValue() == value.intValue()) { return t; } } throw new IllegalArgumentException("cannot parse integer: " + value + " to " + type.getName()); } }
package com.example.demo.type; import java.io.Serializable; public interface StringBaseEnum extends Serializable { /** * Get value * @return */ String getCode(); /** * Getting tag information * @return */ String getLabel(); public static <T extends StringBaseEnum> T valEnum(Class<T> type, String code) { if (code == null) { throw new IllegalArgumentException("StringBaseEnum value should not be null"); } if (type.isAssignableFrom(Enum.class)) { throw new IllegalArgumentException("illegal StringBaseEnum type"); } T[] enums = type.getEnumConstants(); for (T t : enums) { if (t.getCode().equals(code)) { return t; } } throw new IllegalArgumentException("cannot parse String: " + code + " to " + type.getName()); } }
Writing here, I think it will lead to too much code, no focus. Give me a github address.
https://github.com/coderhuang/webflux-demo
Writing articles while still in the company, first dig a pit here