Será que você sabe tudo das configurações do seu projeto com Spring?

O objetivo do post é esclarecer alguns detalhes de configuração providos pelo Spring que, talvez, não seja claro para todo mundo que usa o ecossistema oferecido pelo framework. Os três primeiros parágrafos cobrem o tópico relativo a annotation @Configuration. Depois cada um cobre um tema diferente, então fique a vontade para ler na ordem que você quiser :).

O primeiro ponto é o uso da annotation @Configuration. A ideia é que você minimize a quantidade de código necessário para ensinar ao Spring quais classes do seu sistema são responsáveis  por criar objetos que serão gerenciados pelo framework. Vamos supor que você está numa aplicação web, usando o Spring MVC. Geralmente você vai ter uma classe de configuração relativa ao Servlet em si, como está exibido no código abaixo.

    public class ServletSpringMVC extends
		AbstractAnnotationConfigDispatcherServletInitializer {

	@Override
	protected Class<?>[] getRootConfigClasses() {
		return new Class[] {AppWebConfiguration.class};
	}

        ...

    }

Como exemplificado, a única classe que você precisa para o método getRootConfigClasses(que vai ser explicado em outro parágrafo) é a que representa a “entrada” das suas configurações. Dê uma olhada no exemplo abaixo:

      @EnableWebMvc
      @ComponentScan(basePackages="br.com.casadocodigo.loja")
      @EnableCaching
      public class AppWebConfiguration extends WebMvcConfigurerAdapter {

	@Bean
	public LocaleResolver localeResolver() {
		return new CookieLocaleResolver();
	}

     }

Perceba que essa classe já define alguns métodos anotados com @Bean, mas também está anotada com a @ComponentScan indicando o pacote base que deve ser varrido. É justamente aí que entra a annotation @Configuration. Durante a varredura, o Spring vai procurar por qualquer classe anotada com ela ou com @Component e, caso encontre, vai carregar essa classe e já invocar todos os métodos anotados com @Bean.  Lembre sempre disso, você não precisa adicionar todas as classes que servem de configuração! Outro ponto importante é: se a classe é de configuração, anote ela com @Configuration e não com @Component. Semântica é muito importante em qualquer sistema.

O segundo tópico tem a ver com o escopo de criação dos objetos que são gerenciados pelo container do Spring. Por default, todos os beans vivem no escopo de aplicação. Isso quer dizer que uma vez que o objeto foi criado, a mesma instância será utilizada por todo tempo de vida da aplicação. Não importa a classe que você esteja anotando, pode ser um @Repository, @Service ou @Controller.  O que você precisa lembrar é: caso queira criar um atributo nessa classe que não seja gerenciado pelo Spring, tenha em mente que ele será compartilhado por todo mundo na sua aplicação. Caso você queira mudar o escopo, como a maioria já deve saber, basta usar a annotation @Scope.  Na minha humilde opinião, o escopo default dos controllers deveria ser o de request. Caso você se interesse por isso, criei um exemplo que aplica esse escopo em todo mundo anotado com @Controller.

Essa é para a galera que usa o Spring Security. Quando você usa a parte de segurança, já vem habilitada a proteção contra o CSRF. Quando usamos as tags de formulário do Spring MVC, meio que por magia, começa a aparecer um campo hidden com o nome _csrf. Sabemos que a configuração do Spring Security faz esse campo aparecer, mas como? Caso você dê uma olhada na classe WebMvcSecurityConfigurationverá que ela possui um método que retorna um objeto do tipo RequestDataValueProcessor. Você pode criar implementações dessa interface para adicionar campos no formulário que usam a tag form do Spring MVC. Eu por exemplo já fiz uso, quando precisei adicionar o hidden com o estado do wizard do SetupMyProject. Isso é uma característica que eu acho muito legal no Spring MVC, como o framework tem muito feedback da comunidade, a arquitetura dele foi realmente pensada para resolver desde os problemas mais comuns nas aplicações web até as situações mais específicas.

A última configuração vem da classe responsável pela configuração da Servlet, a que geralmente herda de AbstractAnnotationConfigDispatcherServletInitializer. Existem dois métodos que você pode usar para adicionar a classe de configuração, o getRootConfigClasses e o getServletConfigClasses. Resumindo, você pode usar sempre o getRootConfigClasses. A diferença é que usando o primeiro as suas configurações são carregadas dentro de um Listener da especificação de Servlet, especificamente uma instância do objeto do tipo ContextLoaderListener. Enquanto que usando a segunda opção, suas configurações são carregadas dentro do DispatcherServlet do Spring MVC.  Usar o primeiro é até melhor, já que você garante que as configurações estarão carregadas em qualquer circunstância.

