Java

Padrões de Projeto (Design Patterns)

Padrões de Projeto podem ser entendidos como descrições de problemas específicos e comuns que ocorrem no desenvolvimento de software e suas respectivas soluções padronizadas e genéricas. Não se trata de um código pronto que deve ser utilizado em uma aplicação, mas sim de uma espécie de template orientando como resolver um problema específico que pode ocorrer em diversas situações. Resultando em soluções elegantes, utilizando dos conceitos fundamentais de orientação a objetos, tais como abstração, polimorfismo, herança, etc., resultando em códigos com baixo acoplamento, coesos e reutilizáveis.

Para cada um dos padrões existe uma motivação, ou seja, a razão pela qual ele foi criado, entender essa motivação é essencial para conseguir fazer o uso desses padrões de forma coerente. Muitos desenvolvedores tentam forçar o uso de padrões de projeto no código o tempo todo, porém é muito importante conhecer a motivação do padrão para decidir se realmente o uso do mesmo faz sentido na situação que se apresenta, caso contrário os padrões podem atrapalhar ao invés de ajudar.

Quatro autores, conhecidos como “The Gang of Four – GOF” , lançaram o livro “Design Patterns: Elements of Reusable Object-Oriented Software” que é uma das referências mais conhecidos sobre Design Pattern. Eles classificaram um conjunto de padrões em três categorias, são elas: Padrões de Criação, Padrões Estruturais e adrões Comportamentais.

Padrões Criacionais são aqueles que abordam questões referentes a criação de objetos e instanciação de classes, os padrões abordados nessa categoria são: Abstract Factory, Builder, Factory Method, Prototype e Singleton.

Padrões Estruturais são os relacionados a composição e e relacionamentos de classes e objetos, fazem parte dessa categoria os padrões: Adapter, Bridge,Composite, Decorator, Facade, Flyweight, Private Class Data e Proxy.

E por fim os Padrões Comportamentais tratam de questões relacionadas a comunicação entre os objetos, responsabilidades e algorítimo.

Arquitetura de Software, Arquitetura Monolítica, Engenharia de Software, Microservices, Padrões de Projeto

Micros-serviços: características, benefícios e desvantagens em relação à arquitetura monolítica que impactam na decisão do uso desta arquitetura.

A busca por melhores formas de se construir sistemas
computacionais tem sido intensa e contínua. Nesta era de alta
disponibilidade de Internet, propagação dos dispositivos
móveis, juntamente com o advento da internet das coisas (IOT
– Internet of Things) e a computação nas nuvens, desenvolver
sistemas que utilizem destes recursos e que ainda possam
suportar a alta demanda de usuários e suas requisições, bem
como a diversidade de tipos de clientes existentes neste
cenário, pode ser um grande desafio.
De acordo com [1] no ano de 2016 estima-se que haverá 6,4
bilhões de “coisas” conectadas à rede mundial de
computadores, partindo de um aumento de 30% em 2015 e
chegando a 20,8 bilhões até 2020, sendo que em 2016 a
previsão é de 5,5 milhões de novas “coisas” que se conectarão
à rede todos os dias.
Diante deste cenário fatores como escalabilidade,
desempenho, disponibilidade e produtividade surgem como
pontos importantes a serem considerados no momento de se
construir uma aplicação. E para alcançar estes itens, muitos
conceitos têm sido discutidos e novas formas de se organizar e
construir sistemas computacionais vêm sendo colocadas em
prática, deixando de lado formas tradicionais de se
desenvolver uma aplicação, como é o caso das aplicações
monolíticas, cujo o perfil, nem sempre se encaixa nesta atual
perspectiva.
A arquitetura baseada em micros-serviços surge neste
panorama como uma alternativa ao tradicional padrão
arquitetural monolítico. Muito tem se falado deste estilo
arquitetural, colocando-a no topo das expectativas exageradas
de diversas pesquisas de 2015 do Gartner Hype Cycle,
explicado em [23], como por exemplo sobre serviços em [22],
desenvolvimento em [20] e arquitetura de aplicações em [21].
Este artigo tem como objetivo apresentar esta arquitetura
comparando suas características, vantagens e desvantagens em
relação ao estilo arquitetural monolítico, bem como, apresentar
os cenários onde a escolha deste estilo se torna conveniente.
Passando também pelos desafios de se construir um sistema
desde o início utilizando esta arquitetura e o de decompor um
sistema monolítico já existente, contribuindo na decisão de
quando e como utilizar ou não o padrão de arquitetura em
micros-serviços. Também é abordada a relação entre este
padrão arquitetural e Service Oriented Architecture – SOA,
comentando rapidamente também sobre o padrão de
linguagem existente para a construção de sistemas baseados
em micros-serviços.

