2

I am struggling with an issue where spring-boot isn't serving front-end files(created through angular) on 8080. I ran ng build that converted .ts ng component files to .js and generated in outputPath:/resource/static folder( I set outputPath in angular.json file). Created a controller to serve content from resources/static.

    @Controller
    public class AppController {
        @GetMapping("/")
        public String index() {
            return "index";
        }
     }

main class (src/mainjava/webapp/app):

@Configuration
@EnableAutoConfiguration
@ComponentScan({"webapp"})
public class Application extends WebMvcAutoConfiguration {

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

Ran ng build --base-href . generates files as shown in below image.

index.html :

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Welcome app</title>
  <base href="/">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
  <app-root></app-root>
<script type="text/javascript" src="runtime.js"></script><script type="text/javascript" src="polyfills.js"></script><script type="text/javascript" src="styles.js"></script><script type="text/javascript" src="vendor.js"></script><script type="text/javascript" src="main.js"></script></body>
</html>

Note: This is a gradle project.Front-end code resides in : src/main/java/webapp/frontend dir

Application.yml in /resources

server:
  servlet:
    context-path: /
  port: 8080

On tomcat start:

Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-09-13 12:45:34.372  INFO 96027 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-09-13 12:45:34.384  INFO 96027 --- [           main] .m.m.a.ExceptionHandlerExceptionResolver : Detected @ExceptionHandler methods in exceptionHandle
2018-09-13 12:45:34.405  INFO 96027 --- [           main] o.s.b.a.w.s.WelcomePageHandlerMapping    : Adding welcome page: class path resource [static/index.html]
2018-09-13 12:45:34.566  INFO 96027 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2018-09-13 12:45:34.568  INFO 96027 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Bean with name 'dataSource' has been autodetected for JMX exposure
2018-09-13 12:45:34.575  INFO 96027 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Located MBean 'dataSource': registering with JMX server as MBean [com.zaxxer.hikari:name=dataSource,type=HikariDataSource]
2018-09-13 12:45:34.620  INFO 96027 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''

I even tried adding html file under /resources to see if tomcat serves any contents from this folder. I can't access page1.html as well so not sure how would angular/ng content be different that it can't serve when tomcat is up and running.

resources/static

Do I need any other configuration to have spring-boot serve angular frontend code? Any suggestion is appreciated.

@DavidT Answers to your Ques:

  • Yes in build.gradle:compile('org.springframework.boot:spring-boot-starter-web:2.0.2.RELEASE')

  • static content here: MYPROJECT/MYPROJECT-web/src/main/resources/static/

  • Since spring-boot didn't pick angular static content from path, I referred online resources that suggested to add a controller specifically to serve it. [I have 3 ng components accessible- login: http://localhost:4200/,home: http://localhost:4200/home,sale:http://localhost:4200/sale. But to access on tomcat port I thought to put files under static; rest angular will take care of routing.]

  • When run ng build from frotnend dir, generates angular files under frontend/src dir. Either I can manually copy, paste manually to put in static folder or change outputPath to point to resources/static in angular.json which directly put it there on running ng build cmd. Exact files in above resources/static screenshot.

  • I haven't used javascript console but opening index.html with browser option from IntellijIdea, inspect on webpage I see error-

Refused to execute script from '' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled.

Replacing <script type to "text/html" removes these errors from inspect but still no UI on http://localhost:8080/.

The strange part is when I pasted the same index.html file from that demo project to mine in static folder, it doesn't display anything when browsed to http://localhost:8080. But noticed when open this file from browser option in IntellijIdea (this URI in browser: http://localhost:63342/MY-PROJ/MY-PROJ-WEB-main/static/index.html , then it shows the content

Is <base href="/"> an issue or scripts tags?

anonymous-explorer
  • 365
  • 1
  • 12
  • 26

4 Answers4

1

Steps to success without being complicated like in the link above:

  1. Went to https://start.spring.io/
  2. Selected a gradle project
  3. Added Web dependency
  4. Downloaded and unarchived the result (didn’t change name from demo)
  5. Create: demo/src/main/resources/static/index.html with the following contents:
    <html><body>YOU ARE IN!</body></html>
  6. Issue the following in the demo directory to run your application: ./gradlew bootRun
  7. Open a browser and go to http://localhost:8080/

You now have proof that putting something into MY PROJECT/src/main/resources/static/ will produce the contents of your HTML file.

So I have the following questions:

