- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我希望我的回复包括以下内容:
"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/
我目前正在尝试对部分 URL 进行编码,但不是全部 这是一个示例: http://localhost:8080/resourceSearch?type=http%3A%2F%2Fexample.com
我希望我的回复包括以下内容: "keyMaps":{ "href":"http://localhost/api/keyMaps{/keyMapId}", "templated":true }
我正在尝试使用 spring-hateoas 将 HATEOAS 应用于我的 spring boot 应用程序.在我将我的 REST 调用包装在 HystrixCommand 之前,这一直很好用: @
我正在学习有关 Spring REST 的教程,并尝试将 HATEOAS 链接添加到我的 Controller 结果中。 我有一个简单的用户类和一个 CRUD Controller 。 class U
我正在尝试将 Spring HATEOAS 合并到现有的服务工具和 REST API 中。但是,我遇到的问题之一是 ControllerLinkBuilder 似乎删除了尾部斜杠(这是由于现有约束的要
设置:所以我有一个用 java 编写的 RESTfull API,使用 spring-boot 和 spring-hates 添加链接到资源(超媒体驱动的 RESTful Web 服务)。我拥有的一切
Spring HATEOAS 提供了得心应手的ControllerLinkBuilder创建指向 Controller 方法的链接,这些链接将作为 href 添加到返回给客户端的 JSON/XML 中
在使用 ControllerLinkBuilder 和 methodOn 功能时,我不明白的一件事是,当您的 Controller 具有这样的方法签名时,您应该做什么: public HttpEnti
我正在尝试调用 Spring 的 ControllerLinkBuilder.methodOn()使用非 String 类型,它总是失败。而我不知道是哪种Converter使用以及在哪里注册。 这是我
我在 Boot 应用程序中使用 Spring Hateoas 以避免在 View 中手动创建链接。它在 Thymeleaf View 中工作得很好,当 Controller 调用服务发送同样由 Thy
我在 spring Async 方法中调用 ControllerLinkBuilder.linkTo 方法,但它无法找到当前请求。 service.setUrl(linkTo(Controller.c
从 websocket 调用 ControllerLinkBuilder.linkTo 时出现以下错误。 java.lang.IllegalStateException: Could not fin
我是一名优秀的程序员,十分优秀!