Clique no link para fazer download do Artigo Completo Sobre Microservices.

 

Java

First Java Concepts: JavaBeans Standards – regras de nomes

Especificação JavaBeans define um modelo de componente de software e foi criada para auxiliar desenvolvedores a criar componentes Java que possam ser utilizados de forma fácil por outros desenvolvedores em uma IDE.

A Oracle define que um Java Bean é um componente de software reutilizável que pode ser manipulado visualmente em uma ferramente de desenvolvimento.

Um JavaBean, chamado muitas vezes de apenas Bean, é definido por algumas convenções e regras relativas a  nomenclatura, construção e comportamento. Ele deve ser uma classe que contém propriedades e estas propriedades são atributos privados de uma classe que definem o estado da mesma. Sendo as propriedades privadas, elas só podem ser acessadas dentro de outras classes através de métodos.

Os métodos que são responsáveis por mudar o valor de uma propriedade da classe são chamados de métodos setters e os métodos que retornam o valor de uma propriedade são chamdos de métodos getters.

O nome das propriedades e seus métodos de acesso devem seguir as seguintes regras e convenções:

  • Para propriedades que não sejam booleana, métodos getters devem ter o prefixo get. 

private int size;

public int getSize(){

return this.size;

}

  • Para propriedades booleanas, métodos getters podem ter o prefixo tanto get como is.

private boolean stopped;

public int isStopped(){

 return this.stopped;

}

  • Métodos setters devem ter prefixo set.

private int size;

public void setSize(int size){

this.size = size;

}

  • Métodos getters and setters devem ter a o prefixo apropriado (get, set or is) seguido do nome da propriedade, onde a primeira letra deve ser maiúscula.
  • Métodos setters devem ser públicos, não retornarem nada (void) e receber como argumento o tipo da propriedade que o mesmo corresponde.
  • Métodos getters devem ser públicos, o retorno deve ser do mesmo tipo da propriedade a que este corresponde e não devem receber nenhum argumento.
  • Para métodos utilizados para registrar um novo listener o prefixo deve ser add seguido pelo do tipo do listener.

addActionListener(ActionListener listener){...}

addMyListener(MyListener listener){...}

  • Métodos utilizados para remover um listener devem utilizar o prefixo remove seguido do tipo do listener.

removeActionListener(ActionListener listener){...}

removeMyListener(MyListener listener){...}

  • O tipo do listener que será adicionado ou removido deve ser passado como argumento para o método.
  • Métodos de listeners devem terminar com a paralavra “Listener”.
  • Um Bean deve ter um construtor padrão sem argumentos.
  • A classe deve implementar a interface java.io.Serializable.

 

Referências:

JavaBeans API specification

SCJP Sun® Certified Programmer for Java™ 6 Study Guide

Java

First Java Concepts – Convenção de Código Java – padrões de nomes

A Sun Microsystems, que foi adquirida pela Oracle, criou um documento chamado Java Code Conventions, a última revisão feita neste documento foi em 1999. Este documento tem como objetivo padronizar a forma de se codificar em Java para facilitar o entendimento de um código por alguém que não seja seu autor, aumentando a legibilidade, clareza e a facilidade de manutenção do mesmo.

Este post abordará padrões de nomes adotados pela convenção.

 

Classes e Interfaces

Nomes de classes e interfaces devem ter a primeira letra maiúscula, quando o nome é formado por varias palavras, a primeira letra de cada palavra deve ser maiúscula, este formato é conhecido como camelCase . É recomendado evitar o uso de abreviaturas, ao menos que esta seja mais conhecida do que a palavra inteira, ex: URL e HTML.

Para classes, os nomes devem normalmente ser substantivos e para Interfaces normalmente são utilizados adjetivos.

Exemplos:


