In questa pagina sono raggruppati tutti gli articoli riguardo Java e Spring Boot.
Questa non è una guida al linguaggio Java e non è una guida per la programmazione ma è solo una lista di esempi di codice e casi d'uso specifici. Si rimanda alla documentazione di Java e Spring Boot e alle tante guide disponibili in internet che possono essere trovati grazie ai motori di ricerca. Questi articoli riguardano il linguaggio Java, per leggerli bisogna conoscere le basi di Java, si da per scontato che il lettore possa compilare codice con un ambiente di sviluppo (come Eclipse o Code).
In questa pagina sono disponibili anche esempi di codice riguardo ai servizi AWS come le funzioni AWS-Lambda e l'uso della libreria AWS-SDK, anche in questo caso non si tratta di documentazione o guide riguardo al Cloud AWS ma si tratta solo di esempi di codice con il puro scopo divulgativo.
![]() |
Il tool Apache Maven è considerato il miglior tool di gestione dei pacchetti e delle dipendenze, in questa serie di articoli viene usato in tutti i progetti. |
![]() |
Eclipse è un ambiente di sviluppo (SDK), in questi articoli viene usato per la gestione di tutti i progetti Java, è possibile usare altri SDK compatibili con Maven. |
![]() ![]() |
Java mette a disposizione la tecnologia Java Enterprise Edition (J2EE) per la creazione di siti web dinamici che è diventata negli anni la tecnologia più usata in quanto robusta e facile da usare. In questo tipo di applicazioni è possibile usare le Java Server Page per creare pagine web ed è possibile creare applicazioni di grandi dimensioni con framework evoluti come Struts. |
![]() ![]() |
La precedente versione di questa pagina trattavano argomenti più datati come il framework Struts 2 e la libreria Java Gnome GTK. |
![]() |
AWS-SDK per Java è la libreria ufficiale di AWS per gestire risorse nel Cloud. In questo sito si fa riferimento alla versione 2, gli esempi sono disponibili nella pagina dedicata ad AWS e, i più interessanti, sono elencati anche in questa pagina. |
Maven è uno tool creato dal team di Apache per la gestione della compilazione dei progetti Java con lo scopo di gestire e organizzare le dipendenze di un qualsiasi progetto. È pensato per semplificare il processo di compilazione e semplificare la gestione delle dipendenze del progetto. Apache Maven è ormai diventato uno strumento essenziale per qualsiasi sviluppatore Java diventato uno strumento standard universalmente usato.
Maven è pensato per gestire anche il ciclo di vita del software con una serie di plug-in per l'esecuzione di test e la creazione di documentazione, ciò semplifica la gestione del progetto e garantisce che tutto venga svolto in modo coerente ed efficiente.
In tutti i successivi articoli di questa categoria verrà usato questo tool quindi si da per scontato che lettore abbiamo installato Maven, in questo articolo vengono introdotti i pochi comandi base che devono essere usati per la gestione dei progetti con questa libreria, a titolo introduttivo vengono usati i comandi da riga di comando (la shell di GNU Linux oppure il "cmd" Ms Windows) ma dai prossimi articoli verrà usato Eclipse o Visual Studio Code che risultano molto più comodi visto che mettono a disposizione un tool grafico.
I comandi di Maven possono essere riassunti in pochi punti:
- mvn compile: usato per compilare un progetto
- mvn clean: rimuove tutti i compilati esistenti
- mvn test: esegue tutti gli step di testing se presenti
- mvn install: esegue il deploy del pacchetto (Jar o War) nel repository locale se configurato
- mvn package: esegue la compilazione, il testing e l'installazione, viene quasi sempre usato al posti dei precedenti 4 comandi
- mvn deploy: esegue il precedente comando e poi carica il pacchetto (Jar o War) in un repository remoto se configurato
Mentre il comando base per creare un progetto è:
mvn archetype:generate -DgroupId=it.alnao -DartifactId=progettoJava
con questo comando viene avviato il generatore di progetti indicando i due parametri base (gruppo e artefatto), il programma chiede all'utente di inserirli se non sono indicati nel comando.
Il progetto creato presenta tre files:
- pom.xml: file di configurazione del progetto
- App.java: classe java base
- AppTest.java: classe java di test, vedere la sezione dedicata per approfondire l'argomento
Il file pom.xml presenta tutta una serie di informazione del progetto tra cui:
- nome del progetto e dati base come artifactId, groupId, versione
- proprietà del compiilatore tra cui la versione (dalla 1.7 in poi)
- elenco di tutte le librerie dipendenti
- comandi per la compilazione e plug-in con le varie configurazioni
Come visto in precedente per compilare il progetto il comando principale è:
mvn package
nel dettaglio il processo di compilazione esegue tutta una serie di passi che verranno descritti nei prossimi articoli, se la compilazione va a buon fine viene creato un file jar all'interno della cartella target, il comando per avviare il jar è il classico di java:
java -jar ./target/*.jar
ma lanciando il primo progetto senza modifiche si potrebbe ottenere un errore di compilazione in quanto, di default, il jar creato non è auto-avviante e non c'è nessuna "main-class", per configurare la classe da impostare come main modificare il file pom.xml aggiungendo il tag "configuration" nel plug-in "maven-jar-plugin":
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>dependency/</classpathPrefix>
<mainClass>it.alnao.App</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
come facilmente intuibile, nel tag xml è presente la configurazione che indica al compilatore di aggiungere nel manifest quale è la classe principale, in questo esempio è presente anche il "classpathPrefix" indispensabile se si vuole aggiungere qualche libreria dipendenza nel progetto.
Infatti è possibile aggiungere una dipendenza ad un progetto modificando il file pom.xml nella sezione-tag "depedencies", per esempio per aggiungere log4j al progetto :
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
questa viene aggiunta ma il compilatore deve essere configurato per "portare" la libreria nella cartella target e quindi deve essere aggiunto un ulteriore plugin al pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
</execution>
</executions>
</plugin>
e il comando per la compilazione diventa
mvn clean dependency:copy-dependencies package
infatti per poter eseguire la compilazione è indispensabile prima copiare le dipendenze dentro alla cartella "dependency" configurata nel precedente plugin.
public class App {
private static final Logger logger = LogManager.getLogger(App.class);
public static void main( String[] args ) {
BasicConfigurator.configure();
System.out.println( "Hello World!" );
logger.info("We've just greeted the user!");
}
}
Questo è un semplice esempio di classe java per verificare che la libreria log4j venga correttamente inclusa nel progetto e copiata nella cartella target.
Per la creazione di progetti web è possibile usare un archetipo specifico, impostandolo fin dalla creazione del progetto con il comando
mvn archetype:generate -DgroupId=it.alnao -DartifactId=02webModule -DarchetypeArtifactId=maven-archetype-webapp
questo tipo di progetto crea sempre tre files ma di tipo diverso:
- una pagina jsp
- un file di configurazione dell'applicazione web.xml
- il file pom.xml con caratteristiche ben diverse da quelle viste nel progetto classico
questo tipo di progetto viene approfondito nel dettaglio nei prossimi articoli.
Esiste anche un tipo specifico chiamato "maven-archetype-j2ee-simple" che va a create una completa applicazione j2ee con dei sotto-progetti specifici per ear, projects, servlets e il codice sorgente nella cartella src.
I dettagli sulla tool maven è disponibile al sito ufficiale, tutti i dettagli sugli archetipi è disponibile in questa pagina della documentazione ufficiale, l'elenco completo di tutti i plugin e le librerie disponibili come dipendenze è disponibile al repository ufficiale (mvnrepository), è consigliato tenere sempre a portata di mano questi link. Questi semplici esempi sono disponibili nel respository:
https://github.com/alnao/JavaExamples/tree/master/GenericJava
In qualsiasi progetto Java, in progetti puri o in framework strutturati, la gestione del log è un tema molto importante che deve essere sempre tenuto sotto controllo, la libreria principale è log4j sviluppata dalla comunità open-source di Apache Software Foundation. Di questa libreria esisono due versioni (uno e due), nei nuovi progetti viene usata la versione 2 ma in tutti i progetti degli ultimi 10 anni è usata la versione 1 quindi è bene avere sempre sotto mano le specifiche di entrambe le versioni. L'importazione della prima versione nel file pom di maven:
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
La seconda versione della libreria, presente di default in alcuni archetipi di maven, è importata con due dipendenze principali:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.13.0</version>
</dependency>
Storicamente la libreria necessita di un file di configurazione che deve essere posizionata nella cartella <resources> dentro al progetto, cioè nella cartella "src/main" se si tratta di un progetto java standard. La prima versione prevede un file properties dove è possibile configurare il sistema di logging, si rimanda alla documentazione ufficiale per tutti i dettagli su come impostare e usare al meglio la libreria. La seconda versione della libreria prevede un file di configurazione di tipo XML che deve essere "log4j2.xml", la documentazione ufficiale è ricca di esempi, il più semplice file di configurazione è:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
La scelta di una delle due librerie implica il dover adattare il codice Java sorgente delle classi alla libreria scelta, in particolare la classe principale LogManager è presente in entrambe le versioni ma in pacakge differenti:
//V1
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
//V2
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class App {
private static final Logger logger = LogManager.getLogger(App.class);
public static void main( String[] args ) {
BasicConfigurator.configure(); //only in V1
logger.debug("We've just greeted the user!");
logger.info("We've just greeted the user!");
logger.fatal("We've just greeted the user!");
}
}
In ogni caso si rimanda sempre alla documentazione ufficiale per maggiori informazioni ed esempi.
Eclipse è un ambiente di sviluppo (SDK), in questi articoli viene usato per la gestione di tutti i progetti Java, è possibile usare anche altri tool compatibili con Java-Maven come Visual Studio Code di Microsoft o i tool a pagamento come IntelliJ.
In Eclipse i progetti sono raggruppati in un workspace, tipicamente si usa una cartella del sistema come base di tutto lo spazio di lavoro e ogni sotto-cartella rappresenta un progetto, in questi articoli saranno usati solo progetti Java-Maven ma è possibile usare questo programma anche per altri tipi di progetto come i vecchi progetti J2EE e i progetti java puri.
Per creare un progetto Maven, si deve avvia la procedura guidata di creazione di un progetto dal menù principale e selezionando la voce "New", il tipo "Project" e poi cercare il wizard "Maven project". Nella finestra successiva si deve selezionare il Archetype, esattamente si si esegue in fase di creazione con la console testuale vista nel precedente articolo. Qui è possibile anche selezionare un tipo da una lista che Eclipse scarica da internet dai vari repository ufficiali e non, disponibili in tutto il monto. Se si vuole creare un progetto base senza particolari esigenze, è consigliato usare gli archetipi disponibili dal sito "org.apache.maven.archetypes", per esempio selezionando il tipo "maven-archetype-simple".
Nella seconda videata della procedura guidata è richiesto l'inserimento dei valori come il GroupId e il ArtifactId, esattamente come nella procedura da riga di mando. Una volta lanciato il processo di creazione nella vista console di Eclipse è possibile verificare tutti i messaggi di conferma che maven darebbe se il comando fosse lanciato da riga di comando. Al termine il progetto è pronto all'uso nella vista dei progetti con il suo pom.xml generato in automatico.
Eclipse permette anche di importare un progetto Maven non presente nel workspace, è consigliato importare progetti che si trovano nella stessa cartella del workspace stesso altrimenti potrebbero esserci problemi di conflitti da files, la procedura di import può essere lanciata dal menù principale nella voce "Import" e selezionando il wizard "Existing maven projects". Nella procedura guidata è necessario indicare la posizione esatta del file pom.xml, senza questo file infatti non si può parlare di progetto di tipo Maven.
Un progetto di tipo Maven in Eclipse si può riconoscere da una piccola lettera M presente nell'icona del progetto a fianco dell'icona J che indica Java come tipo di linguaggio del progetto, questo tipo di progetti hanno un menù dedicato tra le opzioni del progetto accessibili cliccando con il tasto destro nel progetto stesso. La funzionalità più interessante è la possibilità di aggiungere con una piccola procedura guidata una dipendenza la progetto, questa è l'alternativa più semplice al modificare il file pom.xml manualmente, per esempio per voler inserire la dipendenza dalla libreria log4j, disponbile all'indirizzo ufficiale è possibile aggiungere manualmente nel pom il tag:
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
oppure è possibile inserire i tre valori (groupId, artifactId e version) nella procedura guidata di Eclipse. Un semplice esempio di utilizzo di Log4J
package it.alnao.mavenEclipse;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
public class App {
private static final Logger logger = LogManager.getLogger(App.class);
public static void main( String[] args ){
BasicConfigurator.configure();
System.out.println( "Hello World!" );
logger.info("Hello world");
//set a breakpoint here to debug project
System.out.println( "END!" );
}
}
Per i progetti di questo tipo il programma mette a disposizione di compilazione nel sotto-menù "Run as" dove è possibile lanciare i comandi standard maven:
- "Maven install" che esegue il comando di installazione delle librerie dipendenti
- "Maven build" esegue la compilazione del progetto, alla prima esecuzione bisogna impostare "package" come Goal della compilazione così maven usa la cartella target come destinazione del jar corrispondente
- "Maven test" esegue tutte i test indicati nel file di configurazione
- "Java application" esegue il progetto come fosse una applicazione java senza compilare il jar
Eclipse dispone anche di una procedura per eseguire i debug di un progetto, per esempio inserendo un breakpoint in un punto del codice Java e poi cliccando sul sotto-menu "Debug" del progetto e selezionando la voce "Java application".
Per la creazione di applicazioni web Java mette a disposizione la tecnologia Java 2 Enterprise Edition (spesso abbreviata con la sigla J2EE), tecnica diventata negli anni uno standard molto usato in quanto robusto, sicuro ma anche flessibile. Il successo è dovuto soprattutto al linguaggio Java stesso che può fondersi con le tecnologie di frontend come HTML e Javascript. La tecnologia si può dividere in alcune componenti base. Si tratta delle tecnologie legate alla produzione di interfacce web dinamiche, le cui componenti si possono dividere in tre parti:
- pagine web Java Server Pages (JSP), Java Server Faces (JSF), Custom Tag oppure framework specifici come Struts
- logiche di business con Enterprise JavaBeans (EJB, giunti alla specifica 3.0), JNDI e Java Message Service (JMS)
- librerie esterne: esposizione di webservice, gestione di protocolli di rete.
La tecnologia permette facilmente di gestire la tecnologia model-view-controller (MVC) infatti, come standard universalmente usato i componenti si dividono in:
- model: classi Bean/DAO java spesso esterne ai progetti J2EE
- view: pagine web/jsp scritte in HTML con i tag messe a disposizione dalle varie librerie importabili
- controller: classi servlet oppure uso di un framework specifico come Struts
Eclipse mette a disposizione una procedura guidata per creare "Dynamic web Project" che rispettano lo standard J2EE ma conviene usare l'archetipo messo a disposizione dal Maven che risulta più completo e oggi lo standard mondiale per le applicazioni web in Java, da riga di comando si può lanciare
mvn archetype:generate -DarchetypeArtifactId = maven-archetype-webapp
oppure è possibile usare la procedura guidata di Eclipse selezionando l'archetipo "maven-archetype-webapp" Nel progetto creato vengono create le cartelle e i files:
- src/main/java: contiene tutte le classi java del progetto
- src/main/resources: contiene i file di properties del progetto
- src/main/webapp: contiene tutti i file jsp e la sotto-cartella WEB-INF
- src/main/webapp/WEB-INF: contiene tutti i componenti dell'applicazione che non si trovano nella root dell'applicazione, difficile definizione.
- src/main/webapp/WEB-INF/web.xml: file di configurazione del progetto J2EE, questo descrive tutte le componenti del progetto web
- src/main/webapp/WEB-INF/index.jsp: pagina di esempio
- src/main/webapp/WEB-INF/lib: cartella che può contenere jar usati dall'applicazione
- src/main/webapp/resources: può contenere tutte le componenti statiche del progetto web come immagini e stili
Talvolta, in alcune vecchie versioni dello standard J2EE la cartella "WebApp" veniva indicata con il nome di "WebContent". Una volta creato il progetto è possibile impostare la vista "Servers" di Eclipse per avviare dal programma il progetto web: prima bisogna impostare la "Server runtimes" nelle preferenze di Ecipse e poi agganciare l'applicazione nella view "Servers". Trattandosi di un progetto Maven standard è possibile compilarlo con il comando
mvn clean package
oppure usando il "mvn build" di Eclipse impostando il goal di tipo "package". Il risultato della compilazione non è un jar ma è un file war, questo può essere caricato in qualsiasi web-server java come Tomcat. In questo semplice progetto c'è solo una pagina che viene caricata e non c'è nessun codice java compilato.
Le servelt sono le classi java che, all'interno di un progetto web, hanno il compito di controllare il comportamento dell'applicazione, inteso proprio come controller nel paradigma MVC. Le classi sono composte da due proprietà una request (di tipo HttpServletRequest) e una response (di tipo HttpServletResponse), attraverso il primo oggetto è possibile accedere a tutte le informazioni utili come i parametri di input e gli oggetti in sessione mentre il secondo oggetto, inizialmente vuoto, deve essere valorizzato con la risposta che si vuole inviare al client, inoltre è disponibile anche un oggetto ServletContext (di tipo javax.servlet.ServletContext) con la quale è possibile accedere alle informazioni del contesto (context) di un’applicazione cioè tutte le informazioni generali. Le classe implementa uno dei metodi HTTP usati per la chiamata: doGet, doPost, doPut, doDelete.
Per creare una classe di questo tipo è possibile usare la procedura guidata di Eclipse che è possibile eseguire dal menù "New" selezionando il tipo "Classe Java Servlet" oppure è indispensabile creare a mano la classe con proprietà e metodi. Alla prima creazione, può comparire un errore di compilazione risolvibile facilmente impostando il "Java build path" del progetto java di Eclipse aggiugnendo le librerie ServerRuntime e WebAppLibraries. Da notare che, se si è usati la procedura guidata di Eclipse, questo avrà modificato in automatico il file web.xml impostando la servlet, se invece si è scelto di creare le classi a mano è indispensabile censire la servlet nel file:
<servlet>
<servlet-name>PrimaServlet</servlet-name>
<display-name>PrimaServlet</display-name>
<description></description>
<servlet-class>it.alnao.mavenExamples.PrimaServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>PrimaServlet</servlet-name>
<url-pattern>/PrimaServlet</url-pattern>
</servlet-mapping>
Questi due tag nel file di configurazione impostano due parametri: assegnano alla classe java un nome e assegnano a quel nome un pattern, questo ultimo sarà il endpoint nel quale la servelt sarà esposta nell'applicazione web. Infatti il webserver risponderà con la servelt dal endpoint:
http://localhost:<porta>/05mavenWebapp/PrimaServlet
Per stampare codice HTML da una servlet bisogna usare la classe "Printer", un semplice esempio di codice di servlet per visualizzare una frase:
private static final String HTML_TOP = "<html><head><title>Primo esempio servlet: tabelline</title></head><body>";
private static final String HTML_BOTTOM = "</body></html>";
private static final String TABLE_TOP = "<h3>Tabelline</h3><table width='80%'>";
private static final String TABLE_BOTTOM = "</table>";
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println(HTML_TOP);
out.println("Questa tecnica non è molto usata");
out.println(HTML_BOTTOM);
}
Tuttavia questa tecnica è poco usata in quanto non rispetta il paradigma di MVC: le servlet devono solo occuparsi della fase controller e non del view, per separare i compiti il controller richiama le componenti view (cioè le classi JSP) con un dispatcher.
request.setAttribute("nomeInRequest", "Alberto");
request.getSession().setAttribute("cognomeInSessione","Nao");
request.getRequestDispatcher("prova.jsp").forward(request, response);
In questo semplice esempio alla pagina di prova è possibile trasmettere dei dati attraverso la request oppure attraverso la sessione, si rimanda alla documentazione ufficiale per un approfondimento di cosa sono e come usare queste due tecniche. La pagina di default è sempre "index.jsp", tuttavia è possibile personalizzare la pagina di ingresso con un tag nel file di configurazione web.xml:
<welcome-file-list>
<welcome-file>prova.jsp</welcome-file>
</welcome-file-list>
La parte Java all'interno delle pagine JSP viene compilata in maniera sequenziale dalla prima riga, quindi all'inizio di ogni file si possono inserire le direttive che servono al compilatore Java per indicare come compilare la pagina, istruzioni simili alle import nelle classi Java, queste istruzioni vengno dette direttive e si indicano in una pagina con il tag:
<%@ page import="java.util.*" %>
per importare una o più classi e sono da usare come gli import java, usare una classe java in una jsp senza import genera un errore di compilazione che però viene segnalato solo in fase di esecuzione quindi solo quando la pagina jsp viene eseguita.
<%@ include file="filedaincludere.jsp" %>
in questo secondo esempio viene usata la direttiva include per includere nella corrente pagina un altro file jsp che verrà compilato assieme. Altre direttive molto usate sono sono:
<%@ page contentType="text/html" %>
<%@ taglib prefix="myprefix" uri="taglib/miataglib.tld" %>
importa nella pagina JSP una tag-lib che essere identificata tramite una URI (questo argomento viene approfondito nei prossimi articoli). Per quanto riguarda il codice java dentro le pagine jsp, di base si usano le scriptlet, sistema creato proprio per "mischiare" il codice HTML (client) e il codice Java (server) anche se questo sistema è considerato deprecato viene ancora usato ma molti anche per ragioni di retro-compatibilità nei progetti di grandi dimensioni. La prima disputa sul termine scriplet è se, in lingua italiana, il termine sia maschile (gli scriplet) o femminile (le scriptlet), ogni programmatore ha la propria opinione. In un corpo di pagina, una scriplet inizia con <%
e termina con %>
, per esempio:
<%
int i=0;
i++;
%>
In particolare si possono usare scriplet anche per fare cicli o condizioni di elementi HTML, per esempio
<%
for (int i = 0; i < 5; i++){
%> Ciao Mondo! <%
}
%>
<%!
, per esempio:<%!
public int void contaParole (String s){
StringTokenizer st = new StringTokenizer(s);
return st.countTokens();
}
%>
Ed è possibile definire il metodo jspInit che viene lanciato una sola volta e serve per inizializzare gli elementi in pagina e il metodo jspDestroy per la pulizia a fine caricamento. Le scriplet vengono usate soprattutto per inviare al client dei valori dal server, cioè passare dei valori da Java all'HTML, l'uso del tag <%=, da notare che in questo caso è possibile inserire una sola riga e NON si deve mettere il ; (punto e virgola) finale, credo sia l'unico caso in java:
<%=i%>
<%=contaParole("Quante sono queste parole?")%>
Da notare che gli oggetti request, session, out, exception e application sono oggetti considerati impliciti nella pagina quindi non serve importarli e/o definirli, per esempio è possibile usare:
<% out.print("valore"); %>
<%=valore%>
<%
String valoreId=request.getParameter("id");
session.setAttribute("id",valoreId);
%>
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+
":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Prova</title>
</head>
<body>
Pagina di prova
<br/>
BasePath = <%=basePath%>
<br />
<%=request.getAttribute("nomeInRequest") %>
<%=request.getSession().getAttribute("cognomeInSessione") %>
</body>
</html>
La caratteristica principale della programmazione di Java è l'uso delle classi e degli oggetti, esattamente come nei file di una classe, all'interno di un file jsp è possibile ed usare usare classi se importate ovviamente metatag:
<%@ page import="it.alnao.manuali.java.NomeClasse"%>
dopo l'import è possibile usare la classe nelle scriptlet, per esempio un metodo statico è richiamabile con:
<% NomeClasse.NomeMetodoStatico(); %>
Per JSP Tags si intendono elementi java utilizzabili nel codice delle pagine jsp, distribuiti dentro a delle librerie particolari dette TagLib che definiscono la "firma" del tag e anche la propria implementazione, l'uso di questi permette di separare il codice "client" da quello "server" con lo scopo di evitare di scrivere codice Java puro nelle pagine jsp e di superare i limiti della programmazione XHTML. Tutti i Custom tag hanno questa sintassi:
<prefix:tag attr1="value" ... attrN="value" />
oppure:
<prefix:tag attr1="value" ... attrN="value" >Body</prefix:tag>
esattamente come un tag di HTML o come i tag standard JSP. Per usare un custom tag dentro ad una jsp bisogna importgare la TagLib e poi definirla, all'interno di ogni TagLib è presente un file TLD che rappresenta le firme dei tag e definisce quali classi java implementano quel tag, è fondamentale conscere il TLD di una taglib.
Il più semplice tag è quello messo a disposizione proprio dal J2EE, nello specifico il tag jsp permette di eseguire operazioni basiche su request e response, per esempio se si vuole usare un oggetto che è già presente in request o in sessione si può ridurre il codice scritto usando il tag usebean, per esempio:
<jsp:useBean id="NomeBean" scope="session" class="it.alnao.manuali.java.NomeClasse"/>
questo tag prende dalla sessione l'oggetto NomeVariabile, lo casta al tipo indicato e crea nella pagina una variabile di nome NomeVariabile con quel valore, cioè questo tag sostituisce l'istruzione
<% NomeClasse var=(NomeClasse) request.getSession().getAttribute("NomeBean"); %>
molto usato in quei progetti dove vengono usate le scriplet e non linguaggi più evoluti come le jstl o i tag Struts, analogamente al tag useBean esistono i tag setProperty e getProperty che servono a valorizzare e leggere proprietà di un oggetto bean, la sintassi è
<jsp:setProperty name="NomeBean" property="NomeProp" param="Valore" /> <jsp:getProperty name="NomeBean" property="NomeProp">
Da notare che per usare questi tag non serve importare nessuna libreria jar perchè sono tag "standard" java e vengono riconosciuti automaticamente dal WebServer, è presente anche un tag per importare altre pagine jsp in maniera dinamica:
<jsp:import
alternativa al bruttissimo:
<%@ include file="filedaincludere.jsp" %>
ma è corretto nominarlo ed evitarlo se possibile.
Per Custom tags si intendoo tag sviluppati all'interno del progetto o comunque non rilasciati ufficialmente dalla libreria J2EE, all'interno delle applicazioni JEE si hanno a disposizione più modi di creare un custom-tag, uno dei metodi più classici è quello di usare una classe java e un TLD per la descrizione del tag detti TLD acronimo di Tag Library Descriptor. Il primo passo per creare un TLD-TAG è quello di creare un file TLD nella giusta cartella del progetto WebContent/WEB-INF/tld/nome.tld
, ricordandosi che ad un tld non corrisponde un solo tag ma corrisponde una libreria che può comprendere anche più tag, una documentazione completa dei file TLD può essere trovata nella documentazione ufficiale , lo scheletro base di questo tipo di file è:
<?xml version="1.0" encoding="UTF-8"?> <taglib version="2.0" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"> <description>Alnao tag library</description> <tlib-version>1.0</tlib-version> <short-name>alnao</short-name> <tag> <name>TagCommentoSenzaParametri</name> <tag-class>it.alnao.prova.tags.TagCommentoSenzaParametri</tag-class> <body-content>JSP</body-content> </tag> <tag> <description>Importo</description> <name>Importo</name> <tag-class>it.alnao.prova.tags.ImportoTag</tag-class> <body-content>JSP</body-content> <attribute> <name>positiveStyle</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>negativeStyle</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag> </taglib>
in questo file viene definita una libreria assegnandogli anche uno short-name e un elenco di tag dove, per ogni elemento, è definito il nome, la classe e gli attributi se presenti. Poi serve implementare la classe TagCommentoSenzaParametri che deve espandere la classe TagSupport, per esempio un tag java che scrive un commento in pagina è
package it.alnao.prova.tags; import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.tagext.TagSupport; public class TagCommentoSenzaParametri extends TagSupport { private static final long serialVersionUID = 1L; public int doStartTag() throws JspException { String s="\n\n<!-- prova tag AlNao.it -->\n\n"; try { JspWriter out = pageContext.getOut(); out.println(s); } catch (Exception e) { e.printStackTrace(); } return SKIP_BODY; } public int doEndTag() throws JspException { return EVAL_PAGE; } }
mentre un esempio di tag per la visualizzazione di importi è:
package it.alnao.prova.tags; import java.io.IOException; import java.math.BigDecimal; import java.util.Locale; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.BodyTagSupport; public class ImportoTag extends BodyTagSupport { private static final long serialVersionUID=1L; private String positiveStyle = null; private String negativeStyle = null; private String bodyTag = null; public int doStartTag() throws JspException { return EVAL_BODY_BUFFERED; } public int doAfterBody() throws JspException { bodyTag = getBodyContent().getString().trim(); if (bodyTag != null) { Number decimal; DecimalFormat df = new DecimalFormat(); decimal = df.parse(bodyTag); if (decimal != null) { if (decimal.doubleValue() > 0) { //positivo bodyTag = "<span class=\"" + getPositiveStyle() + "\">"; } else { if (decimal.doubleValue() < 0) { //negativo bodyTag = "<span class=\"" + getNegativeStyle() + "\">"; } } else { //zero bodyTag = "<span class=\"defaultClass\">" ;//+ bodyTag } } else { //non è un numero bodyTag = "<span>"; } return (SKIP_BODY); } public int doEndTag() throws JspException { bodyTag = bodyTag + "</span>"; try { this.pageContext.getOut().print(this.bodyTag); } catch (IOException ioe) { throw new JspException(ioe); } return EVAL_PAGE; } ... metodi get e set delle proprietà ... }
All'interno delle pagine jsp, per poter usare questi tag è necessario importarli con una scriptlet:
<%@ taglib uri="/WEB-INF/tld/nome.tld" prefix="nomeTLD" %>
e poi è necessario usare il prefisso definito per chiamare i singoli tag, per esempio:
<nomeTLD:TagCommentoSenzaParametri /> <nomeTLD:Importo positiveStyle="classeCCS1" negativeStyle="classeCCS2">-12.12</nomeTLD:Importo>
Un metodo più semplice per creare TLD-TAG è usare classi java pure e, grazie alla tecnica dell'ereditarietà di Java, utilizzare classi già esistenti per evitare di scrivere codice già presente in altri tag, per esempio è possibile creare un tag condizionale "if" personalizzato che abbia due parametri in input, se sono uguali il corpo del tag verrà visualizzato in pagina, altrimenti il codice verrà saltato, riportando il codice di esempio di questo tag condizionale:
import javax.servlet.jsp.JspTagException; import javax.servlet.jsp.jstl.core.ConditionalTagSupport; public class IfTag extends ConditionalTagSupport { private String value1 = null; private String value2 = null; public IfTag() { super(); } protected boolean condition() throws JspTagException { if (value1==null || value2==null) throw new JspTagException ("Parametri nulli"); return value1.equals(value2); } }
dopo aver definito il file tld corrispettivo, in una qualsiasi pagina jsp poi basta usare il tag così:
<MieiTag:IfTag value1="uno" value2="due"> <% //questo codice non viene eseguito perchè "uno" è diverso da "due" %> </MieiTag:IfTag> <MieiTag:IfTag value1="tre" value2="tre"> <% //questo codice viene eseguito perchè le stringhe sono uguali %> Viene mostrato questo messaggio perchè "tre"=="tre" </MieiTag:IfTag>
Allo stesso modo è possibile scrivere un tag "else" che estende la classe "if" in questo modo ma che nega il valore del metodo condition:
public class ElseTag extends IfTag{ protected boolean condition() throws JspTagException { return ! super(); } }
nota: la classe ConditionalTagSupport si trova nella libreria jstl che deve essere importata nel file di configurazione di Maven.
Creare un custom-tag con una classe java è una tecnica molto elegante ma può risultare complicata se si deve scrivere un TAG che comprende molto codice client all'interno perché, per scrivere codice HTML dalla classe, si usa il metodo out che può risultato non semplicissimo da usare e il risultato rischia di diventare una classe molto lunga con molte stringhe costanti all'interno del codice. Esiste una alternativa alla tecnica dei Java-TLD: usare un file jsp dedicato al posto di una classe Java. Prima di tutto bisogna sempre definire un TLD e il riferimento al tag senza però nessun parametro anche se previsti, per esempio:
<tag-file> <name>tag_esempio</name> <path>/WEB-INF/tags/esempio.tag</path> </tag-file>
poi è necessario creare il file che per convenzione ha estensione tag anche se in realtà è un file jsp, questo file deve sempre iniziare con il meta-tag specifico previsto da J2EE:
<%@ tag %>
e al suo interno deve essere presente l'elenco degli attributi, cioè i parametri del tag, per esempio:
<%@ attribute name="oggetto" required="true" rtexprvalue="true" description="." %>
e dopo si inserisce il codice HTML/Java del tag come se fosse un file jsp, per esempio
<DIV class="classeDiv"> L'oggetto ha nome <%=request.getParameter("oggetto")%> </DIV>
Per richiamare il tag da qualsiasi pagina JSP basta invocarlo richiamando il tag definito nel TLD:
<tagLib:tag_esempio oggetto="valore" />
Scegliere tra con una classe Java o con un file jsp è una questione di gusti, tipicamente si usano i file jsp quando il codice HTML è tanto e il codice Java è poco, viceversa si usano le classi quando il codice Java è molto complicato oppure se si deve definire un tag che estende un altro tag. La documentazione ufficiale è sempre il punto di riferimento per tutti gli sviluppatori.
Apache Struts è un framework open source per lo sviluppo di applicazioni studiato come estensione/evoluzione delle servlet dei progetti J2EE. Permette di creare applicazioni Web di grandi dimensioni, agevola la parallelizazione degli sviluppi e offre delle potentissime tag-lib, la validazione dei form e la gestione della localizzazione/l'internazionalizzazione. In questo sito si fa riferimento sempre alla mitica versione 1.3 del framework, la versione 2 non mi è mai piaciuta ma una guida è disponile vecchia versione del sito. La base del framework si basa su alcuni concetti:
- classi Action gestiscono la logica di business e la logica di forward tramite metodi specifici, di fatto sono estensioni evolute delle classi Servelet
- classi Form gestiscono i dati inseriti dall'utente nelle pagine definendo le regole di validazione dei dati
- le pagine jsp non devono aver nessuna logica ma hanno solo il compito di visualizzare i dati
Un utente esperto avrà notato che queste tre componenti rispettano l'architettura MVC dove il Model sono le classi Form, le view sono le classi jsp e il controtroller sono le classi Action. Il framework per funzionare correttamente ha bisogno che tutte le classi Form e le classi action vengano censite in file di configurazione che storicamente viene sempre chiamato:
struts-config.xml
che deve essere censito nel web.xml. Per creare un semplice esempio di progetto con questo framework si parte da un progetto webapp standard con maven:
mvn archetype:generate -DgroupId=it.alnao -DartifactId=06Struts -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false
E bisogna importare le dipendenze del core e della tablib:
<dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> </dependency> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts-core</artifactId> <version>1.3.10</version> </dependency> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts-taglib</artifactId> <version>1.3.10</version> </dependency>
Nel web.xml si vede censire una (e una sola) servlet dove si indica la posizione del file di configurazione xml previsto dal framework:
<servlet> <servlet-name>action</servlet-name> <servlet-class>org.apache.struts.action.ActionServlet</servlet-class> <init-param> <param-name>config</param-name> <param-value>/WEB-INF/struts-config.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.nao</url-pattern> </servlet-mapping>
Nel file di configurazione si deve procedere al censimento di due blocchi: il primo riguarda i form-beans, cioè tutte le classi Form del progetto, il secondo definisce l'elenco di tutte le action con il corrispettivo form, path, classe e tutte le classi jsp sulle quali le classi Action potranno fare il forward:
<struts-config> <form-beans> <form-bean name="loginForm" type="it.alnao.mavenExamples.PrimoForm" /> </form-beans> <action-mappings> <action name="loginForm" path="/login" type="it.alnao.mavenExamples.PrimaAction" scope="request" input="/index.jsp"> <forward name="failure" path="/index.jsp" redirect="true" /> <forward name="success" path="/success.jsp" redirect="true" /> </action> </action-mappings> </struts-config>
La classe Action estende un tipo previsto dall'architettura e deve definire obbligatoriamente un metodo execute
che permette di definire logiche di business (come per esempio la validazione di un username-password) con conseguenti logiche di business (per esempio quale pagina visualizzare a seconda se le credenziali sono valide):
public class PrimaAction extends Action { @Override public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { PrimoForm loginForm = (PrimoForm) form; if (loginForm.getUserName() == null || loginForm.getPassword() == null || ! loginForm.getUserName().equalsIgnoreCase("alnao") || ! loginForm.getPassword().equals("bellissimo")) { return mapping.findForward("failure"); } else{ return mapping.findForward("success"); } } }
La classe Form oltre a definire tutti i campi come un semplice Bean/model definiscono due metodi: reset e validate, il primo serve ad inizializzare i dati di un form, il secondo serve a validarli. Qualora una classe action viene eseguita e il suo form non sia valido, la servlet non viene eseguita ma viene eseguito un forward automatico nella pagina definita come input nel file xml di configurazione:
public class PrimoForm extends ActionForm { private String userName = null; //TODO Setter & Getter private String password = null; @Override public void reset(ActionMapping mapping, HttpServletRequest request) { this.password = null; } @Override public ActionErrors validate(ActionMapping mapping, HttpServletRequest request){ // TODO Auto-generated method stub return super.validate(mapping, request); } }
Il sistema di validazione dei dati viene attivato solo se nella pagina jsp viene essere usato un tag form previsto dalla libreria standard struts e gli input previsti dalla libreria standard del framework. Nel metodo presente nella classe ActionForm è possibile creare logiche di validazione come nell'esempio. Il form della pagina che invia dati:
<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html"%> ... <html:form action="/login" focus="userName"> <p>Username : <html:text property="userName" /></p> <p>Password : <html:password property="password" /></p> <p><html:submit value="login" /></p> </html:form>
La tag-lib di struts prevede tre grandi tag: html, bean e logic che verranno descritti in un articolo dedicato.
Il tag più usato è il bean:message per la visualizzazione delle label, questo viene usato perché il framework gestisce nativamente il concento di localizzazione e multilingua: i messaggi vengono censiti in file di proprietà, per esempio il file di default di solito si chiama Application.properties
e deve essere posizionato in un package dell'applicazione:
success.message=Benvenuto
E' possibile creare un secondo file per una specifica lingua, per esempio un file dedicato ai messaggi in lingua inglese Application_en.properties
che deve essere posizionato nello stesso package del generale:
success.message=Welcome
Il bundle (cioè il gruppo di file di tipo properties) deve essere censito nel file di xml di configurazione con l'indicazione del package e del nome:
<message-resources parameter="it.alnao.Application" key="ApplicationBundle" />
Nella pagina jsp, per visualizzare i messaggi, bisogna prima importare la libreria e poi visualizzare i messaggi indicando il nome del bundle e il nome del messaggio:
<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %> ... <p><bean:message key="success.message" bundle="ApplicationBundle"/></p>
Per attivare la gestione del multi-lingua nel framework bisogna impostare il "locale" nella prima action chiamata:
request.getSession().setAttribute(Globals.LOCALE_KEY, request.getLocale());
con questa istruzione il framework riuscirà a recuperare la lingua del browser (della request) e selezionerà il messaggio corrispondente al file indicato nel file di configurazione. L'esempio completo funzionante può essere trovato al solito repository:
https://github.com/alnao/JavaExamples/tree/master/GenericJava/06Struts
Una Software Development Kit, spesso abbreviato con la sigla SDK, è una libreria che permette ad un programmatore di interfacciarsi con i servizi AWS tramite codice scritto in un linguaggio utilizzando delle specifiche API messe a disposizione. A differenza della CDK di AWS, che può essere usata solo per creare e configurare risorse, la SDK permette anche di interagire con i servizi, per esempio con le librerie SDK è possibile recuperare la lista di un bucket mentre con la CDK è possibile solo creare e distruggere uno storage S3. La libreria è documentata molto bene nel sito ufficiale e sono disponibili moltissimi esempi gratuiti che è possibile studiare nel repository ufficiale gratuito, gli usi più comuni sono lo sviluppo di applicazioni che interagiscono con i servizi nel Cloud sia come codice serverless tramite il servizio AWS Lambda Function sia come di applicazioni client.
Quando si usano le librerie di AWS (CDK e SDK) bisogna sempre ricordare che queste usano i profili configurati con la AWS-CLI: esattamente come per il comando CLI-SAM anche per la SDK viene usato il parametro di default se non specificato diversamente, se non c'è nessun profilo configurato queste librerie non sono utilizzabili, tuttavia è possibile impostare il profilo direttamente nel codice senza dover usare i profili CLI del sistema.
Per il linguaggio di programmazione Python la libreria SDK messa a disposizione da AWS è boto3, installabile grazie al gestore dei pacchetti pip:
pip install boto3
oppure nei sistemi Debian 12 è installabile con il pacchetto ufficiale:
apt-get install python3-boto3
#Elenco profili disponibili import boto3 lista_profili=boto3.session.Session().available_profiles for profilo in lista_profili: print(profilo) #Elenco bucket import boto3 s3 = boto3.resource('s3') for bucket in s3.buckets.all(): print(bucket.name)
Package names begin with software.amazon.awssdk in SDK 2.x, whereas the SDK 1.x uses com.amazonaws
Per iniziare a lavorare con SDK in Java è necessario configurare la libreria nel file di configurazione, aggiungendo i riferimenti al repository maven nel pom.xml con il tag:
<dependencyManagement> <dependencies> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>bom</artifactId> <version>2.16.1</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
<dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>auth</artifactId> </dependency> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>profiles</artifactId> </dependency>
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider; import software.amazon.awssdk.profiles.ProfileFile; import software.amazon.awssdk.profiles.ProfileFile.Type; ... public static ProfileFile loadCredentialsFromFile() throws FileNotFoundException { File configfile = new File(System.getProperty("user.home"), ".aws/credentials"); ProfileFile profileFile = ProfileFile.builder() .content(new FileInputStream(configfile)) .type(Type.CREDENTIALS).build(); return profileFile; } public static Set<String> loadProfilesFromFile() throws FileNotFoundException{ ProfileFile p=loadCredentialsFromFile(); return p.profiles().keySet(); } public static AwsCredentialsProvider loadCredentialFromFile() throws FileNotFoundException { return loadCredentialFromFile(DEFAULT_PROFILE); } public static AwsCredentialsProvider loadCredentialFromFile( String profileName) throws FileNotFoundException { ProfileFile p=loadCredentialsFromFile(); AwsCredentialsProvider profileProvider = ProfileCredentialsProvider.builder() .profileFile(p) .profileName(profileName) .build(); return profileProvider; } ...
Esattamente come per i servizi CloudFormation e CDK bisogna ricordare che la SDK è gratuita ma tutte le risorse gestite possono essere a pagamento e bisogna sempre prestare attenzione a quello che viene creato nel Cloud per evitare addebiti indesiderati.
Elastic Compute Cloud, abbreviato con la sigla EC2, è servizio principale di servizio di calcolo (compute in inglese) nel Cloud di Amazon Web Services (AWS). Si tratta di un servizio che permette di avviare istanze remote per virtualizzare server o desktop con la posssilità di configurare la sicurezza, networking, storage, capacity e molto altro. Il servizio permette di gestire processi molto pesanti ma anche molti piccoli grazie alla scalabilità che permette di ridimensionare le istanze in base alle necessità di calcolo e al carico di lavoro. Questo non è un articolo che tratta di questo servizio nello specifico, si rimanda alla documentazione ufficiale per tutti i dettagli a riguardo, si da per scontato che un utente abbia almeno le conoscenze basi del servizio EC2 come i SecurityGroup, la gestione delle chiavi KeyPair, gli storage EBS e il bilanciamento del traffico ELB.
Questo articolo ha lo scopo di descrivere i principali comandi per la gestione delle istanze EC2 nel cloud usando gli strumenti messi a disposizione da AWS come la CLI, il servizio CloudFormation e le librerie CDK/SDK, lo scopo finale è automatizzare la gestione del servizio di virtualizzazione EC2.
La CLI mette a disposizione un unico comando con alcuni sottocomandi, tutte le informazioni sono disponibili nel solito sito ufficiale. I principali comandi sono:
- recuperare l'elenco di tutte le istanze:
aws ec2 describe-instances
- recuperare il dettaglio di una istanza partendo dal nome dell'instanza (come tag name):
aws ec2 describe-instances --filters "Name=tag:Name,Values=testAlberto"
- recuperare il dettaglio di una istanza partendo dal id istanza:
aws ec2 describe-instances --instance-ids i-094d7505c54b0xxxx
- filtrare i dati ritornati dai precedenti comandi per ottenere solo alcuni dati delle istanze (come id, stato e indirizzi ip):
aws ec2 describe-instances --instance-ids i-094d7505c54b0xxxx --query "Reservations[*].Instances[*].[InstanceId, ImageId, State, PrivateIpAddress, PublicIpAddress]"
- impostare un tag di una istanza per assegnare un nome alla istanza:
aws ec2 create-tags --resources i-094d7505c54b0xxxx --tags Key=Name,Value=testAlbertoLinux3b
- eseguire lo stop di una istanza:
aws ec2 stop-instances --instance-ids i-094d7505c54b0xxxx
- eseguire il comando di start di una istanza:
aws ec2 start-instances --instance-ids i-094d7505c54b0xxxx
Quasi tutti i comandi ritornano i dati secondo il fomato specifico al momento della configurazione della AWS-CLI, se si è impostato il tipo Json le risposte saranno del tipo:
{"StartingInstances": [{ "CurrentState": { "Code": 0, "Name": "pending" }, "InstanceId": "i-094d7505c54b0e029", "PreviousState": { "Code": 80, "Name": "stopped" } } ] }
L'elenco completo di tutti i parametri e i possibili utilizzi è disponibile nelle pagine dedicate nella pagina ufficiale: ec2 e describe-instances. Per creare/avviare una nuova istanza è disponibile il comando run-instances, documentato nella pagina ufficiale, il comando ha alcuni parametri obbligatori che corrispono ai dati obbligatori per l'avvio di una istanze EC2 da console:
- immagine ami
- numero di istanze da avviare
- tipo (consigliato t2.micro)
- chiavi di accesso (se si tratta di istanza Linux)
- security group
- subnet-id
Un semplice esempio di avvio nella AZ Irlandese è:
aws ec2 run-instances --image-id ami-06e0ce9d3339xxxx --count 1 --instance-type t2.micro --key-name Keeeey --security-group-ids sg-0f2d1afe5832e7xxxx --subnet-id subnet-0b6f53c0291c1xxxx
La risposta di questo comando è la conferma che una nuova istanza è stata avviata con tutti i dati, compresi quelli di default, alcuni dei principali dati ritornati dal json sono:
"ImageId": "ami-06e0ce9d3339cb039", "InstanceId": "i-02849762f5cf6d1e1", "Placement": { "AvailabilityZone": "eu-west-1b", "GroupName": "", "Tenancy": "default" }, "PrivateDnsName": "ip-10-199-12-207.eu-west-1.compute.internal", "PrivateIpAddress": "10.199.12.207", "PublicDnsName": "", "State": { "Code": 0, "Name": "running" },
Per terminare l'istanza esiste un comando specifico, ben documentato nella pagina ufficiale, il comando ha bisogno in input solo dell'istanza, per esempio:
aws ec2 terminate-instances --instance-ids i-02849762f5cf6xxxx
Con CloudFormation è possibile creare e gestire istanze EC2 in template con il tipo base "AWS::EC2::Instance", ben documentato nella pagina ufficiale, i parametri minimi per avviare una istanza sono:
EC2Instance: Type: AWS::EC2::Instance Properties: InstanceType: !Ref 'InstanceType' # t2.micro free tier SecurityGroups: [!Ref 'InstanceSecurityGroup'] KeyName: !Ref 'KeyName' ImageId: !Ref 'LatestAmiId'
L'esempio più semplice con solo i quattro parametri fondamentali è disponibile nel repository pubblico ufficiale di AWS:
github.com/awslabs/aws-cloudformation-templates/blob/master/aws/services/EC2/EC2InstanceWithSecurityGroupSample.yaml
Un esempio leggermente più complesso con la creazione di un web-server esposto in internet con uno script user-data e una configurazione più avanzata della rete è disponibile nel repository:
github.com/alnao/AWSCloudFormationExamples/tree/master/Esempio02istanzeEC2
Da notare che, per creare uno stack da questo template, è necessario inserire tre parametri obbligatori: KeyName, VpcId e SubnetId mentre AMI, security group sono parametri con un valore di default.
La libreria CDK permette la creazione e l'avvio di istanze EC2 da codice con la libreria ufficiale, un semplice esempio di creazione con la libreria Java:
final Instance engineEC2Instance = Instance.Builder.create(this, id + "-ec2") .instanceName(id + "-ec2") .machineImage(armUbuntuMachineImage) .securityGroup(securityGroup) .instanceType(InstanceType.of(InstanceClass.BURSTABLE4_GRAVITON,InstanceSize.SMALL)) .vpcSubnets(SubnetSelection.builder() .subnetType(SubnetType.PUBLIC).build()) .vpc(vpc) .build();
maggiori informazioni sono disponibili nella documentazione ufficiale.
La libreria SDK mette a disposizioni tool per gestire le Istanze, la documentazione ufficiale descrive metodi e procedure disponibili per la gestione del servizio Ec2. Per creare istanze è disponibile metodo per Java specifico:
RunInstancesRequest runRequest = RunInstancesRequest.builder() .imageId(amiId) .instanceType(InstanceType.T1_MICRO) .maxCount(1) .minCount(1) .build(); RunInstancesResponse response = ec2.runInstances(runRequest); String instanceId = response.instances().get(0).instanceId(); Tag tag = Tag.builder().key("Name").value(name).build(); CreateTagsRequest tagRequest = CreateTagsRequest.builder() .resources(instanceId).tags(tag).build(); ec2.createTags(tagRequest);
Per ottenere la lista delle istanze di un account è disponibile un metodo nella libreria specifica, si riporta un esempio dove si può notare che il metodo ritorna al massimo 100 (o 1000) elementi quindi si usa deve usare il sistema a token per ottenerere l'elenco completo:
Region region = Region.EU_WEST_1; //default irland Ec2Client ec2 = Ec2Client.builder().region(region) .credentialsProvider( Profiles.loadCredentialFromFile() ).build(); do { DescribeInstancesRequest request = DescribeInstancesRequest.builder() .maxResults(6).nextToken(nextToken).build(); DescribeInstancesResponse response = ec2.describeInstances(request); for (Reservation reservation : response.reservations()) { for (Instance instance : reservation.instances()) { list.add(instance); } } nextToken = response.nextToken(); } while (nextToken != null); for (Instance instance : list) { System.out.println("Instance:" + instance.instanceId() + " " + instance.tags().get(0).value() + " " + instance.instanceType() + " " + instance.state().name()); }
Per il linguaggio Python, la libreria SDK-Boto3 mette a disposizione metodi specifici simili a quelli disponibili per la libreria in linguaggio Java, per esempio i 4 metodi principali per gestire le istanze sono: import boto3
def get_lista_istanze(profile_name): boto3.setup_default_session(profile_name=profile_name) ec2 = boto3.client('ec2') response = ec2.describe_instances() return response def set_tag(instance_id, tag_key, tag_value): if tag_key=='': return ec2 = boto3.resource('ec2')# region_name=AWS_REGION) tags=[{'Key': tag_key,'Value': tag_value}] instances = ec2.instances.filter(InstanceIds=[instance_id,],) for instance in instances: instance.create_tags(Tags=tags) print("set_tag " + instance_id) return tags def stop_instance(instance_id): ec2_client = boto3.client('ec2')#, region_name=”us-west-2" print ("stop_instance " + instance_id) response = ec2_client.stop_instances(InstanceIds=[instance_id]) return response def start_instance(instance_id): ec2_client = boto3.client('ec2') print ("start_instance " + instance_id) response = ec2_client.start_instances(InstanceIds=[instance_id]) return response
In questo gruppo di funzioni sono esposti i metodi per eseguire start e stop di una istanza, esiste anche il metodo "terminate" per terminare una istanza ma è sconsigliato prevedere questo tipo di operazioni da un programma se non strettamente necessario.
Simple Storage Service, abbreviato con la sigla S3, è il principale servizio di archiviazione del servizio Cloud di AWS, studiato per memorizzare e recuperare qualsiasi volume di dati, in qualunque momento e da qualunque luogo. Le caratteristiche principali del servizio sono: gli oggetti sono salvati in contenitori chiamati bucket (non a caso il logo di questo servizio è proprio un secchio), ogni elemento ha un nome (key), gli oggetti sono organizzati in strutture (path), l'accesso agli oggetti può essere personalizzato grazie a regole IAM, gli accessi possono essere salvati in registri specifici nel servizio CloudWatch. E' possibile cancellare o spostare oggetti e il servizio permette di attivare il sistema di versioning per avere la storia di tutti gli oggetti. Per qualsiasi informazione e approfondimenti si può fare riferimento alla pagina dedicata al servizio S3 nel sito ufficiale.
La AWS-CLI mette a disposizione tutta una serie di comandi per la gestione dei bucket e degli oggetti, in particolare "mb" può essere usato per creare bucket:
$ aws s3 mb s3://bucket-name
ricordandosi che il nome deve essere globalmente unico (globally unique unique across all of Amazon S3) e deve rispettare le regole imposte da AWS. La lista dei bucket disponibili si recupera con il comando:
$ aws s3 ls
e per cancellare un bucket (che non contiene nessun oggetto) si usa il comando rb:
$ aws s3 rb s3://bucket-name
Per ottenere la lista di tutti gli oggetti contenuti in un bucket:
$ aws s3 ls bucket-name
E per muovere oggetti tra bucket o scaricare un oggetto cancellandolo si usa la sintassi:
$ aws s3 mv s3://bucket-name/example.txt s3://bucket-name2/ $ aws s3 mv s3://bucket-name/filename.txt ./
Mentre per copiare tra bucket o dal sistema locale da/per un bucket si usa la sintassi:
$ aws s3 cp s3://bucket-name/example.txt s3://my-bucket/ $ aws s3 cp ./filename.txt s3://bucket-name $ aws s3 cp s3://bucket-name/filename.txt ./
I comandi possono essere combinati con i comandi Linux, per esempio per scrivere o leggere un oggetto:
$ echo "hello world" | aws s3 cp - s3://bucket-name/filename.txt $ aws s3 cp s3://bucket-name/filename.txt -
Il comando Sync permette di tenere sincronizzato una cartella locale con un bucket, quindi eventuali orfani vengono cancellati e nuovi file vengono copiati, la sintassi preve solo la cartella sorgente e il bucket di destinazione:
$ aws s3 sync . s3://my-bucket/path
Per svuotare un bucket da tutti gli oggetti contenuti si può usare il comando rm con il parametro ricorsivo:
$ aws s3 rm s3://my-bucket/path --recursive
è ovvio che bisogna sempre prestate attenzione a questo ultimo comandi in quanto rimuove tutti gli oggetti e, senza sistema di versionamento attivo, gli oggetti vengono cancellati in maniera permanente. Tutti i parametri e le caratteristiche di questo comando sono disponibili alla pagina della documentazione ufficiale.
I template CloudFormation spesso hanno al proprio interno definizione o riferimenti a bucket S3, il tipo specifico AWS::S3::Bucket
che ha come unico parametro obbligatorio il nome (che deve sempre rispettare le regole previste da AWS)
Resources: S3Bucket: Type: 'AWS::S3::Bucket' Properties: BucketName: !Ref NomeBucket
La documentazione ufficiale è ricca di esempi e può essere sempre consultata come fonte principale di informazioni. Il più semplice esempio è la gestione di siti web esposti dallo stesso servizio S3 senza l'uso di CloudFront o altri servizi dedicati, ispirato alla documentazione ufficiale con in aggiunta le regole ACL, nel template è indispensabile aggiungere la regola di accesso al bucket tramite un oggetto di tipo BucketPolicy:
S3BucketPolicy: Type: AWS::S3::BucketPolicy Properties: Bucket: !Ref NomeBucket PolicyDocument: Version: 2012-10-17 Statement: - Sid: AllowSSLRequestsOnly Action: 's3:GetObject' Effect: Allow Resource: !Join - '' - - 'arn:aws:s3:::' - !Ref NomeBucket - /* Principal: '*'
L'esempio completo funzionante può essere trovato al solito repository
github.com/alnao/AWSCloudFormationExamples/tree/master/Esempio03bucketS3sito
La libreria CDK mette a disposizione classi per la gestione dei bucket, la documentazione ufficiale è ricca di esempi pratici. Per il linguaggio Java la principale risorsa è proprio il builder di Bucket:
Bucket bucket = Bucket.Builder.create(this, "MyBucket") .versioned(true) .encryption(BucketEncryption.KMS_MANAGED) .build();
Per il linguaggio Python la creazione di bucket è ancora più semplice, un esempio ripreso dalla guida ufficiale:
from aws_cdk import (aws_s3 as s3,core) class MyStack(core.Stack): def __init__(self, scope: core.Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) # Create an S3 bucket bucket = s3.Bucket(self, "MyBucket", bucket_name="my-unique-bucket-name",#unique bucket name versioned=True, # enable versioning for the bucket encryption=s3.BucketEncryption.S3_MANAGED ) app = core.App() MyStack(app, "MyStack") app.synth()
La libreria SDK è ricca di classi e metodi per la gestione dei bucket e dei contenuti, per il linguaggio di programmazione Python il sito ufficiale mette a disposizione diversi esempi i principali metodi messi a disposizione del servizio S3 sono:
#Lista dei bucket s3_client.list_buckets()["Buckets"] #Lista di oggetti response = s3_client.list_objects_v2( Bucket=bucket_name, Delimiter="/", Prefix=path, ) if "Contents" in response: response["objects"]=response["Contents"] if "CommonPrefixes" in response: response["folders"]=response["CommonPrefixes"] #Lista di oggetti con metodo paginante s3_paginator = s3_client.get_paginator('list_objects_v2') for page in s3_paginator.paginate(Bucket=bucket_name, Prefix=path, Delimiter='/'): #, StartAfter=start_after): if "Contents" in page: response["objects"]=response["objects"] + page["Contents"] #sum to append if "CommonPrefixes" in page: response["folders"]=response["folders"] + page["CommonPrefixes"] #sum to append #Contenuto di un file di testo content = s3_client.get_object(Bucket=bucket_name, Key=key)["Body"].iter_lines() #Scrivere un file di testo string_encoded = body.encode("utf-8") s3_client.put_object(Bucket=bucket_name, Key=key, Body=string_encoded)
Nel la libreria per il linguaggio Java le classi disponibili sono nel package:
software.amazon.awssdk.services.s3
Per esempio per ottenere la lista completa di tutti i bucket si può usare il semplice metodo:
S3Client client = S3Client.builder().build(); ... public static List<Bucket> getBucketList(S3Client s3Client){ ArrayList<Bucket> l=new ArrayList<Bucket>(); ListBucketsRequest listBucketsRequest = ListBucketsRequest.builder().build(); ListBucketsResponse listBuckets = s3Client.listBuckets(listBucketsRequest); listBuckets.buckets().stream().forEach(x -> l.add(x)); return l; }
Un semplice esempio dei vari metodi messi a disposizione della libreria può essere trovato al solito repository oppure mella documentazione ufficiale sono disponibili molti esempi di gestione dei bucket
È online la nuova versione del sito con contenuti aggiornati. Nessun articolo e nessun contenuto di questo sito è stato creato con IA o generatori automatici di testi ma tutto è stato scritto con molta pazienza personalmente da Alberto Nao. Tutto il codice presente nel sito Tutti gli esempi di codice nel sito sono coperti da
free software!
I contenuti di AlNao.it potrebbero avere inesattezze o refusi. Non potrà in alcun caso e per qualsiasi motivo essere ritenuta responsabile di eventuali imprecisioni ed errori né di danni causati. Il sito web e tutte le informazioni ed i contenuti in esso pubblicati potranno essere modificati in qualsiasi momento e di volta in volta e senza preavviso. Poiché ogni materiale sarà scaricato o altrimenti ottenuto attraverso l’uso del servizio a scelta e a rischio dell’utente, ogni responsabilità per eventuali danni a sistemi di computer o perdite di dati risultanti dalle operazioni di scarico effettuato dall'utente, ricade sull'utente stesso e non potrà essere imputata ad AlNao.it che declina ogni responsabilità per eventuali danni derivanti dall'inaccessibilità ai servizi presenti sul sito o da eventuali danni causati da virus, file danneggiati, errori, omissioni, interruzioni del servizio, cancellazioni dei contenuti, problemi connessi alla rete, ai provider o a collegamenti telefonici e/o telematici, ad accessi non autorizzati, ad alterazioni di dati, al mancato e/o difettoso funzionamento delle apparecchiature elettroniche dell’utente stesso.
AlNao.it ha adottato ogni possibile accorgimento al fine di evitare che siano pubblicati, nel sito web, contenuti che descrivano o rappresentino scene o situazioni inappropriate o tali che, secondo la sensibilità degli utenti, possano essere ritenuti lesivi delle convinzioni civili, dei diritti umani e della dignità delle persone, in tutte le sue forme ed espressioni. In ogni caso non garantisce che i contenuti del sito web siano appropriati o leciti in altri Paesi, al di fuori dell’Italia. Tuttavia, qualora tali contenuti siano ritenuti non leciti o illegali in alcuni di questi Paesi, ti preghiamo di evitare di accedere al nostro sito e ove scegliessi, in ogni caso, di accedervi, ti informiamo che l’uso che deciderai di fare dei servizi forniti dal sito sarà di tua esclusiva e personale responsabilità. L’utente sarà esclusivo responsabile della valutazione delle informazioni e del contenuto ottenibile mediante il sito web. Il sito web e tutte le informazioni ed i contenuti in esso pubblicati potranno essere modificati in qualsiasi momento e di volta in volta e senza preavviso.
Le pagine di questo sito sono protette dal diritto d’autore (copyright), in particolare a norma della legge sul diritto d’autore e il contenuto del sito è protetto contro duplicazioni, traduzioni, inserimento o trasformazione dello stesso in altri media, incluso l’inserimento o la trasformazione con mezzi elettronici. La riproduzione e lo sfruttamento economico di tutto o di parte del contenuto di questo sito sono consentite solo a seguito del consenso scritto dell’avente diritto. Sia il contenuto che la struttura del sito sono protetti dal diritto d’autore. In particolare, la duplicazione di informazioni o dati, l’uso dei testi o di parte di essi o delle immagini contenute nel sito (eccetto per le foto ad uso stampa) è consentita solo previo consenso scritto dell’avente diritto. Anche le illustrazioni, a norma dell’art. 1 della legge 633/1941 – e successive modifiche e integrazioni – sono protette dal diritto d’autore. Il diritto di pubblicazione e riproduzione di questi disegni è di titolarità dell’avente diritto. Il diritto d’autore sui disegni rimane in vigore anche per i disegni automaticamente o manualmente aggiunti a un archivio. Nulla di quanto contenuto in questo sito vale come concessione a terzi dei diritti di proprietà industriale ed intellettuale indicati in questa sezione. Ci riserviamo tutti i diritti di proprietà intellettuale del sito web.
Marchi ed immagini riferibili a soggetti terzi utilizzati in questo sito non appartengono a AlNao.it e sono da ritenersi di proprietà esclusiva dei rispettivi titolari. Le denominazioni dei prodotti pubblicati su questo sito web o delle società menzionate, anche qualora non siano indicate con il simbolo identificativo della registrazione del marchio sono marchi di titolarità di terzi e sono protetti dalla legge sui marchi (D.lgs. 30/2005 e successive modifiche e integrazioni) e dalle norme in tema di concorrenza sleale. Qualsiasi riproduzione degli stessi è da ritenersi vietata ai sensi di legge. In particolare è espressamente vietato qualsiasi uso di questi marchi senza il preventivo consenso scritto del relativo titolare ed, in particolare, è vietato utilizzarli in modo da creare confusione tra i consumatori in merito all'origine dei prodotti o per finalità di sponsorizzazione, nonché in qualsiasi modo tale da svilire e discreditare il titolare del marchio. Tutti i diritti che non sono espressamente concessi sono riservati al titolare del marchio.
In aggiunta a quanto indicato, AlNao.it non potrà essere ritenuto in alcun caso responsabile di alcun danno derivante dall'utilizzo o dall'impossibilità di utilizzare il sito web, i contenuti, le informazioni o connessi alla qualità degli stessi.