1

I have a spring boot config file similar to following,

server:
  port: 8002
  servlet:
    context-path: /api/
...

spring:
  mvc:
    static-path-pattern: "/resources/**"
...

I have copy pasted the build files from my angular project inside resources/resources/static.

Don't know if this is relevant. Here goes my JwtFilter.java,

@Component
public class JwtFilter extends OncePerRequestFilter {

    final private JwtUtil jwtUtil;

    @Autowired
    JwtFilter(JwtUtil jwtUtil) {
        this.jwtUtil = jwtUtil;
    }

    @Override
    protected void doFilterInternal(
      HttpServletRequest httpServletRequest,
      HttpServletResponse httpServletResponse,
      FilterChain filterChain
    ) throws ServletException, IOException {
        Cookie[] cookies = httpServletRequest.getCookies();
        if(cookies == null) {
            cookies = new Cookie[]{};
        }
        Cookie jwtCookie = Arrays.stream(cookies)
          .filter(cookie -> cookie.getName().equals(StringConstants.JWT_AT_COOKIE_NAME))
          .findFirst()
          .orElse(null);

        Cookie rtCookie = Arrays.stream(cookies)
          .filter(cookie -> cookie.getName().equals(StringConstants.RT_COOKIE_NAME))
          .findFirst()
          .orElse(null);

        if (rtCookie == null) {
            httpServletResponse.sendError(401, "REFRESH_TOKEN_NOT_FOUND");
            return;
        }

        String jwt = null;
        String uid = null;

        try {
            if (jwtCookie != null) {
                jwt = jwtCookie.getValue();
                uid = jwtUtil.extractSubject(jwt);
            } else {
                httpServletResponse.sendError(401, "User not authenticated!");
            }

            if (uid != null) {
                if (!jwtUtil.validateToken(jwt)) {
                    httpServletResponse.sendError(401, "EXPIRED_JWT_TOKEN_EXCEPTION");
                    return;
                }
            }
        } catch (SignatureException exception) {
            httpServletResponse.sendError(403, exception.getMessage());
            return;
        }
        filterChain.doFilter(httpServletRequest, httpServletResponse);
    }

    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) {
        String path = request.getRequestURI();
        return path.equals("/api/auth") || path.equals("/api/auth/");
    }
}

I have tried adding those js build files to META-INF/resources, public & resources. No go there as well.

Dir structure is:

  • java/ ...
  • resources/
    • resources/
      • META-INF/
        • resources/ [contains angular build files]
      • public/ [contains angular build files]
      • resources/ [contains angular build files]
      • static/ [contains angular build files]

Now if I go to http://localhost:8002/ then it just says HTTP Status 404 – Not Found.

Nikhil.Nixel
  • 555
  • 2
  • 11
  • 25

1 Answers1

0

The project structure needs a bit more work on it.

Check out the question here.

Build angular 11 with Spring boot 2.x in one single jar

Delete this.

spring:
  mvc:
    static-path-pattern: "/resources/**"

You want to put npm build artifacts inside src/main/resources/static.

Firstly, npm run build and you will find the artifacts inside dist/.

Copy whatever from dist/ into src/main/resources/static/. For example, the dist/index.html will be copied and pasted into src/main/resources/static/index.html.

Force Springboot to Serve index.html

However, there is a catch here. If you do mind a hash fragment #/foo/bar in the url, you need to tell Springboot to serve index.html on 404.

@SpringBootApplication
public class BlogApiApplication {

    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(BlogApiApplication.class);
        app.run(args);
    }


    @Bean
    public EmbeddedServletContainerCustomizer containerCustomizer() {

        return new EmbeddedServletContainerCustomizer() {
            @Override
            public void customize(ConfigurableEmbeddedServletContainer container) {

                ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/index.html");

                container.addErrorPages(error404Page);
            }
        };
    }
}

In this way, you do not need hash mode. The same thing goes with React, Vue.

Reference

justthink
  • 439
  • 3
  • 6
  • I think the `Force Sprinboot to Serve 'index.html'` is specific to Sprinbboot 1. For Springboot 2 its different I THINK. If you know that as well. please. I tried this. ```@Bean public ErrorPageRegistrar errorPageRegistrar() { return registry -> registry.addErrorPages( new ErrorPage(HttpStatus.NOT_FOUND, "/index.html") ); }``` Didn't work though. – Nikhil.Nixel May 20 '21 at 15:21
  • It worked after I added filter to ignore index.html and any related js files. Also needed to comment out servlet.context-path: /api/. Is there any way to use prefix /api but also be able to use website like normal without prefix – Nikhil.Nixel May 20 '21 at 16:05
  • 1
    @Nikhil.Nixel Conventionally, the front-end artifacts are not nested into a `.jar` package. The best practice is to use a web server, such as Nginx, to serve your front-end code from a different place. If you would like to learn that, try `URL rewrite` and `reverse proxy` in Nginx. – justthink May 21 '21 at 00:58
  • If an Nginx server is not your choice, try not to use `servlet.context-path`. Adding `/api` ahead of your API paths would be much more organizable. – justthink May 21 '21 at 01:01
  • I was able to bundle everything under one single jar file, once I placed those build files [html, js, assets] in static, resources, public. And I surrendered routing controls through the error page. Added /api to all controllers manually. – Nikhil.Nixel May 21 '21 at 05:13