Вы можете использовать ServerHttpRequest
в качестве параметра метода для получения uri
:
@RestController
public class GreetingController {
@GetMapping("/greeting")
public Mono getGreeting(ServerHttpRequest serverHttpRequest) {
return Mono.just(new Greeting("greeting", serverHttpRequest.getURI().toString()));
}
}
Предпочтительно
blockquote>linkToCurrentResource
должен понимать заголовкиX-Forwarded-???
, если работает за балансировщиком нагрузки.Затем вы можете выставить
ForwardedHeaderTransformer
@Bean
.Из документации:
Извлечь значения из заголовков «
blockquote>Forwarded
» и «X-Forwarded-*
», чтобы переопределить запросURI
(то естьHttpRequest.getURI()
), чтобы он отражал составленный протокол и адрес.@Configuration open class MvcConfig { @Bean open fun forwardedHeaderTransformer() = ForwardedHeaderTransformer() }
Вот несколько тестов:
@ExtendWith(SpringExtension::class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT, properties = ["server.port=4333"]) class GreetingController2Test { @Autowired private lateinit var restTemplate: TestRestTemplate @Test fun `should return uri`() { val responseEntity = restTemplate.getForEntity("/greeting", Greeting::class.java) val greeting = responseEntity.body!! assertEquals("http://localhost:4333/greeting", greeting.uri) } @Test fun `should return uri composed from forwarded-??? headers`() { val headers = HttpHeaders() headers["X-Forwarded-Host"] = "external-uri.com" headers["X-Forwarded-Proto"] = "https" headers["X-Forwarded-Prefix"] = "/prefix" val httpEntity = HttpEntity(null, headers) val responseEntity = restTemplate.exchange("/greeting", HttpMethod.GET, httpEntity, Greeting::class.java) val greeting = responseEntity.body!! assertEquals("https://external-uri.com/prefix/greeting", greeting.uri) } }
И
Greeting.kt
:data class Greeting( val g: String? = null, val uri: String? = null )
Править: Удалены предыдущие решения для двух наборов. См. историю редактирования для деталей.
Вот способ сделать это рекурсивно для произвольного числа наборов:
public static Set<Set<Object>> cartesianProduct(Set<?>... sets) {
if (sets.length < 2)
throw new IllegalArgumentException(
"Can't have a product of fewer than two sets (got " +
sets.length + ")");
return _cartesianProduct(0, sets);
}
private static Set<Set<Object>> _cartesianProduct(int index, Set<?>... sets) {
Set<Set<Object>> ret = new HashSet<Set<Object>>();
if (index == sets.length) {
ret.add(new HashSet<Object>());
} else {
for (Object obj : sets[index]) {
for (Set<Object> set : _cartesianProduct(index+1, sets)) {
set.add(obj);
ret.add(set);
}
}
}
return ret;
}
Обратите внимание, что невозможно хранить любую универсальную информацию типа с возвращенными наборами. Если бы Вы знали заранее, из какого количества наборов Вы хотели взять продукт, Вы могли определить универсальный кортеж для содержания этого много элементов (например, Triple<A, B, C>
), но нет никакого способа иметь произвольное число универсальных параметров в Java.
Количество наборов могло бы варьироваться так, я не могу сделать этого во вложенном цикле foreach.
Две подсказки:
Память (и обрабатывающий) место, необходимое для Декартова произведения, может выйти из-под контроля довольно быстро. Наивная реализация может исчерпать память и занять много времени. Было бы хорошо знать операции, которые Вы планируете выполнить в таком наборе для предложения стратегии реализации.
В любом случае сделайте что-то как Наборы. SetView на наборах Google. Это - набор, который поддерживается другими наборами, поскольку они добавляются. Идея для их проблемы там состоит в том, чтобы избежать вызова addAll. Идея для Вашей проблемы состоит в том, чтобы не делать NxMxK, добавляет к набору.
Наборы Google могут быть найдены здесь, и упомянутый класс здесь