Prefira as tags de formulário do Spring MVC!

Uma das coisas que atrasa o desenvolvimento de um projeto é quando o programador resolve investir tempo para construir uma parte do software que já foi pensada por uma biblioteca ou framework. Quando pensamos no Spring MVC, um caso que me vem a mente são formulários que não são construídos usando as tags providas pelo framework.

    <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
    <%@taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>

      <div class="form-group">
          <input type="text" name="nome" value="${profissional.nome}"/>
      </div>
      <div class="form-group">
        <input type="text" name="cpf" value="${profissional.cpf}"/>          
      </div>
      <div class="form-group">
        <input type="text" name="dataNascimento" 
          value="<fmt:formatData value="${profissional.dataNascimento.time}" pattern="dd/MM/yyyy"/>
      </div>
      <div class="form-group">       
       <select name="estado">
        <c:forEach items="${estados}" var="estadoAtual">
<option value="${estadoAtual.value}" ${profissional.estado == estadoAtual ? 'selected' : ''}>${estadoAtual.nome}
          </option>
        </c:forEach>
       </select>
      </div>

Desenvolvendo dessa forma, vai fazer com que o programador perca tempo implementando toda aquela lógica de manter o estado dos campos nos erros de validação, ou quando o usuário tiver que entrar numa tela de edição. Só que fica pior, viu o código para manter o estado do  select? E para exibir data formatada?

Para todos os casos citados, você poderia usar as tags de formulário do Spring MVC. O mesmo form que foi mostrado acima, poderia ser escrito da seguinte forma:

    <%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
    <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
    <div class="form-group">                    
        <form:input path='nome' type='text'/>
        <form:errors path='nome'/>          
    </div>
   <div class="form-group">                    
        <form:input path='cpf' type='text'/>
        <form:errors path='cpf'/>          
    </div>
    <div class="form-group">                    
        <form:input path='dataNascimento' type='text'/>
        <form:errors path='dataNascimento'/>          
    </div>
    <div class="form-group">
      <form:select path='estado' itemLabel="nome" itemValue="value" items="${estadoList}"/>
      <form:errors path='estado'/>
    </div>

Você simplesmente usa as tags disponíveis referenciando as propriedades do seu objeto e deixa o Spring MVC fazer o trabalho dele. Por exemplo, ele já vai verificar o estado relacionado com seu objeto e deixar a opção escolhida para você. Só que ainda vai além, no campo de data ele vai usar a annotation de formatação que você usou no seu atributo e já vai exibir a data da maneira correta.

  public class Profissional {
      
     ...
     @DateTimeFormat(iso=ISO.DATE)
     private Calendar dataNascimento;
     @NotNull
     private Estado estado;

     ...
  }  

Isso tudo somado, poupa um bom tempo de desenvolvimento que pode ser investido para melhorar outras partes importantes do seu código.

Lembre de sempre tirar proveito do que o seu framework já possui, não gastando tempo escrevendo algo que já foi pensado e implementado por outras pessoas cujo foco era exatamente facilitar a sua vida! Como é o último dia do mês, faço aqui o meu jabá dizendo que isso e muitas outras coisas podem ser encontradas no meu livro na Casa do Código :).

Lidando com exceptions dentro do Spring MVC

Em qualquer projeto que participamos, uma das única coisas que temos certeza, é que uma exception vai acontecer. Tanto é que a especificação de Servlets já define uma maneira formal de fazer o tratamento das básicas.

  <error-page>
  	<error-code>404</error-code>
  	<location>/WEB-INF/views/errors/404.jsp</location>
  </error-page>

  <error-page>
  	<exception-type>java.lang.Exception</exception-type>
  	<location>/WEB-INF/views/errors/500.jsp</location>
  </error-page>

