My uploaded photos does not show on the webpage. What could it be?

I have a Spring Boot app and I’ve deployed it via Dockerfile. Then I created a volume (named: get_your_travel_app_data) for this app and then mounted it like so:

image

I deployed it again, and an uploads folder has been created on the server, so it seems the mount process maybe was okay. So after I used this command: fly ssh console -a get-your-travel-app -C "df -h" , I got this:

image

I uploaded successfully more pictures via my webpage, and then these pictures appeared in the uploads folder (I checked them via flyctl ssh console and I can see them in the uploads folder). But when I reload my webpage, the uploaded pictures does not appear where they should be, so I see just this:

image

As my pictures are under the uploads folder (as I gave this as destination in the Dockerfile), I used in my code an absolute path to reach the content of this folder of the server, so this: /uploads. I use thymeleaf as template engine in my Spring Boot app, so my src attribute of the <img> tag is like: <img th:src=@{'/uploads/' + ${picture1.jpg}} > . The syntax of this src attribute should be okay, as if I use pictures from my localhost then they appear fine. Maybe the path is wrong?

Or what can be wrong? Why I don’t see the pictures I’ve uploaded? I searched for similar posts here but I didn’t find an exact solution for my problem…I really appreciate if anybody can help. Thank you!

You are going to want to do is to get your webserver (tomcat?) to serve these files. Perhaps this link will help: https://spring.io/blog/2013/12/19/serving-static-web-content-with-spring-boot ; this may be as simple as mounting your volume at /app/public/uploads instead of simply /uploads. Once you have that working, you may want to look into App Configuration (fly.toml) · Fly Docs

1 Like

Yes, my webserver is an embedded tomcat inside my app. So thank you for your quick reply and for these links, I will play around them, and will come back later. I’ve spent so many hours with this already, I’m really happy that somebody already knows what is my problem and wrote good insights about it what I didn’t think and know. Thank you.

Ok guys, I need further help.
So there are many combinations of the configuration of the different files (Dockerfile, fly.toml) , and I tried already a ton of them, and I’m so unlucky nothing had worked so far.
I think it’s easier if I copy here my Dockerfile and my fly.toml file too and give more data too, and maybe some of you guys can help me, maybe @rubys ?
Ok, so my Dockerfile is (so I’m totally new with all of these things):

FROM ibm-semeru-runtimes:open-11-jre-focal
WORKDIR /app/public
COPY target/GetYourTravel-0.0.1-SNAPSHOT.jar GetYourTravel-0.0.1-SNAPSHOT.jar
ENV _JAVA_OPTIONS="-XX:MaxRAM=70m"
CMD java $_JAVA_OPTIONS -Dspring.datasource.url=$SPRING_DATASOURCE_URL -Dspring.datasource.username=$SPRING_DATASOURCE_USERNAME -Dspring.datasource.password=$SPRING_DATASOURCE_PASSWORD -jar GetYourTravel-0.0.1-SNAPSHOT.jar

My fly.toml file is (I will leave the SPRING_DATASOURCE_URL and the SPRING_DATASOURCE_USERNAME environments empty by the environment part):

# fly.toml file generated for get-your-travel-app on 2023-03-30T18:07:34+02:00

app = "get-your-travel-app"
kill_signal = "SIGINT"
kill_timeout = 5
primary_region = "ams"
processes = []

[env]
  MANAGEMENT_METRICS_EXPORT_PROMETHEUS_ENABLED = "false"
  SPRING_DATASOURCE_URL = ""
  SPRING_DATASOURCE_USERNAME = ""
  _JAVA_OPTIONS = "-XX:MaxRAM=70m"

[experimental]
  auto_rollback = true

[mounts]
  destination = "/app/public/uploads"
  source = "get_your_travel_app_data"

[[services]]
  http_checks = []
  internal_port = 8080
  processes = ["app"]
  protocol = "tcp"
  script_checks = []
  [services.concurrency]
    hard_limit = 25
    soft_limit = 20
    type = "connections"

  [[services.ports]]
    force_https = true
    handlers = ["http"]
    port = 80

  [[services.ports]]
    handlers = ["tls", "http"]
    port = 443

  [[services.tcp_checks]]
    grace_period = "1s"
    interval = "15s"
    restart_limit = 0
    timeout = "2s"

