Esportare una webapp in Spring Boot in file .jar

di il
39 risposte

39 Risposte - Pagina 2

  • Re: Esportare una webapp in Spring Boot in file .jar

    Sempre grazie per il tuo supporto, è un piacere leggerti. Si, è esatto quello che scrivi. Vorrei pubblicare tutto ma senza pagare un centesimo perché non sono un’azienda, da questo progetto non monetizzo nulla. Sto smanettando su Docker perché configurare manualmente tutti i vari servizi richiede troppo tempo nel caso decida o sia obbligato a cambiare provider. Io ho a disposizione una VPS gratuita ed un nome a dominio gratuito. Ovviamente la VPS che ho a disposizione non è configurata. Sul server trovo Ubuntu 22.04 LTS appena installato senza niente sopra. Se un domani decidessi di passare ad una VPS diversa con Docker non devo più preoccuparmi di installare Tomcat, Java, PostgreSQL, ecc…. Ormai la containerizzazione è una pratica diffusa e consolidata. L’installazione dei singoli servizi è una pratica forse attuata da chi produce app commerciali come le tue dove la sicurezza è molto importante ma per i miei scopi didattici Docker è più che sufficiente come soluzione. In passato ho provato ad installare Tomcat, un DB e richiede davvero troppo tempo, non voglio assolutamente percorrere quella strada. Se hai altre idee scrivi pure ma la mia soluzione è gratuita al 100%.

    Non riesco a capire perché questo template non venga letto. Ho anche provato ad aggiungere ad application.properties il codice seguente ma non risolvo.
    spring.thymeleaf.prefix=classpath:/templates/
    spring.thymeleaf.suffix=.html
    Potrebbe essere un bug di Spring Boot? Se si dove e come posso segnalarlo?
    Se setto:
    spring.profiles.active=sviluppo
    nel file application.properties, IntelliJ apre il sito nel browser e funziona tutto a meraviglia.
    I 3 properties sono identici e mi sembrano ben scritti:
    application.properties
    
    spring.profiles.active=sviluppo
    spring.datasource.driver-class-name=org.postgresql.Driver
    spring.datasource.url=...
    spring.datasource.username=...
    spring.datasource.password=...
    server.port=8443
    server.ssl.key-store=...
    server.ssl.key-store-password=...
    server.ssl.keyStoreType=...
    server.ssl.keyAlias=...
    logging.level.org.springframework=INFO
    spring.sql.init.mode=always
    spring.sql.init.continue-on-error=false
    
    application-docker.properties
    
    spring.datasource.driver-class-name=org.postgresql.Driver
    spring.datasource.url=jdbc:postgresql://postgresql-postgis:5432/...
    spring.datasource.username=...
    spring.datasource.password=...
    spring.sql.init.schema-locations = classpath:schema.sql
    server.port=8443
    server.address=0.0.0.0
    server.ssl.key-store=classpath:KeyStore.jks
    server.ssl.key-store-password=mysecret
    server.ssl.keyStoreType=JKS
    server.ssl.keyAlias=mydomain
    logging.level.org.springframework=DEBUG
    spring.sql.init.mode=always
    spring.sql.init.continue-on-error=false
    
    application-sviluppo.properties
    
    spring.datasource.driver-class-name=org.postgresql.Driver
    spring.datasource.url=jdbc:postgresql://127.0.0.1:5432/...
    spring.datasource.username=...
    spring.datasource.password=...
    spring.sql.init.schema-locations = classpath:drop.sql, classpath:schema.sql
    server.port=8443
    server.address=127.0.0.1
    server.ssl.key-store=classpath:KeyStore.jks
    server.ssl.key-store-password=mysecret
    server.ssl.keyStoreType=JKS
    server.ssl.keyAlias=mydomain
    logging.level.org.springframework=INFO
    spring.sql.init.mode=always
    spring.sql.init.continue-on-error=false
    
  • Re: Esportare una webapp in Spring Boot in file .jar

    iBaffiPro ha scritto:


    Io ho a disposizione una VPS gratuita ed un nome a dominio gratuito.
    Ah beh ... allora ok. È chiaro che una VPS è ben di più di un "comune" hosting Tomcat, perché hai una intera macchina (sebbene virtuale) su cui puoi fare a sufficienza quello che vuoi (compreso l'uso di Docker se non proibito per altre ragioni).

    iBaffiPro ha scritto:


    spring.thymeleaf.prefix=classpath:/templates/
    spring.thymeleaf.suffix=.html
    Questi sono già i valori di default (da reference di Boot), non servirebbe affatto ri-specificarli nei properties.

    iBaffiPro ha scritto:


    Se setto:
    spring.profiles.active=sviluppo
    nel file application.properties, IntelliJ apre il sito nel browser e funziona tutto a meraviglia.
    Chiariamo una cosa: il profilo Spring non è bene che sia impostato così con spring.profiles.active.
    Sarebbe meglio impostarlo dall'esterno: variabile di ambiente o opzione command-line

    1)
    export SPRING_PROFILES_ACTIVE=docker
    java -jar blabla.jar

    2)
    java -jar blabla.jar --spring.profiles.active=docker
  • Re: Esportare una webapp in Spring Boot in file .jar

    Grazie per la dritta. Ho provato il tuo consiglio ma non ho risolto.
    
    FROM openjdk:11.0.15-jre-slim
    EXPOSE 8080
    EXPOSE 8443
    WORKDIR /demoapp
    COPY target/prova-10.0.jar /demoapp/
    CMD ["java", "-jar", "/demoapp/prova-10.0.jar", "--spring.profiles.active=docker"]
    
    "export SPRING_PROFILES_ACTIVE=docker" non saprei come usarlo dato che uso docker-compose e non docker.
    Se faccio in questo modo:
    
        environment:
          SPRING_PROFILES_ACTIVE: docker
    
    non risolvo.
    Tutto molto strano...
    Alcune pagine vengono renderizzate altre no... tutto molto strano...
  • Re: Esportare una webapp in Spring Boot in file .jar

    iBaffiPro ha scritto:


    "export SPRING_PROFILES_ACTIVE=docker" non saprei come usarlo dato che uso docker-compose e non docker.
    Nel Dockerfile:

    RUN export SPRING_PROFILES_ACTIVE=docker

    iBaffiPro ha scritto:


    Alcune pagine vengono renderizzate altre no... tutto molto strano...
    Verifica che nel jar i template ci siano e nel posto giusto. Occhio, che quello è il "fat jar" quindi la struttura è diversa per via del classloader custom di Spring Boot.
  • Re: Esportare una webapp in Spring Boot in file .jar

    Nel jar i file sono nel posto giusto:
    
    prova-10.0\BOOT-INF\classes\templatesprova-10.0\BOOT-INF\classes\application-docker.properties
    
    Ho anche provato "RUN export SPRING_PROFILES_ACTIVE=docker" ma non risolvo.
    
    FROM openjdk:11.0.15-jre-slim
    EXPOSE 8080
    EXPOSE 8443
    WORKDIR /demoapp
    COPY target/prova-10.0.jar /demoapp/
    RUN export SPRING_PROFILES_ACTIVE=docker
    CMD ["java", "-jar", "/demoapp/prova-10.0.jar"]
    
  • Re: Esportare una webapp in Spring Boot in file .jar

    Ho provato anche ad usare un'altra immagine di Docker (ce ne sono centinaia) ma il problema resta sempre lo stesso:
    FROM openjdk:11
    EXPOSE 8080
    EXPOSE 8443
    WORKDIR /usr/src/myapp
    COPY ./target/prova-10.0.jar /usr/src/myapp/
    RUN export SPRING_PROFILES_ACTIVE=docker
    CMD ["java", "-jar", "/usr/src/myapp/prova-10.0.jar"]
    
    container-java-eb     | 2022-05-30 22:13:47.376 ERROR 1 --- [0.0-8443-exec-5] o.a.c.c.C.[.[.[/it].[dispatcherServlet]  : Servlet.service() for servlet [dispatcherServlet] in context with path [/it] threw exception [Request processing failed; nested exception is org.thymeleaf.exceptions.TemplateInputException: Error resolving template [/test-server-asincrono], template might not exist or might not be accessible by any of the configured Template Resolvers] with root cause
    
  • Re: Esportare una webapp in Spring Boot in file .jar

    iBaffiPro ha scritto:


    ma il problema resta sempre lo stesso:
    org.thymeleaf.exceptions.TemplateInputException: Error resolving template [/test-server-asincrono], template might not exist or might not be accessible by any of the configured Template Resolvers
    Quindi NON ti funziona per un solo profilo o per tutti? Se non funziona solo con il profilo es. docker, mi pare molto strano.
    Fai il build del jar (rifallo da zero, possibilmente), lancia l'applicazione normalmente standalone con il profilo sviluppo. Funziona? Se sì, (ri)fai l'immagine (con quel jar!) e prova ora con Docker.

    E verifica anche di NON aver usato @Profile in maniera sconsiderata, ovvero in posti dove non ha senso o non è appropriato.

    iBaffiPro ha scritto:


    Ho provato anche ad usare un'altra immagine di Docker (ce ne sono centinaia)
    FROM openjdk:11
    Sì ce ne sono tante perché ci sono svariate varianti. Quest'ultima che hai usato è il JDK completo quindi con il compilatore ecc... Che non serve ed appesantisce solo la tua immagine finale.

    Quella che avevo indicato io, openjdk:11.0.15-jre-slim:
    a) è una versione ben precisa, non solo "11" per indicare l'ultima della 11.x
    b) è il JRE (quindi senza compilatore e altri tools)
    c) è "slim", indica che il runtime è, come si dice in gergo, "headless", ovvero non ha tutta la parte legata alle interfacce grafiche (AWT, ecc...) che per applicazioni "server" di fatto ... non serve a un piffero. Quindi ancora meno roba nella immagine.

    Ma per tua cultura/curiosità, puoi provare anche altre distribuzioni del OpenJDK:
  • Re: Esportare una webapp in Spring Boot in file .jar

    Non mi funziona solo per 1 profilo, il profilo docker.
    Se guardi i 2 properties sono quasi uguali.
    Il profilo sviluppo lo uso in locale su IntelliJ/Windows 10 e funziona con queste specifiche:
    spring.sql.init.schema-locations = classpath:drop.sql, classpath:schema.sql
    server.address=127.0.0.1
    Il profilo docker lo uso su Docker/Ubuntu 22.04 LTS e "funziona in parte" con queste specifiche:
    spring.sql.init.schema-locations = classpath:schema.sql
    #server.address=127.0.0.1
    Non voglio cancellare il DB al riavvio della WebApp e se uso 127.0.0.1 oppure localhost, su Linux, come detto in precedenza, la WebApp non renderizza nulla.

    Ho rimosso tutti i @Profile ma ne avevo solo uno nella classe del main(), quello che mi avevi fatto notare e che avevi detto che era inutile.
  • Re: Esportare una webapp in Spring Boot in file .jar

    iBaffiPro ha scritto:


    Il profilo sviluppo lo uso in locale su IntelliJ/Windows 10 e funziona con queste specifiche:
    spring.sql.init.schema-locations = classpath:drop.sql, classpath:schema.sql
    server.address=127.0.0.1
    Il profilo docker lo uso su Docker/Ubuntu 22.04 LTS e "funziona in parte" con queste specifiche:
    spring.sql.init.schema-locations = classpath:schema.sql
    #server.address=127.0.0.1
    Ok ma tutto questo non mi pare che c'entri qualcosa con l'errore segnalato

    org.thymeleaf.exceptions.TemplateInputException: Error resolving template [/test-server-asincrono], template might not exist or might not be accessible by any of the configured Template Resolvers

    Ovvero "non trova il template". E il fatto che il problema sia solo sul profilo docker (e non sviluppo) pare molto strano.
    Però ora che ci penso ..... sulla macchina fisica hai sicuramente (presumo) il Oracle JDK mentre nel container Docker hai l'OpenJDK.

    Mostra quello che hai scritto nel controller per far restituire e indicare quel template lì che sta dando problemi.
  • Re: Esportare una webapp in Spring Boot in file .jar

    Controller:
    
    @Controller
    public class ControlloPagineWeb {
    
        // questa pagina fornisce l'errore 500
        @RequestMapping(value = "/storico-elementi", method = RequestMethod.GET)
        public String storicoElementiGET(
                Model model,
                Principal principal,
                HttpSession session,
                HttpServletRequest request,
                HttpServletResponse response
        ) {
            try {
                variabiliGeneraliPerPaginaHTML(principal, model, session, request, response);
                model.addAttribute("titolo", "Storico elementi");
                model.addAttribute("messaggio", "Storico elementi");
                return "/storico-elementi";
            }catch (Exception e){
                return "/storico-elementi";
            }
        }
    	
        // questa pagina viene renderizzata senza problemi
        @RequestMapping(value = "/cerca-elementi", method = RequestMethod.GET)
        public String cercaElementiGet(
                Model model,
                Principal principal,
                HttpSession session,
                HttpServletRequest request,
                HttpServletResponse response
        ) {
            variabiliGeneraliPerPaginaHTML(principal, model, session, request, response);
            model.addAttribute("titolo", "Cerca elementi");
            model.addAttribute("messaggio", "Cerca elementi");
            CercaElementi cercaElementi = new CercaElementi();
            model.addAttribute("CercaElementi", cercaElementi);
            return "cerca-elementi";
        }
    	
    }
    
    JDK su IntelliJ:
    https://www.oracle.com/it/java/technologies/javase/jdk11-archive-downloads.html
    Windows x64 Compressed Archive
    (jdk-11.0.15 >> decompresso sono 255 MB)
    Maven su IntelliJ:
    Binary zip archive >> apache-maven-3.8.5-bin.zip >> apache-maven-3.8.5 >> 9.68MB
    Tomcat scaricato da Spring Boot ed inserito nel .jar finale:
    2022-05-31 18:59:46.856  INFO 12236 --- [  restartedMain] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.63]
    Java su Docker:
    FROM openjdk:11.0.15-jre-slim
    Su IntelliJ io leggo Oracle OpenJDK
    Immagine.png
    Immagine.png

  • Re: Esportare una webapp in Spring Boot in file .jar

    iBaffiPro ha scritto:


    Controller:
    
                return "/storico-elementi";
            }catch (Exception e){
                return "/storico-elementi";
            }
    Togli gli slash !!!!!!!!!

    Il prefisso di default è già con lo slash finale:

    classpath:/templates/

    quindi lo slash non va mai messo in testa quando indichi un template.

    PS. Oracle JDK e OpenJDK evidentemente si comportano diversamente.
  • Re: Esportare una webapp in Spring Boot in file .jar

    Bravissimo AndBin! Sei il numero 1 in assoluto!!!



    SEMPLICEMENTE MAGNIFICO!!!

    Non sapevo che esistessero 2 versioni di JDK e non capisco neppure per quali ragioni devono esistere 2 versioni di JDK. Questo è un gran pasticcio megagalattico! Ma che senso ha!?!?!?!
  • Re: Esportare una webapp in Spring Boot in file .jar

    iBaffiPro ha scritto:


    Non sapevo che esistessero 2 versioni di JDK e non capisco neppure per quali ragioni devono esistere 2 versioni di JDK. Questo è un gran pasticcio megagalattico! Ma che senso ha!?!?!?!
    Principalmente "questioni di licenza". Basta che cerchi in rete Oracle JDK vs OpenJDK
    E per il OpenJDK, come ho già anticipato prima, esistono varie distribuzioni/pacchettizzazioni. Basta vedere: https://en.wikipedia.org/wiki/OpenJDK#OpenJDK_build


    Comunque presta sempre attenzione a questi dettagli. Se ci sono 2 property con default come:
    Property                    Default
    ---------------------------------------------------
    spring.thymeleaf.prefix     classpath:/templates/
    spring.thymeleaf.suffix     .html
    Se è stato preimpostato uno slash dopo templates, NON è un caso. Così si può fare semplicemente return "home" e Spring compone

    classpath:/templates/home.html

    Che è corretto. Ma se metti "/home" risulta poi un doppio slash e questo può essere mal "digerito" dal runtime Java (come presumo faccia il OpenJDK dove non ti funziona).
  • Re: Esportare una webapp in Spring Boot in file .jar

    Si si è proprio come scrivi! Meno male che te ne sei accorto, non sapevo più dove sbattere la testa. Grazie infinite.
    Per caso sai se è possibile escludere dal .jar alcuni file come facevo con il .war?
    
                <configuration>
                    <packagingExcludes>
                        WEB-INF/classes/funzioni.sql,
                        WEB-INF/classes/drop.sql,
                        ...
                    </packagingExcludes>
                </configuration>
    
    Altra cosa che non ho capito bene è cosa accade nel contenitore.
    In pratica quando scrivo "COPY target/prova-10.0.jar /demoapp/" Docker copia in /demoapp il file .jar e lo decomprime?
    Ti faccio questa domanda perché mi sono accorto che a questa configurazione manca il volume del servizio.
    Immagina di aver creato un'app simile a WordPress. Le immagini delle notizie non finiscono nel db ma sul disco dell'OS (ipotizziamo che non si voglia usare MongoDB ma solo PostgreSQL o MySQL). Per questa ragione io devo creare un volume che espone dal contenitore la cartella nella quale finiscono tutte le immagini. Quando si crea un'app di questo tipo dove possono essere salvate le immagini? In 'prova-10.0\BOOT-INF\classes\cartella-immagini' è lecito? Posso creare un volume per /demoapp? Tu come ti comporti con le tue applicazioni che salvano immagini o comunque dei dati sul disco?
  • Re: Esportare una webapp in Spring Boot in file .jar

    iBaffiPro ha scritto:


    Per caso sai se è possibile escludere dal .jar alcuni file come facevo con il .war?
    Sì, basterebbe configurare il maven-jar-plugin. (non ho modo di fare una prova ora)
    https://maven.apache.org/plugins/maven-jar-plugin/examples/include-exclude.html

    iBaffiPro ha scritto:


    Altra cosa che non ho capito bene è cosa accade nel contenitore.
    In pratica quando scrivo "COPY target/prova-10.0.jar /demoapp/" Docker copia in /demoapp il file .jar e lo decomprime?
    No, non decomprime nulla. COPY copia dalla tua macchina al file-system della immagine.

    La tua immagine finale, quella di cui fai il run è basata su uno o più layer. Ma ciascun layer di fatto è una immagine, semplicemente è una immagine intermedia che non ha un nome esplicito ma solo il ID autogenerato.

    I comandi che metti nel Dockerfile generano i layer. Il COPY genera un nuovo layer in cui dice che ci sono un tot di file (uno o più) a certe locazioni del filesystem. Nel caso del COPY sopra, il layer è composto da un singolo file (il jar) in quella locazione specifica ( /demoapp ).
    Immagina che ciascun layer sia come uno di quei fogli di acetato trasparente che si usano nelle scuole. Sul foglio ci puoi scrivere sopra ma è trasparente, quindi vedi attraverso. Sul layer (il "foglio trasparente") ci sono le informazioni che descrivono ciò che c'è in più/in meno o differente sul filesystem.
    Ora, immagina di prendere tutti i fogli trasparenti (i layer) e di metterli uno sopra l'altro e poi guardare dall'alto partendo dall'ultimo layer generato. Ecco, quello che vedi è il risultato finale, ovvero la tua immagine.

    iBaffiPro ha scritto:


    Ti faccio questa domanda perché mi sono accorto che a questa configurazione manca il volume del servizio.
    Immagina di aver creato un'app simile a WordPress. Le immagini delle notizie non finiscono nel db ma sul disco dell'OS (ipotizziamo che non si voglia usare MongoDB ma solo PostgreSQL o MySQL).
    Le immagini che si creano come detto prima sono read-only, a sola lettura. Quando crei un nuovo container per eseguire l'immagine, il container è semplicemente uno strato in più ma attenzione, SCRIVIBILE. In sostanza, le applicazioni che girano nel container POSSONO scrivere sul file-system e questi dati sono persistenti. Perlomeno ... fintanto che il container non viene eliminato.

    Il problema è che se devi rifare l'immagine perché c'è qualcosa da aggiornare, il container lo devi ricreare e ... perdi tutto. Per questo sono stati ideati i "volumi" in Docker. Che sono separati dai container, possono essere riutilizzabili e anche eventualmente essere condivisi tra container differenti.
    Inoltre c'è la questione che il file-system del container, quello che è scrivibile, è basato su un "union filesystem" ed è quindi meno efficiente per via di questra stratificazione. Mentre i volumi scrivono direttamente sul file-system della macchina host, quindi più performante.
Devi accedere o registrarti per scrivere nel forum
39 risposte