Exercício - Implantar um aplicativo Java EE (Jakarta EE) no JBoss EAP no Serviço de Aplicativo do Azure

Concluído

Neste exercício, você implantará um aplicativo Java EE (Jakarta EE) no JBoss EAP no Serviço de Aplicativo do Azure. Use o plug-in Maven para configurar o projeto, compilar e implantar o aplicativo e configurar uma fonte de dados.

Configurar o aplicativo com o plug-in Maven para o Serviço de Aplicativo do Azure

Vamos configurar o aplicativo executando a meta de configuração no plug-in Maven para o Serviço de Aplicativo do Azure.

./mvnw com.microsoft.azure:azure-webapp-maven-plugin:2.9.0:config

Importante

Se você alterar a região do seu servidor MySQL, você também deverá mudar para a mesma região do seu servidor de aplicativos Java EE para minimizar os atrasos de latência.
No comando, selecione Java 11 para versão Java e JBoss EAP 7 para pilha de tempo de execução.

Elemento de entrada valor
Available subscriptions: Your appropriate subsctioption
Choose a Web Container Web App [\<create\>]: 1: <create>
Define value for OS [Linux]: Linux
Define value for javaVersion [Java 17]: 2: Java 11
Define value for runtimeStack: 1: Jbosseap 7
Define value for pricingTier [P1v3]: P1v3
Confirm (Y/N) [Y]: Y

Depois de executar o comando, você receberá mensagens como as seguintes no terminal:

$ ./mvnw com.microsoft.azure:azure-webapp-maven-plugin:2.9.0:config
[INFO] Scanning for projects...
[INFO] 
[INFO] ---------< com.microsoft.azure.samples:jakartaee-app-on-jboss >---------
[INFO] Building jakartaee-app-on-jboss 1.0-SNAPSHOT
[INFO] --------------------------------[ war ]---------------------------------
[INFO] 
[INFO] --- azure-webapp-maven-plugin:2.5.0:config (default-cli) @ jakartaee-app-on-jboss ---
[WARNING] The POM for com.microsoft.azure.applicationinsights.v2015_05_01:azure-mgmt-insights:jar:1.0.0-beta is invalid, transitive dependencies (if any) will not be available, enable debug logging for more details
[INFO] Auth type: OAUTH2
Username: YOUR_EMAIL_ADDRESS@microsoft.com
Available subscriptions:
[INFO] Subscription: YOUR_SUBSCRIPTION(********-****-****-****-************)
[INFO] It may take a few minutes to load all Java Web Apps, please be patient.
Web Container Web Apps in subscription Microsoft Azure Internal Billing-CDA:
* 1: <create>
  2: jakartaee-app-on-jboss-yoshio (linux, jbosseap 7.2-java8)
Please choose a Web Container Web App [<create>]: 
Define value for OS [Linux]:
* 1: Linux
  2: Windows
  3: Docker
Enter your choice: 
Define value for javaVersion [Java 8]:
* 1: Java 8
  2: Java 11
Enter your choice: 
Define value for runtimeStack:
  1: Jbosseap 7.2
  2: Jbosseap 7
* 3: Tomcat 8.5
  4: Tomcat 9.0
Enter your choice: 1
Define value for pricingTier [P1v3]:
  1: P3v3
  2: P2v3
* 3: P1v3
Enter your choice: 
Please confirm webapp properties
Subscription Id : ********-****-****-****-************
AppName : jakartaee-app-on-jboss-1625038814881
ResourceGroup : jakartaee-app-on-jboss-1625038814881-rg
Region : westeurope
PricingTier : P1v3
OS : Linux
Java : Java 8
Web server stack: Jbosseap 7.2
Deploy to slot : false
Confirm (Y/N) [Y]: 
[INFO] Saving configuration to pom.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  01:43 min
[INFO] Finished at: 2021-06-30T16:40:47+09:00
[INFO] ------------------------------------------------------------------------
$ 

