Logo Passei Direto
Buscar
Material
páginas com resultados encontrados.
páginas com resultados encontrados.
left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

Prévia do material em texto

Camada de visão
Utilização de ferramentas como Thymeleaf e Bootstrap na construção da camada View de uma arquitetura
MVC para Web, em sistemas baseados no framework Spring, viabilizando a criação de interfaces
responsivas e design profissional, com pouco esforço de programação.
Prof. Denis Cople
1. Itens iniciais
Propósito
Definir interfaces de sistemas Web criados com o framework Spring, com grande produtividade, obedecendo ao
padrão arquitetural MVC, além da garantia de responsividade, por meio de ferramentas como Thymeleaf e
Bootstrap, as quais viabilizam a criação de interfaces com design profissional.
Preparação
Antes de começar, é necessário configurar o ambiente com a instalação do JDK, Spring Tools Suite e NetBeans
completo, em versão com suporte a projetos Maven, além de adicionar o servidor Tomcat EE na instalação da
IDE. Também será necessário acessar a internet tanto para testes quanto para o download de artefatos via
Maven. Por fim, acesse os arquivos dos projetos desenvolvidos.
Objetivos
Reconhecer as sintaxes básicas utilizadas na Web para definição de
páginas.
Aplicar o Thymeleaf por meio de templates para definição da camada View
do MVC.
Empregar o Bootstrap na construção da interface para garantia de
produtividade.
Introdução
Abordaremos os elementos necessários para a construção de interfaces de usuário robustas, com
responsividade e aspecto profissional, por meio de ferramentas utilizadas amplamente no mercado. Nosso foco
inicial será na compreensão das sintaxes básicas para a construção de páginas, incluindo HTML, Java Script e
CSS, além da utilização de JQuery UI.
Na sequência, veremos como pode ser feita a integração com sistemas Spring Web, por meio de templates do
Thymeleaf, dentro de uma arquitetura MVC, de forma muito simples e concisa.
Por fim, aplicaremos o framework Bootstrap em um sistema cadastral completo, com a definição de telas
alinhadas aos melhores princípios de design e responsividade exigidos pelo mercado, além de incluir os
componentes de segurança necessários para definir um modelo de autenticação básico, integrando-se às
interfaces criadas com muita fluidez. 
• 
• 
• 
https://stecine.azureedge.net/repositorio/00212ti/03593/docs/Projetos.zip
https://stecine.azureedge.net/repositorio/00212ti/03593/docs/Projetos.zip
1. Implementação de uma página simples da web
HTML 5
A linguagem HTML (Hypertext Markup Language) fornece a base estrutural para as páginas disponibilizadas na
Internet. Visa estruturar a página com base em tags, ou etiquetas, em que temos uma Q, segundo o perfil de
exibição, formulários de cadastro e elementos para a navegação entre páginas. Inclusive, o nome hipertexto se
refere à capacidade de navegação ao longo do texto.
Sintaxe
A sintaxe XHTML equivale ao HTML 4.0 Strict, que evoluiu para o HTML 5.
Toda página apresenta um cabeçalho (head), em que temos o título (title) apresentado no topo da janela do
navegador, ligações (link) com recursos externos, folhas de estilo e demais elementos de uso geral. Na
sequência, deve ser definido o corpo da página (body), contendo a parte visual de nosso documento.
No corpo do documento, temos elementos estruturais de texto, como a utilização de fontes padronizadas para 
títulos, delimitação de parágrafos e criação de listas. Embora o HTML não diferencie maiúsculas e minúsculas, as
páginas serão validadas na W3C apenas se as tags forem escritas com letras minúsculas. Vejamos algumas tags:
Tags  Utilização 
h1, h2, h3,
h4, h5, h6 
Aplica a formatação padronizada para títulos, em que h1
utiliza fonte maior, e vai diminuindo com a numeração.
br, hr, p  Enquanto p define um parágrafo, br é uma quebra de linha
simples, e hr efetua a quebra com o desenho de uma linha
horizontal.
ul, ol, li  Listas com marcadores numéricos são definidas com o uso de
ol, enquanto as simbólicas utilizam ul. Em ambos os casos,
itens são definidos com li.
Tabela: Tags básicas HTML
Denis Cople.
Tags básicas
Vejamos uma aplicação no Exemplo001.html.
python
 
A tag meta permite definir metadados, aqui definida a página de código UTF-8, permitindo o uso de acentuação
em palavras da língua portuguesa. No HTML, também temos símbolos especiais, chamados de entidades, que
são iniciadas com ‘e comercial &;’ e fechadas com ponto e vírgula, como b, representando o símbolo de 
copyright.
Outro elemento é o comentário utilizado no HTML, iniciado com sinal de exclamação e duas subtrações, e
fechado com duas subtrações.
Abrindo a página no navegador, teremos o resultado a seguir. Para facilitar os testes, podemos criar um aplicativo
Web, no NetBeans, e acrescentar a página HTML.
 
 
 
 
 
 
Primeira página
 
UNIVERSIDADE ©2022
 
 
 Nosso primeiro exemplo, apenas com 
 estruturas básicas 
 e uma quebra de linha.
 
 Departamentos:
 
 
Desenvolvimento
 
Financeiro
 
 
• 
• 
Visualização de Exemplo001.html
Tabelas
Nas tabelas, temos uma divisão em linhas, e cada linha com suas respectivas colunas, definindo células de
informação. Com base em atributos como colspan e rowspan, as células podem ser combinadas, e ainda temos a
possibilidade de uma linha de cabeçalho. Vejamos algumas tags:
Tags  Utilização 
table  Define uma tabela, podendo ter borda e largura
especificados.
tr  Define uma linha da tabela.
td, th  Definem células de informação, ou colunas, na linha, sendo
que th é utilizada no cabeçalho.
thead,
tbody,
tfoot 
Definem trechos de cabeçalho, corpo e rodapé na tabela, para
que ocorra o reconhecimento a partir de outras ferramentas.
Tabela: Tags para desenho de tabelas.
Denis Cople.
O uso de tabelas é indicado para a exibição de dados tabulares, como a seguir.
python
 
A tabela foi criada com alguns atributos visuais, incluindo a borda de espessura 1 e utilização de 100% do espaço
horizontal disponível. Note o uso de colspan na primeira e última linhas, em que células subsequentes são 
mescladas, com base no valor definido por meio do atributo.
Vejamos a saída da página Exemplo002.html. 
Visualização de Exemplo002.html
Formulários
Nos formulários, podemos contar com os componentes mais tradicionais das interfaces de usuário, como botões,
caixas de texto e caixas de seleção. Vejamos algumas tags:
Tags  Utilização 
form  Define um formulário, sendo necessário indicar o endereço
para onde as informações serão enviadas e o método HTTP
utilizado.
 
 
 
 
 
Nome Telefones
Ana 111-1111 111-2222
Luiz 222-1111 
Total de contatos: 2
 
Tags  Utilização 
Input  Desenha um componente de entrada, em que o atributo type
permite a escolha de sua aparência, podendo ser text, button,
checkbox, radio, reset ou submit, em que os últimos são os
botões de reinício e envio.
Select,
datalist 
Expressam elementos de entrada multivalorados, ou seja, as
caixas de seleção em que os valores são expressos na forma
de listas.
Textarea  Define um componente de entrada para textos maiores,
permitindo a quebra de linhas.
Label  Utilizado para descrever um campo do formulário. É muito útil
para otimizar a visualização em dispositivos móveis.
Fieldset,
legend 
Utilizados para configurar grupos de campos de entrada, com a
adição de uma legenda e uma borda.
Tabela: Tags para criação de formulários.
Denis Cople.
Para textos maiores, devemos utilizar o textarea, que permite quebra de linhas, sendo configurado em termos do
número de linhas e colunas.
Quanto a elementos multivalorados, como listas, temos as opções select e datalist, ambos definindo os
elementos da lista por meio de option. No entanto, o datalist deve ser utilizado para pequenos conjuntos de
valores fixos, enquanto o select, que permite o uso de uma chave e um texto para a opção, reflete melhor um
conjunto dinâmico.
Vejamos componentes no Exemplo003.html.
python
 
Nosso formulário tem como destino um endereço fictício, associado por meio de action, usando o métodocontrolador, obtendo cada um 
deles na variável depto, e utilizamos cada ocorrência para a construção de uma linha da tabela. Os valores de 
cada campo da entidade são acessados com o uso de cifrão, utilizado tanto para o preenchimento das células 
de valores quanto na definição dos links de forma dinâmica.
 Já podemos executar o aplicativo e acessar o endereço http://localhost:8080/departamentos, obtendo a saída 
a seguir:
 
 
 
Departamentos
 Novo Departamento
 
IdDepto Nome Opcoes
 Excluir
 Alterar
 
Listagem dos departamentos .
Agora, vamos definir o segundo template, com o nome deptodata.html.
python
 
Nosso formulário utilizará o objeto depto, fornecido pelo controlador, por meio de th:object, e iniciará a ação 
definida por th:action para a rota /departamentos/cadastro, no modo POST. Observe a utilização de asterisco 
para acesso aos campos do objeto, com base em th:field, em cada um dos campos de nosso formulário.
Como a chave primária é gerada automaticamente para o departamento, ela é colocada em um campo 
escondido (hidden), evitando a edição pelo usuário. Já o campo referente ao nome será apresentado em branco 
para a inclusão, ou com o valor corrente na alteração.
 
 
 
Dados do Departamento
 
 
 
 
 Nome
 
 
 Cadastrar 
 
 
Já podemos acessar os diversos links oferecidos pela tela de listagem, pois o controlador está preparado para 
todas as rotas solicitadas. Clicando na opção "Novo Departamento", abriremos o formulário de dados em branco.
Formulário para inclusão e alteração de departamento.
Templates para funcionários
Vamos definir as telas para funcionários, iniciando com o arquivo funclist.html.
python
 
 
 
 
Funcionários
 Novo Funcionário 
 
Matricula Nome Cadastro Depto Opções
 Excluir
 Alterar
 
Há muita similaridade com a tela de listagem de departamentos, agora com as rotas iniciadas por /funcionários, 
mas temos algumas pequenas novidades. Note o uso da macro, precedida por cerquilha, com o nome dates.form
at, que permite formatar a data de cadastro, bem como o acesso ao nome do departamento de forma direta, a 
partir do atributo de relacionamento existente na classe Funcionario.
Acessando o endereço http://localhost:8080/funcionarios, podemos testar a tela, obtendo a saída a seguir:
Listagem de funcionários.
O formulário para funcionários será definido no template funcdata.html.
python
 
Nesse caso, temos a chave primária digitada pelo usuário. Há também a definição de um campo de seleção para 
o campo departamento, em que as opções são preenchidas a partir da lista de departamentos com o nome dept
os, fornecida pelo controlador. Observe a utilização de th:each, para a iteração, th:value, para definição do valor 
fornecido pela opção, e th:text, para o texto apresentado.
Com o template criado, acessando os links para alteração ou inclusão, teremos a exibição da tela a seguir:
 
 
 
Dados do Funcionário
 
 
 
 Matricula
 
 
 
 
 Nome
 
 
 
 
 Departamento
 
 
 
 Cadastrar 
 
 
Formulário para inclusão e alteração de funcionário.
Teoria na prática
Utilizando Thymeleaf com Spring Boot 
 
 
 
 
 
 
 
Conteúdo interativo
 
Acesse a versão digital para assistir ao vídeo.
 
 
 
 
Vem que eu te explico!
Os vídeos a seguir abordam os assuntos mais relevantes do conteúdo que você acabou de estudar.
Características do Thymeleaf
 
 
 
 
 
 
 
Conteúdo interativo
 
Acesse a versão digital para assistir ao vídeo.
 
 
 
 
Filtro de Interceptação
 
 
 
 
 
 
 
Conteúdo interativo
 
Acesse a versão digital para assistir ao vídeo.
 
 
 
 
Verificando o aprendizado
Questão 1
As diretivas utilizadas no Thymeleaf permitem uma integração muito simples entre o template HTML e o 
contexto do framework Spring, possibilitando recuperação de valores e reutilização de fragmentos, entre 
diversas outras possibilidades. Se quisermos recuperar o nome da empresa a partir de um parâmetro global, 
para que seja apresentado em cada página, qual símbolo seria utilizado pela diretiva de recuperação?
 
