Spring Boot
Angular
Single Page Application
Redirects
Web Development

Spring Boot with redirecting with single page angular2

Data Structures & Algorithms practice on Codemia

Step through 300+ coding interview problems with animated visualisers that show the data structure changing as the code runs. The Blind 75 are free.

Practice algorithms

Introduction

A single-page Angular app expects the browser to load index.html first and let the client router handle deep links. Spring Boot, on the other hand, will try to resolve a request such as /users/42 on the server unless you explicitly forward unknown frontend routes.

When you click around inside the app, Angular changes the URL in the browser and renders the matching component. That works because the JavaScript bundle is already loaded. The problem appears when a user refreshes the page or opens a deep link directly. The browser asks Spring Boot for /users/42, and if the backend does not own that route, the server returns 404.

The fix is to distinguish API routes from frontend routes and forward the frontend ones to the Angular entry page.

Typical Project Layout

A common setup is:

  • Spring Boot serves backend endpoints under /api
  • the built Angular files live in src/main/resources/static
  • unknown non-API paths forward to /index.html

A controller that forwards frontend routes can look like this:

java
1import org.springframework.stereotype.Controller;
2import org.springframework.web.bind.annotation.GetMapping;
3
4@Controller
5public class SpaForwardController {
6
7    @GetMapping(value = {"/", "/users", "/users/**", "/settings", "/projects/**"})
8    public String forward() {
9        return "forward:/index.html";
10    }
11}

This tells Spring MVC to serve the Angular shell page while preserving the visible URL.

Forwarding Unknown Routes More Flexibly

Hard-coding every route works for small apps, but it becomes noisy as the frontend grows. A better pattern is to forward every request that:

  • does not target /api
  • does not look like a static asset
  • should be handled by the Angular router

One way to do that is with a view controller configuration.

java
1import org.springframework.context.annotation.Configuration;
2import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
3import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
4
5@Configuration
6public class SpaWebConfig implements WebMvcConfigurer {
7    @Override
8    public void addViewControllers(ViewControllerRegistry registry) {
9        registry.addViewController("/{spring:[^.]*}")
10                .setViewName("forward:/index.html");
11        registry.addViewController("/**/{spring:[^.]*}")
12                .setViewName("forward:/index.html");
13        registry.addViewController("/{spring:[^.]*}/**{spring:?!(\\.js|\\.css|\\.png|\\.svg)$}")
14                .setViewName("forward:/index.html");
15    }
16}

The intent is to forward paths that do not contain a file extension, while leaving asset files alone.

Keep API and Frontend Routing Separate

The cleanest deployment boundary is to reserve a server prefix for backend endpoints.

java
1import org.springframework.web.bind.annotation.GetMapping;
2import org.springframework.web.bind.annotation.RestController;
3
4@RestController
5public class UserController {
6    @GetMapping("/api/users/me")
7    public String currentUser() {
8        return "mark";
9    }
10}

Then Angular can call /api/users/me, while /dashboard or /users/42 are treated as frontend routes and forwarded to the SPA shell.

On the Angular side, ordinary router configuration is enough:

typescript
1import { Routes } from '@angular/router';
2import { DashboardComponent } from './dashboard.component';
3import { UserDetailComponent } from './user-detail.component';
4
5export const routes: Routes = [
6  { path: '', component: DashboardComponent },
7  { path: 'users/:id', component: UserDetailComponent }
8];

Development Versus Production

During local development, you often run Angular and Spring Boot on different ports. In that setup, Angular CLI serves the frontend and proxies API calls to Spring Boot. The forwarding rule matters mainly in production, where Spring Boot serves the built SPA files directly.

That distinction matters because developers sometimes try to solve a production routing problem only in Angular. The Angular router cannot help if the server never returns index.html in the first place.

Common Pitfalls

A common mistake is using a redirect instead of a forward. Redirecting to /index.html changes the browser URL and loses the deep-link path. Forwarding keeps the original path so Angular can inspect it and render the right component.

Another problem is forwarding API endpoints by accident. If /api requests also go to index.html, your frontend may receive HTML where it expected JSON. Keep the backend namespace explicit.

Static assets are another source of confusion. If the server forwards requests for .js or .css files to the SPA entry page, the browser loads HTML instead of a script bundle and the app fails to boot.

Finally, do not rely on wildcard patterns you do not understand. Test direct navigation, refresh, and bookmarked URLs for several frontend routes before calling the deployment done.

Summary

  • Angular deep links fail unless Spring Boot forwards them to index.html.
  • Keep backend endpoints under a clear prefix such as /api.
  • Use server-side forwarding, not a redirect, for frontend routes.
  • Exclude real static assets from the forwarding rule.
  • Test refresh and direct navigation in production-style deployment.

Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Data Structures & Algorithms practice on Codemia

Step through 300+ coding interview problems with animated visualisers that show the data structure changing as the code runs. The Blind 75 are free.

Practice algorithms