Só que, em geral, quase todo framework MVC que nós usamos já fornece um mecanismo alternativo de tratamento para as exceptions. Com o Spring MVC não podia ser diferente. E o legal é que as possibilidades oferecidas por ele vão além das fornecidas pela especificação. Por exemplo, no SetupMyProject quando uma pessoa tenta baixar um projeto com um token que não existe, é lançada uma exception do tipo NotFoundStatusException, indicando justamente o problema. Em um código convencional, exceptions apenas representam problemas, mas nesse caso também representa um status, que no caso é o 404.  Talvez a maneira mais direta de tratar ela seria da seguinte forma.

	public HttpEntity<byte[]> download(String token,
		HttpServletResponse response) {

		try {
                   //logica para buscar o setup e gerar o projeto
		} catch (NotFoundStatusException e) {
			response.setStatus(404);
            ModelAndView notFound = new ModelAndView("errors/404");
            notFound.addObject("message","the setup does not exist");
            return notFound;
	}

Só que esse código já nos obriga a receber um parâmetro a mais e adicionar um try/catch no nosso método. Caso deixemos ela estourar, vamos ter que mapear no web.xml, só que aí perdemos a chance de tratar como 404. E nesse caso, a página de 404 teria que ter uma mensagem customizada, como faríamos? Para este tipo de situação o Spring MVC já provê um saída.

    public HttpEntity<byte[]> download(String token,HttpServletResponse response) {
          //logica para buscar o setup e gerar o projeto
          return download;
    }

    public ModelAndView handleNotFoundStatusException
	 (NotFoundStatusException ex) {
	 ModelAndView modelAndView = modelAndViewForTokenExceptions(ex);
	 pageMessages.info("token.not_found",
	    "You need to generate a project before download", modelAndView);
	 return modelAndView;
     }

Perceba que basta você anotar o método com @ExceptionHandler e aí você pode receber a exception específica como argumento.  Aqui você já pode adicionar qualquer mensagem que você queira e direcionar para página que você necessite. Só que ainda podemos ir além, podemos informar ao Spring MVC que na verdade, essa exception deve gerar um status 404.

     @ResponseStatus(value=HttpStatus.NOT_FOUND)
     public class NotFoundStatusException extends RuntimeException
		implements RequestedSetupTokenAwareException {

           ...
     }

Você pode usar essa estratégia em qualquer controller seu! Um último ponto é: como você vai tratar aquelas exceptions que você não espera? Da maneira atual, teríamos que colocar um @ExceptionHandler em cada um dos controllers do sistema ou apelar para o modelo de aspectos suportado pelo framework. Para contornar isso, desde a versão 3.2, o Spring MVC possui uma annotation para indicar que certa classe concentra tratamentos globais relativos a um conjunto de controllers.

        @ControllerAdvice
	public class GlobalExceptionHandler {

		@Autowired
		private AccessEnvironment env;
		@Autowired
		private MailSender mailer;
		@Autowired
		private ThreadPoolTaskExecutor executor;

		private Logger logger = LoggerFactory
				.getLogger(GlobalExceptionHandler.class);

		@ExceptionHandler(value = Exception.class)
		public ModelAndView defaultErrorHandler(HttpServletRequest req, Exception e)
				throws Exception {

			SimpleMailMessage email = createBaseEmail();
			email.setText(ExceptionUtils.getStackTrace(e));

			executor.execute(() -> {
				logger.error("Enviando mensagem de erro");
				mailer.send(email);
			});

			return new ModelAndView("errors/500");
		}

Você pode usar a annotation @ControllerAdvice sempre que precisar concentrar algum tratamento que seria espalhado em todos os controllers. No nosso exemplo criamos um método anotado com @ExceptionHandler, mas nada nos impede de criar um método anotado com @InitBinder por exemplo. Agora, toda vez que um controller lançar uma exception, caso ninguém forneça um tratamento mais específico, ela vai cair no tratamento global do @ControllerAdvice. Um ponto a mais que merece ser observado é que o envio do email foi feito a partir de outra Thread. Isso é bem importante, já que você não quer fazer seu usuário esperar por conta de um envio de email.

Esse post foi um pouco mais curto e mais simples, entretanto tratar exceptions é uma parte muio importante do sistema. O melhor é que você trate as possibilidades de erro com o mesmo cuidado que você trata as possibilidades de sucesso nas lógicas, para que você forneça feedback positivo o tempo inteiro. Tanto para o usuário quanto para a própria parte interna da aplicação.

Começando com a magia do Spring Boot

No livro sobre Spring que escrevi para a Casa do Código e no SetupMyProject fiz a opção pelo uso normal das extensões do Spring. Para criar o projeto web, usei o Spring MVC no seu modo convencional configurando tudo que era necessário, assim como fiz para a parte da JPA, Spring Security etc. No fim acho realmente importante que as pessoas conheçam bem as tecnologias que usam, para terem um olhar crítico sobre a ferramenta e poderem achar os pontos de extensão necessários para os projetos do dia a dia.

Na época da escrita do livro, o time do Spring já tinha lançado uma outra extensão chamada Spring Boot, cujo objetivo era acelerar o processo de configuração da aplicação, estabelecendo configurações defaults baseadas nas experiências dos desenvolvedores do próprio Spring, assim como pelo feedback provido pelos usuários do framework. Optei por não usá-lo, justamente pelos motivos citados no primeiro parágrafo. Agora, com tudo mais sedimentado e com um conhecimento realmente bom do framework resolvi que era hora de começar a construir uma aplicação com o Spring Boot, já que, principalmente durante a escrita do livro, fui obrigado a navegar muito pelos internals do Spring e tudo mais. Peguei como exemplo a própria app do livro, ela possui regras boas o suficiente para me fazer passar por diversos problemas. O código inicial já está no github.

Então vamos começar! O primeiro passo, como não poderia ser diferente, é a criação do projeto. Você pode realizar este passo no próprio SetupMyProject. O zip vai vir com o mínimo configurado, mas é aí que você já vai perceber a diferença. Para conseguir subir o servidor e acessar a primeira rota, só precisamos de uma classe configurada no projeto.

	@SpringBootApplication
	@Controller
	public class CasadocodigoSpringbootApplication {

		@RequestMapping("/")
		@ResponseBody
		public String index(){
			return "funciona?";
		}

		public static void main(String[] args) {
			SpringApplication.run(CasadocodigoSpringbootApplication.class, args);
		}
	}

Aqui já temos um pouco de mágica. Você vai rodar sua aplicação web a partir de um bom e velho método main. A classe SpringApplication vai ler as configurações da classe passada como argumento e pronto, você tem a sua aplicação no ar. A outra parte da mágica acontece por conta da annotation @SpringBootApplication. Ela é um Sterotype do Spring Boot que já encapsula algumas outras annotations, como a @EnableAutoConfiguration. Essa última, por sua vez, carrega a AutoConfigurationPackages que é responsável por configurar os pacotes que devem ser escaneados, baseados na localização da sua classe.

Um outro ponto bem impressionante é o pom.xml criado, você vai perceber que ele possui pouquíssimas dependências! Vamos dar uma rápida olhada.

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.3.0.BUILD-SNAPSHOT</version>
	</parent>	

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
	</dependencies>

Perceba que você adiciona algumas dependências que eles chamam de starters. A grande sacada é fazer com esses artefatos já baixem tudo que você precisa. E aqui, eu preciso dizer que, pelo menos para mim, eles tomaram uma decisão bastante acertada. Ao invés de te dar a opção de escolher entre vários frameworks, servidores web, libs específicas e etc, eles tomaram algumas decisões e empurraram pra gente. Para a maioria dos projetos isso não muda e, se for preciso, você pode sobreescrever tudo que eles fizeram. A motivação deles foi a mesma que tivemos ao construir o SetupMyProject. Já estamos cheios de frameworks, precisamos é de uma maneira mais fácil de usá-los.

Por mais que já tenhamos o projeto configurado, provavelmente esse não é bem o modelo que vamos seguir. Os nossos controllers não vão ser declarados dentro da mesma classe de configuração. O normal é criar uma outra classe que representa este seu controller.

        @Controller
	@Transactional
	@RequestMapping("/produtos")
	public class ProductsController {

		@Autowired
		private ProductDAO products;
		@Autowired
		private FileSaver fileSaver;
		@Autowired
		private ServletContext ctx;
		@Autowired
		private InternalResourceViewResolver resolver;

		@RequestMapping(method=RequestMethod.GET)
		@Cacheable(value="lastProducts")
		public ModelAndView list() throws ServletException, IOException{
			System.out.println("ola");
			ModelAndView modelAndView = new ModelAndView("products/list");
			modelAndView.addObject("products", products.findAll());
			return modelAndView;
		}

		...

	}

E agora é só pedir para escanear o pacote… Opa, não precisa mais! Como eu criei esse classe em um pacote abaixo do pacote da classe de configuração, todas as classes já vão ser escaneadas de maneira automática. Agora é necessário configurar o acesso a JPA e, nesse momento, nossos corações vão ficar felizes novamente. O nosso único trabalho é adicionar um starter no pom.xml. 

	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-data-jpa</artifactId>
	</dependency>

Quase tudo que você acha que deveria fazer para configurar o acesso ao banco com a JPA, vai ser feito automagicamente. Não será necessário configurar persistence.xml, EntityManagerFactory, EntityManager, PlatformTransactionManager nem nada, tudo vai ser feito pra você. A única coisa que você precisa entregar a ele é o DataSource com os  dados de acesso ao banco. Podemos criar um método com essa configuração na própria classe que contém nosso main. 

@SpringBootApplication
	public class CasadocodigoSpringbootApplication {
		@Bean
		public DataSource dataSource(Environment environment) {
			DriverManagerDataSource dataSource = new DriverManagerDataSource();
			dataSource.setDriverClassName("com.mysql.jdbc.Driver");
			dataSource.setUrl("jdbc:mysql://localhost:3306/casadocodigo");
			dataSource.setUsername("root");
			dataSource.setPassword("");
			return dataSource;
		}

		public static void main(String[] args) {
			SpringApplication.run(CasadocodigoSpringbootApplication.class, args);
		}
	}

Além disso, ele também já inclui as dependências para a Spring Data JPA, para facilitar a criação dos seus DAOs. Para completar essa primeira parte da migração do projeto, foi necessário fazer uma pequena configuração extra para os jsps. O Spring Boot sugere que você use outra tecnologia de view, mas como o jsp era a utilizada no projeto do livro, eu resolvi ir com ela mesmo. Como o tomcat está sendo executado de forma embedded, é necessário que adicionemos uma nova dependência no pom, que é a do compilador de jsps para este tipo de cenário.

	<dependency>
		<groupId>org.apache.tomcat.embed</groupId>
		<artifactId>tomcat-embed-jasper</artifactId>
		<scope>provided</scope>
	</dependency>

Além disso, como é procedimento normal, precisamos configurar um prefixo e um sufixo para busca da nossa view. Podemos fazer isso do jeito tradicional, adicionando um método que retorna um InternalResourceViewResolver. Só que podemos aproveitar a oportunidade para já apresentar um outro detalhe que você pode tirar proveito, que são os arquivos de configuração externos. Você pode criar um arquivo chamado application.properties na raiz do seu classpath, geralmente em src/main/resources. Lá você pode colocar configurações específicas das tecnologias utilizadas no projeto, abaixo segue o meu exemplo.

  spring.mvc.view.prefix=/WEB-INF/jsp/
  spring.mvc.view.suffix=.jsp

  #hibernate
  spring.jpa.hibernate.ddl-auto=update

Perceba que ele é bem diferente de um spring-context.xml da vida. Você não tem que declarar um bean para ser usado, simplesmente configura as propriedades do bean já escolhido. 

Para fechar com chave de ouro, pelo menos para mim :), eles deram mais um passo pensando na vida fácil do usuário. Nessa semana eles lançaram um novo starter chamado de DevToolsUma facilidade adicionada foi a de recarregamento do projeto para cada mudança que você faz no código. Só que, como eles mesmos disseram, esse recarregamento é mais esperto do que um simples hot deploy de um servidor web tradicional. Além disso, ainda adicionaram o suporte para o Live Reloadque possibilita o recarregamento automático das páginas no seu navegador sempre que você alterar uma classe sua no servidor!

Ufa! Falei bastante hoje :). Acho o Spring Boot um projeto muito útil e que, com certeza, você devia dar uma olhada. É um approach que por muito eu esperava no mundo Java e espero que influencie outros projetos a fazer o mesmo. Por fim, acho importante lembrar que você deve continuar procurando o motivo do acontecimento das coisas, para não ficar um “programador de Spring Boot” ao invés de um programador  Java.