A
 
Arroba
 
 
B
 
Cifrão
 
 
C
 
Til
 
 
D
 
Asterisco
 
 
E
 
Cerquilha
 
A alternativa E está correta.
 
Segundo a Standard Expression Syntax, o uso de cerquilha (#) permite recuperar textos padronizados a 
partir de arquivos de propriedades, particularmente com a definição de um arquivo message.properties, 
no diretório resources, em que serão colocadas as mensagens do sistema, como pares de chave e valor, 
com a recuperação posterior a partir da chave.
Questão 2
Os templates do Thymeleaf utilizam atributos nas tags HTML, definidos em seu namespace, para definir ações 
diversas, como controle de visibilidade e substituição de conteúdo para a tag, sendo normalmente adotado o 
prefixo th. Se quisermos repetir determinado trecho, para todos os elementos de uma coleção, qual seria o 
atributo adotado na tag principal do trecho?
 
A
 
Th:each
 
 
B
 
Th:text
 
 
C
 
Th:object
 
 
D
 
Th:action
 
 
E
 
Th:value
 
A alternativa A está correta.
 
A utilização de th:each permite repetir a tag e seu conteúdo interno, ou seja, o trecho da página, para 
cada objeto da coleção. Em termos práticos, recuperamos uma coleção enviada pelo controlador, 
precedida de cifrão, atribuindo a um objeto em cada iteração. O objeto pode ser acessado no conteúdo 
interno, recuperando suas propriedades. Um exemplo de utilização desse controle de fluxo seria 
th:each="depto: $$ {deptos}".
 
 
3. Estudo de caso com Framework Bootstrap
 
 
Framework do Bootstrap
O framework Bootstrap permite a definição de interfaces muito agradáveis, com uma estética alinhada aos 
padrões de mercado, além de trazer elementos que garantem a responsividade, ou seja, adapta-se a diferentes 
plataformas de forma natural. Com o Bootstrap, obtemos um conjunto de componentes responsivos, com visual 
moderno, perfeitamente alinhados aos padrões estabelecidos no mercado.
 O Bootstrap encapsula o framework JQuery, adicionando diversas funcionalidades por meio de classes CSS. 
Podemos baixar o framework no endereço https://getbootstrap.com/. Além de oferecer diversas opções de 
formatação para componentes, como botões e caixas de texto, temos a definição de contêineres, muito úteis 
para a organização da tela.
Estilos de botões
Para compreender a utilização do Bootstrap, vamos criar o arquivo Exemplo015.html, em um projeto Web do 
NetBeans, dando continuidade aos exemplos iniciais do conteúdo.
python
 
No cabeçalho do arquivo, temos as importações necessárias para uso do Bootstrap, ou seja, a folha de estilo boo
tstrap.min.css e o script bootstrap.bundle.min.js, ambos obtidos a partir do repositório npm, na versão 5.0.2. 
Todos os arquivos que utilizarem o framework deverão ter as mesmas importações de nosso exemplo.
Podemos observar a definição da área principal do aplicativo, com a classe container, e diferentes formatações 
para os botões, com a classe btn, que pode ser especializada para suas subclasses, como btn-success e btn-
info, modificandoo aspecto dos botões, segundo padrões adotados nas diferentes plataformas, particularmente 
Web e móvel.
Abrindo a página em um navegador, teremos o seguinte resultado:
 
 
 
 
Estilos de Botões
 Básico
 Padrão
 Primário
 Sucesso
 Informação
 Aviso
 Perigo
 Link 
Botões formatados pelas classes do Bootstrap.
Caixas de diálogo modais
O uso de caixas de diálogo modais permite uma comunicação simples e organizada com o usuário. Vamos 
explorar essa funcionalidade no arquivo Exemplo016.html.
python
 
Na primeira parte do código, temos um botão, configurado com o aspecto btn-danger, e dois atributos 
especiais, data-bs-toggle e data-bs-target: o primeiro define que será alterada a visibilidade de um elemento 
modal, e o segundo indica o modal a partir do id. Em seguida, temos a construção do modal em si, com id myMod
al, por meio de tags div.
 
 
 
 
 
 
Exemplo de Modal
 
 Excluir Registro
 
 
 
 
Comentário
 
A divisão de nível mais alto do diálogo é configurada com as classes modal e fade, além de usar um 
atributo role, com valor dialog, o que indica uma caixa de diálogo. Em seguida, temos um segundo 
nível, configurado como modal-dialog, e um terceiro, do tipo modal-content, que será responsável 
pelo conteúdo interno da caixa de diálogo.
 
 
O conteúdo do diálogo é composto de três áreas, configuradas como modal-header, para as informações de 
título, modal-body, para as informações que serão exibidas, e modal-footer, para a parte inferior do diálogo, 
normalmente com alguns botões de resposta.
Os dois botões são configurados para o fechamento do diálogo, por meio do atributo data-bs-dismiss, utilizando 
o valor modal. O primeiro é o botão de fechamento padrão para janelas, posicionado no canto superior direito, e 
o segundo, um botão padrão, colocado na parte inferior. Podemos observar nosso diálogo sendo ativado:
Diálogo modal com Bootstrap.
Sistema de Grid
O sistema de grid do Bootstrap é outro elemento importante, utilizado na organização da tela a partir de 
divisões. Ele segmenta a tela em até 12 colunas, que podem ser combinadas, como na listagem seguinte, que 
deverá ficar no arquivo Exemplo017.html.
python
 
 
 
 
 
 
 
UM
 
UM
 
DOIS
 
QUATRO
 
QUATRO
 
 
 
 
QUATRO
 
OITO
 
 
 
 
DOZE
 
>
 
Temos a primeira linha (row) com duas células de uma coluna (col-sm-1), uma célula de duas colunas (col-sm-2) 
e duas de quatro colunas (col-sm-4), a segunda linha com uma célula de quatro colunas e uma de oito colunas (c
ol-sm-8), e apenas uma célula de 12 colunas (col-sm-12) na terceira linha. O resultado pode ser observado a 
seguir:
Organização da página pelo sistema de grid.
Componentes para navegação
Os componentes nav e navbar permitem a construção simples de menus para o sistema. Vamos adicionar o 
arquivo Exemplo018.html, com o conteúdo a seguir:
python
 
A barra de navegação do exemplo poderia ser utilizada como menu principal do sistema, pois viabiliza mudança 
de páginas e indicação da opção corrente de forma automática. Definimos o componente de navegação no nível 
mais alto, utilizando fundo escuro (navbar-dark e bg-dark), além do preenchimento horizontal (navbar-expand-
lg).
O conteúdo do menu é divido em três colunas, segundo os valores de grid do Bootstrap. A primeira contém a 
opção principal do menu (navbar-brand), e a última, um botão comum, no estilo btn-danger. Na coluna do meio, 
temos uma lista, configurada como navbar-nav, em que cada item é uma opção de navegação (nav-item) 
contendo um link (nav-link), sendo a opção corrente configurada no link por meio da classe active.
A execução do exemplo gerará o seguinte resultado:
 
 
 
 
 
 
 
 Cadastro
 
 
 
 
 
 
Departamentos
 
 
 
Funcionarios
 
 
 
 
 
 Logout
 
 
 
#
#
#
#
#
Menu de navegação criado com NavBar.
Uso de Bootstrap com Thymeleaf
Definição do menu
Utilizar o framework Bootstrap sob o Thymeleaf é uma tarefa simples, pois não requer grandes modificações nos 
templates HTML. Nossa preocupação inicial será apenas a inclusão de uma dependência no arquivo pom.xml, 
como no fragmento a seguir:
python
 
Os elementos WebJars são as bibliotecas do Bootstrap oferecidas no formato jar, para permitir a utilização ao 
nível do projeto, sem a necessidade de acesso ao repositório remoto. Aqui foi escolhida a versão 5.0.2, devido à 
existência de documentação mais completa.
 Vamos acrescentar a página menu.html no projeto ExemploTh002, nosso exemplo de CRUD, no diretório templat
es, como as demais páginas, utilizando o conteúdo a seguir:
 
 org.webjars
 bootstrap
 5.0.2
 
python
 
O código utilizado é apenas uma adaptação de nosso menu anterior, mas, agora, com indicação real de 
navegação. Esse template será incluído em todas as páginas, aproveitando o recurso de fragmentos oferecido 
pelo Thymeleaf.
 
 
 
No primeiro nível, temos a definição do nome do fragmento como menuprincipal, por meio do atributo 
th:fragmente. Todos os endereços dos links passam a apontar para as rotas de nosso sistema, sempre 
por meio do atributo th:href, com a utilização de arroba para correção. 
 
Temos ainda a indicação da opção ativa com uma inclusão condicional de classe, efetuada no atributo th:classap
pend, com base em uma condição na qual o estilo active será utilizado apenas quando a variável pagina tiver o 
valor equivalente ao do teste.
 
 
 
 
 Cadastro
 
 
 
 
 
Departamentos
 
 
Funcionarios
 
 
 
 
 
 Logout
 
 
 
Navegação utilizando o menu
Agora, vamos definir uma nova página inicial, com o nome home.html, no diretório templates, de acordo com a 
listagem seguinte:
python
 
Executando novamente o aplicativo, teremos acesso às páginas de departamento com exibição do menu, tanto 
para a listagem quanto para o cadastro, e poderemos retornar para a listagem rapidamente com o clique sobre a 
opção de menu. Também teremos a indicação da opção de cadastro em uso, com fonte mais clara, como 
podemos observar na imagem seguinte:
Listagem de departamentos com inclusão do menu.
O mesmo procedimento deve ser feito para os templates funcdata e funclist, mas, agora, com a utilização do 
valor "funcionarios" na variável do fragmento:
python
 
 
 
 
 
 
 
Alteração das interfaces do CRUD
Templates com listas
Nossa interface está funcional, mas ainda muito simples, o que ajustaremos com a utilização das classes do 
Bootstrap. Vamos começar alterando o template deptolist:
python
 
 
 
 
 
 
Departamentos
 
 
 Novo Departamento
 
 
IdDepto Nome Opcoes
 Excluir
 Alterar
 
Definimos as classes de botão para os links e a formatação da tabela, em que foram utilizadas as classes table e 
table-striped, para expandir o conteúdo na largura da página e trabalhar com alternância de fundo nas linhas. 
Temos uma classe col-sm-2, aplicada às células com os links de alteração e exclusão, para que não utilizem um 
espaçamento maior do que o necessário.
 Todos os links receberam a classe btn, sendo adotado btn-danger para exclusão, e btn-primary para inclusão e 
alteração, além da adoção de tamanho pequeno para os botões de alteração e exclusão, por meio da classe btn-
sm. O resultado é apresentado a seguir: 
Listagem de departamentos formatada com Bootstrap.
O mesmo tipo de alteração deverá ser efetuado no template funclist.
python
 
O resultado das alterações efetuadas pode ser observado na imagem seguinte, obtida durante a execução do 
sistema:
 
 
 
 
 
Funcionários
 
 
 Novo Funcionário
 
 
 
Matricula Nome Cadastro DeptoOpções
Excluir
Alterar
 
 
Listagem de funcionários formatada com Bootstrap.
Templates de cadastros
Podemos modificar os formulários do sistema, a começar pelo template deptodata.
python
 
 
 
 
 
 
Dados do Departamento
 
 
 Nome
 
 
 Cadastrar
 
 
As alterações efetuadas foram mínimas, incluindo o encapsulamento do conteúdo original em uma div com a 
classe container, e o uso das classes btn e btn-primary no botão de envio. Quanto aos componentes de entrada, 
cada conjunto formado por label e input é colocado em uma div do tipo form-group, além do uso da classe form-
control no input e form-label no label, o que traz, além de boa organização, alguns efeitos visuais no ganho de 
foco.
O resultado das mudanças pode ser observado a seguir:
Formulário de departamento formatado com Bootstrap.
Alterações semelhantes precisam ser efetuadas no template funcdata.
python
 
 
 
 
 
 
Dados do Funcionário
 
 
 Matricula
 
 
 
 
 
 Nome
 
 
 
 
 
 
Departamento
 
 
 
 
 
 Cadastrar 
 
 
A presença de uma caixa de seleção levou à adoção da classe form-select. Vejamos o resultado das 
modificações:
Formulário de funcionário formatado com Bootstrap.
Tratamento de erros
Em muitas situações, você deve ter tentado excluir um departamento e ocorreu um erro, o que normalmente é 
causado pela quebra da integridade referencial, imposta pelo relacionamento de um para muitos. É interessante 
informar o erro ao usuário de forma adequada, utilizando mensagens claras. Faremos isso aproveitando nossa 
tela inicial, no template home, de acordo com a listagem seguinte:
python
 
Tudo que fizemos foi acrescentar uma div com a classe container, no primeiro nível, e uma div interna com as 
classes alert e alert-danger, que será responsável por emitir um alerta, na tela principal, com a mensagem de 
erro. O texto da mensagem é preenchido pelo atributo th:text, mas será exibido apenas se um objeto de 
mensagem for enviado a partir do controlador, com base na condição utilizada no atributo th:if.
 
 
 
 
 
 
Precisamos alterar o método excluir, em DepartamentoController, para o tratamento de erros na utilização da 
rota /departamentos/excluir.
java
 
Execute novamente o aplicativo e tente remover um departamento que tenha funcionários, o que fará exibir a 
mensagem enviada a partir do tratamento da exceção pelo controlador, como observado a seguir:
Mensagem de erro exibida na tela principal.
Acréscimo de autenticação no aplicativo
Configuração da autenticação
Nosso aplicativo está totalmente funcional, mas seria interessante acrescentar algum modelo de autenticação. 
Não trabalharemos com um padrão robusto, mas apenas com um exemplo simples, adotando usuário fixo no 
controlador de autenticação, o que não impedirá a utilização de todo o fluxo de execução, com os componentes 
associados e a integração com Thymeleaf.
Inicialmente, vamos acrescentar a dependência para o Spring Security no arquivo pom.xml.
@GetMapping("/departamentos/excluir")
public String excluir(Model model, Integer idDepto) {
 try {
 repositorio.deleteById(idDepto);
 }catch(Exception ex){
 model.addAttribute("mensagem", 
 "Erro ao remover departamento. "+
 "Verifique se não há funcionários associados.");
 return "home";
 }
 model.addAttribute("departamentos", repositorio.findAll());
 return "deptolist";
}
python
 
Tentando executar novamente o aplicativo, será exibida a tela de login, impedindo a utilização do sistema, pois a 
autenticação não está configurada. Precisamos configurá-la criando a classe AuthController, no pacote com.univ
ersidade.
java
 
 
 org.springframework.boot
 spring-boot-starter-security
 
 
 org.thymeleaf.extras
 thymeleaf-extras-springsecurity5
 
 @EnableWebSecurity
@Configuration
public class AuthController extends WebSecurityConfigurerAdapter
 @Bean
 @Override
 public UserDetailsService userDetailsService() {
 UserDetails user = User.builder().username("usu1")
 .password(passwordEncoder().encode("1234"))
 .roles("USER").build();
 return new InMemoryUserDetailsManager(user);
 }
 @Bean
 public PasswordEncoder passwordEncoder() {
 return new BCryptPasswordEncoder();
 }
 
 @Override
 protected void configure(final HttpSecurity http) throws Exception {
 http.authorizeRequests()
 .antMatchers("/", "/login").permitAll()
 .anyRequest().authenticated()
 .and().formLogin()
 .and().logout().logoutSuccessUrl("/");;
 }
 @Override
 public void configure(WebSecurity web) throws Exception {
 web.ignoring().antMatchers("/webjars/**");
 }
}
As anotações Configuration e EnableWebSecurity integram nossa classe ao contexto do Spring, definindo-a 
como controladora de segurança-padrão. Ainda em termos da integração, temos dois beans: um para gerência 
da criptografia (passwordEncoder), que utiliza algoritmo BCrypt, e outro para a base de usuários (userDetailsSer
vice), em que é criado apenas um usuário, com login usu1 e senha 1234, o qual é anexado ao gestor em memória.
 
 
 