  • Did you add SpringMVC into your spring boot project using something like compile('org.springframework.boot:spring-boot-starter-web')?

  • Did you put your static content into MY PROJECT/src/main/resources/static/?

  • Why do you need a controller to serve static content if one is provided for you? Especially one that is mapped to /?
  • Is angular putting *.html files into MY PROJECT/src/main/resources/static/?
  • What does the javascript console say? Is runtime.js found?

Please see https://spring.io/guides/gs/serving-web-content/ in section Add a Home Page

Please see https://stackoverflow.com/questions/24661289/spring-boot-not-serving-static-content content for other ideas of what not to do (and why).

This was originally posted on https://www.quora.com/How-can-spring-boot-serve-angular-static-files/answer/David-Talalayevsky

DavidT
  • 356
  • 2
  • 7
  • Thanks @DavitT for the reply. Plz see the answers to your ques at the end of my post. I just updated them. – anonymous-explorer Sep 15 '18 at 22:49
  • And I followed demo gradle project and know for sure that content in MY PROJECT/src/main/resources/static/ displays content of index.html on 8080. But I don't understand how is it different from what I currently have in the same path except those are angular generated .html and .js files and why isn't picking up then. – anonymous-explorer Sep 16 '18 at 15:03
  • Although in my case, I see a 200 response on inspect and [ ] on webpage. – anonymous-explorer Sep 16 '18 at 15:23
  • @Soc So now you have narrowed down the issue to angular output and the fact that your web page has something wrong with it. You will really need to look at the console and learn to read it (See something like https://www.webnots.com/how-to-use-developer-tools-in-chrome/ specifically section 4, but all the other stuff is important too). First tell Angular to output something super simple like "Hello World". If it doesn't it is your web page, if it does, then it is some of your JavaScript code. Then follow those two paths. – DavidT Sep 16 '18 at 23:14
0

This is because you are using the @RestController annotation that implicitly includes @ResponseBody. You must use @Controller for Spring boot to automatically load a html template.

@Controller
public class AppController {
    @GetMapping("/")
    public String index() {
        return "index";
    }
 }
Gianni Azizi
  • 222
  • 1
  • 9
  • I have tried with @Controller annotation as well and when browsed to localhost:8080 still shows no UI content just [ ] on webpage. Although I notice on Angular symbol on the chrome tab so it is trying to pick up the content but nothing on UI display. – anonymous-explorer Sep 07 '18 at 17:58
  • Oh ok, you must change the default folder, this can help you : https://www.logicbig.com/tutorials/spring-framework/spring-boot/boot-serve-static.html – Gianni Azizi Sep 07 '18 at 18:03
  • So technically whatever content I place in one of those folders in classpath( /resources, /static, /public etc.) starting tomcat , it should have picked up index.html and related content. Even though I explicitly specified and set spring.resources.static-locations (see updated code above) , localhost:8080 still shows no UI. – anonymous-explorer Sep 07 '18 at 18:38
  • Actually, I inserted a page1.html with just a heading to verify if tomcat picks up anything from resources folder and seems like it doesn't. I can't see its content as well on webpage. – anonymous-explorer Sep 07 '18 at 18:47
  • Can you try to replace "@Configuration @EnableAutoConfiguration @ComponentScan({"webapp"})" by "@SpringBootApplication" ? – Gianni Azizi Sep 08 '18 at 09:06
  • Tried it but still no UI on localhost:8080. Is there something wrong in my index.html? This is what get's generated on ng build along with other .js files which are mentioned as scripts. Anything else I could try ? – anonymous-explorer Sep 08 '18 at 15:59
0

On Controller method try to put @RequestMapping annotation just an suggestion

Like this:

@Controller
@RequestMapping("/")
public class AppController{ 
 }

And on ComponentScan (basepackages{"com.packagename of modal classes"})

Vishal Torne
  • 366
  • 5
  • 24
0

It happens because spring try to process you requests and it not understand that they should go to static. Try to add following config:

@Configuration
public class MvcConfig implements WebMvcConfigurer {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/ui/**").setViewName("/");
    }
}

where addViewController("/ui/**") it is pattern for accessing you angular pages

kopn9k
  • 21
  • 7