gpt4 book ai didi

spring - 带有 ControllerLinkBuilder 的模板变量

转载 作者:IT老高 更新时间:2023-10-28 13:58:25 25 4
gpt4 key购买 nike

我希望我的回复包括以下内容:

"keyMaps":{
"href":"http://localhost/api/keyMaps{/keyMapId}",
"templated":true
}

这很容易实现:

add(new Link("http://localhost/api/keyMaps{/keyMapId}", "keyMaps"));

但是,当然,我宁愿使用 ControllerLinkBuilder,像这样:

add(linkTo(methodOn(KeyMapController.class).getKeyMap("{keyMapId}")).withRel("keyMaps"));

问题在于,当变量“{keyMapId}”到达 UriTemplate 构造函数时,它已被包含在编码 URL 中:

http://localhost/api/keyMaps/%7BkeyMapId%7D

所以 UriTemplate 的构造函数不会将其识别为包含变量。

如何说服 ControllerLinkBuilder 我想使用模板变量?

最佳答案

在我看来,Spring-HATEOAS 的当前状态不允许通过 ControllerLinkBuilder 执行此操作(我非常希望被证明是错误的),所以我自己使用以下类用于模板化查询参数:

public class TemplatedLinkBuilder {

private static final TemplatedLinkBuilderFactory FACTORY = new TemplatedLinkBuilderFactory();
public static final String ENCODED_LEFT_BRACE = "%7B";
public static final String ENCODED_RIGHT_BRACE = "%7D";

private UriComponentsBuilder uriComponentsBuilder;

TemplatedLinkBuilder(UriComponentsBuilder builder) {
uriComponentsBuilder = builder;
}

public static TemplatedLinkBuilder linkTo(Object invocationValue) {
return FACTORY.linkTo(invocationValue);
}

public static <T> T methodOn(Class<T> controller, Object... parameters) {
return DummyInvocationUtils.methodOn(controller, parameters);
}

public Link withRel(String rel) {
return new Link(replaceTemplateMarkers(uriComponentsBuilder.build().toString()), rel);
}

public Link withSelfRel() {
return withRel(Link.REL_SELF);
}

private String replaceTemplateMarkers(String encodedUri) {
return encodedUri.replaceAll(ENCODED_LEFT_BRACE, "{").replaceAll(ENCODED_RIGHT_BRACE, "}");
}

}

public class TemplatedLinkBuilderFactory {

private final ControllerLinkBuilderFactory controllerLinkBuilderFactory;

public TemplatedLinkBuilderFactory() {
this.controllerLinkBuilderFactory = new ControllerLinkBuilderFactory();
}

public TemplatedLinkBuilder linkTo(Object invocationValue) {
ControllerLinkBuilder controllerLinkBuilder = controllerLinkBuilderFactory.linkTo(invocationValue);
UriComponentsBuilder uriComponentsBuilder = controllerLinkBuilder.toUriComponentsBuilder();

Assert.isInstanceOf(DummyInvocationUtils.LastInvocationAware.class, invocationValue);
DummyInvocationUtils.LastInvocationAware invocations = (DummyInvocationUtils.LastInvocationAware) invocationValue;
DummyInvocationUtils.MethodInvocation invocation = invocations.getLastInvocation();
Object[] arguments = invocation.getArguments();
MethodParameters parameters = new MethodParameters(invocation.getMethod());

for (MethodParameter requestParameter : parameters.getParametersWith(RequestParam.class)) {
Object value = arguments[requestParameter.getParameterIndex()];
if (value == null) {
uriComponentsBuilder.queryParam(requestParameter.getParameterName(), "{" + requestParameter.getParameterName() + "}");
}
}
return new TemplatedLinkBuilder(uriComponentsBuilder);
}
}

其中嵌入了普通的 ControllerLinkBuilder,然后使用类似的逻辑来解析为空的 @RequestParam 注释参数,并将它们添加到查询参数中。此外,我们的客户端重新使用这些模板化的 URI 来执行对服务器的进一步请求。为了实现这一点并且不需要担心剥离未使用的模板参数,我必须执行反向操作(交换 {params}null),我正在使用自定义 Spring RequestParamMethodArgumentResolver 如下

public class TemplatedRequestParamResolver extends RequestParamMethodArgumentResolver {

public TemplatedRequestParamResolver() {
super(false);
}

@Override
protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest webRequest) throws Exception {
Object value = super.resolveName(name, parameter, webRequest);
if (value instanceof Object[]) {
Object[] valueAsCollection = (Object[])value;
List<Object> resultList = new LinkedList<Object>();
for (Object collectionEntry : valueAsCollection) {
if (nullifyTemplatedValue(collectionEntry) != null) {
resultList.add(collectionEntry);
}
}
if (resultList.isEmpty()) {
value = null;
} else {
value = resultList.toArray();
}
} else{
value = nullifyTemplatedValue(value);
}
return value;
}

private Object nullifyTemplatedValue(Object value) {
if (value != null && value.toString().startsWith("{") && value.toString().endsWith("}")) {
value = null;
}
return value;
}

}

这还需要替换我使用的现有 RequestParamMethodArgumentResolver:

@Configuration
public class ConfigureTemplatedRequestParamResolver {

private @Autowired RequestMappingHandlerAdapter adapter;

@PostConstruct
public void replaceArgumentMethodHandlers() {
List<HandlerMethodArgumentResolver> argumentResolvers = new ArrayList<HandlerMethodArgumentResolver>(adapter.getArgumentResolvers());
for (int cursor = 0; cursor < argumentResolvers.size(); ++cursor) {
HandlerMethodArgumentResolver handlerMethodArgumentResolver = argumentResolvers.get(cursor);
if (handlerMethodArgumentResolver instanceof RequestParamMethodArgumentResolver) {
argumentResolvers.remove(cursor);
argumentResolvers.add(cursor, new TemplatedRequestParamResolver());
break;
}
}
adapter.setArgumentResolvers(argumentResolvers);
}

}

很遗憾,虽然 {}模板化 URI 中的有效字符,但它们在 URI 中无效,这可能是您的客户端代码的问题取决于它的严格程度。我更喜欢 Spring-HATEOAS 内置的更简洁的解决方案!

关于spring - 带有 ControllerLinkBuilder 的模板变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25017037/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com