Atenção
 
No método configure, tendo como parâmetro um objeto do tipo HttpSecurity, efetuamos todo o 
controle de autenticação, com bloqueio por padrão, mas liberando as rotas para a raiz e para o login. 
Outro elemento configurado é o modelo utilizado para o login, que, no caso, será feito a partir de um 
formulário (formLogin), além do redirecionamento do logout para a página inicial, por meio de 
logoutSuccessUrl, impedindo que seja solicitado um novo login de imediato.
 
 
O segundo método configure, com parâmetro do tipo WebSecurity, é necessário para garantir a funcionalidade 
do Bootstrap, mesmo que o usuário não esteja autenticado. Para tal, usamos a diretiva ignoring, aplicada a toda 
rota partindo de webjars.
Já podemos executar nosso projeto e verificar como o login é solicitado quando acessamos o cadastro de 
departamentos ou o de funcionários. Nosso próximo passo será implementar o logout, com a modificação do 
template menu, apenas no trecho em que encontramos o botão de saída do sistema, conforme o fragmento de 
código apresentado a seguir:
python
 
Trocamos o botão por um link, apontando para a rota logout, e permitimos sua visualização apenas quando há 
um usuário logado, o que é feito com o teste isAuthenticated, no atributo sec:authorize. Apenas com a utilização 
dos extras do Thymeleaf para integração com Spring Security, incluídos nas dependências do projeto, foi 
possível utilizar o dialeto específico voltado para a segurança.
 
 
 Logout
 
Personalização das telas de login e logout
Como passo final, vamos personalizar a tela de login para que fique integrada ao ambiente de nosso sistema. 
Começamos com a criação de um template com o nome login.html.
python
 
 
 
 
 
 
Efetue o Login
 
 
 
 
 
 
 
 
 
 
 
 Usuário ou senha inválido(s).
Por se tratar de uma personalização, devemos manter a chamada do formulário e o nome de cada campo. No 
caso, os campos são username e password, com envio de informação para /login, no modo POST. Temos ainda 
uma div configurada como alert-danger para avisar que os valores utilizados são inválidos, a qual é ativada 
apenas quando existe param.error fornecido pelo controlador do Spring Security.
 Todas as demais configurações utilizadas são semelhantes às que foram adotadas nas demais páginas do 
sistema. Podemos observar a aparência da nova tela de login a seguir:
Login personalizado no sistema.
Precisamos também de um template com o nome logout.html para a confirmação da saída.
pythonLogout do Usuário
 
Clique no botão para confirmar o logout
 
 
 
Novamente, temos que nos integrar ao comportamento do framework. Tudo de que precisamos é uma chamada 
para a rota /logout em modo POST. Nossa janela apenas apresenta um título, mensagem para o usuário, e botão 
do tipo btn-danger, para efetivar o logout, como podemos observar a seguir:
Confirmação de logout personalizada no sistema.
Para que as personalizações sejam efetivadas, precisamos adicionar dois mapeamentos em modo GET na classe 
HomeController.
java
 
As rotas chamadas no modo GET direcionarão para nossos templates, enquanto o modo POST é interceptado 
pelo Spring Security, mantendo todo o arcabouço de autenticação.
Precisamos alterar o método configure, com parâmetro do tipo HttpSecurity, em nossa classe AuthController, 
responsável pela autenticação dos usuários, de acordo com o fragmento de código apresentado a seguir. Note 
que incluímos apenas os elementos necessários para indicar as rotas para o login (loginPage) e para o logout (log
outUrl):
java
 
Ao trabalhar com modelos mais robustos de autenticação, podem ser necessárias alterações no arquivo applicati
on.properties, bem como no acesso a bancos de dados externos.
@GetMapping("/login")
public String showLogin(Model model) {
 return "login";
} 
@GetMapping("/logout")
public String showLogout(Model model) {
 return "logout";
}
@Override
protected void configure(final HttpSecurity http) throws Exception {
 http.authorizeRequests()
 .antMatchers("/", "/login").permitAll()
 .anyRequest().authenticated()
 .and().formLogin().loginPage("/login")
 .and().logout().logoutUrl("/logout").logoutSuccessUrl("/");
}
Teoria na prática
Construção de Menus com Bootstrap.
 
 
 
 
 
 
 
Conteúdo interativo
 
Acesse a versão digital para assistir ao vídeo.
 
 
 
 
Vem que eu te explico!
Os vídeos a seguir abordam os assuntos mais relevantes do conteúdo que você acabou de estudar.
Fundamentos do Bootstrap
 
 
 
 
 
 
 
Conteúdo interativo
 
Acesse a versão digital para assistir ao vídeo.
 
 
 
 
Personalizando o Spring Security
 
 
 
 
 
 
 
Conteúdo interativo
 
Acesse a versão digital para assistir ao vídeo.
 
 
 
 
Verificando o aprendizado
Questão 1
O framework Bootstrap viabiliza a construção de interfaces responsivas, alinhadas com os melhores padrões de 
design, de forma extremamente simples, com base em classes CSS, o que permite, inclusive, a escolha de 
temas personalizados para cada empresa. Por exemplo, se nosso sistema pergunta, em uma caixa de diálogo, 
se desejamos excluir todos os registros, qual seria a classe CSS correta para o botão de confirmação?
 
A
 
btn-primary
 
 
B
 
btn-success
 
 
C
 
btn-info
 
 
D
 
btn-danger
 
 
E
 
btn-link
 
A alternativa D está correta.
 
As classes específicas para botões apresentam cores e formatos padronizados para cada ambiente de 
execução quando adotamos o Bootstrap. Quanto ao exemplo de nosso sistema, a exclusão de todos os 
registros de uma base é sempre uma operação perigosa, que exige plena atenção do usuário na 
confirmação, o que levará à adoção da classe btn-danger, como em 
Confirmar , causando a utilização da cor vermelha, normalmente associada ao perigo.
Questão 2
Uma caraterística muito interessante do Thymeleaf é sua fácil integração com o modelo de segurança do 
Spring, com base no Spring Security, o que permite a definição de templates com o controle da disponibilidade 
de elementos para perfis específicos de usuários, ou simplesmente a alternância da visibilidade de algum trecho 
quando ocorre autenticação. Para o segundo caso, qual método retorna ao estado atual da autenticação?
 
A
 
isLogged
 
 
B
 
isAuthorized
 
 
C
 
isAuthenticated
 
 
D
 
isCertified
 
 
E
 
isOpened
 
A alternativa C está correta.
 
Para integrar o Thymeleaf com Spring Security precisamos apenas acrescentar a dependência thymeleaf-
extras-springsecurity na versão utilizada pelo projeto. Com o acréscimo dessa dependência, o prefixo sec 
(Security) fica disponível para uso nos atributos das tags, com acesso aos mecanismos de segurança do 
ambiente. 
O método isAuthenticated retorna true para um usuário autenticado. Logo, a visibilidade do componente 
pode ser alternada facilmente, com o acréscimo do atributo sec:authorize="isAuthenticated()".
 
 
4. Conclusão
 
 
Considerações finais
De forma geral, pessoas têm competências diferentes. Muitos programadores não apresentam habilidade para a 
construção de interfaces de usuário complexas, algo que é uma característica dos designers. Entretanto, com a 
alta padronização das interfaces atuais, surgiram ferramentas que viabilizam a construção de interfaces de alta 
qualidade com baixo esforço.
Mesmo com a disponibilidade dessas ferramentas, o conhecimento dos princípios elementares para a 
construção de páginas é necessário, principalmente para sua organização estrutural. É preciso conhecer 
sintaxes como HTML, Java Script e CSS, além de frameworks comuns no mercado, como JQuery UI.
Após a compreensão dos princípios para a construção das páginas, precisamos integrá-las com os 
componentes da camada Controller, dentro de uma arquitetura MVC. O uso de Thymeleaf nos proporcionou essa 
integração de forma natural, com base em templates HTML, que podem ser manipulados por designers, por 
meio de ferramentas de edição apropriadas.
Com as interfaces integradas, os sistemas garantem as funcionalidades definidas nos requisitos, mas o mercado 
exige características como responsividade e padronização no design das páginas. O Bootstrap permite o 
acréscimo dessas características de forma não invasiva, por meio de classes para estilização, garantindo 
qualidade e produtividade necessárias.
 
 
Podcast
 