Lidando com eventos dentro do Spring

No livro que escrevi  sobre o Spring MVC na Casa do Código, construo um projeto similar ao e-commerce usado na própria editora. Gosto bastante de exemplos baseados em lojas online, por mais que sejam batidos, eles possuem o necessário para discutirmos diversas aspectos dentro do desenvolvimento de um projeto. Por exemplo, quando uma compra é fechada e aprovada é necessário que algumas ações sejam tomadas: enviar um email, gravar a compra no banco de dados, disparar o processo de geração do ebook  etc.

A maneira simples resolver isso é invocando todos os métodos necessários logo após a compra ter sido aprovada.

	@RequestMapping(value = "checkout", method = RequestMethod.POST)
	public ModelAndView checkout(@AuthenticationPrincipal SystemUser user) {

			BigDecimal total = shoppingCart.getTotal();
			String uriToPay = "http://book-payment.herokuapp.com/payment";
			try {
				restTemplate.postForObject(uriToPay,
						new PaymentData(total), String.class);

                                paymentDAO.persist(new Payment(shoppingCart,user));
                                mailSender.send(...);

				return new ModelAndView("redirect:/payment/success");
			} catch (HttpClientErrorException exception) {
				return new ModelAndView("redirect:/payment/error");
			}			

	}

E se a gente precisar colocar mais um passo? E se a execução de algum dos passos envolver uma condição da compra sendo efetuada? Agora o email só é disparado caso a compra tenha um valor maior que R$ 100,00. Para todos esses casos somos obrigados a ficar alterando o trecho de código responsável, não importa a localização dele. Você pode tirar essa responsabilidade do controller e jogar para outra classe, quando um novo passo precisar ser adicionado será necessário alterar o trecho de código. Este tipo de situação em um projeto, onde um acontecimento gera a necessidade de execução de vários eventos, já é bem conhecido no mundo de desenvolvimento Orientado a Objetos e, inclusive, criaram até um Design Pattern cujo objetivo é justamente lidar com isso, o Observer. 