Depois que o comando terminar, você poderá ver que a seguinte entrada é adicionada ao seu arquivo Maven pom.xml .

  <build>
    <finalName>ROOT</finalName>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>3.3.2</version>
      </plugin>
        <plugin>
            <groupId>com.microsoft.azure</groupId>
            <artifactId>azure-webapp-maven-plugin</artifactId>
            <version>2.9.0</version>
            <configuration>
                <schemaVersion>v2</schemaVersion>
                <resourceGroup>jakartaee-app-on-jboss-1625038814881-rg</resourceGroup>
                <appName>jakartaee-app-on-jboss-1625038814881</appName>
                <pricingTier>P1v3</pricingTier>
                <region>centralus</region>
                <runtime>
                    <os>Linux</os>
                    <javaVersion>Java 11</javaVersion>
                    <webContainer>Jbosseap 7</webContainer>
                </runtime>
                <deployment>
                    <resources>
                        <resource>
                            <directory>${project.basedir}/target</directory>
                            <includes>
                                <include>*.war</include>
                            </includes>
                        </resource>
                    </resources>
                </deployment>
            </configuration>
        </plugin>
    </plugins>
  </build>

Importante

Verifique o <region> elemento. Se não for o mesmo local de instalação do MySQL, altere-o para o mesmo local.

Depois de adicionar a configuração acima para implantação no Azure, adicione as seguintes entradas XML para implantar o arquivo de inicialização. O recurso <type>startup</type> implanta o script especificado como startup.sh (Linux) ou startup.cmd (Windows) no /home/site/scripts/. Configuramos o script de inicialização na etapa a seguir.

              <!-- Please add following lines -->
              <resource>
                <type>startup</type>
                <directory>${project.basedir}/src/main/webapp/WEB-INF/</directory>
                <includes>
                  <include>createMySQLDataSource.sh</include>
                </includes>
              </resource>
              <!-- Please add following lines -->

Nota

Você pode especificar o seguinte recurso para implantar no XML:

  • type=<war|jar|ear|lib|startup|static|zip>

    • type=warimplantará o arquivo war em /home/site/wwwroot/app.war se path não for especificado
    • type=war&path=webapps/<appname>\ se comportará exatamente como o wardeploy, descompactando o aplicativo para /home/site/wwwroot/webapps/<appname>
    • type=jar implantará o arquivo war no /home/site/wwwroot/app.jar. path parâmetro será ignorado
    • type=ear implantará o arquivo war no /home/site/wwwroot/app.ear. path parâmetro será ignorado
    • type=lib implantará o jar em /home/site/libs. path parâmetro deve ser especificado
    • type=static implantará o script no /home/site/scripts. path parâmetro deve ser especificado
    • type=startup implantará o script como startup.sh (Linux) ou startup.cmd (Windows) no /home/site/scripts/. path parâmetro será ignorado
    • type=zip descompactará o zip para /home/site/wwwroot. path é opcional.

Agora, verifique os valores para o nome do grupo de recursos e o nome do aplicativo no arquivo XML acima. Observe esses nomes ou atribua-os melhor às variáveis de ambiente.

<resourceGroup>jakartaee-app-on-jboss-1625038814881-rg</resourceGroup>
<appName>jakartaee-app-on-jboss-1625038814881</appName>

Se você estiver usando Bash, configure as variáveis de ambiente com o seguinte comando. Você usará esses valores mais tarde.

export RESOURCEGROUP_NAME=jakartaee-app-on-jboss-1625038814881-rg
export WEBAPP_NAME=jakartaee-app-on-jboss-1625038814881

Compilar e construir o aplicativo Java EE

Depois de definir as configurações de implantação do Serviço de Aplicativo do Azure, compile e empacote o código-fonte.

./mvnw clean package

A seguinte saída aparece no terminal:

[INFO] Packaging webapp
[INFO] Assembling webapp [jakartaee-app-on-jboss] in [/private/tmp/mslearn-jakarta-ee-azure/target/ROOT]
[INFO] Processing war project
[INFO] Copying webapp resources [/private/tmp/mslearn-jakarta-ee-azure/src/main/webapp]
[INFO] Webapp assembled in [369 msecs]
[INFO] Building war: /private/tmp/mslearn-jakarta-ee-azure/target/ROOT.war
[INFO] WEB-INF/web.xml already added, skipping
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  7.656 s
[INFO] Finished at: 2023-03-04T12:35:43-05:00
[INFO] ------------------------------------------------------------------------

Implantar o aplicativo Java EE no JBoss EAP no Serviço de Aplicativo do Azure

Depois de compilar e empacotar o código, implante o aplicativo:

./mvnw azure-webapp:deploy

A seguinte mensagem aparece no terminal:

[INFO] Creating resource group jakartaee-app-on-jboss-1625038814881-rg in region westeurope...
[INFO] Successfully created resource group jakartaee-app-on-jboss-1625038814881-rg.
[INFO] Creating app service plan...
[INFO] Successfully created app service plan asp-jakartaee-app-on-jboss-1625038814881.
[INFO] Creating web app jakartaee-app-on-jboss-1625038814881...
[INFO] Successfully created Web App jakartaee-app-on-jboss-1625038814881.
[INFO] Trying to deploy artifact to jakartaee-app-on-jboss-1625038814881...
[INFO] Deploying (/private/tmp/mslearn-jakarta-ee-azure/target/ROOT.war)[war]  ...
[INFO] Successfully deployed the artifact to https://jakartaee-app-on-jboss-1625038814881.azurewebsites.net
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  02:11 min
[INFO] Finished at: 2023-03-04T12:38:39-05:00
[INFO] ------------------------------------------------------------------------

Observe a URL do aplicativo implantado, particularmente a seguinte linha na saída do Maven:

[INFO] Successfully deployed the artifact to https://jakartaee-app-on-jboss-1625038814881.azurewebsites.net

Configurar uma conexão de banco de dados

O aplicativo de exemplo se conecta ao seu banco de dados MySQL e exibe dados.

Na configuração do projeto Maven no pom.xml, especificamos o driver JDBC MySQL da seguinte maneira:

    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>${mysql-jdbc-driver}</version>
    </dependency>

Como resultado, o JBoss EAP instala automaticamente o driver JDBC no seu pacote de implementação (ROOT.war). Você pode se referir ao nome do driver JDBC MySQL da seguinte maneira:

ROOT.war_com.mysql.cj.jdbc.Driver_8_0

Criar o objeto MySQL DataSource no JBoss EAP

Para acessar o Banco de Dados do Azure para MySQL, você precisa configurar o objeto no JBoss EAP e especificar o DataSource nome JNDI em seu código-fonte.

Para criar um objeto MySQL DataSource no JBoss EAP, criamos o seguinte script de shell de inicialização. O arquivo de script está createMySQLDataSource.sh sob o /WEB-INF diretório.

Nota

No script, vinculamos o MySQL DataSource usando um comando JBoss CLI. A cadeia de conexão, o nome de usuário e a senha usam as variáveis MYSQL_CONNECTION_URLde ambiente , MYSQL_USERe MYSQL_PASSWORD.

A origem do arquivo de script é mostrada a seguir. Esse arquivo de script já foi carregado no Serviço de Aplicativo, mas ainda não foi configurado para ser invocado.

#!/usr/bin/bash

# In order to use the variables in JBoss CLI scripts
# https://access.redhat.com/solutions/321513
#
sed -i -e "s|.*<resolve-parameter-values.*|<resolve-parameter-values>true</resolve-parameter-values>|g" /opt/eap/bin/jboss-cli.xml

/opt/eap/bin/jboss-cli.sh --connect <<EOF
data-source add --name=JPAWorldDataSourceDS \
--jndi-name=java:jboss/datasources/JPAWorldDataSource \
--connection-url=${MYSQL_CONNECTION_URL} \
--driver-name=ROOT.war_com.mysql.cj.jdbc.Driver_8_0 \
--user-name=${MYSQL_USER} \
--password=${MYSQL_PASSWORD} \
--min-pool-size=5 \
--max-pool-size=20 \
--blocking-timeout-wait-millis=5000 \
--enabled=true \
--driver-class=com.mysql.cj.jdbc.Driver \
--jta=true \
--use-java-context=true \
--valid-connection-checker-class-name=org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLValidConnectionChecker \
--exception-sorter-class-name=com.mysql.cj.jdbc.integration.jboss.ExtendedMysqlExceptionSorter
exit
EOF

Agora, configure sua instância do Serviço de Aplicativo para invocar o script de inicialização:

az webapp config set --startup-file '/home/site/scripts/startup.sh' \
-n ${WEBAPP_NAME} \
-g ${RESOURCEGROUP_NAME}

Depois que o script for executado, ele será invocado sempre que o servidor de aplicativos for reiniciado.

Nota

Se o artefato de implantação não ROOT.warfor , você também precisará alterar o --driver-name=YOUR_ARTIFACT.war_com.mysql.cj.jdbc.Driver_8_0 valor.