Para encerrar, ouça sobre processo de criação para páginas HTML, bem como a integração com a 
camada de controle de um sistema Spring Web por meio do Thymeleaf.
 
 
 
 
 
 
 
 
Conteúdo interativo
 
Acesse a versão digital para ouvir o áudio.
 
 
 
 
 
 
Explore +
Acesse o guia CSS Tutorial, disponibilizado pela W3Schools, e navegue pelas opções do menu, no lado esquerdo 
da página, para aprender tudo que é necessário sobre CSS.
 
Explore os diversos exemplos disponibilizados pelo JQuery UI (jqueryui.com), navegando pelas opções do menu 
lateral esquerdo e utilizando a opção "view source" para conferir os códigos.
 
Confira o guia Bootstrap 5 Tutorial - An Ultimate Guide for Beginners e navegue pelas opções do menu lateral 
esquerdo para aprender a utilizar o Bootstrap com base em exemplos.
 
Leia o artigo Working with Fragments in Thymeleaf, oferecido pelo Baeldung, e compreenda melhor a utilização 
de fragmentos no Thymeleaf.
 
Leia o artigo Use Thymeleaf Templates with Spring WebFlux to Secure Your Apps, de Jimena Garbarino, 
descrevendo a autenticação em arquitetura de fluxo com Spring e Thymeleaf.
Referências
BOAGLIO, F. SpringBoot. 1. ed. São Paulo: Casa do Código, 2017.
 
BURKE, B; MONSON, R. Enterprise Java Beans 3.0. 5. ed. São Paulo: Pearson, 2007.
 
DEBLAUWE, W. Taming Thymeleaf. 1. ed. USA: Lulu Press, 2021.
 
DEITEL, H; DEITEL, P. Java, Como Programar. 10. ed. São Paulo: Pearson, 2016.
 
HORSTMANN, C. Modern Java Script For The Impatient. 1. ed. USA: Addison-Wesley, 2020.
 
MAZZA, L. HTML5 e CSS3. 1. ed. São Paulo: Casa do Código, 2014.
 
PATEL, N. Spring 5.0 Projects. 1. ed. Reino Unido: Packt Publishing, 2019.
 
SOUZA, N. Bootstrap 4. 1. ed. São Paulo: Casa do Código, 2018.
 
SPILCA, L. Spring Security In Action. 1. ed. USA: Manning, 2020.
 
TURNQUIST, G. Learning Spring Boot 2.0. 2. ed. Reino Unido: Packt Publishing, 2017.
 
ZAKAS, N. High Performance Java Script. 1. ed. USA: O'Reilly, 2010.
 
 
	Camada de visão
	1. Itens iniciais
	Propósito
	Preparação
	Objetivos
	Introdução
	1. Implementação de uma página simples da web
	HTML 5
	Sintaxe
	Tags básicas
	Primeira página
	UNIVERSIDADE ©2022
	Tabelas
	Formulários
	MathML
	Âncoras
	CSS
	Folhas de estilo
	Qualificador hover
	Exemplos práticos
	Exemplo 1
	Exemplo 2
	Java Script
	Operadores do Java Script
	Estrutura condicional
	Biblioteca Java Script
	Fatoriais de 3 a 8
	Primos entre 50 e 75
	Tratamento de eventos
	Notação JSON
	JQuery
	Aplicação básica
	Diálogos modais e respostas a eventos
	Tarefas
	Comentário
	Chamadas assíncronas
	Receitas para Drinks
	Comentário
	Teoria na prática
	Conteúdo interativo
	Vem que eu te explico!
	Sintaxe HTML
	Conteúdo interativo
	Formatação com CSS
	Conteúdo interativo
	Verificando o aprendizado
	2. CRUD utilizando o framework Thymeleaf
	Framework Thymeleaf
	Camada model
	Dica
	Gerenciador para os modelos do Thymeleaf
	Comentário
	Camada Controller
	Camada View
	Comentário
	Filtro de interceptação
	Comentário
	Spring Boot com Thymeleaf
	Criação do projeto
	Controlador Spring Web
	Configuração dos templates
	Departamentos:
	Definição de mensagens
	Departamentos
	Persistência e controle
	Camada de persistência
	Camada de controle
	Comentário
	Interface do CRUD
	Templates para departamentos
	Departamentos
	Dados do Departamento
	Templates para funcionários
	Funcionários
	Dados do Funcionário
	Teoria na prática
	Conteúdo interativo
	Vem que eu te explico!
	Características do Thymeleaf
	Conteúdo interativo
	Filtro de Interceptação
	Conteúdo interativo
	Verificando o aprendizado
	3. Estudo de caso com Framework Bootstrap
	Framework do Bootstrap
	Estilos de botões
	Estilos de Botões
	Caixas de diálogo modais
	Exemplo de Modal
	Comentário
	Sistema de Grid
	Componentes para navegação
	Uso de Bootstrap com Thymeleaf
	Definição do menu
	Navegação utilizando o menu
	Alteração das interfaces do CRUD
	Templates com listas
	Departamentos
	Funcionários
	Templates de cadastros
	Dados do Departamento
	Dados do Funcionário
	Tratamento de erros
	Acréscimo de autenticação no aplicativo
	Configuração da autenticação
	Atenção
	Personalização das telas de login e logout
	Efetue o Login
	Logout do Usuário
	Clique no botão para confirmar o logout
	Teoria na prática
	Conteúdo interativo
	Vem que eu te explico!
	Fundamentos do Bootstrap
	Conteúdo interativo
	Personalizando o Spring Security
	Conteúdo interativo
	Verificando o aprendizado
	4. Conclusão
	Considerações finais
	Podcast
	Conteúdo interativo
	Explore +
	ReferênciasPOST
do protocolo HTTP. Após o preenchimento dos dados, o clique no componente do tipo submit, ou botão de
envio, tentará enviar os dados em background para o endereço, o que causará um erro de acesso, mas, no caso
de uma rota real, estaria enviando esses dados para um componente do servidor capaz de tratá-los, como um
Servlet, por exemplo.
O id deve ser utilizado nos relacionamentos internos da página, enquanto name define a variável que será
enviada para o servidor. O value define o valor que será enviado para o servidor, associado à variável definida via
name, devendo ser fixado para todos os componentes que não permitem edição de valor via teclado.
A lista de valores simples datalist deve ser associada ao componente do tipo input por meio do atributo list. Note
o uso de id para o relacionamento, da mesma forma que nas tags do tipo label, para associação com os
componentes corretos.
O metadado viewport, de grande utilidade na garantia da responsividade, configura a página para se adequar ao
espaço de visualização oferecido pelo dispositivo.
Executando a página no navegador, teremos a tela de entrada. 
Nome Completo
 
 
 
 
 
 
 
 
 Nome:
 
 Sobrenome:
 
 
 
 Declaro aceitar todos os termos de uso do aplicativo.
 Cobrança:
 
 
 
 
 
Formulário Exemplo003.html
MathML
O MathML é uma linguagem de marcação para exibir e capturar estruturas e conteúdo matemático. Vejamos um
Exemplo004.html.
python
 
A sintaxe MathML é bastante complexa e extensa, mas a listagem nos traz muitos elementos de utilização
comum. Inicialmente, definimos uma linha principal com mrow, e na sequência, temos a integral e seus limites,
dentro de msubsup, com o símbolo em mo, limite inferior em mn e limite superior em mi.
O conteúdo interno da integral será uma fração, com mfrac, em que a parte superior deve ficar em uma tag 
mrow, a qual envolve, no exemplo, um logaritmo na base 3, definido com msub, com a função em mi e a base em 
 
 
 
 
 
 
 ∫ 1 t 
 
 
 log 3 
 x
 
 x
 
 ⅆ x
 
 
 
mn, seguido da variável x na tag mi, enquanto a parte inferior tem apenas a variável x em uma tag mi. Na última
parte, temos o sinal diferencial, em uma tag mo, seguido da variável para integração x na tag mi.
Toda a expressão matemática deve ser encapsulada em uma tag math, em que devemos estar atentos para a
utilização do namespace adequado. Para testar, devemos utilizar o Firefox, pois nem todos os navegadores
oferecem suporte direto ao MathML, sendo necessário adicionar plugins a navegadores como Chrome e Edge.
Apresentação do Exemplo004.html, via Firefox.
Âncoras
As âncoras, com base na tag a, definem a navegação entre páginas e conteúdo, justificando a classificação dos
documentos como hipertexto. Uma âncora pode definir um local dentro de uma página extensa, navegar para o
trecho nomeado, ou definir um link para algum endereço. É bastante comum sua utilização junto a imagens,
incorporadas às páginas por meio da tag img.
Vejamos o Exemplo005.html.
python
 
Como um dos objetivos é demonstrar a navegação interna da página, para situações em que o conteúdo é muito
extenso, foram adicionadas muitas quebras de linha. Para marcar o local da página, utilizamos o atributo id da
âncora, enquanto a navegação para o trecho ocorre com o uso do valor de id, precedido por cerquilha, no
atributo href.
A navegação para outros sites ou páginas também é definida no atributo href, com o descritivo da âncora
colocado entre a tag e seu fechamento. No lugar do texto descritivo, podemos usar uma imagem (img), definindo
um ícone clicável.
O resultado da execução da página, que receberá o nome Exemplo005.html, é apresentado a seguir. Como temos
uma página extensa, foi dividida em duas partes, em que o clique sobre a âncora com texto "própria" levará para
o final dela.
 
 
 
 
 Podemos utilizar âncoras para navegar até algum site, como o 
 Spring IO, 
 ou para um local da própria página.
 
 
 
Link para exemplo001
 
 
 
 Aqui fica o local marcado.
 
https://spring.io/projects
exemplo001.html
exemplo001.html
exemplo001.html
exemplo001.html
exemplo001.html
exemplo001.html
Visualização do Exemplo005.html.
CSS
Folhas de estilo
Com o papel estrutural que o HTML assumiu, vários dos atributos de configuração tipográfica das versões
antigas se tornaram obsoletos, deslocando-se a responsabilidade para as folhas de estilo, ou CSS (Cascade
Style Sheets).
As folhas de estilo podem ser adicionadas na tag do HTML (inline), em um trecho delimitado por style, ou em um 
arquivo externo. Em termos de reutilização e responsividade, a melhor opção é o uso de arquivo externo, pois
permite centralizar as formatações e versionar para cada plataforma, ou seja, utilizar pontos de quebra para
formatações específicas.
Vamos voltar ao primeiro exemplo de HTML e aplicar algumas formatações sobre as tags, adotando um setor
delimitado por style.
python
 
Aqui definimos elementos comuns para algumas tags visuais, como cor da fonte (color), cor do fundo
(background-color) e alinhamento do texto (text-align). Também temos uma borda do tipo tracejada sendo
aplicada ao redor das listas.
Podemos aplicar as formatações a várias tags simultaneamente, desde que as separemos por vírgula, e qualquer
atributo definido será combinado com as formatações já existentes. Aliás, as folhas de estilo são denominadas
como "em cascata" porque podem ser sobrepostas.
Qualificador hover
O qualificador hover permite definir uma formatação para o momento em que o mouse repousa sobre o
componente. No exemplo, a página tem fundo preto e fonte branca como padrão, mas, quando o mouse passa
sobre um parágrafo, ele muda a cor de fundo para marrom.
 
 
 
 
 
 
 
Formatações aplicadas às tags do arquivo Exemplo001.html.
Para formatar um elemento específico da página, o seletor correto seria um identificador, ou id, em que uma
utilização comum é na criação de áreas para organização do conteúdo. Como o padrão tableless desencoraja o
uso de tabelas com esse fim, o uso de áreas identificadas, com base em tags do tipo div, formatadas via CSS,
transformou-se na estratégia preferencial.
Identificadores são voltados para a individualização de algum componente na página, sendo definidos na folha
de estilo com um nome precedido de cerquilha. Para que a formatação seja utilizada, devemos ter um
componente com atributo id utilizando o mesmo nome.
Exemplos práticos
Exemplo 1
A seguir, um arquivo de folha de estilos com o nome Exemplo006.css.
python
 