O pattern já é bem conhecido, tem até suporte dentro do próprio Java. Caso você queira criar uma classe que representa um evento, pode herdar de java.util.EventObject e trabalhar com ela dentro do seu código. O único ponto negativo é que com pattern ou sem pattern, você ainda é obrigado a guardar uma lista de objetos que precisam ser notificados, ou seja, o código continua nas suas mãos. Pensando nisso, alguns frameworks já fornecem a implementação deste Design Pattern para você. Aqui no post, vamos discutir como tirar proveito disso com o Spring.

O primeiro passo é trocar todo aquele código de controle sobre a execução dos eventos. Vamos simplesmente usar a classe ApplicationContext e informar que aconteceu um novo evento no sistema.

        public ModelAndView checkout(@AuthenticationPrincipal SystemUser user) {
          ...

	  restTemplate.postForObject(uriToPay,new PaymentData(total), String.class);
	  applicationContext.publishEvent(new NewPurchaseEvent(this, shoppingCart, user));
        }

O método publishEvent é o responsável por notificar todo mundo que está esperando pelo evento representado pelo objeto do tipo NewPurchaseEvent. Agora vamos dar uma olhada nessa classe.

  public class NewPurchaseEvent extends ApplicationEvent {

	/**
	 *
	 */
	private static final long serialVersionUID = 7410524290553788367L;
	private final ShoppingCart cart;
	private final SystemUser systemUser;

	public NewPurchaseEvent(Object source, ShoppingCart cart,
			SystemUser systemUser) {
		super(source);
		this.cart = cart;
		this.systemUser = systemUser;
	}

	public ShoppingCart getCart() {
		return cart;
	}

	public SystemUser getSystemUser() {
		return systemUser;
	}

  }

