Пользовательский обработчик аргументов для @PathVariable - PullRequest
0 голосов
/ 21 мая 2018

Сценарий: мой контроллер принимает значение Long для идентификатора, который является переменной пути.

Мне нужно передать String, который является внешней ссылкой на идентификатор.Поэтому мне нужно разрешить строковую ссылку на ее значение Long.

Попытка: при наличии аннотации @PathVariable мой пользовательский распознаватель аргументов не вызывается, так как PathVariableMethodArgumentResolver находится выше, чем мой настраиваемый распознаватель в списке распознавателей, и он просто поддерживает все аргументы с @PathVariable annotation

Работает нормально, если удалить @PathVariable и добавить собственную аннотацию.Но затем Swagger получает идентификатор в качестве параметра тела запроса и выдает следующую ошибку:

TypeError: Failed to execute 'fetch' on 'Window': Request with GET/HEAD method cannot have body.

Мой пользовательский преобразователь:

@Override
public boolean supportsParameter( MethodParameter methodParameter )
{
    return methodParameter.hasParameterAnnotation( ExternalRefParam.class );
}

@Override public Object resolveArgument( MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory ) throws Exception
{
    Map nameValueMap = (Map) nativeWebRequest.getAttribute( HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, 0 );
    switch( methodParameter.getParameterName() )
    {
        case CART_ID:
            return resolveCartId( nameValueMap );
        case PRODUCT_KEY:
            return resolveProductKey( nameValueMap );
    }
    return -1L;
}

Подпись контроллера:

public ResponseEntity<Cart> readCart( 
                @ApiParam(value = "Cart ID", required = true) @ExternalRefParam Long cartId,  HttpServletRequest request )

1 Ответ

0 голосов
/ 09 апреля 2019

У меня была похожая проблема, когда я хотел добавить собственный преобразователь аргументов, который преобразовывал бы строковое значение переменной пути в верхний регистр.Я решил это, создав GenericConverter, который преобразовал строку string => string для переменных пути, аннотированных определенной аннотацией.

Тип аннотации переменной пути был просто аннотацией тегирования, подобной этой:

    @Target(ElementType.PARAMETER)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Uppercase {
        String value() default "";
    }

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

    @PostMapping(value = "/clients/{clientId}/postalAddress")
    @ResponseStatus(HttpStatus.CREATED)
    public IdResponse create(
        @PathVariable("clientId") @Uppercase final String clientId,
        @RequestBody @NotNull @Valid final AddressRequest request) {...}

А затем был запущен универсальный конвертер для запуска на любом аргументе String, а метод convert проверил, что аргумент был помечен Uppercaseаннотация, чтобы знать, если это должно быть в верхнем регистре.Это также означало, что Swagger API по-прежнему сообщает о переменной пути как о пути и правильно извлекает значение переменной пути, а затем запускает конвертер, если он помечен Uppercase.

    public class CarPolicyIdAttributeConverter implements GenericConverter {

        @Override
        public Set<ConvertiblePair> getConvertibleTypes() {
            final ConvertiblePair[] pairs = new ConvertiblePair[] {
                new ConvertiblePair(String.class, String.class)
            };
            return ImmutableSet.copyOf(pairs);
        }

        @Override
        public Object convert(final Object source, final TypeDescriptor sourceType, final TypeDescriptor targetType) {
            if (targetType.getAnnotation(Uppercase.class) != null) {
                return ((String)source).toUppercase();
            }
            return source;
        }
    }
...