De acordo com a formatação adotada, toda tag div definirá uma área com largura (width) de 200 pixels e altura
(height) de 150 pixels, utilizando texto alinhado ao centro e tamanho de fonte ajustado para 40 pixels. Em
seguida, temos a individualização das características para cada uma das áreas que será criada. A combinação
das formatações da div e do identificador definirão o posicionamento e as dimensões dessas áreas.
Nas formatações específicas, temos a definição da cor de fundo (background-color), estilo da borda (boder-
style), e posicionamento absoluto, em relação ao limite superior esquerdo da página, considerado como origem
dos eixos horizontal e vertical. Com os valores utilizados, teremos uma área a 10 pixels do topo e 10 pixels da
esquerda, e outras duas áreas utilizando os valores 110 e 210, respectivamente.
A página Exemplo006.html, com a listagem a seguir, utiliza a folha de estilos definida anteriormente.
Div {text-align: center; font-size:40px; width:200px; height:150px}
#camada1 {background-color: yellow; border-style: dotted; 
 position: absolute; top:10px; left:10px}
#camada2 {background-color: range; border-style: dashed; 
 position: absolute; top:110px; left:110px}
#camada3 {background-color: gold; border-style: solid; 
 position:absolute; top:210px; left:210px}
python
 
A página é bastante simples, com a definição das áreas por meio de tags do tipo div, relacionadas aos estilos
específicos por meio do atributo id. Devemos lembrar que teremos a combinação das formatações para a tag e
para o identificador em cada área.
O relacionamento entre os arquivos HTML e CSS foi definido por meio da tag link, em que temos o atributo rel
com o valor stylesheet (folha de estilos), e o nome do arquivo em href. Vejamos o resultado da interface:
Exemplo de CSS.
Ao contrário dos identificadores, que definem formatações para elementos específicos, as classes, definidas
com a utilização de ponto antes do nome, servem para formatar elementos que se repetem ao longo da página. 
Exemplo 2
 
 
 
 
 
 
Primeira Camada
 
Segunda Camada
 
Terceira Camada
 
Vamos criar a página Exemplo007.html, contendo a listagem a seguir.
python
 
O que temos no código é a definição de uma lista principal, em que os itens são links para outras páginas e
endereços, além de um item contendo outra lista, o que seria um submenu, com mais alguns links. A relação com
a folha de estilos ocorre por meio da tag link, na divisão head, a qual não terá efeito antes da criação do arquivo.
 
 
 
 
 
 
 
Inicio
 
Exemplos...
 
 
Primeiro
 
Segundo
 
 
 
Pesquisa
 
 
• 
• 
◦ 
◦ 
• 
exemplo007.html
#
exemplo001.html
exemplo002.html
https://www.google.com
Página com menu, sem a folha de estilos.
Como podemos observar, temos a exibição das listas, contendo as âncoras, em que os links estão funcionais,
mas ainda sem a formatação adequada. Veremos que as folhas de estilos efetuam modificações extremas na
forma de apresentação, permitindo que o HTML assuma apenas o papel estrutural, de acordo com a divisão de
responsabilidades exigida pela W3C.
Vamos estilizar nosso menu por meio da criação do arquivo Exemplo007.css, contendo a listagem a seguir.
python
 
Se voltarmos ao nosso código HTML, veremos que a lista principal, na primeira tag ul, tem o valor menu no
atributo class, definindo a utilização das formatações associadas à classe menu, da folha de estilos. Da mesma
forma, a lista interna é atribuída à classe submenu, que também será especificada na folha de estilos.
Começamos com uma formatação geral, por meio do asterisco, para a remoção das margens da página, além da
definição da fonte com 12 pixels, na tag body. Nos passos seguintes, temos as classes menu e submenu sendo
configuradas.
A classe menu remove o marcador dos itens de lista para todos os elementos internos, com base no
atributo list-style, além de usar cor de fundo amarela e posicionamento relativo à esquerda da página,
por meio do valor left no atributo float, para cada item. Para o submenu, temos posicionamento de 25
pixels em relação ao topo do contêiner atual, no caso o item do menu, e fundo laranja, não sendo
visível inicialmente, devido ao uso de none para display.
 *{margin: 0; padding: 0}
body{font-size: 12px}
.menu{list-style:none; background-color: yellow; float:left}
.menu li{position:relative; float:left; 
 border-right:1px dashed black}
.menu li a{color:black; text-decoration:none; 
 padding:5px 10px; display:block}
.menu li a:hover{background:black; color:white}
.submenu{position:absolute; top:25px; left:0;
 background-color:orange; display:none}
.submenu li{border-bottom: 1px dashed black; 
 display:block; width:120px}
.menu li:hover ul, .menu li.over ul{display:block}
As demais formatações apresentam duas características interessantes na criação de seletores: o agrupamento e
a dependência. Podemos agrupar seletores separados por vírgula, em que a mesma formatação é aplicada a
todos, ou especificar uma dependência por meio do uso de espaço, em que o estilo é aplicado apenas quando a
hierarquia é observada.
Segundo as características definidas, uma tag li, dentro de um elemento menu, respeitará uma sequência de
posicionamento a partir da esquerda, além de apresentar uma borda tracejada de 1 pixel à direita (border-right).
Da mesma forma, na formatação seguinte, temos as âncoras dentro das tags li, a partir de menu, com remoção
do sublinhado, por meio de text-decoration, definição do espaçamento em padding, e visualização (display)
como bloco, em que temos a área preenchida, sem outros elementos HTML ao redor, a não ser que sejam
configurados com valor left em float.
Ainda com relação às âncoras, o qualificador hover fará com que seja utilizado fundo preto e fonte
branca quando o mouse estiver sobre elas.
Temos ainda a formatação para a tag li, a partir de submenu, com definição da borda inferior, visualização em
bloco e largura de 120 pixels. Como o submenu estará dentro de menu, temos formatações que se propagam
para li, como a borda direita, ao mesmo tempo em que, devido à precedência da visualização do contêiner, as
tags li de submenu ficarão invisíveis no início.
Para que o submenu fique visível, temos uma formatação muito específica, em que o qualificador hover é
aplicado uma tag li de menu sequenciada por ul, mudando o valor do atributo display da ul para block enquanto o
mouse estiver sobre o item. Vejamos a interface resultante:
Página com menu, utilizando a folha de estilos.
Java Script
O dinamismo das páginas exige a utilização de uma linguagem de programação adequada, no caso o Java Script,
e interação baseada na utilização de eventos. 
Imagem ilustrativa JavaScript.
Utilizamos o Java Script para controle de elementos da página
HTML e sua interatividade, em que o código pode ser incluído
na própria página, ou organizada no formato de biblioteca, como
um arquivo externo. Caracterizada originalmente como uma
linguagem para o navegador, hoje temos muitas tecnologias que
adotam Java Script no lado servidor, como NodeJS.
Uma variável pode ser declarada com o uso de var, ou
simplesmente por meio da inicialização. Como o Java Script não
é fortemente tipado, a variável assume o tipo do valor associado
a ela. Os tipos com os quais a linguagem trabalha são: numérico,
booleano, texto, objeto e vetor, este último como objeto da classe Array.
Operadores do Java Script
Vamos começar pela criação da página Exemplo008.html.
python
 
No exemplo, são declaradas três variáveis, com a utilização de var, sendo efetuadas algumas operações
aritméticas sobre elas. A cada passo, é impresso na página o valor das variáveis, dentro de tags do tipo li, por
meio de document.writeln, com a concatenação dos valores no texto efetuada pelo sinal de adição.
Com relação aos operadores do Java Script, podem ser observados na tabela seguinte:
Operador  Tipo  Utilização 
+ += ++  Aritmético Operação de adição. Quando colocado à esquerda
da igualdade, o valor é somado à variável
receptora. Duplo mais incrementa um. Também é
utilizado na concatenação de texto.
- -= --  Aritmético Operação de subtração. Quando posicionado à
esquerda, temos a subtração do valor no receptor.
Duplo menos decrementa um.
 
 
 
 
 
 
 
 
Operador  Tipo  Utilização 
* *=  Aritmético Multiplicação de valores. Quando posicionado à
esquerda, temos a multiplicação do receptor pelo
valor.
/ /=  Aritmético Operação de divisão. Quando posicionado à
esquerda, temos a divisão do receptor pelo valor.
% %=  Aritmético Resto da divisão inteira. Quando posicionado à
esquerda, obtemos o resto da divisão do receptor
pelo valor.
> >=  Relacional Comparação entre valores, dos tipos maior e maior
ou igual, com resultado do tipo booleano.
Lógico Operação de negação. Inverte o resultado da
operação lógica.
Tabela: Operadores oferecidos na sintaxe do Java Script.
Denis Cople.
A divisão inteira trunca o valor no Java, mas não no Java Script, pois não temos como diferenciar entre inteiro e
ponto flutuante. Outra diferença para o Java é a comparação de texto: no Java, é necessário o método equals,
enquanto o Java Script adota o operador de igualdade padrão.
Vejamos a interface gerada: 
Utilização de Java Script em Exemplo008.html.
Estrutura condicional
A similaridade entre Java Script e derivados do C também ocorre na sintaxe para as estruturas de decisão e de
repetição. Vejamos um exemplo de estrutura condicional, no arquivo Exemplo009.html.
python
 
A função prompt serve para solicitar ao usuário a digitação de um valor a partir de um diálogo de entrada,
enquanto a função eval efetua a conversão do texto para número. De acordo com nosso exemplo, a variável x
recebe o valor digitado pelo usuário, com o uso da função prompt, ocorrendo a conversão para numérico por
meio de eval.
Com base no valor digitado, a página apresentará uma das alternativas de frase, sempre com o encapsulamento
na tag h1, ocorrendo a escolha da frase pela estrutura condicional if..else, segundo a condição x > 5. Vejamos o
resultado final:
Execução da página Exemplo009.html, com estrutura condicional.
As funções, bem como os métodos da orientação a objetos, são processos nomeados, que podem ou não
apresentar parâmetros e retornar valores. Criamos funções no Java Script com o uso de function, e elas podem
retornar valores para o chamador por meio de return.
Biblioteca Java Script
Vamos começar com a definição do arquivo ExemploLib.js, em que teremos uma biblioteca Java Script.
 
 
 
 
 
 
javascript
 
Nessa biblioteca, temos duas funções: cálculo do fatorial e a verificação se o número fornecido é primo. Em 
ambos os casos, temos um parâmetro de entrada x e uso de return para fornecimento do resultado, embora não 
sejam elementos obrigatórios.
 
 
 
A função fatorial é recursiva, com base em uma condicional, em que valores menores do que 2 
causam o retorno de 1, enquanto outros especificam o retorno a partir da multiplicação do valor pelo 
fatorial do anterior.
 