class Product;

class Person;

class SystemOperation;

interface Runnable;

interface Serializable;

Métodos

Nos métodos, a primeira letra do nome deve ser minúscula e se for composta por outras palavras a forma camelCase deve ser utilizada também. Os nomes são formados geralmente por verbos e podem ser seguidos de substantivos.


getProduct();

changePerson();

run();

Variáveis

Como nos métodos, a primeira letra deve ser minúscula e se for composta por mais de uma palavra, o formato camelCase deve ser utilizado. É recomendado que as variáveis tenham nomes curtos e significativos e que não seja utilizado nome com apenas um carácter exceto para variáveis temporárias.


int i;

String name;

int productNumber;

Constantes

Constantes são marcadas como variáveis static e final. Elas devem ter o nome todo em letra maiúscula e quando composta de mais de uma palavra, etas devem ser separadas por underline (_).


int MAX_NUMBER;

String DEFAULT_LANGUAGE;

Referências:

Java Code Conventions

SCJP Sun® Certified Programmer for Java™ 6 Study Guide

Java

First Java Concepts – Identificadores Legais

Identificadores são os nomes utilizados para identificar uma variável, método, classe, pacote  e/ou uma interface, ou seja, são os próprios nomes dados à eles.

Para que um identificador seja válido ele deve seguir algumas regras:

  • Devem ser compostos de uma ou mais letras ou números UNICODE-16,  no caso do alfabeto latim seria as letras de A-Z e a-z, os dígitos de 0-9 e os símbolos de underline (_) e cifrão($):
  • Eles devem começar com uma letra, cifrão ou underline, nunca com um número.
  • Depois do primeiro carácter, ele pode ser composto de qualquer combinação de letras, números, underline e cifrão.
  • Não há limite de número de carácteres que um identificador pode conter.
  • Palavras chaves Java não podem ser usadas como identificadores. Ex: class, final, if, etc. Mais abaixo há uma tabela com todas as palavras chaves do Java.
  • Não se pode utilizar literais que representam tipos lógicos booleanos (true e false).
  • Não se pode utilizar literais que representa o tipo nulo (null).
  • Identificadores são case sensitive, sendo assim, A é diferente de a.
  • Não é permitido caracteres em branco.

Exemplos de identificadores legais:


int _myVariable;
int $myVariable;
int ____my_variable;
int $_;
int this_is_a_valid_identifier;
int MyVariable;
int c;
int _1_2_3;
int __4_u;

Exemplo de identificadores ilegais:


int !myVarieable;

int @b;

int :c;

int d#;

int My Variable;

int 1_2_3;

int 4u;

int _1-2-3;

Para testar copie estes exemplos de identificadores inválidos pra uma classe qualquer e você verá que a classe ficará com erro.

Lista de Palavras Chaves Java.

 

Referências:

SCJP Sun® Certified Programmer for Java™ 6 Study Guide

The Java Language Specification, Java SE 7 Edition

Java

First Java Concepts – Classe, Objeto, Estado e Comportamento

O que são classes, objetos, estado e comportamento em Java?

 

Classe

É um modelo ou especificação que descreve o estado (atributos) e o comportamento (métodos) que os objetos criados a partir desta classe irão suportar.

 

Objeto

O objeto é a instância da classe que é criada em tempo de execução quando a JVM encontra a palavra chave new, quando isso acontece, ele utiliza a classe para criar um objeto. Cada objeto tem seu próprio estado e acesso a todos os comportamentos definidos pela classe.

 

Estado

É relativo aos atributos da classe. Cada objeto tem seu conjunto próprio de atributos, os quais foram definidos na classe. Os valores atribuídos aos atributos de um objeto definem o seu estado.

 

Comportamento

São os métodos da classe. Onde os algoritmos são implementados e os dados manipulados. Os métodos definem o comportamento do objeto.

 

 

Referência: SCJP Sun® Certified Programmer for Java™ 6 Study Guide

Java, Struts 2

Mais um exemplo utilizando o doubleSelect do Struts 2

No exemplo mostrado no post anterior, foi utilizado um HashMap com valores pré-definidos para popular os selects. Neste exemplo, será utilizado um método que retornará uma array com os dados filtrados.

