Объедините функциональность @ModelAttribute и @RequestBody в Spring MVC - PullRequest
1 голос
/ 18 февраля 2020

Рассмотрим @ PostMapping весной MVC, и мы хотим отобразить тело запроса в DTO, а также другие параметры запроса, такие как переменные запроса и пути.

Для сопоставление тела запроса мы можем использовать аннотацию @ RequestBody для параметра, которая скажет Spring использовать RequestResponseBodyMethodProcessor.

Для сопоставления параметры запроса мы можем использовать аннотацию @ ModelAttribute (или избегать любых аннотаций; тот же эффект), которая скажет Spring использовать ServletModelAttributeMethodProcessor.

Но есть ли способ объединить эти два ? Есть ли способ заставить Spring сначала отобразить DTO с параметрами запроса, а затем переопределить данные, десериализованные из JSON в теле?

Единственный способ, которым я вижу это в данный момент, - это создание собственного HandlerMethodArgumentResolver но я бы хотел сначала использовать любую существующую функциональность Spring.

1 Ответ

0 голосов
/ 24 февраля 2020

Оказывается, нет, во время написания все равно нет.

RequestMappingHandlerAdapter.getDefaultArgumentResolvers содержит конфигурацию по умолчанию для ресовлеров аргументов, и у нас есть:

  • RequestResponseBodyMethodProcessor, обрабатывающая @RequestBody аннотация и
  • ServletModelAttributeMethodProcessor обработка @ModelAttribute или любого параметра без каких-либо аннотаций.

Всегда выполняется только один распознаватель, даже если вы попробуйте использовать композит.

Мое решение

@ControllerAdvice
@RequiredArgsConstructor
@Order(HIGHEST_PRECEDENCE)
public class ServletRequestBinderRequestBodyAdvice extends RequestBodyAdviceAdapter {

    private final ServletRequest servletRequest;

    @Override
    public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }

    @Override
    public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        copyDefaultPropertiesThatWhereOverwritenWithNull(parameter, body);

        new ExtendedServletRequestDataBinder(body).bind(servletRequest);

        return body;
    }

    private void copyDefaultPropertiesThatWhereOverwritenWithNull(MethodParameter parameter, Object arg) {
        Object argWithDefaults = instantiateClass(parameter.getParameterType());
        copyPropertiesSkippingNulls(argWithDefaults, arg);
    }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...