23

I'm trying to run Spring boot app with some HTML5 and JavaScript and I have a problem.

I have project structure like this:

enter image description here

My Spring MVC Controller is calling file offer.html and that works ok.

My offer.html file look like this:

<!DOCTYPE html>
<html lang="en" ng-app="coByTu">
<head>
    <title>Page</title>
    <script type="text/javascript" src="../js/lib/angular.js" />
    <script type="text/javascript" src="../js/src/offer.js" />
</head>
<body>

</body>
</html>

And when I'm typing my app URL http://localhost:8080/offerView

response from server is:

enter image description here

I have no idea why my app doesn't see this script files, could any one have any idea what i did wrong?

Piotr Żak
  • 2,083
  • 6
  • 29
  • 42

7 Answers7

59

Basically all content that needs to be served staticly (such as javascript files) should be placed under the static folder. https://spring.io/blog/2013/12/19/serving-static-web-content-with-spring-boot

I've thrown together a quick working example to show how it is done: https://github.com/ericbv/staticContentWithSpringBoot

File structure: enter image description here

HTML file:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Page</title>
    <script type="text/javascript" th:src="@{/js/lib/angular.js}" />
    <script type="text/javascript" th:src="@{/js/src/offer.js}" />
</head>
<body>

Using th:src will make sure that the links are context aware

Edit: added the th:src to make the references context aware

Community
  • 1
  • 1
Eric
  • 644
  • 7
  • 14
  • 1
    I sugest to not use thymeleaf here :) ` ` is good enought. – Piotr Żak Nov 26 '15 at 09:39
  • Ass I assume when Spring Boot creates `Resource Handlers` for files contained in `/static` directory, and I want reffer to this Resource Handler in my offer.html using tag ` – Piotr Żak Nov 26 '15 at 09:43
  • 2
    Thats a bad practice. Not using thymeleaf here will break the page when there is a contextPath (i.e. when used inside of a standalone application server) – Eric Nov 26 '15 at 13:54
  • I have tried it without thymaleaf and everything works fine. What is bad practice? – Piotr Żak Nov 26 '15 at 14:53
  • 2
    It wont work if your app has a contextpath. In general you will have a context path when running your app from a standalone application server or because its added in application.properties. If you want to simulate a context path (to see when using just src breaks) add the folowing line to your applicaiton.properties file: "server.contextPath=/context" This will cause the page url to be localhost:8080/context/offerView Now in this case it will only work with the thymeleaf variant of src because this will take the context into account. – Eric Nov 26 '15 at 19:09
  • 1
    So app stack is Angular + Thymaleaf + Spring Boot, but as I want build single page application I don't understand Thymeleaf role as template engine here. – Piotr Żak Nov 27 '15 at 14:30
7

just for anyone to find this page with the same issue. The way I resolved the 'script is not executed' problem was pretty simple.

Simply replaced :

<script type="text/javascript" src="js/src/Test.js" />

with

<script type="text/javascript" src="js/src/Test.js" ></script>

(Test is located in 'static/js/src') Hopefully this is helpful to anyone but me :)

cheers

Chris
  • 103
  • 2
  • 10
3

You need to put your static js files into static folder. See more here: https://spring.io/blog/2013/12/19/serving-static-web-content-with-spring-boot

jny
  • 8,007
  • 3
  • 37
  • 56
1

I think you need to move the js directory (and contents) into the static directory (rather than having it in templates).

robjwilkins
  • 5,462
  • 5
  • 43
  • 59
0

Set the document root directory which will be used by the web context to serve static files using ConfigurableEmbeddedServletContainer.setDocumentRoot(File documentRoot).

Working example:

package com.example.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import java.io.File;
import java.nio.file.Paths;

@Configuration
public class WebConfigurer implements ServletContextInitializer, EmbeddedServletContainerCustomizer {
    private final Logger log = LoggerFactory.getLogger(WebConfigurer.class);

    private final Environment env;
    private static final String STATIC_ASSETS_FOLDER_PARAM = "static-assets-folder";
    private final String staticAssetsFolderPath;

    public WebConfigurer(Environment env, @Value("${" + STATIC_ASSETS_FOLDER_PARAM + ":}") String staticAssetsFolderPath) {
        this.env = env;
        this.staticAssetsFolderPath = staticAssetsFolderPath;
    }

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        if (env.getActiveProfiles().length > 0) {
            log.info("Web application configuration, profiles: {}", (Object[]) env.getActiveProfiles());
        }
        log.info(STATIC_ASSETS_FOLDER_PARAM + ": '{}'", staticAssetsFolderPath);
    }

    private void customizeDocumentRoot(ConfigurableEmbeddedServletContainer container) {
        if (!StringUtils.isEmpty(staticAssetsFolderPath)) {
            File docRoot;
            if (staticAssetsFolderPath.startsWith(File.separator)) {
                docRoot = new File(staticAssetsFolderPath);
            } else {
                final String workPath = Paths.get(".").toUri().normalize().getPath();
                docRoot = new File(workPath + staticAssetsFolderPath);
            }
            if (docRoot.exists() && docRoot.isDirectory()) {
                log.info("Custom location is used for static assets, document root folder: {}",
                        docRoot.getAbsolutePath());
                container.setDocumentRoot(docRoot);
            } else {
                log.warn("Custom document root folder {} doesn't exist, custom location for static assets was not used.",
                        docRoot.getAbsolutePath());
            }
        }
    }

    @Override
    public void customize(ConfigurableEmbeddedServletContainer container) {
        customizeDocumentRoot(container);
    }

}

Now you can customize your app with command line or profiles (src/main/resources/application-myprofile.yml: static-assets-folder: myfolder):

> java -jar demo-0.0.1-SNAPSHOT.jar --static-assets-folder="myfolder"
> java -jar demo-0.0.1-SNAPSHOT.jar --spring.profiles.active=myprofile
kinjelom
  • 6,105
  • 3
  • 35
  • 61
0

For Spring Boot beginners, I had a similar issue. My jQuery code was working fine within < script > tags at the bottom of my html doc (a thymeleaf template), but when I put the exact same code into an external .js doc in the static/js folder, it no longer responded. Super simple fix - just needed to put all that .js doc code inside this: $(document).ready(function () { ...code ... }); and then it worked fine. Hope this helps someone.

Forrest
  • 2,968
  • 1
  • 27
  • 18
0

I added spring.mvc.static-path-pattern=/static/** to application.properties file and now it works.

In html I use like this src="/static/js/jQuery.min.js"

Andry Max
  • 25
  • 1
  • 6