O projeto que está sendo utilizado é o mesmo do exemplo do post anterior, sendo assim, não irei postar novamente as libs e as configurações. Para ver o post anterior clique aqui.

Na página index.jsp foi adicionado mais um link para uma outra action:


<h3>A simple example to how use dobleselect from Struts 2!</h3>

<p><s:a action='test' > Go to dobleselect! </s:a></p>
 <p><s:a action='prepareLists' > Go to dobleselect 2! </s:a></p>

Este segundo link irá chamar o mótodo prepareLists() da Action CityStateAction. Abaixo segue o código desta action.


public class CityStateAction extends ActionSupport{

private static final long serialVersionUID = -2739421817296013920L;

 public ArrayList<State> states;
 public ArrayList<City> cities;

 @Action("prepareLists")
 public String prepareLists(){

  states = new ArrayList<>();
  cities = new ArrayList<>();

  State mg = new State();
  mg.setName("Minas Gerais");
  mg.setAcronym("MG");

  State sp = new State();
  sp.setName("São Paulo");
  sp.setAcronym("SP");

  State rj = new State();
  rj.setName("Rio de Janeiro");
  rj.setAcronym("RJ");

  states.add(mg);
  states.add(sp);
  states.add(rj);

  createCity(mg, "Pouso Alegre");
  createCity(mg, "Poços de Caldas");
  createCity(mg, "Belo Horizonte");

  createCity(sp, "Campinas");
  createCity(sp, "Ribeirão Preto");
  createCity(sp, "Atibaia");

  createCity(rj, "Paraty");
  createCity(rj, "Angra dos Reis");
  createCity(rj, "Resende");

 return SUCCESS;
 }

 public void createCity(State state, String name){

  City city = new City();
  city.setName(name);
  city.setState(state);

  cities.add(city);
 }

 public ArrayList<City> getCitiesByState(State top){
  return populateCitiesList(top);
 }

 public ArrayList<City> populateCitiesList(State state){
  ArrayList<City> citiesByState = new ArrayList<>();

  for(City city : cities){
   if(city.getState().equals(state)){
    citiesByState.add(city);
   }
  }
  return citiesByState;
 }

 public ArrayList<State> getStates() {
  return states;
 }

 public void setStates(ArrayList<State> states) {
  this.states = states;
 }

 public ArrayList<City> getCities() {
  return cities;
 }

 public void setCities(ArrayList<City> cities) {
  this.cities = cities;
 }
}

Como nesta action o método que está sendo chamado não é o execute(), é necessário utilizar a annotaion @Action e passar como parâmetro qual action que chamará este método.
O método prepareLists() popula uma lista de Estados contendo três itens: MG, SP e RJ. Ele popula também uma lista de cidades, contendo três cidades para cada um dos três estados.
Para popular a select de cidades que dependerá da select de estados, será utilizado o método getCitiesByState(…), que receberá o estado selecionado e a partir dele retornará uma lista com as cidades que pertencem ao mesmo.
Quando o método prepareLists() retornar SUCCESS a página prepareLists-success será carregada:

<h3>Filling dobleselect lists with a action method</h3>
<s:form action="test">
<s:doubleselect name="state" listKey="name" listValue="name" list="states"
doubleName="city" doubleListKey="name" doubleListValue="name"                doubleList="getCitiesByState(top)" label="Choose a State/City">
</s:doubleselect>
 </s:form>

No atributo list que corresponde a lista da primeira select, foi passado a lista states que foi populada na Action.
No atributo doubleList é passado o método getCitiesByState(…) da action passando o item que foi selecionado na primeira select.

Página index.jsp
prepareLists-success.jsp: lista de estados
prepareLists-success.jsp: selecionando as cidades do estado de MG.
prepareLists-success.jsp: selecionando o estado de SP na segunda select são carregadas as cidades relacionados a ele.
prepareLists-success.jsp: lista de cidades do estado do RJ
Estrutura do projeto exemplo.

Clique aqui para download do projeto de exemplo.

Java, Struts 2

Um simples exemplo utilizando o doubleselect do Struts 2

Este é um simples exemplo de como preencher um <s:doubleselect> do Struts 2 utilizando um HashMap.

