Spring Boot在servlet上下文之外获取应用程序基本url

Posted

技术标签:

【中文标题】Spring Boot在servlet上下文之外获取应用程序基本url【英文标题】:Spring boot get application base url outside of servlet context 【发布时间】:2017-03-17 00:44:21 【问题描述】:

设置如下 - 我有一个定时任务会发送验证电子邮件,以便用户:

@Scheduled(cron = " 0 0-59/1 * * * * ")
public void sendVerificationEmails() 
    //...

在这些电子邮件中,我需要包含一个指向同一个 webapp 的链接。但是我找不到任何关于如何在没有 servlet 上下文的情况下获取应用程序基本 url 的参考资料。

奖金

如果我可以在此处设置 thymeleaf 模板解析器来处理这些链接,这也会有所帮助,但为此我需要一个 WebContext,它需要一个 HttpServletRequest 的实例。

【问题讨论】:

属性文件怎么样。顺便说一句,为什么您不想使用 servlet 上下文? ***.com/questions/20405474/spring-boot-context-root @kuhajeyan 因为它不是网络请求,而是不同的范围。属性文件呢? 在这里查看我的答案,***.com/a/53896961/3307037。它很整洁,可以让您摆脱所有不便携且容易出错的连接 【参考方案1】:

假设您的应用程序使用嵌入式 tomcat 服务器,那么您的应用程序的 url 可能如下所示:

@Inject
private EmbeddedWebApplicationContext appContext;

public String getBaseUrl() throws UnknownHostException 
    Connector connector = ((TomcatEmbeddedServletContainer) appContext.getEmbeddedServletContainer()).getTomcat().getConnector();
    String scheme = connector.getScheme();
    String ip = InetAddress.getLocalHost().getHostAddress();
    int port = connector.getPort();
    String contextPath = appContext.getServletContext().getContextPath();
    return scheme + "://" + ip + ":" + port + contextPath;

这是一个嵌入式码头服务器的例子:

public String getBaseUrl() throws UnknownHostException 
    ServerConnector connector = (ServerConnector) ((JettyEmbeddedServletContainer) appContext.getEmbeddedServletContainer()).getServer().getConnectors()[0];
    String scheme = connector.getDefaultProtocol().toLowerCase().contains("ssl") ? "https" : "http";
    String ip = InetAddress.getLocalHost().getHostAddress();
    int port = connector.getLocalPort();

    String contextPath = appContext.getServletContext().getContextPath();
    return scheme + "://" + ip + ":" + port + contextPath;

【讨论】:

我不是在问如何发送电子邮件或使用百里香模板,这与问题无关,事实上,如果您仔细阅读问题,您会意识到我已经使用百里香模板并发送电子邮件。真正的问题是应用程序是否知道它的基本 url,以及如何获取它 - 您的解决方案是自己提供它,这根本没有帮助(并且是部署方面的粗略做法)。此外,如果您不使用WebContext 使上下文具有 HTTP 感知能力,则百里香叶中的 @ 链接将不起作用@ 你说得对,我完全误解了你的问题,也许我编辑的答案你会发现更有用。 部署到不同的 web servlet 容器时是否可以工作? 我只用 tomcat 和 jetty 进行了测试,请参阅我编辑的答案。 由于部署依赖,它很乱。不过我认为这是一个正确的答案。【参考方案2】:

在我的设置中,我有一个 @Configuration 类设置上下文路径(硬编码)和 @Value 从 application.properties 注入端口号。上下文路径也可以提取到属性文件并以相同的方式注入,您可以使用:

@Value("$server.port")
private String serverPort;
@Value("$server.contextPath")
private String contextPath;

你也可以在你的组件中实现 ServletContextAware 以获得一个 ServletContext 的钩子,它也会给你上下文路径。

我猜你想在你的电子邮件中发送一个完整的 url(包括完整的服务器名称),但你不能确定电子邮件接收者是否直接通过主机名访问你的应用程序服务器,即它可以在 Web 服务器、代理等后面。当然,您也可以添加一个您知道可以从外部访问的服务器名称作为属性。

【讨论】:

在新版本的SpringBoot中,是@Value("$server.context-path"),但这是一个很好的解决方案,谢谢。

以上是关于Spring Boot在servlet上下文之外获取应用程序基本url的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Spring Boot Tests 中设置 servlet 上下文路径?

在 HttpServletRequest 上下文之外测试 Spring Boot WebClient

Vaadin Flow & Spring Boot 无法通过 servlet 上下文找到资源

使用spring boot loader WarLauncher时如何在war文件之外加载属性文件?

Spring Boot 整合监听器

在spring boot的管理端口中使用prometheus metrics servlet