Monday, June 25, 2012

Customizar mensagens de formatação/conversão no Spring MVC 3

O Spring MVC provê funcionalidades para conversão e validação dos dados de formulários web, resolvendo a entrada de valores numéricos e datas, algo rotineiro em desenvolvimento de aplicações web. No Spring MVC versão 3, além do suporte a anotações, algumas melhorias foram implementadas nesse setor.

Objetivo desse post é demonstrar como customizar/modificar as mensagens de erro geradas pelo Spring MVC durante a conversão de valores (string) para data e/ou número.

De acordo com o trecho de código, a seguir, o bean Pedido é define alguns critérios para conversão e validação de dados:
import java.util.Date;
import java.math.BigDecimal;
public classe Pedido {

   @NotNull
   @DateTimeFormat(pattern = "dd/MM/yyyy")
   private Date dataAbertura;

   @NotNull
   @Digits(integer = 8, fraction = 2)
   @NumberFormat(style=Style.NUMBER)
   private BigDecimal valor;

   ...
}

As anotações @NotNull@Digits são definidas em Bean Validation (JSR 303), o Spring as utiliza para validar o estado do objeto Pedido no lado servidor. As outras duas anotações são definidas pelo Spring Framework:

  • @DateTimeFormat: indica qual formato deve ser aplicado durante a conversão do conteúdo de um atributo data e/ou hora. A propriedade pattern, utilizada no exemplo acima, indica que a string informada pelo usuário deve respeitar dia/mês/ano. Outra opção é utilizar a propriedade style, que pré-define formatos para a data. Essa anotação pode demarcar atributos do tipo Date, Calendar, Long ou atributos do Joda Time.
  • @NumberFormat: indica qual formato deve ser aplicado durante a conversão do conteúdo de um atributo numérico. A propriedade style, utilizada no exemplo acima, indica que a string informada pelo usuário deve respeitar um número decimal de acordo com as configurações do locale corrente. Outra alternativa seria utilizar propriedade pattern, e estipular o formato numérico suportado. 

O próximo código demonstra um trecho da controller de pedidos, mais especificamente a assinatura do método que persiste (inclui) o objeto pedido:
...
@RequestMapping("/pedidos") @Controller
public class PedidoController {

  @RequestMapping(method = RequestMethod.POST)
  public String create(@Valid Pedido pedido,
        BindingResult bindingResult, Model uiModel) {
   
       if (bindingResult.hasErrors()) {
          //validador não aceitou o pedido, ele nao devera ser persistido
         ...
       }
       //o pedido foi validado com sucesso, pode ser persistido.
       ...
  }

}


O argumento pedido é um objeto preenchido com as informações inseridas pelo usuário, no formulário. Note que a variável foi demarcada com @Valid (outra anotação de Bean Validation), dessa forma o Spring MVC valida essas informações, no lado servidor, de acordo com as definições da classe. Caso exista alguma(s) inconsistência(s), o Spring MVC preenche o objeto bindingResult com o(s) erro(s). Por exemplo, se a data do pedido não for preenchida o if dentro do método deve cancelar o fluxo de inserção e retornar para o formulário.

Imagine que no formulário HTML o usuário preencheu um conteúdo incoerente para o campo valor do pedido, por exemplo: 'abc'. Considerando que o formulário não realiza nenhuma validação/formatação no lado cliente (browser), como o Spring MVC se comportará ?

No momento de carregar o objeto o Spring MVC não consegue resolver 'abc' como um número decimal para o atributo (propriedade) valor. O objeto pedido é carregado com as informações que o Spring consegue converter. Antes de acionar o método na controller, o objeto bindingResult é notificado sobre o erro durante a conversão. Ao entrar no método create, em PedidoController, o atributo valor do pedido é null, o mesmo trecho que valida o estado do pedido (bindingResult.hasErrors()) é executado.

Dessa forma o formulário é recarregado, e o Spring MVC apresenta uma mensagem de erro contendo o seguinte texto:

"Failed to convert property value of type java.lang.String to required type java.math.BigDecimal"

Em outro cenário de conversão de dados, caso o usuário entre com o conteúdo inválido no campo da data, o mesmo fluxo é executado, mas a mensagem apresentada será:

"Failed to convert property value of type java.lang.String to required type java.util.Date"

É possível customizar as mensagens com erro(s) de conversão do Spring?

Sim! No arquivo properties, com as mensagens internacionalizadas (messages.properties) é possível modificar o conteúdo default as mensagens de conversão do Spring MVC.

É possível definir duas mensagens com erro de conversão de acordo com o tipo do atributo. O exemplo a seguir determina duas mensagens quer serão apresentadas para todos os atributos da aplicação, do tipo java.util.Date e java.math.BigDecimal. A seguir um exemplo de como isso pode ser feito:
typeMismatch.java.util.Date=Conteúdo inválido para campo data!
typeMismatch.java.math.BigDecimal=Conteúdo inválido para campo numérico!

Outra opção é definir uma mensagem especifica para um determinado atributo. O exemplo a seguir determina um mensagem exclusiva para o atributo valor do objeto pedido (pedido deve ser o nome do argumento definido no método dentro da controller):

typeMismatch.pedido.valor=O valor do pedido não foi preenchido corretamente!

Seguindo essa estratégia você utiliza o mecanismo de conversão e validação do Spring MVC, com uma mensagem mais amigável para o usuário.

Na documentação do Spring é possível encontrar mais detalhes sobre o mecanismo de validação e conversão adotado pelo framework MVC.

@edermag
www.yaw.com.br

1 comment:

Cazuza Neto said...

Este poste me deu uma grande ajuda! Parabéns!