Primeiramente, foram utilizadas as seguinte bibliotecas:

  • asm-3.3.jar
  • asm-commons-3.3.jar
  • commons-fileupload-1.2.2.jar
  • commons-io-2.0.1.jar
  • commons-lang3-3.1.jar
  • commons-logging-1.1.1.jar
  • freemarker-2.3.19.jar
  • javassist-3.11.0.GA.jar
  • ognl-3.0.5.jar
  • struts2-convention-plugin-2.3.4.jar
  • struts2-core-2.3.4.1.jar
  • xwork-core-2.3.4.1.jar

Após adicionar as bibliotecas acima, é necessário adicionar a seguinte configuração no web.xml

</pre>
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
 id="WebApp_ID" version="2.5">
 <display-name>DoubleSelectTest</display-name>

 <filter>
  <filter-name>struts2</filter-name>
  <filter-class>
   org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
  </filter-class>
  <init-param>
   <param-name>struts.devMode</param-name>
   <param-value>true</param-value>
  </init-param>
 </filter>

 <filter-mapping>
  <filter-name>struts2</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping>

 <welcome-file-list>
  <welcome-file>index.jsp</welcome-file>
 </welcome-file-list>

</web-app>
<pre>

Não é necessário criar um arquivo struts.xml pois será utilizado o plugin de convenção de nomenclatura do Struts 2 ao invés de xml para mapeamento da Action.

No arquivo index.jsp existirá apenas uma mensagem e logo abaixo um link que chamará a o método execute() da action TestAction.

</pre>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>

<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Doubleselect Struts 2</title>
</head>
<body>

  <h3>A simple example to how use dobleselect from Struts 2!</h3>

  <p><s:a action='test' > Go to dobleselect! </s:a></p>

</body>
</html>
<pre>

Pela convenção de nomenclatura padrão do Plugin de Convenção do Struts 2 (struts2-convention-plugin-2.3.4.jar) que está sendo utilizado, esta url irá procurar pela TestAction e chamar o método execute();

Abaixo segue o código da classe TestAction:


package cris.test.action;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.opensymphony.xwork2.ActionSupport;

public class TestAction extends ActionSupport{

private static final long serialVersionUID = 6939102585085668554L;

    public List<String> listFruit;
    public List<String> listColor;

    public String fruitOrColor1;
    public String fruitOrColor2;

    public Map<String, ArrayList<String>> listCorlorOrFruits;

    public String execute(){

     listFruit = new ArrayList<>();
     listColor = new ArrayList<>();

     listFruit.add("Apple");
     listFruit.add("Orange");
     listFruit.add("Strawberry");

     listColor.add("Red");
     listColor.add("Blue");
     listColor.add("Purple");

     listCorlorOrFruits = new HashMap<String, ArrayList<String>>();
     listCorlorOrFruits.put("Fruits", (ArrayList<String>) listFruit);
     listCorlorOrFruits.put("Colors", (ArrayList<String>) listColor);

     return "success";
   }

   public List<String> getListColor() {
    return listColor;
   }

   public void setListColor(List<String> listColor) {
    this.listColor = listColor;
   }

   public String getFruitOrColor1() {
    return fruitOrColor1;
   }

   public void setFruitOrColor1(String fruitOrColor1) {
    this.fruitOrColor1 = fruitOrColor1;
   }

   public String getFruitOrColor2() {
    return fruitOrColor2;
   }

   public void setFruitOrColor2(String fruitOrColor2) {
    this.fruitOrColor2 = fruitOrColor2;
   }

   public Map<String, ArrayList<String>> getListCorlorOrFruits() {
    return listCorlorOrFruits;
   }

   public void setListCorlorOrFruits(
       Map<String, ArrayList<String>> listCorlorOrFruits) {
    this.listCorlorOrFruits = listCorlorOrFruits;
   }

   public List<String> getListFruit() {
    return listFruit;
   }

   public void setListFruit(List<String> listFruit) {
    this.listFruit = listFruit;
   }
}

Dentro do método execute foi criado duas listas, uma com frutas e outra com cores. Estas listas foram adicionadas dentro de HashMap. Cada lista contém sua chave correspondente no HashMap.

É importante também que os getters and setters sejam colocados na Action. Então o método execute será responsável por preencher as listas.