Configurar as variáveis de ambiente para se conectar ao MySQL

Depois de configurar o script de inicialização, configure o Serviço de Aplicativo para usar determinadas variáveis de ambiente:

az webapp config appsettings set \
  --resource-group ${RESOURCEGROUP_NAME} --name ${WEBAPP_NAME} \
  --settings \
  MYSQL_CONNECTION_URL='jdbc:mysql://mysqlserver-**********.mysql.database.azure.com:3306/world?useSSL=true&requireSSL=false' \
  MYSQL_PASSWORD='************' \
  MYSQL_USER=azureuser

Gorjeta

Os valores de MYSQL_CONNECTION_URL, MYSQL_USER e MYSQL_PASSWORD foram definidos a partir da unidade anterior.

Confirme a referência DataSource no código

Para acessar o banco de dados MySQL de seu aplicativo, você precisa configurar a referência da fonte de dados em seu projeto de aplicativo. Implementamos o código de acesso ao banco de dados usando Java Persistence API (JPA).

A configuração para a DataSource referência foi adicionada no persistence.xml, que é o arquivo de configuração do JPA.

Aceda ao seguinte ficheiro:

├── src
│   ├── main
│   │   ├── resources
│   │   │   └── META-INF
│   │   │       └── persistence.xml

Verifique se o DataSource nome corresponde ao nome usado na configuração. O código já criou o nome JNDI como java:jboss/datasources/JPAWorldDataSource:

  <persistence-unit name="JPAWorldDatasourcePU" transaction-type="JTA">
    <jta-data-source>java:jboss/datasources/JPAWorldDataSource</jta-data-source>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties>
      <property name="hibernate.generate_statistics" value="true" />
      <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
    </properties>
  </persistence-unit>
</persistence>

Em seguida, você pode acessar o banco de dados MySQL referenciado no nome da unidade da PersistenceContext seguinte maneira:

@Transactional(REQUIRED)
@RequestScoped
public class CityService {

    @PersistenceContext(unitName = "JPAWorldDatasourcePU")
    EntityManager em;

Aceda à aplicação

No aplicativo de exemplo, implementamos três pontos de extremidade REST. Você pode acessar o aplicativo e validar esses pontos de extremidade usando um navegador da Web ou um curl comando.

Para acessar o aplicativo, você precisa fazer referência à URL do aplicativo, que você obteve de uma seção anterior:

[INFO] Successfully deployed the artifact to  
https://jakartaee-app-on-jboss-1606464084546.azurewebsites.net

Execute o seguinte comando para obter todas as informações do continente no formato JSON.

Screenshot that shows area as the REST endpoint.

$ curl https://${WEBAPP_NAME}.azurewebsites.net/area
["North America","Asia","Africa","Europe","South America","Oceania","Antarctica"]$ 

Se especificar o continente no URL, pode obter todos os países/regiões no continente especificado.

Screenshot that shows continent as the REST endpoint.

$ curl https://${WEBAPP_NAME}.azurewebsites.net/area/Asia | jq '.[] | { name: .name, code: .code }'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--   100 16189  100 16189    0     0  65278      0 --:--:-- --:--:-- --:--:-- 65542
{
  "name": "Afghanistan",
  "code": "AFG"
}
{
  "name": "United Arab Emirates",
  "code": "ARE"
}
{
  "name": "Armenia",
  "code": "ARM"
}
{
  "name": "Azerbaijan",
  "code": "AZE"
}
{
  "name": "Bangladesh",
  "code": "BGD"
}
....

Finalmente, se você especificar um código de país/região depois /countriesde , você pode obter todas as cidades que têm população superior a 1 milhão dentro do país/região.

Screenshot that shows cities as the REST endpoint.

$ curl https://${WEBAPP_NAME}.azurewebsites.net/countries/JPN | jq '.[].name'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--   100   788  100   788    0     0   2671      0 --:--:-- --:--:-- --:--:--  2662
"Tokyo"
"Jokohama [Yokohama]"
"Osaka"
"Nagoya"
"Sapporo"
"Kioto"
"Kobe"
"Fukuoka"
"Kawasaki"
"Hiroshima"
"Kitakyushu"

Resumo do exercício

Agora você validou os endpoints REST do aplicativo e testou que seu aplicativo pode obter dados do seu banco de dados MySQL.

Na próxima unidade, você examinará os logs do servidor.