change URL mapping for Vaadin Flow and Spring

Hi,

Changing the url as described on https://vaadin.com/docs/v11/flow/spring/tutorial-spring-configuration.html
does not work on the https://vaadin.com/start/latest/project-base-spring.
I have downloaded the starter app and only added “vaadin.urlMapping=/my_mapping/” to the application.properties file. To access the page I need to use this extra mapping now but the page is not rendered correctly and clicking on the “Click me” gives “Server connection lost”.

Thanks for the report, I’ve created a bug report for it.

I think the urlMapping part is correct but it does not correctly set the frontend paths. Also there is an issue about it.

For solving this issue, you can set the context-path in you application.properties file, this way:

server.servlet.context-path=/foo

I solved the issue creating a dedicated servlet for mapping the frontend resources.

You can find further information about the issue here:
https://github.com/vaadin/flow/issues/4685
https://github.com/vaadin/spring/issues/348

I created a project with an example:

https://github.com/DiegoSanzVi/urlMappingVaadinSpringBoot

Please note that at the moment an additional Servlet is required which handles webjar for non-root context.”

Here is my application.properties file:

server.port=8080
vaadin.urlMapping=/foo/*

Here is my code:

/**
 * The entry point of the Spring Boot application.
 */
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    public ServletRegistrationBean frontendServletBean() {
        ServletRegistrationBean bean = new ServletRegistrationBean<>(new VaadinServlet() {
            @Override
            protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                if (!serveStaticOrWebJarRequest(req, resp)) {
                    resp.sendError(404);
                }
            }
        }, "/frontend/*");
        bean.setLoadOnStartup(1);
        return bean;
    }
}

You can also do it with a single SpringServlet. Just add a mapping for /frontend/*:

@Bean
public ServletRegistrationBean<SpringServlet> springServlet(ApplicationContext context) {
    return new ServletRegistrationBean<>(new SpringServlet(context), "/foo/*", "/frontend/*");
}

Plus this in your config file:

vaadin.urlMapping=/foo/*
server.servlet.context-path=/

That way you can use for example Spring Boot Actuator endpoints as well. Also, you can use for example @Value("${vaadin.urlMapping}") String vaadinUrlMapping to get the value from the config file and avoid duplicating /foo/*.

Alejandro Duarte:
You can also do it with a single SpringServlet. Just add a mapping for /frontend/*:

@Bean
public ServletRegistrationBean<SpringServlet> springServlet(ApplicationContext context) {
    return new ServletRegistrationBean<>(new SpringServlet(context), "/foo/*", "/frontend/*");
}

This gives log message:
Servlet springServlet was not registered (possibly already registered?)

So this approach overrides servlet (along with configuration) that was imposed by the com.vaadin.flow.spring.SpringBootAutoConfiguration.

Is this something to worry about?

Since this post here is one of the first that shows up when googling for that topic, here is the latest official documentation on that topic: https://vaadin.com/docs/v14/flow/spring/tutorial-spring-configuration.html

Please notice, that IntelliJ might autocomplete to “url-mapping”, but “urlMapping” is the correct property.

What if I want to compile first and then deploy to different server setups and configure the differences? In short, I do not like a solution where I must compile the context path into my artifact.

You can override application.properties in different ways, so there is no need to recompile the project for different setups.

https://www.tutorialspoint.com/spring_boot/spring_boot_application_properties.htm

Alejandro Duarte:
You can also do it with a single SpringServlet. Just add a mapping for /frontend/*:

@Bean
public ServletRegistrationBean<SpringServlet> springServlet(ApplicationContext context) {
    return new ServletRegistrationBean<>(new SpringServlet(context), "/foo/*", "/frontend/*");
}

Plus this in your config file:

vaadin.urlMapping=/foo/*
server.servlet.context-path=/

That way you can use for example Spring Boot Actuator endpoints as well. Also, you can use for example @Value("${vaadin.urlMapping}") String vaadinUrlMapping to get the value from the config file and avoid duplicating /foo/*.

This works wonders, but I hit a dead end. I’m trying to implement Spring Security with a LoginForm following [this tutorial]
(https://vaadin.com/learn/tutorials/modern-web-apps-with-spring-boot-and-vaadin/adding-a-login-screen-to-a-vaadin-app-with-spring-security) but have found no way to make it work.

Spring keeps on showing the default login form instead of my LoginForm. Been stuck at this for a good while now.