如何在非servlet环境中使用UriComponentsBuilder?

时间:2016-11-10 12:04:14

标签: java spring spring-mvc

文档说明如果我不在servlet调用线程中,但仍想使用UriComponentsBuilder(例如在批量导入中),我可以使用ServletUriComponentsBuilder.fromCurrentContextPath()

@see https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-uri-building

我从文档中尝试了以下内容:

public String createUrl() {
    UriComponentsBuilder base = ServletUriComponentsBuilder.fromCurrentContextPath().path("/en");
    MvcUriComponentsBuilder builder = MvcUriComponentsBuilder.relativeTo(base);
    builder.withMethodCall(on(BookingController.class).getBooking(21)).buildAndExpand(42);

    URI uri = uriComponents.encode().toUri();
    return uri.toString();
}

用于测试非servlet调用:

@PostConstruct
public void init() {
    builder.createUrl();
}

但总是得到例外:

Caused by: java.lang.IllegalStateException: Could not find current request via RequestContextHolder
    at org.springframework.util.Assert.state(Assert.java:392) ~[spring-core-4.3.4.RELEASE.jar:4.3.4.RELEASE]
    at org.springframework.web.servlet.support.ServletUriComponentsBuilder.getCurrentRequest(ServletUriComponentsBuilder.java:190) ~[spring-webmvc-4.3.4.RELEASE.jar:4.3.4.RELEASE]
    at org.springframework.web.servlet.support.ServletUriComponentsBuilder.fromCurrentContextPath(ServletUriComponentsBuilder.java:158) ~[spring-webmvc-4.3.4.RELEASE.jar:4.3.4.RELEASE]

那么这里可能出现什么问题?

1 个答案:

答案 0 :(得分:1)

您提到的文档明确指出静态方法适用于Servlet环境:

  

Servlet环境中的ServletUriComponentsBuilder子类   提供静态工厂方法[...]

因此,如果您不在所述Servlet环境中,则需要使用普通的UriComponentsBuilder:

UriComponentsBuilder.newInstance().scheme("http").host("example.com")

哪个适合您的代码

public String createUrl() {
    UriComponentsBuilder base = UriComponentsBuilder.newInstance().scheme("http").host("example.com").path("/en");
    MvcUriComponentsBuilder builder = MvcUriComponentsBuilder.relativeTo(base);
    builder.withMethodCall(on(BookingController.class).getBooking(21)).buildAndExpand(42);

    URI uri = uriComponents.encode().toUri();
    return uri.toString();
}

这背后的原因是在servlet环境中,您可以通过查询Servlet / ServletContext等来访问scheme和主机以及上下文路径。在webapp外部运行,此信息(方案,主机,上下文路径)需要来自其他地方。