Перехват до привязки QueryValue в Micronaut - PullRequest
1 голос
/ 01 ноября 2019

Я искал использовать HttpServerFilter для изменения входящего запроса до выполнения метода конечной точки в контроллере. В моем запросе у меня есть @QueryValue привязки. Похоже, что выполнение этих привязок происходит до HttpServerFilter, поэтому, если бы я захотел изменить параметры запроса, я бы не смог этого сделать.

Есть ли место, где я могу перехватить и изменить запросдо @QueryValue привязки?

1 Ответ

1 голос
/ 02 ноября 2019

Это может быть решено с помощью HttpServerFilter, но вы должны обновить значение параметра в согласованном маршруте, а не в запросе. Это связано с тем, что RoutingInBoundHandler сначала пытается выполнить требования аргумента маршрута, а затем выполняет цепочку фильтров. См. Приведенный ниже пример, как это сделать:

Фильтр, который вызывает службу изменения:

@Filter("/hello/**")
public class ModifyRequestFilter implements HttpServerFilter {
    private final ModifyRequestService service;

    public ModifyRequestFilter(ModifyRequestService service) {
        this.service = service;
    }

    @Override
    public Publisher<MutableHttpResponse<?>> doFilter(HttpRequest<?> request, ServerFilterChain chain) {
        return service.modify(request)
                .switchMap(aBoolean -> chain.proceed(request));
    }
}

Служба, которая выполняет изменение, где находится код ключа: ((NettyHttpRequest<?>) request).getMatchedRoute().getVariableValues().put("value", "modified in filter");:

@Singleton
public class ModifyRequestService {
    Flowable<Boolean> modify(HttpRequest<?> request) {
        return Flowable.fromCallable(() -> {
            ((NettyHttpRequest<?>) request).getMatchedRoute().getVariableValues().put("value", "modified in filter");
            return true;
        }).subscribeOn(Schedulers.io());
    }
}

И контроллер:

@Controller("/hello")
public class HelloController {
    @Get("/")
    public String index(@QueryValue String value) {
        return "Hello " + value;
    }
}

Другой вариант - использовать собственный класс контейнера для значений, которые вы хотите изменить с помощью собственного преобразователя типов.

Например CustomValueкласс является контейнером значений:

public class CustomValue {
    private String value;

    public CustomValue(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }
}

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

@Singleton
@BootstrapContextCompatible
public class CustomConverterRegistrar implements TypeConverterRegistrar {
    @Override
    public void register(ConversionService<?> conversionService) {
        conversionService.addConverter(CharSequence.class, CustomValue.class, 
            s -> new CustomValue(s + "-updated"));
    }
}

А вот примерконтроллер:

@Controller("/hello")
public class HelloController {
    @Get("/in-query")
    public String inQuery(@QueryValue CustomValue value) {
        return "Hello " + value.getValue();
    }

    @Get("/in-path/{value}")
    public String inPath(CustomValue value) {
        return "Hello " + value.getValue();
    }
}

и тест на скручивание с результатом:

$ curl http://localhost:8080/hello/in-query/?value=test
Hello test-updated
$ curl http://localhost:8080/hello/in-path/testFromPath
Hello testFromPath-updated
...