Perceba que ela herda de ApplicationEvent, uma classe do próprio Spring que herda de EventObject. A única diferença é que ela também adiciona um timestamp, apenas para saber quando o evento foi criado. Sempre quando você trabalhar com este modelo de programação, que também é conhecido como publish/subscriber, é importante que você tenha classes específicas que representam os eventos. Dessa forma você vai conseguir criar tratadores também bem específicos, mantendo a coesão do código. Agora que um novo evento está sendo disparado, quem deve tratá-lo?

   public class PurchaseEmailEventListener implements ApplicationListener<NewPurchaseEvent>{

	@Autowired
	private MailSender mailer;

	@Override
	public void onApplicationEvent(NewPurchaseEvent event) {
		System.out.println("Enviando email de nova compra "+event.getCart().getTotal());
		SimpleMailMessage email = new SimpleMailMessage();
		email.setFrom("compras@casadocodigo.com.br");
		email.setTo(event.getSystemUser().getLogin());
		email.setSubject("Nova compra");
		email.setText("corpodo email");
		mailer.send(email);
	}

   }

   public class PurchaseSaveDatabaseEventListener implements  ApplicationListener<NewPurchaseEvent>{

	@Override
	public void onApplicationEvent(NewPurchaseEvent event) {
		System.out.println("salvando no banco de dados");
	}

  }

