← Back to list

Migrating a JSP app to spring boot

Quite a few companies still in 2025 have to manage older legacy applications that were build with Java EE technologies. Although these apps…

Anastasios Savvopoulos · 2025-07-30 09:45 · 2 claps · 3.8 min read
#spring-boot #app-migration #app-modernization #cloud-native #cloud-foundry
Open on Medium ↗
Wiki topics: ☁️ · DevOps & Cloud

Migrating a JSP app to spring boot

Quite a few companies still in 2025 have to manage older legacy applications that were build with Java EE technologies. Although these apps are working well and they are robust, they are quickly becoming difficult to maintain as new technologies emerge and support for these older ones slows down.

This article is meant to be a starting guide for a software engineer that wants to migrate an older JSP app that relies on an external server like Tomcat, to a new cloud native application using spring boot.

Let’s go then!

I am going to be basing this guide in an example that I wrote that includes a sample jsp application with a view and a servlet. You can find the code for the example application as well as the final spring *bootified *app in my GitHub repo.

Here is the current JSP app structure. It’s a fairly simple app with a single servlet, an index welcome view and a second home view.

File Structure

File Structure

To start migrating to spring boot we start with the pom file. The current dependency of Jakarta EE 9 needs to be replaced with the following spring related dependencies. Start by removing the following dependency:

<dependency>
  <groupId>jakarta.platform</groupId>
  <artifactId>jakarta.jakartaee-web-api</artifactId>
  <version>9.0.0</version>
  <scope>provided</scope>
</dependency>

Now let’s add the spring boot framework dependency as a parent dependency:

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>3.2.2</version>
  <relativePath />
</parent>

And the starter dependency in the dependencies section:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>

Next we want to transition to an embedded tomcat server so that our app is self-sufficient according to the 12 factor app principles:

<dependency>
  <groupId>org.apache.tomcat.embed</groupId>
  <artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>

We will still need some dependencies for the JSP dynamic home page.

<dependency>
 <groupId>org.glassfish.web</groupId>
 <artifactId>jakarta.servlet.jsp.jstl</artifactId>
</dependency>

<dependency>
  <groupId>jakarta.servlet.jsp.jstl</groupId>
  <artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
</dependency>

Finally let’s create the base bootstrap class for our new spring boot jsp application:

@SpringBootApplication
public class SpringBootJspApplication extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(SpringBootJspApplication.class);
    }

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

Dealing with the Servlet

The original JSP app that we are migrating from has a simple hello servlet that also reads a resource from the Tomcat context.xml configuration. Our job is to keep functionality but modernize it a bit by taking advantage of the spring boot capabilities. The original file looks like this:

@WebServlet("/helloservlet")
public class HelloServlet extends HttpServlet {

    @Resource(name = "foo")
    private String foo;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");

        var out = resp.getOutputStream();

        out.println("This is a Jakarta EE 9 Servlet!");
        ...
        //some more print outs 
        out.println("resource with foo = " + foo);

        ...
        //even more print outs

    }
}

Taking advantage of spring boot and the amazing DI framework we will change this class into a component so it can be automatically registered as a bean and also make a few changes for dealing with the foo resource:

@Component
public class HelloServlet extends HttpServlet {

    @Resource(name = "envConfiguration")
    private EnvConfiguration envConfiguration;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");

        var out = resp.getOutputStream();

        out.println("This is a Jakarta EE 9 Servlet!");
        ...
        //some more print outs

        out.println("resource with foo = " + envConfiguration.getFoo());

        ...
        //even more print outs

    }

}

As you can see we moved the resource out of the context.xml into a simple class named EnvConfiguration that is managed by application.properties. The benefit here is that the class is concrete and can be used by the developer easier in tests as well as provide easy access to the devops to be overridden in any environment during deployment. The configuration class is shown below:

@Configuration
@ConfigurationProperties(prefix = "env")
public class EnvConfiguration {

    private String foo;

    public String getFoo() {
        return foo;
    }

    public void setFoo(String foo) {
        this.foo = foo;
    }
}

And this is how it can be simply configured in the properties file:

env.foo=bar-value

Finally we can also gather all our servlets under an /api/ url pattern to indicate to an api client that these are not meant to be dynamic web pages. This can be done by adding this bean in our SpringBootJspApplication class.

@Bean
public ServletRegistrationBean<HelloServlet> myServletRegistration(HelloServlet servlet) {
    ServletRegistrationBean<HelloServlet> registration = new ServletRegistrationBean<>(servlet,
            "/api/helloservlet/*");
    registration.setLoadOnStartup(1);
    return registration;
}

What about the home.jsp?

Again in the properties file we can tell spring where our views are located and what kind of files we use like that:

spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp

We can also now use the Controller annotation to create a controller class and manage all our view with the same pattern like that:


@Controller
public class IndexController {

    @GetMapping("/")
    public String indexView() {
        return "index";
    }

     @GetMapping("/hello")
    public String servletView(Model model) {
        model.addAttribute("servletValue", "Hello from JSP!");
        return "hello";
    }
}

Compared to the original JSP everything is neatly defined in one class and managed through strings, instead of using configuration in web.xml, controllers, servlets etc.

Conclusion

As you can see with a few changes we managed to migrate a JSP application relying on an external tomcat container to a more modern cloud native spring boot app by taking advantage of the spring framework capabilities.

Now of course real production apps will be more complex and require more work for migration but this guide here is meant to be a starting point for you.

One more thing…

Both applications can be found in my Github repo (links below) and if you take a closer look you can also find a manifest file that can help you deploy them to cloud foundry :)

Thank you for reading.


메타데이터
post_id
ebfce5a27015
slug
migrating-a-jsp-app-to-spring-boot-ebfce5a27015
url
https://medium.com/@anastasios.savvopoulos/migrating-a-jsp-app-to-spring-boot-ebfce5a27015
canonical_url
https://medium.com/@anastasios.savvopoulos/migrating-a-jsp-app-to-spring-boot-ebfce5a27015
author_url
https://medium.com/@anastasios.savvopoulos
status
ok
fetched_at
2026-08-01 03:37:46