[[statics]]
  guest_path = "/uploads"
  url_prefix = "/app/public/uploads"

(I’ve tried more combinations of guest_path and url_prefix, but of course it’s possible that not everything yet, but really more, this is just the last one.)

My file structure inside my Spring Boot project (I just want you guys could see where my uploads folder is here):

And one other thing, tha classpath part of my Spring Boot app - related to this: https://spring.io/blog/2013/12/19/serving-static-web-content-with-spring-boot what @rubys mentioned above. So this in my case is (I think it should be fine, but if no, tell me please, but this part seems very self-evident):

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {

        if (!registry.hasMappingForPattern("/uploads/**")) {
            registry
                    .addResourceHandler("/uploads/**")
                    .addResourceLocations("classpath:/static/uploads/");
        }

        if (!registry.hasMappingForPattern("/static/**")) {
            registry
                    .addResourceHandler("/static/**")
                    .addResourceLocations("classpath:/static/");
        }

        if (!registry.hasMappingForPattern("/resources/**")) {
            registry
                    .addResourceHandler("/resources/**")
                    .addResourceLocations("classpath:/resources/");
        }
    }

So, again, my problem is: I can upload new photos via my webpage, and then these new photos will appear in the uploads folder under /app/public/ , so I can see them via flyctl ssh console. But these uploaded photos don’t appear on my website, somehow I can’t reach them: I use this src attribute of the <img> (thymeleaf syntax) :
<img th:src=@{'/app/public/uploads/' + ${picture}} >

What can be wrong guys? Maybe it’s not necessary to mount my volume, or the absolute path is wrong, or both, or wrong / incomplete Dockerfile or fly.toml, or… ?

Using the command: fly ssh console -a get-your-travel-app -C "df -h" gives this:

image

Many many thanks!!

I’m rusty on Tomcat, and never personally used Spring, but here goes.

Let’s start with your toml. If you get your [[statics]] section right, the request will never make it to your server, the files will be served by fly’s proxy directly, which is good.

There I think you have the values backwards. What that says is that https://get-your-travel-app.fly.dev/app/public/uploads/image.jpg should be mapped to /uploads/image.jpg on disk. Swap guest_path and url_prefix. This may be enough.

Next you seem to be mapping /uploads/** to classpath:/static/uploads. What you probably want instead is file:/app/public/uploads. Either that, or mount your get_your_travel_app_data to a directory named “static” that is placed along your classpath.

What makes configurations like these confusing is that an initial “/” means different things in different places. Depending on the context, it may mean the root of your filesystem. Or the root of your URL. Or a subdirectory on your classpath. Keeping this straight is confusing.

2 Likes

IT’S WORKING!!!
THANK YOU @rubys !!! One of the best day ever!!!

So your mentions was brilliant, I just kept to understand more these things like classpath, [[static]] section, and that the addResourceHandler and addResourceLocations methods what really do…so I swapped the guest_path and the url_prefix paths as you said:

[[statics]]
  guest_path = "/app/public/uploads"
  url_prefix = "/uploads"

Then I changed my addResourceHandlers method as you recommended:

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {

        if (!registry.hasMappingForPattern("/uploads/**")) {
            registry
                    .addResourceHandler("/uploads/**")
                    .addResourceLocations("file:/app/public/uploads/");
        }
    }

and then the one last part:

changing the src attribute of the <img> tag from this:
<img th:src=@{'/app/public/uploads/' + ${picture}} >
to this:
<img th:src=@{'/uploads/' + ${picture}} >

Because of the fly.toml [[static]] section, as any requests starting with /uploads/… will be mapped to /app/public/uploads on the disk, just as you @rubys said. :slight_smile:
So the whole picture has came together and everything works!
Thank you very very much for your time and help @rubys !!! :slightly_smiling_face:

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.