A interface ApplicationListener deve ser implementada sempre que um novo tratador de evento for criado. Ela define apenas o método onApplicationEvent, que é onde você vai colocar a implementação do seu evento. Apenas para fim de curiosidade, ela herda de uma interface chamada java.util.EventListener, que já vem disponível dentro do próprio Java. A EventListener só serve para marcar que a classe é uma tratadora de eventos, esse tipo de interface é comumente chamada de interface de marcação. Quem for usar os observers do CDI pode usar ela para conseguir encontrar as classes depois.

Analisando o código, conseguimos chegar numa solução bem desacoplada. O local onde o evento é disparado não sabe nada sobre quem está tratando o mesmo. Também conseguimos adicionar novos tratadores sem precisar alterar a lógica do fechamento do pagamento. Uma última coisa que de vez em quando é solicitado é que os eventos aconteçam numa determinada ordem. Na teoria, os eventos não deviam se conhecer e, portanto, não deveria existir ordem. Só que sabemos que na prática, a teoria é outra :). Caso você se encontre nessa situação, basta que seus listeners implementem a interface org.springframework.core.Ordered.

   public class PurchaseSaveDatabaseEventListener implements ApplicationListener<NewPurchaseEvent>,Ordered{

	@Autowired
	private PaymentDAO paymentoDAO;

	@Override
	public void onApplicationEvent(NewPurchaseEvent event) {
               Payment payment = event.buildPayment();
               paymentDAO.persist(payment);
	}

	@Override
	public int getOrder() {
		return 0;
	}

   }

Eles vão ser executados começando pelo número mais baixo, nesse caso você sempre vai gravar a compra antes. A parte ruim é que se tiver muitos eventos você pode acabar se perdendo um pouco, mas de todo jeito pode ser útil para determinados cenários.

Por hoje é isso, espero que os posts estejam sendo úteis para quem está lendo. Ainda tem muitos por vir!

Download de arquivos no Spring MVC

Em um dos projetos que participo atualmente, temos que disponibilizar um zip para download ao fim de uma sequência de telas. Caso eu já tivesse o arquivo pronto, não teria nenhuma dificuldade. Bastaria criar um link na página apontando para o local do arquivo, desta maneira o usuário realizaria o download dele tranquilamente. Uma outra situação, que é o meu caso, é quando necessitamos construir o arquivo naquele determinado momento, em função do que foi solicitado pelo usuário.  Abaixo segue o exemplo do código do método do controller que disponibiliza o download.

@RequestMapping(method = RequestMethod.GET)
    public HttpEntity<byte[]> download(String token) {
        byte[] zipBytes = //pega os bytes de qualquer arquivo
	HttpHeaders httpHeaders = new HttpHeaders();
	httpHeaders.add("Content-Disposition", "attachment; filename=\""+fileToBePacked.getName()+"\"");
	HttpEntity<byte[]> entity = new HttpEntity<byte[]>(zipBytes,httpHeaders);
	return entity;
    }

Perceba que o código é bem direto. Apenas retornamos o array de bytes que representa os dados do arquivo que acabamos de montar. Neste exemplo, apenas para fins de curiosidade, usei o projeto zt-zip(https://github.com/zeroturnaround/zt-zip) da Zero Turnaround  para poder gerar o zip. Um detalhe mais interessante é o uso da classe  HttpEntity, ela permite que você construa a resposta HTTP de maneira bem customizada, definindo os headers que você achar necessário.  No nosso caso adicionamos o header Content-Disposition, para que fosse possível definir o nome do arquivo a ser baixado.

Este foi um post bem simples, mas espero que seja útil :). Continuarei na saga de fazer um post por semana, mesmo que de vez em quando  o assunto seja simples. Por sinal, para você que leu, prefere posts sempre práticos ou quer ver um post sobre algum detalhe mais interno do framework? Especificamente para o dia de hoje, eu fiquei em dúvida sobre qual caminho seguir.

 

Spring MVC, proteja-se do Mass Assignment

Vários sites possuem formulários de cadastro para novos usuários. Também não é incomum que esses mesmo sites, para que possam diferenciar os tipos de  usuários, usem um atributo para guardar os diferentes perfis.

	@Entity
	public class SystemUser {

		@Id
		private String login;
		private String password;
		@ManyToMany(fetch = FetchType.EAGER)
		private List<Role> roles = new ArrayList<>();

		//getter e setters

	}

