Response processing - front and rear data interaction

elementary analysis:

As we all know, in the front end of the front-end and back-end separation project, we use Jquery to realize ajax asynchronous request and data interaction with the back-end: that is, take the data from the front-end page and request it to the corresponding controller layer method, then the back-end processes the data requested by the front-end through business logic, and finally returns the corresponding state to the front-end;

Principle of HTTPMessageConverter:

Convert the entity class data in your project into JSON data or reverse it, and use the read-write method;

Design restful style API for front-end and back-end interaction through json data: how to parse the data? Some httpmessageconverters will be automatically configured during startup in spring MVC, so what is the function? It can support json data types. When the back-end receives a request, it will judge whether it can be read and read if it can be read. When the result is returned, it will judge whether it can be written and write if it can be written;

public interface HttpMessageConverter<T> {
    boolean canRead(Class<?> var1, @Nullable MediaType var2);

    boolean canWrite(Class<?> var1, @Nullable MediaType var2);

    List<MediaType> getSupportedMediaTypes();

    T read(Class<? extends T> var1, HttpInputMessage var2) throws IOException, HttpMessageNotReadableException;

    void write(T var1, @Nullable MediaType var2, HttpOutputMessage var3) throws IOException, HttpMessageNotWritableException;
}

1. So, the problem is read to write to write, but if your data has to be converted, does it need a Converter? In WebMvcConfigurationSupport class, there is a very key method: addDefaultHttpMessageConverters();

protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
		StringHttpMessageConverter stringConverter = new StringHttpMessageConverter();
		stringConverter.setWriteAcceptCharset(false);

		messageConverters.add(new ByteArrayHttpMessageConverter());
		messageConverters.add(stringConverter);
		messageConverters.add(new ResourceHttpMessageConverter());
		messageConverters.add(new SourceHttpMessageConverter<Source>());
		messageConverters.add(new AllEncompassingFormHttpMessageConverter());

		if (romePresent) {
			messageConverters.add(new AtomFeedHttpMessageConverter());
			messageConverters.add(new RssChannelHttpMessageConverter());
		}

		if (jackson2XmlPresent) {
			ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.xml().applicationContext(this.applicationContext).build();
			messageConverters.add(new MappingJackson2XmlHttpMessageConverter(objectMapper));
		}
		else if (jaxb2Present) {
			messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
		}

		if (jackson2Present) {
			ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().applicationContext(this.applicationContext).build();
			messageConverters.add(new MappingJackson2HttpMessageConverter(objectMapper));
		}
		else if (gsonPresent) {
			messageConverters.add(new GsonHttpMessageConverter());
		}
	}

It can be seen from the above that this is used for judgment. Find the Converter required by the data and add it to the messageconverter if necessary; It should be noted here that when we configure our own messageconverter (where the Converter is specially stored), the addDefaultHttpMessageConverters() method will not be called by spring MVC;

2. getMessageConverter(): used to determine whether the converters are customized or configured by spring MVC by default (it's a bit confusing here. Is isEmpty to determine the content in the converter?): My understanding is: if the converter is empty (meaning there is nothing to take), we will create a new set (converter's), and then configure the current converter, (this should be when we need a converter for some data. If this converter does not exist, we will create a new converter set and configure a converter corresponding to this data to convert the data) - that is, our own converter; Then judge whether the content in the converter is empty. If it is empty, spring MVC will load addDefaultHttpMessageConverters() to obtain the converter corresponding to the attribute;

protected final List<HttpMessageConverter<?>> getMessageConverters() {
		if (this.messageConverters == null) {
			this.messageConverters = new ArrayList<HttpMessageConverter<?>>();
			configureMessageConverters(this.messageConverters);
			if (this.messageConverters.isEmpty()) {
				addDefaultHttpMessageConverters(this.messageConverters);
			}
			extendMessageConverters(this.messageConverters);
		}
		return this.messageConverters;
	}

 

3. Processing of MessageConverters:

Traverse each converter to compare until Jackson's processing type is found;

// Traverse messageConverters
for (HttpMessageConverter<?> converter : this.messageConverters) {
    Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
        // The key points to keep in mind in the above class diagram are to judge whether MappingJackson2HttpMessageConverter is of GenericHttpMessageConverter type
    if (converter instanceof GenericHttpMessageConverter) {
        GenericHttpMessageConverter<?> genericConverter = (GenericHttpMessageConverter<?>) converter;
        if (genericConverter.canRead(targetType, contextClass, contentType)) {
            if (logger.isDebugEnabled()) {
                logger.debug("Read [" + targetType + "] as \"" + contentType + "\" with [" + converter + "]");
            }
            if (inputMessage.getBody() != null) {
                inputMessage = getAdvice().beforeBodyRead(inputMessage, parameter, targetType, converterType);
                body = genericConverter.read(targetType, contextClass, inputMessage);
                body = getAdvice().afterBodyRead(body, inputMessage, parameter, targetType, converterType);
            }
            else {
                body = getAdvice().handleEmptyBody(null, inputMessage, parameter, targetType, converterType);
            }
            break;
        }
    }
    else if (targetClass != null) {
        if (converter.canRead(targetClass, contentType)) {
            if (logger.isDebugEnabled()) {
                logger.debug("Read [" + targetType + "] as \"" + contentType + "\" with [" + converter + "]");
            }
            if (inputMessage.getBody() != null) {
                inputMessage = getAdvice().beforeBodyRead(inputMessage, parameter, targetType, converterType);
                body = ((HttpMessageConverter<T>) converter).read(targetClass, inputMessage);
                body = getAdvice().afterBodyRead(body, inputMessage, parameter, targetType, converterType);
            }
            else {
                body = getAdvice().handleEmptyBody(null, inputMessage, parameter, targetType, converterType);
            }
            break;
        }
    }
}

4. Then judge the reading operation: can read,

protected Object _readMapAndClose(JsonParser p0, JavaType valueType)
        throws IOException
    {
        try (JsonParser p = p0) {
            Object result;
            JsonToken t = _initForReading(p);
            if (t == JsonToken.VALUE_NULL) {
                // Ask JsonDeserializer what 'null value' to use:
                DeserializationContext ctxt = createDeserializationContext(p,
                        getDeserializationConfig());
                result = _findRootDeserializer(ctxt, valueType).getNullValue(ctxt);
            } else if (t == JsonToken.END_ARRAY || t == JsonToken.END_OBJECT) {
                result = null;
            } else {
                DeserializationConfig cfg = getDeserializationConfig();
                DeserializationContext ctxt = createDeserializationContext(p, cfg);
                JsonDeserializer<Object> deser = _findRootDeserializer(ctxt, valueType);
                if (cfg.useRootWrapping()) {
                    result = _unwrapAndDeserialize(p, ctxt, cfg, valueType, deser);
                } else {
                    result = deser.deserialize(p, ctxt);
                }
                ctxt.checkUnresolvedObjectId();
            }
            // Need to consume the token too
            p.clearCurrentToken();
            return result;
        }
    }

At this time, the parsing has been completed, and the process of the back-end result (that is, the state returned to the front-end) has not been completed;

Keywords: Front-end Spring Boot server

Added by nosti on Tue, 01 Feb 2022 05:49:10 +0200