Spring boot get application base url outside of servlet context

21,335

Solution 1

Suppose your app is using embedded tomcat server, then url to your app may be found as follows:

@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;
}

Here is an example for embedded jetty server:

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;
}

Solution 2

In my setup I have a @Configuration class setting up the context path (hardcoded) and @Value injecting the port number from application.properties. The context path could also be extracted to a properties file and injected the same way, you would use:

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

You can also implement ServletContextAware in your component in order to get a hook to the ServletContext which would also give you the context path.

I am guessing you would like to ship a complete url (including the full server name) in your emails, but you can't really be sure that the e-mail receivers are accessing your application server directly by hostname, i.e. it could be behind a web server, a proxy etc. You could of course add a server name which you know can be accessed from outside as a property as well.

Share:
21,335
Ben
Author by

Ben

Updated on July 09, 2022

Comments

  • Ben
    Ben almost 2 years

    The setup is following - I have a timed task that would send verification emails so users:

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

    And in those emails I need to include a link leading back to the same webapp. However I can not find any references of how to get app's base url without servlet context.

    BONUS

    It would also help if I could set up thymeleaf template resolver here to work with those links, but for that I need a WebContext which requires an instance of HttpServletRequest.

  • Ben
    Ben over 7 years
    I'm not asking how to send emails or use thymeleaf templates, that's not relevant to the question and in fact, if you'd read the question carefully, you would realize that I already use thymeleaf templates and send emails. The real question is if the app is aware of it's base url, and how to get it - and your solution is to provide it myself, which does not help at all (and is a crude practice from deployment side). Besides @{} links in thymeleaf wont work if you dont make the the context HTTP-aware with WebContext
  • eparvan
    eparvan over 7 years
    You're right, I completely misunderstood your question, perhaps my edited answer you'll find more useful.
  • Ben
    Ben over 7 years
    Will this work when deployed to a different web servlet container?
  • eparvan
    eparvan over 7 years
    I've tested only with tomcat and jetty, see my edited answer.
  • Ben
    Ben over 7 years
    It's messy because of deployment-dependency. Nevertheless I think this is a correct answer.
  • Karl.S
    Karl.S over 6 years
    In new versions of SpringBoot, it's @Value("${server.context-path}"), but's it's a good solution, thx.