Search code examples
javaspringspring-bootsame-origin-policy

How to host angular build files in springboot server?


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.


Solution

  • 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