O formulário de cadastro do site, para usuários que estejam apenas interessados em receber newsletter, poderia ser algo como segue:

	<form action="/admin/users" method="post">
		<input type="text" name="login"/>
		<input type="password" name="password"/>

                ...
	</form>

Abaixo temos um exemplo de código de controller para tratar esse cadastro.

	@RequestMapping(method=RequestMethod.POST)
	public ModelAndView savePossibleBuyer(SystemUser systemUser,RedirectAttributes redirectAttributes){
		systemUser.addRole(new Role("ROLE_NEWS"));
		userDAO.save(systemUser);
		redirectAttributes.addFlashAttribute("success", "Usuário cadastrado com sucesso");
		return new ModelAndView("redirect:/produtos/");
	}

Esse trecho de implementação talvez nos passe a impressão que todo novo usuário cadastrado, através desse formulário, vai possuir apenas o perfil ROLE_NEWS. Agora imagine que a pessoa que esteja preenchendo o cadastro seja um pouco mais maliciosa do que de costume e, por conta disso, tente fazer a seguinte alteração no seu form.

	<form action="/admin/users" method="post">
		<input type="text" name="login"/>
		<input type="password" name="password"/>
		<input type="hidden" name="roles[0].name" value="ADMIN"

		...
	</form>

Lembre que isso é facilmente atingível através da manipulação do HTML apresentado no navegador. E agora, o que vai acontecer? O Spring MVC vai fazer o bind do input cujo name é  roles[0].name com os métodos de acesso do atributo roles. Com isso, ao invés de você adicionar apenas um perfil associado com o novo usuário, você vai acabar inserindo dois e, ainda por cima, um deles talvez seja de administrador. Essa é uma técnica de invasão conhecida como Mass Assignment e que, inclusive, já foi explorada uma vez para hackearem o github.

Existem algumas formas de você se defender dela, mas a primeira é entender o motivo que você ficou exposto. Quase todos os frameworks que conhecemos permitem que associemos valores dos formulários diretamente com nossas classes de modelo, e aí é que mora o problema. Várias vezes criamos getters e setters indiscriminadamente e, como os mesmos são usados para receberem os valores dos parâmetros, o sistema acaba ficando suscetível a este tipo de situação. Então uma primeira saída é justamente prestar atenção nos métodos de acesso que criamos.

Só que de vez em quando, por conta de algum framework que está sendo utilizado, somos obrigados a criar mais métodos de acesso do que gostaríamos e aí é que entra uma segunda estratégia. Há muito tempo atrás o tão famoso Struts nos forçava sempre a criar uma classe que representasse o form para receber os dados enviados através das páginas e aí, só depois, que construíamos o objeto final. Era um pouco mais trabalhoso, mas em compensação nos fazia pensar com carinho para cada formulário que existisse no sistema.  Para esse nosso caso, poderíamos seguir essa sugestão.

	public class NewsletterUserForm {

		private String login;
		private String password;

		//getters e setters

		public SystemUser buildSystemUser(){
			SystemUser user = new SystemUser();
			user.setLogin(login);
			user.setPassword(password);
			user.addRole(new Role("ROLE_NEWS"));
			return user;
		}

	}

E agora podemos alterar o código do controller, para tratar do cadastro.

	@RequestMapping(method=RequestMethod.POST)
	public ModelAndView savePossibleBuyer(NewsletterUserForm formUser,...){
		userDAO.persist(formUser.buildSystemUser());
                ....
	}

Caso você ache que é um pouco exagerado já começar se protegendo desse jeito, pode usar um terceiro recurso, provido pelo próprio Spring MVC.

    @InitBinder
    protected void initBinder(WebDataBinder binder) {
	  binder.setAllowedFields("login","password");
    }

Lembre que o método anotado com @InitBinder é responsável por realizar configurações que serão aplicadas sobre os parâmetros que serão recebidos nos métodos do controller. Nesse caso, estamos dizendo que só aceitamos os parâmetros cujos nomes são login e password. Qualquer outro valor que seja passado será ignorado! A classe WebDataBinder ainda permite que você faça diversas outras configurações, por exemplo configurar uma validação customizada.

Pronto, desse jeito você se protege de receber valores indesejados e ainda consegue aproveitar sua classe de modelo entre vários formulários. E você, como faz para se proteger de valores não esperados? Tem alguma outra sugestão?