Este método irá redirecionar para página test-success.jsp que deve estar dentro de WebContent/WEB-INF/content. Abaixo segue o código desta página:

</pre>
<%@ taglib prefix="s" uri="/struts-tags" %>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
 pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Doubleselect Struts 2</title>
</head>
<body>

 <h3>Filling dobleselect lists with a HashMap</h3>

 <s:form action="test">
   <s:doubleselect name="fruitOrColor1" list="listCorlorOrFruits.keySet()"
                   doubleName="fruitOrColor2" doubleList="listCorlorOrFruits.get(top)"                 label="Color or Fuits">
   </s:doubleselect>
 </s:form>

</body>
</html>

Os atributos name e list se referem ao primeiro Select e os atributos  doubleName e doubleList se refere ao segundo Select que irá depender do primeiro.

No atributo list está sendo passado as keys do Map e no dobleList está sendo passado o valor das keys que são as arrays.

Então quando for selecionado a opção de frutas a lista de frutas será carregada no segundo select e quando a opção cor for selecionada no primeiro select a lista de cores será carregada.

Abaixo segue imagens do exemplo rodando:

Página index.jsp
Página test-success.jsp: Selecionando a opção Fruits a segunda select é preenchida com a lista de frutas
Página test-success.jsp: Selecionando a opção Colors a segunda select é preenchida com a lista de cores.
Estrutura do exemplo no eclipse.

Clique aqui para fazer o download do projeto de exemplo.

Java, Struts 2

Struts 2 – Validação utilizando Annotations

As seguinte bibliotecas foram utilizadas:

  • commons-logging-1.1.1.jar
  • freemarker-2.3.8.jar
  • ognl-2.6.11.jar
  • struts2-core-2.0.11.1.jar
  • xwork-2.0.4.jar

Primeiro será configurado o arquivo struts.xml da seguinte forma:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>

<include file="struts-default.xml" />

<package name="default" extends="struts-default">

<action name="Login">
<result name="input">index.jsp</result>
<result name="success">success.jsp</result>
<result name="error">index.jsp</result>
</action>

</package>
</struts>

Agora será criada uma página index.jsp com um formulário para login.

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Login</title>
<s:head />
</head>
<body>

<s:form action="Login" method="post" validate="true" >
<s:actionmessage/>
<s:textfield name="username" label="Username" size="14" required="true" />
<s:password name="password" label="Password" size="14" required="true" /><br/>
<s:submit name="login" value="Login" type="button" align="center" method="post" required="true"/>

</s:form>

A tag <s:head /> adiciona um link ao css e javascripts utilizado para redenrizar os elementos do struts na página. Também é colocado o atributo validate=”true” e nos campo username e password é colocado o atributo required=”true”.

Também será criada uma página que será exibida quando o usuário e senha digitados no formulário de login correspoderem a string “admin”.

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Success</title>
</head>
<body>
<h1>Success Login! </h1>
</body>
</html>

Agora será criada uma classe para ser a Action e que se chamará LoginAction:


public class LoginAction extends ActionSupport{

private static final long serialVersionUID = -1200187785923962284L;

private String username;
private String password;

public String login(){

if(username == "admin" && password == "admin"){
return "success";
}

return "error";
}

public String post(){
return "success";
}

/**
* @param username the username to set
*/
@RequiredStringValidator(type=ValidatorType.SIMPLE, trim=true, fieldName="username", message="Fill username field")
public void setUsername(String username) {
this.username = username;
}

/**
* @return the username
*/
public String getUsername() {
return username;
}

/**
* @param password the password to set
*/

@RequiredStringValidator(type=ValidatorType.SIMPLE, trim=true, fieldName="password", message="Fill password field")
public void setPassword(String password) {
this.password = password;
}

/**
* @return the password
*/
public String getPassword() {
return password;
}

}

Para a validação, foram colocados nos métodos sets dos atributos a anotação @RequiredStringValidator colocando o tipo de validação, como se trata de textfields será utilizado o o tipo SIMPLE. Colocamos a função trim como true, passamos o nome do campo a ser validado e mensagem que deve aparecer caso a validação falhe.

Página de login antes da submissão dos dados
Formulário de login após submeter formulário com os campos vazios e com espaços em branco.
Página que é mostrada quando os campos de login correspondem a string “admin”