Já para o teste de primalidade, ele foi codificado com base em uma estrutura de repetição, em que ocorre o 
retorno de false quando o parâmetro é divisível por algum valor do loop, segundo o teste do resto da divisão, ou t
rue, após o loop, quando não é divisível por nenhum dos valores, o que é justificado pela regra de que o número 
primo só pode ser dividido por 1 ou por ele mesmo.
Com nossa biblioteca Java Script pronta, vamos criar o arquivo Exemplo010.html.
 function fatorial(x) {
 if (xDiálogos modais e respostas a eventos
Vamos verificar a construção de diálogos modais e implementação da resposta a eventos, criando o arquivo Exe
mplo013.html.
 
 
 
 
 
 
 
 
 
 
 
Data: 
 
python
 
No exemplo, temos uma página para definição de listas de tarefas, com a inclusão de tarefas na lista a partir de 
um diálogo modal.
Vamos analisar o diálogo modal, que é construído sobre um elemento do tipo div, com o título "Definição de 
Tarefas", contendo um formulário em seu interior. Para transformar o componente em um diálogo modal, 
invocamos o modificador dialog, tendo como atributos: altura (height) de 200 pixels, largura (width) de 350 
pixels, abertura automática (autoOpen) desativada e comportamento modal ativado.
O primeiro botão invocará a função criarTarefa, responsável pela adição de uma tarefa à lista, e o segundo 
apenas provocará o fechamento do diálogo a partir de uma função anônima. Temos ainda o evento de 
fechamento do diálogo (close), que limpa o campo de texto (edtTarefa) quando o diálogo é fechado, fornecendo 
um texto vazio para val.
 
 
 
 
 
 
 
 
 
 
 
Tarefas
 
 
 
 
 Tarefa
 
 
 
 
 
 
Abrir Dialogo
 
 
 
 
Comentário
 
A criação da tarefa pode ser observada na função criarTarefa, em que temos a inclusão de um 
elemento do tipo li à lista, identificada como listaTarefas, por meio do método append. Além da 
utilização de uma classe CSS e de um estilo complementar para definição do espaçamento, 
modificando a aparência padrão do item de lista, temos a captura do valor que foi digitado no campo 
de texto, por meio da val, para utilização no item. Note que o fechamento do diálogo é invocado após 
o acréscimo da tarefa.
 
 
Segundo o comportamento padrão de um formulário, ocorreria o envio da informação com o pressionamento da 
tecla "Enter". Para evitar que ocorra uma mudança de endereço, limpando os dados já inseridos, buscamos (find) 
o form a partir de dlgTarefa, e associamos o evento de submit, em que eliminamos o comportamento padrão (pre
ventDefault) e fechamos o diálogo.
 Note o uso do método on, que associa um evento de determinado tipo a uma função para o tratamento. A 
mesma técnica foi adotada para a resposta ao clique no botão btnDialog, que efetua a abertura do diálogo com 
a chamada do tipo open.
 Para a lista, foi utilizado o modificador sortable, que permite arrastar os itens adicionados à lista, modificando 
sua ordem de apresentação.
 A interface criada pode ser observada a seguir: 
Diálogo e lista ordenável, arquivo Exemplo013.html.
Chamadas assíncronas
Algo que se tornou muito comum nos sites atuais foi a utilização de chamadas assíncronas, segundo um 
compêndio de tecnologias conhecido como AJAX. A biblioteca JQuery fornece um método muito simples para 
efetuar chamadas desse tipo. Como o Java Script permite lidar com JSON de forma nativa, o tratamento da 
resposta para Web Services RESTful não oferece qualquer tipo de dificuldade.
 Para demonstrar o uso de AJAX, vamos criar o arquivo denominado Exemplo014.html.
python
 
Em termos de componentes HTML relevantes, temos apenas uma caixa de texto (edtNome), um botão 
(btnEnviar) e uma divisão (listaDrinks). A divisão merece atenção especial, pois serve de base para um 
componente accordion, o qual fornece a criação de áreas retráteis agrupadas, em que cada área receberá um tít
ulo, por meio da tag h3, e o conteúdo em uma div.
Temos a associação do clique ao botão, com uma função de tratamento que limpa o conteúdo interno de listaDri
nks, eliminando os resultados de consultas anteriores, formando o endereço de pesquisa, concatenando o valor 
digitado em edtNome, e efetuando a chamada AJAX.
Como temos uma chamada assíncrona, é fornecido um objeto com o endereço (url) e a manipulação para um 
retorno bem-sucedido (success), em que invocamos tratarDados com a passagem do retorno.
 
 
 
 
 
 
 
 
 
 
 
 
Receitas para Drinks
 
 Pesquisar
 
 
 
 
Comentário
 
O endereço é um serviço RESTful internacional para a consulta de receitas de drinks, que retorna 
diversas informações no formato JSON. Como cada drink normalmente apresenta variações, teremos 
um vetor de registros em que resgataremos os campos strDrink, strDrinkThumb e strInstructions, 
representando, respectivamente, o nome, a foto e a receita do drink. Lembre-se de que as receitas 
estarão em inglês, mas a tradução da página, por meio do navegador, apresentou ótimos resultados 
nos testes efetuados.
 
 
A função tratarDados recebe a resposta no formato JSON, e utiliza o operador forEach sobre o vetor drinks, 
invocando adicionaLinha a cada registro, com a atualização do accordion, ao final, por meio da opção refresh.
O formato de adicionaLinha é padronizado para o uso de forEach, com os parâmetros representando o registro e 
o índice no vetor, em que item servirá de base para construir uma área de nosso accordion, com o título (h3) 
associado a strDrink e o conteúdo (div) definido a partir de uma imagem apontando para strDrinkThumb, ao lado 
do texto referente às instruções da receita (strInstructions). Vejamos o resultado:
Utilização de AJAX.
Existem muitos outros componentes disponíveis na biblioteca JQuery UI, inclusive opções para a criação de 
menus, barras de progresso e abas de navegação. 
Teoria na prática
Construção de páginas com JQuery UI.
 
 
 
 
 
 
 
Conteúdo interativo
 
Acesse a versão digital para assistir ao vídeo.
 
 
 
 
Vem que eu te explico!
Os vídeos a seguir abordam os assuntos mais relevantes do conteúdo que você acabou de estudar.
Sintaxe HTML
 
 
 
 
 
 
 
Conteúdo interativo
 
Acesse a versão digital para assistir ao vídeo.
 
 
 
 
Formatação com CSS
 
 
 
 
 
 
 
Conteúdo interativo
 
Acesse a versão digital para assistir ao vídeo.
 
 
 
 
Verificando o aprendizado
Questão 1
Segundo as diretivas da W3C, enquanto o HTML fica com a responsabilidade de estruturar as páginas, toda 
formatação visual deve ser implementada por meio de folhas de estilo. Mais do que formatações, o CSS permite 
controlar alguns comportamentos, como a mudança do aspecto do componente com a passagem do mouse 
sobre ele, o que é feito com o qualificador
 
A
 
empty.
 
 
B
 
visited.
 
 
C
 
focus.
 
 
D
 
hover.
 
 
E
 
active.
 
A alternativa D está correta.
 
Com o CSS, aplicamos formatações a elementos específicos da página, por meio de seletores, além de 
permitir a definição de alguns comportamentos via qualificadores. Por exemplo, empty define a aparência 
quando o componente não tem filhos, focus para aquele componente que detém o foco, visited é utilizado 
nos links já visitados, active para o momento em que ocorre o clique, e hover para a passagem do mouse 
sobre o componente.
Questão 2
O surgimento do JQuery, um framework construído totalmente em Java Script, trouxe novas possibilidades para 
a criação de páginas para Web. Com uma sintaxe que alia os seletores CSS às melhores práticas de 
programação em Java Script, permitiu a realização de tarefas que antes eram consideradas trabalhosas com 
poucas linhas de código, além de oferecer diversos módulos que expandem sua funcionalidade básica, como 
JQuery UI. Qual métododo JQuery UI deve ser utilizado para criar uma sequência de painéis, cada um com 
título e possibilidade de ocultação?
 
A
 
dialog
 
 
B
 
slider
 
 
C
 
accordion
 
 
D
 
tooltip
 
 
E
 
spinner
 
A alternativa C está correta.
 
Por meio do uso de accordion, conseguimos criar uma sequência de painéis, em que o título de cada um é 
definido via tag h3 e o conteúdo em uma tag div, sendo o método aplicado a uma div que envolve todos 
os pares h3/div. Por padrão, apenas um painel começa selecionado, ficando aberto (visível), enquanto os 
demais apresentam apenas o título. O clique sobre o título de outro painel altera o painel selecionado, 
ocultando o conteúdo dos demais.
 
 
2. CRUD utilizando o framework Thymeleaf
 
 
Framework Thymeleaf
Por meio do framework Thymeleaf, criamos templates HTML, os quais promovem uma separação natural da 
camada de visualização, definindo modelos que funcionam como protótipos de design naturais. Ele trabalha com 
outros formatos, além do HTML, incluindo XML, texto e Java Script, de acordo com o modo de operação 
utilizado. A principal diferença ocorre ao nível das críticas quanto à formação do arquivo ou tags utilizadas.
Como podemos escolher entre diferentes dialetos, cada dialeto trará as regras de formação para o tipo de 
arquivo e integração com os componentes naturais do ambiente, como os managed beans do ambiente Java 
Web.
Camada model
Vamos criar um projeto do tipo Web Application, com gerenciamento pelo Maven, no NetBeans, como na imagem 
a seguir. Nosso projeto terá o nome ExemploTh001, e o Group Id será com.universidade, utilizando servidor Apac
he Tomcat, com Java EE versão 7.
Criação de aplicativo Web com gerenciamento do Maven.
Agora, vamos incluir a dependência do Thymeleaf no arquivo pom.xml, com o acréscimo do fragmento 
apresentado a seguir:
python
 
O projeto deverá apresentar problemas com a adição da dependência, com um sinal de exclamação sobre o 
ícone do projeto no navegador do NetBeans. Clique com o botão direito sobre o projeto e escolha a opção "Resol
ve Project Problems".
 
 
 
Dica
 
 A versão do JDK interferirá na utilização do Maven, sendo aconselhável adotar ao menos a 
plataforma 1.8, que já traz o protocolo SSL atualizado. 
 
 
Com o projeto configurado, vamos iniciar a codificação do aplicativo com a criação da classe Contato, no pacote 
com.une sa.exemploth001.model.
 
 org.thymeleaf
 thymeleaf
 3.0.15.RELEASE
 
java
 
No mesmo pacote, criaremos a classe ContatoRepositorio, simulando o acesso a uma base de dados, para que 
possamos testar as interfaces gerenciadas pelo Thymeleaf.
java
 
As classes representam, respectivamente, uma entidade do sistema e o repositório para ela, em que o meio de 
armazenamento é um HashMap estático. O repositório fornece métodos para incluir, excluir e obter a lista de 
contatos, além de ser inicializada com dois contatos de exemplo.
Gerenciador para os modelos do Thymeleaf
Vamos definir um gerenciador para os modelos do Thymeleaf, com a criação da classe EngineFactory, no pacote 
com.universidade.exemploth001.web.
 public class Contato {
 private String nome;
 private String telefone;
 public Contato(String nome, String telefone) {
 this.nome = nome;
 this.telefone = telefone;
 }
 public Contato() {}
 public String getNome() { return nome; }
 public void setNome(String nome) { this.nome = nome; }
 public String getTelefone() { return telefone; }
 public void setTelefone(String telefone) { 
 this.telefone = telefone;
 }
 }
 public class ContatoRepositorio {
 private static final HashMap contatos = 
 new HashMap();
 static {
 contatos.put("Ana",new Contato("Ana","1111-1111"));
 contatos.put("Carlos", new Contato("Carlos","2222-2222"));
 }
 public void incluir(Contato contato){
 contatos.put(contato.getNome(), contato);
 }
 public void excluir(String nome){
 contatos.remove(nome);
 }
 public Collection obterTodos(){
 return contatos.values();
 }
 }
java
 
A classe segue o padrão Factory, com apenas um método estático, para recebimento de um contexto Web (Servl
etContext) e retorno de um gerenciador de templates. As configurações do gerenciador indicam o uso de 
sintaxe HTML, com arquivos colocados no diretório templates de WEB-INF (prefixo), utilizando extensão html (suf
ixo), além de adotar cache de uma hora.
 Após a definição do objeto de configuração, o gerenciador (TemplateEngine) é instanciado e associado ao 
configurador. Esse gerenciador será recebido por algum objeto capaz de tratar as requisições HTTP como um 
filtro.
 
 
 
Comentário
 
 Antes de chegar até o Servlet, a requisição passa pelos filtros de interceptação definidos, o que 
permite automatizar ações como verificação de usuário e log de eventos. 
 
 
Camada Controller
Antes de criar nosso filtro, vamos definir uma interface de comandos para nosso sistema, com o nome 
IController, no pacote com.unesa.exemploth001.controller.
 public class EngineFactory {
 public static ITemplateEngine buildTemplateEngine(
 ServletContext servletContext) {
 ServletContextTemplateResolver templateResolver = 
 new ServletContextTemplateResolver(servletContext);
 templateResolver.setTemplateMode(TemplateMode.HTML);
 templateResolver.setPrefix("/WEB-INF/templates/");
 templateResolver.setSuffix(".html");
 templateResolver.setCacheTTLMs(3600000L);
 templateResolver.setCacheable(true);
 TemplateEngine templateEngine = new TemplateEngine();
 templateEngine.setTemplateResolver(templateResolver);
 return templateEngine;
 }
 }
java
 
A interface criada definirá o modelo de chamadas da camada controller, utilizado nas ações do sistema, cujas 
classes ficarão no mesmo pacote de IController. Começaremos definindo a classe ContatosList:
java
 
Vamos acrescentar a variável listaContatos, com a listagem de contatos obtida do repositório, para que seja 
utilizada no template. Em seguida, ocorre o processamento para o template "contatos", utilizando o contexto 
Thymeleaf (ctx) e a stream de saída para escrita do HTML (writer).
Definiremos procedimentos parecidos para as demais ações, como ContatosIncluir.
 public interface IController {
 void process(final WebContext ctx, 
 final ITemplateEngine templateEngine, 
 final Writer writer);
 }
 // Pacotes utilizados: java.io e org.thymeleaf
 public class ContatosList implements IController{
 ContatoRepositorio repositorio = new ContatoRepositorio();@Override
 public void process(WebContext ctx, 
 ITemplateEngine templateEngine, Writer writer) {
 ctx.setVariable("listaContatos", repositorio.obterTodos());
 templateEngine.process("contatos",ctx,writer);
 }
 }
java
 
Aqui temos a ação de inclusão de contato, em que devemos obter os parâmetros enviados pela requisição 
HTTP, criação de uma entidade a partir desses dados, e uso do repositório para a inclusão. O restante do 
processo é equivalente ao da ação de listagem anterior.
 Nada muito diferente ocorre para a ação de exclusão, que terá o nome ContatosExcluir. 
java
 
Assim como na inclusão, após obter o nome enviado por meio da requisição e invocar a exclusão a partir do 
repositório, configuramos os dados para exibição dos contatos.
Camada View
Temos o mesmo template para as três ações definidas. Para criá-lo, vamos adicionar uma página HTML com o 
nome contatos, no diretório templates, a partir de WEB-INF, de acordo com código a seguir:
 public class ContatosIncluir implements IController{
 ContatoRepositorio repositorio = new ContatoRepositorio();
 
 @Override
 public void process(WebContext ctx, 
 ITemplateEngine templateEngine, Writer writer) {
 String nome = ctx.getRequest().getParameter("nome");
 String telefone = ctx.getRequest().getParameter("telefone");
 Contato contato = new Contato(nome,telefone);
 repositorio.incluir(contato);
 ctx.setVariable("listaContatos", repositorio.obterTodos());
 templateEngine.process("contatos",ctx,writer);
 }
 }
 public class ContatosExcluir implements IController{
 ContatoRepositorio repositorio = new ContatoRepositorio();
 
 @Override
 public void process(WebContext ctx, 
 ITemplateEngine templateEngine, Writer writer) {
 String nome = ctx.getRequest().getParameter("nome");
 repositorio.excluir(nome);
 ctx.setVariable("listaContatos", repositorio.obterTodos());
 templateEngine.process("contatos",ctx,writer);
 }
 }
python
 
Temos uma página HTML comum, com um formulário contendo dois campos e uma tabela, mas devemos estar 
atentos ao uso de atributos definidos no namespace do Thymeleaf, que foi configurado ao nível da raiz do 
documento, com o alias th. Serão esses atributos que sofrerão modificações pelo gerenciador de templates 
durante o processamento.
 Começando pela tabela, temos o comando th:each, que repetirá o trecho para cada elemento de listaContatos, 
Nome:
 
 
 
 
 
 
 
 
 
 
Telefone:
 
 
 
Nome Telefone Opcoes
Nome Telefone 
 
 Excluir 
 
 
fornecida pelas ações, associando cada um à variável local contato. Em cada célula da linha, teremos o valor 
preenchido, com o uso de th:text, a partir do campo específico de contato. Utilizamos ainda o campo artificial co
ntatoStat para colorização de linhas ímpares.
 
 
 
Comentário
 
Note o uso de cifrão ($) para acesso a um valor, colocado entre chaves. Também temos o uso de 
arroba (@), executado localmente, o que foi utilizado na construção de um link dinâmico, com a 
passagem da rota e seus parâmetros, colocados entre parênteses, definindo o endereço para 
exclusão de um registro específico.
 
 
Quanto ao formulário, o único elemento relevante é o uso do atributo th:action, fornecendo a rota para inclusão, 
em que o uso de arroba corrige eventuais modificações da URL.
 Observamos que precisaremos do mapeamento de rotas para nossas ações, o que será feito pela classe Controll
erMappings, no pacote com.universidade.exemploth001.controller. 
java
 
Nosso mapeamento foi definido com base em um HashMap, em que cada rota é associada a um controlador 
para processamento da ação específica. A classe oferece apenas um método público, com o nome fromPath, 
que recebe a rota e retorna o controlador correto.
 public class ControllerMappings {
 private final static HashMap controladores;
 static {
 controladores = new HashMap();
 controladores.put("/app/contato/list", new ContatosList());
 controladores.put("/app/contato/incluir", new ContatosIncluir());
 controladores.put("/app/contato/excluir", new ContatosExcluir());
 }
 public static IController fromPath(final String path) {
 return controladores.get(path);
 }
 }
Filtro de interceptação
Vamos definir o filtro de interceptação, com a criação da classe AppFilter, que ficará no pacote com.universidade
.exemploth001.web.
java
 
O mapeamento do filtro ocorre para qualquer rota iniciada com app, por meio da anotação WebFilter. Detectada 
uma url com essas características, o fluxo é desviado para o método doFilter, em que é invocado o método 
interno para processamento (process). O fluxo é devolvido para a cadeia de filtros quando o método retorna 
false.
 O processamento do filtro é iniciado com alguns testes para saber se existe uma classe de ação apropriada, 
@WebFilter(urlPatterns = "/app/*")
public class AppFilter implements Filter {
 private ITemplateEngine templateEngine;
 
 @Override
 public void init(final FilterConfig filterConfig)
 throws ServletException {
 this.templateEngine = EngineFactory.buildTemplateEngine(
 filterConfig.getServletContext());
 }
 @Override
 public void doFilter(ServletRequest request, 
 ServletResponse response, FilterChain chain) 
 throws IOException, ServletException {
 if (!process((HttpServletRequest)request,
 (HttpServletResponse)response)) {
 chain.doFilter(request, response);
 }
 }
 private boolean process(final HttpServletRequest request, 
 final HttpServletResponse response)
 throws ServletException {
 try {
 String path = request.getServletPath();
 if (!path.startsWith("/app")) { return false; }
 IController controller = ControllerMappings.fromPath(path);
 if (controller == null) { return false; }
 
 response.setContentType("text/html;charset=UTF-8");
 response.setHeader("Pragma", "no-cache");
 response.setHeader("Cache-Control", "no-cache");
 response.setDateHeader("Expires", 0);
 Writer writer = response.getWriter();
 WebContext context = new WebContext(request, response, 
 request.getServletContext());
 controller.process(context, this.templateEngine, writer);
 return true;
 } catch (IOException e) {
 throw new ServletException(e);
 }
 }
 @Override
 public void destroy() { }
}
retornando false quando um controlador não é encontrado. Caso seja encontrado, a resposta é iniciada com a 
configuração do tipo de conteúdo e alguns cabeçalhos para impedir a utilização de cache no cliente.
 
 
 
Comentário
 
No passo seguinte, um objeto do tipo WebContext é instanciado, e o controlador que foi obtido 
anteriormente processa a resposta, utilizando o objeto instanciado, o gerenciador de templates do 
filtro e o escritor do canal de saída da resposta HTTP. Note que o gerenciador de templates é obtido 
no método init do filtro, a partir de nossa classe EngineFactory.
 
 
Se o processamentonão gerar falhas, o método retorna true ao chamador, mas se uma exceção ocorre, ela é 
encapsulada em um ServletException, sendo ecoada para o contexto de execução com throw. Executando o 
projeto, podemos acessar o endereço http://localhost:8080/app/contato/list, obtendo a saída a seguir:
Visualização da lista de contatos no projeto ExemploTh001.
Spring Boot com Thymeleaf
Criação do projeto
Embora seja possível utilizar o NetBeans para criação de aplicativos Spring Boot, com a simples alteração do 
arquivo pom.xml em um aplicativo padrão Maven algumas plataformas tornam a tarefa mais simples. Uma opção 
muito interessante é o Spring Tools Suite, baseado no Eclipse, que pode ser baixado a partir do endereço https://
spring.io/tools, com a instalação fornecida no formato de um arquivo jar executável, o qual efetua uma simples 
extração de arquivos.
 Para criar o projeto, escolha a opção de menu File, seguida de New e Spring Starter Project, adotando o nome E
xemploTh002, além do grupo com.universidade e pacote de mesmo nome, como pode ser observado na 
imagem seguinte:
Criação de projeto Spring Boot no Spring Tools Suite.
Clicando no botão Next, devemos selecionar os pacotes do Spring que serão adicionados ao arquivo de 
configuração pom.xml. Utilizaremos Spring Data JPA, H2 Database, Thymeleaf e Spring Web, como observado a 
seguir: 
Escolha dos pacotes utilizados no projeto.
Ao clicar em Finish, teremos um projeto Spring Boot com inclusão do Thymeleaf, modelo objeto-relacional do 
JPA, arquitetura MVC do Spring Web e banco de dados do tipo H2, que trabalha em memória, eliminando a 
necessidade de configurações. Para testar o projeto, vamos clicar com o botão direito sobre ele, no Package 
Explorer, situado na divisão esquerda do ambiente, e escolher Run As, seguido de Spring Boot App.
 Poderemos observar as mensagens referentes à execução na divisão inferior, painel Console, na imagem 
seguinte. Apesar de estar em execução, nosso sistema não tem rotas definidas, e a chamada ao endereço de 
base (localhost:8080) retornará um erro.
Acompanhamento da execução no Console do Spring Tools Suite.
Controlador Spring Web
Vamos adicionar a classe HomeController ao pacote com.universidade, utilizando o botão direito sobre o pacote 
e escolhendo New, seguido de Class.
java
 
Aqui definimos um controlador Spring Web, com a anotação Controller, tendo o mapeamento da raiz para o 
método showHome, por meio da anotação GetMapping. No método, temos um parâmetro do tipo Model, para a 
atribuição de valores que serão repassados para o template, e um retorno do tipo texto, que deverá indicar o no
me do template, sem a extensão HTML.
Configuração dos templates
No corpo do método, adicionamos o atributo data, com um objeto do tipo Date, e uma lista de valores texto no 
atributo departamentos. Os valores serão enviados para o template home_tl, que deveremos criar no diretório te
mplates. Vejamos a estrutura de nosso projeto:
@Controller
public class HomeController {
 @GetMapping("/")
 public String showHome(Model model) {
 model.addAttribute("data", new Date());
 List listDepartamentos = Arrays.asList(
 "Financeiro", "Comercial", "Recursos Humanos");
 model.addAttribute("departamentos", listDepartamentos);
 return "home_tl";
 }
}
Estrutura do projeto ExemploTh002.
Para criar o arquivo, utilizamos o botão direito sobre o diretório templates, seguido de New e File, sendo 
adotado o nome home_tl.html. A extensão deve ser digitada, e o conteúdo do novo arquivo é apresentado na 
listagem seguinte.
python
 
Aqui temos a criação de uma lista HTML, em que os elementos são obtidos por meio de th:each, a partir da 
coleção departamentos, fornecida pelo controlador. Cada elemento é recuperado na variável departamento, 
utilizada para substituir o conteúdo valor, com o uso de th:text. Da mesma forma, recuperamos a data para 
preenchimento do elemento span.
 
 
 
Departamentos:
 
 
valor
 
 
 Página gerada em valor
 
• 
 Como os templates são estáticos, devemos parar a execução e reiniciar o servidor, o que é feito de forma rápida 
pela opção relaunch, na barra de ferramentas da IDE, com um ícone mesclando os símbolos stop e run. O 
resultado pode ser observado na imagem a seguir: 
Visualização da página inicial com o template home_tl.html.
A sintaxe para configuração dos templates inclui muitas diretivas. Na tabela seguinte, temos os símbolos 
utilizados pelo Thymeleaf, segundo a Standard Expression Syntax:
Símbolo  Utilização 
${...}  Acessa o valor de uma variável, que pode ser local ou fornecida no Model.
*{...}  Seleciona o campo de um objeto.
#{...}  Recupera mensagens configuradas em um arquivo com extensão properties.
@{...}  Transforma o endereço da rota em uma URL válida.
~{...}  Insere o conteúdo de um fragmento HTML, viabilizando reuso no template.
Tabela: Símbolos utilizados na sintaxe do Thymeleaf.
Denis Cople.
Definição de mensagens
Para demonstrar o uso de mensagens, um recurso muito útil para a definição de mensagens padronizadas, 
inclusive com suporte a idiomas, vamos criar o arquivo messages.properties no diretório resources, mesmo 
diretório de application.properties, com o conteúdo seguinte:
java
 main.titulo=Lista de Departamentos
Em seguida, modificamos nosso arquivo de template (home_tl.html), alterando o trecho do título, conforme 
apresentado a seguir:
python
 
Ao executar novamente o servidor, nossa página apresentará o título definido no arquivo de propriedades, ou 
seja, "Lista de Departamentos".
Aqui utilizamos o Spring Tools Suite por ser uma ferramenta mais prática para a criação dos aplicativos Spring 
Boot, mas, se quiser utilizar o NetBeans, basta criar um projeto-padrão, com base no Maven, e alterar o arquivo p
om.xml, incluindo as dependências corretas, como o que é apresentado a seguir, extraído de projeto exemplo:
Departamentos
python
 
O exemplo demonstra a grande facilidade oferecida pelo Spring Boot, em conjunto com Thymeleaf, para a 
criação de aplicativos.
Persistência e controle
 4.0.0
 
 org.springframework.boot
 spring-boot-starter-parent
 2.6.6
 
 
 com.unesa
 ExemploTh002
 0.0.1-SNAPSHOT
 ExemploTh002
 Demo project for Spring Boot
 
 11
 
 
 
 org.springframework.boot
spring-boot-starter-data-jpa
 
 
 org.springframework.boot
 spring-boot-starter-thymeleaf
 
 
 org.springframework.boot
 spring-boot-starter-web
 
 
 com.h2database
 h2
 runtime
 
 
 org.springframework.boot
 spring-boot-starter-test
 test
 
 
 
 
 
 org.springframework.boot
 spring-boot-maven-plugin
 
 
 
Camada de persistência
Para criar nossa camada de persistência, vamos utilizar um banco de dados do tipo H2, que pode trabalhar em 
memória, sem exigir configurações avançadas. Para acessar outros bancos, o arquivo application.properties 
deverá ser alterado, incluindo as informações necessárias para conexão com o banco de dados e gerenciamento 
de transações.
Já que estamos trabalhando no modelo MVC, nossas entidades e repositórios serão criados no pacote com.unive
rsidade.model. Começaremos definindo uma entidade com o nome Departamento:
java
 
Nossa classe é uma entidade JPA, o que é estabelecido pela anotação Entity, sendo incluídos os campos 
idDepto, chave primária com valor gerado automaticamente, e nome. Também temos um relacionamento de um 
para muitos (OneToMany) com a entidade Funcionario, expresso por um conjunto (Set) de nome funcionarios.
Precisamos, portanto, de uma segunda entidade, com o nome Funcionario:
@Entity
public class Departamento {
 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 private Integer idDepto;
 private String nome;
 @OneToMany(mappedBy="departamento")
 private Set funcionarios;
 public Departamento() {}
 public Integer getIdDepto() { return idDepto; }
 public void setIdDepto(IntegeridDepto) { this.idDepto = idDepto; }
 public String getNome() { return nome; }
 public void setNome(String nome) { this.nome = nome; }
}
java
 
Agora, temos os campos matricula, nome e dataCadastro, sendo matrícula a chave primária, além da 
contraparte do relacionamento estabelecido anteriormente. Note o uso da anotação ManyToOne, especificado 
como obrigatório, em um atributo de nome departamento, que é relacionado à propriedade idDepto da entidade 
anterior (JoinColumn).
 Cada uma das entidades precisará de um repositório JPA, que no Spring é definido por uma simples interface, 
em que a comunicação com o banco é toda implementada pelo framework. Temos o conteúdo do primeiro 
repositório apresentado a seguir:
java
 
Definimos uma herança para a interface JpaRepository, com a especificação do tipo da entidade e de sua chave 
primária. Ocorrerá o mesmo para o segundo repositório:
@Entity
public class Funcionario {
 @Id
 private String matricula;
 private String nome;
 private Date dataCadastro;
 @ManyToOne
 @JoinColumn(name="idDepto", nullable=false)
 private Departamento departamento;
 public Funcionario() {}
 public String getMatricula() { return matricula; }
 public void setMatricula(String matricula) { 
 this.matricula = matricula;
 }
 public String getNome() { return nome; }
 public void setNome(String nome) { this.nome = nome; }
 public Date getDataCadastro() { return dataCadastro; }
 public void setDataCadastro(Date dataCadastro) { 
 this.dataCadastro = dataCadastro;
 }
 public Departamento getDepartamento() { return departamento; }
 public void setDepartamento(Departamento departamento) {
 this.departamento = departamento;
 }
}
public interface DepartamentoRepository extends
 JpaRepository{
}
java
 
Camada de controle
Nossa camada model está completa e já podemos criar a classe DepartamentoController, no pacote com.universi
dade.controller, representando nosso primeiro controlador.
java
 
Temos um controlador capaz de interceptar as rotas HTTP, por meio do mapeamento dos métodos pelas 
anotações GetMapping e PostMapping. Temos ainda o relacionamento com um repositório, instanciado no 
contexto do Spring por meio da anotação Autowired.
 
public interface FuncionarioRepository extends
 JpaRepository{
}
@Controller
public class DepartamentoController {
 @Autowired
 DepartamentoRepository repositorio;
 @GetMapping("/departamentos")
 public String obterTodos(Model model) {
 model.addAttribute("departamentos", repositorio.findAll());
 return "deptolist";
 }
 @GetMapping("/departamentos/excluir")
 public String excluir(Model model, Integer idDepto) {
 repositorio.deleteById(idDepto);
 model.addAttribute("departamentos", repositorio.findAll());
 return "deptolist";
 }
 @GetMapping("/departamentos/cadastro")
 public String cadastrar(Model model) {
 model.addAttribute("depto", new Departamento());
 return "deptodata";
 }
 @PostMapping("/departamentos/cadastro")
 public String cadastrar(Model model,
 @ModelAttribute("depto") Departamento depto) {
 repositorio.save(depto);
 model.addAttribute("departamentos", repositorio.findAll());
 return "deptolist";
 }
}
 
 
Comentário
 
O primeiro mapeamento ocorre para a rota /departamentos, em que o método de reposta adicionará 
uma lista de departamentos aos dados da página, obtida pelo repositório por meio de findAll, 
retornando em seguida o nome do template. Temos na rota /departamentos/excluir um 
comportamento muito similar, mas ocorrendo a exclusão do departamento selecionado a partir de 
idDepto, com base no método deleteById do repositório.
 
 
A inclusão utiliza a rota /departamentos/cadastro nos modos GET e POST, em que o modo GET associará um 
atributo do tipo Departamento aos dados da página para cadastro, cujo nome é retornado ao final, enquanto no 
modo POST recebemos os dados do formulário já preenchido em um parâmetro depto, do tipo Departamento, 
anotado como ModelAttribute, procedendo com a persistência dos dados por meio do método save do 
repositório, obtenção do conjunto de entidades atualizado via findAll, e retorno do template para listagem.
Ainda não criamos nossos templates, mas a execução do aplicativo irá gerar as tabelas do banco H2, assim 
como faria em qualquer outro banco, com a estrutura a seguir:
Estrutura do banco gerado pelo sistema.
Como o banco é recriado a cada execução, por estar trabalhando em memória, precisamos de alguns dados de 
teste, o que será obtido com a execução de alguns comandos SQL. Teremos de adicionar um arquivo com o 
nome import.sql, na raiz de resources, contendo a listagem a seguir, sem quebras de linha nos comandos:
sql
 
Algo interessante em nossa camada de controle é o fato de que o mesmo método utilizado para incluir um 
registro permite também alterá-lo. Com base nessa característica, para adicionar a possibilidade de edição no 
sistema, basta inserir um segundo mapeamento para a rota que inicia o template para preenchimento de dados, 
mas com o acréscimo de um segmento com o identificador, permitindo fornecer os dados atuais da entidade.
 O método adicionado pode ser observado na listagem seguinte, para a classe DepartamentoController:
java
 
O mesmo tipo de modificação pode ser efetuado em FuncionarioController, adicionando o método apresentado 
a seguir. Note que, em ambos os casos, temos a definição da variável que receberá o segmento com a anotação 
PathVariable:
java
 
Com as camadas de persistência e controle prontas, podemos iniciar a construção da camada de visualização, 
ou seja, dos templates. Vejamos a estrutura de projeto até o momento:
INSERT INTO DEPARTAMENTO VALUES (-1,'Financeiro');
INSERT INTO DEPARTAMENTO VALUES (-2,'Comercial');
INSERT INTO FUNCIONARIO (MATRICULA,NOME,DATA_CADASTRO,ID_DEPTO) VALUES 
('ALFA001','Ana',null,-1);
INSERT INTO FUNCIONARIO (MATRICULA,NOME,DATA_CADASTRO,ID_DEPTO) VALUES 
('ALFA002','Carlos',null,-1);
INSERT INTO FUNCIONARIO (MATRICULA,NOME,DATA_CADASTRO,ID_DEPTO) VALUES 
('ALFA003','Maria',null,-2);
INSERT INTO FUNCIONARIO (MATRICULA,NOME,DATA_CADASTRO,ID_DEPTO) VALUES 
('BETA001','Paulo',null,-2);
INSERT INTO FUNCIONARIO (MATRICULA,NOME,DATA_CADASTRO,ID_DEPTO) VALUES 
('BETA002','Beatriz',null,-1);
@GetMapping("/departamentos/cadastro/{idDepto}")
public String cadastrar(Model model, 
 @PathVariable Integer idDepto) {
 Departamento depto = repositorio.findById(idDepto).get();
 model.addAttribute("depto", depto);
 return "deptodata";
}
@GetMapping("/funcionarios/cadastro/{matricula}")
public String cadastrar(Model model, 
 @PathVariable String matricula) {
 Funcionario funcionario = repositorio.findById(matricula).get();
 model.addAttribute("deptos",repositorioDeptos.findAll());
 model.addAttribute("funcionario", funcionario);
 return "funcdata";
}
Projeto com as camadas de controle e persistência.
Interface do CRUD
Templates para departamentos
Agora, vamos criar nossa camada de visualização, que será constituída pelos templates requeridos na camada 
de controle, com o nome definido a partir do retorno de cada método. Todos os arquivos serão criados no 
diretório templates, a partir de resources, com o clique do botão direito sobre o diretório e escolha da opção 
New, seguida de File.
 Nosso primeiro template será definido no arquivo deptolist.hmtl. 
python
 
Temos a definição de um link para inclusão de departamentos, com uso de arroba e indicação da rota /
departamento/cadastro no atributo th:href, seguido da definição de uma tabela para exibição dos dados. Na 
tabela, teremos outros links para exclusão e alteração de um departamento. A exclusão utiliza a sintaxe para uso 
de parâmetros na requisição, enquanto a alteração trabalha com fornecimento da chave em um segmento da 
rota.
 Por meio de th:each, recuperamos os departamentos que foram enviados pelo

Mais conteúdos dessa disciplina