ViewResolvers - facilitando a configuração do Spring MVC

bom, para quem não conhece o framework MVC do Spring framework, o titulo deste post não quer dizer absolutamente nada, mas view resolvers, são beans que pegam, por exemplo, a palavra: home
e traduzem isto para quem vai desenhar a tela para o usuário, como por exemplo:

  • homePage.jsp
  • /WEB-INF/jsps/index.jsp
  • /WEB-INF/vm/home.vm

forçando um pouco, uma view, pode ser considerada como um forward do struts, e cada view resolver, usa uma tecnica diferente para definir, o que significa "home"
bom, tendo isto explicado (eu acho que ficou mais ou menos claro, se não ficou é só alguem me chingar nos comentários ali em baixo), hoje eu descobri que eu posso ter vários ViewResolvers ao mesmo tempo na minha aplicação
ta, mas para que isto serve?
por exemplo, o tipo de view default da minha aplicação é velocity, então eu posso usar a seguinte configuração:

<bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
<property name="resourceLoaderPath">
<value>/WEB-INF/vm/</value>
</property>
</bean>
<bean id="viewResolverVelocity" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass">
<value>org.rsjug.site.utils.RsjugVelocityView</value>
</property>
<property name="suffix">
<value>.vm</value>
</property>
</bean>

isto configura a engine do velocity, e diz que se eu buscar uma view com o nome de "home" o framework vai me retornar: /WEB-INF/vm/home.vm, e se eu procurar uma view com o nome de artigos/lista ele vai me retornar: /WEB-INF/vm/artigos/lista.vm
bom, até agora nada de tão divertido assim, e até pouco tempo eu achava isto até meio limitado, mas eu posso simplesmente adicionar a seguinte configuração no meu prefix-servlet.xml para melhorar um pouco a brincadeira:

<bean id="viewResolverConfig" class="org.springframework.web.servlet.view.XmlViewResolver">
<property name="cache">
<value>true</value>
</property>
<property name="order">
<value>10</value>
</property>
<property name="location">
<value>/WEB-INF/site-views.xml</value>
</property>
</bean>

e agora, dentro do arquivo site-views.xml, eu posso definir que a view com o nome de artigos/lista, é um redirect para uma página, ou então aponta para uma classe que vai me gerar um PDF utilizando os mesmos dados que eu ja ia utilizar no arquivo ".vm" para onde ele apontava antes.
ta, tudo isto é muito bonito, mas e dai, quais são os tais de viewresolvers que vem prontinhos no spring, ou sera que eu vou ter de escrever?
calma, não é bem assim, o spring ja entrega alguns prontos, mas se for necessário pode-se escrever uma classe nova de view, ou de view resolver.
como ali na declaração do: viewResolverVelocity eu setei a classe de view dele, para uma subclasse da view default para velocity do spring para eu poder setar mais alguns parametros para todos os templates (pra falar a verdade, colocar também o request no contexto do velocity, e só precisei escrever uma linha pra isto :D )
mas voltando ao assunto, e pra terminar este negócio que to escrevendo e que muitos dos dois leitores devem estar perguntando: ta, e eu com isto
eu vou só listar quais são os view resolvers que vem prontos pra o uso no spring, quaisquer duvidas é só comentarem ai em baixo (sim, isto é uma campanha por comentarios, ninguem comenta nada aqui :( )
a explicação do que é cada um deles, e no que eles facilitam ou dificultam a vida, pode ser encontrada nos javadocs deles :D

  • org.springframework.web.servlet.view.BeanNameViewResolver - este é o default, caso nenhum seja especificado
  • org.springframework.web.servlet.view.XmlViewResolver
  • org.springframework.web.servlet.view.ResourceBundleViewResolver
  • org.springframework.web.servlet.view.UrlBasedViewResolver
  • org.springframework.web.servlet.view.InternalResourceViewResolver
  • org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver
  • org.springframework.web.servlet.view.velocity.VelocityViewResolver

ahh, esqueci de dizer, alguns deles tem o parametro order, que permite que seja especificado em que ordem eles serão consultados, mas não são todos, e como eu acho meio confuso definir uma view com o mesmo nome para dois viewresolvers diferentes, então nunca realmente precisei disto :D
bom, por enquanto era isto, outro dia eu posto mais alguma coisa do maravilhoso mundo do spring :D

Se você gostou deste post, lembre-se de assinar o RSS feed do blog, para ser notificado de novos posts!

Commons-Attributes - Facilitando a configuração do Spring MVC

bom, uma das maiores criticas ao spring framework, é a quantidade excessiva de XML utilizados, bom, as ultimas versɵes do framework, suportam annotations para diversos tipos de configuração, o que é mais propagandeado é a parte de configuração de transações por annotations, mas a parte que eu mais gostei é a que substitui totalmente a configuração e mapeamento de controllers para a parte web, isto quer dizer que nÉ£o é necessária nem uma linha de configuração para adicionar um novo controller na aplicação.
Por enquanto, o Spring nÉ£o suporta as anotações do JDK 1.5, utiliza apenas o commons-annotations, o que requer um passo extra na compilação da aplicação.
bom, mas chega de papo furado, parece que é fácil demais né? bom, vamos a um pequeno exemplo:

/**
* @author Rodrigo Urubatan Ferreira Jardim
* @@org.springframework.web.servlet.handler.metadata.PathMap("/home.html")
*/

public class HomeController extends AbstractController {
private WorkFlowDao workFlowDao;

public void setWorkFlowDao(WorkFlowDao workFlowDao) {
this.workFlowDao = workFlowDao;
}

protected ModelAndView handleRequestInternal ( HttpServletRequest request, HttpServletResponse response ) throws Exception {
Collection processos = workFlowDao.listaProcessos();
return new ModelAndView("home","processos",processos);
}

}

bom, este controller extremamente complexo, precisa apenas ser compilado, e indexado pelo compilador do commons-attributes que vai atender pela URL "home.html" (sim, eu costumo utilizar a extensÉ£o HTML para as minhas páginas dinÉ¢micas também)
o que determina isto, é apenas aquele comentário em negrito na declaração da classe.

vamos ver como é feita a mágica, é necessária uma pequena alteração no build.xml, e a definição de alguns beans em um XML utilizado pelo spring (eu costumo utilizar applicationContext.xml, ou entÉ£o o proprio <servletname>-servlet.xml, que sera lido automáticamente pelo servlet do spring
vamos ao build.xml:

<target name="init">
<taskdef classpathref="project.class.path" resource="org/apache/commons/attributes/anttasks.properties" />
</target>

<target name="compile" depends="attrib">
<javac classpathref="project.class.path" destdir="${web.bin}" srcdir="${src.dir}" />
<javac classpathref="project.class.path" destdir="${web.bin}" srcdir="${src.temp}" />
</target>

<target name="attrib" depends="init">
<attribute-compiler destdir="${src.temp}">
<fileset dir="${src.dir}" includes="**/*.java" />
</attribute-compiler>
</target>

<target name="all" depends="compile,attrib">
<jar destfile="${web.lib}/${jar.name}" basedir="${web.bin}" compress="true" index="true">
<include name="**/*.*" />
</jar>
<attribute-indexer jarFile="${web.lib}/${jar.name}">
<classpath refid="project.class.path" />
</attribute-indexer>
</target>

o pulo do gato neste build.xml é a task: attribute-indexer que permite que o spring encontre os controller automáticamente
e as configurações necessárias no spring:

<bean id="autoproxy"
class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" singleton="true">
<property name="customTargetSourceCreators">
<list>
<ref local="poolingTargetSourceCreator" />
</list>
</property>
</bean>
<bean id="transactionAttributeSource"
class="org.springframework.transaction.interceptor.AttributesTransactionAttributeSource"
autowire="constructor" singleton="true">
</bean>
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor"
autowire="byType" singleton="true">
</bean>
<bean id="transactionAdvisor"
class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor"
autowire="constructor" singleton="true">
</bean>
<bean id="attributes"
class="org.springframework.metadata.commons.CommonsAttributes" singleton="true"/>
<bean id="poolingTargetSourceCreator"
class="org.springframework.aop.framework.autoproxy.metadata.AttributesPoolingTargetSourceCreator"
autowire="constructor" singleton="true">
</bean>
<bean id="commonsAttributesHandlerMapping" class="org.springframework.web.servlet.handler.metadata.CommonsPathMapHandlerMapping" singleton="true"/>

aqui, todos estes beans colaboram de alguma forma, o default-autowire do contexto esta setado para: byName, isto quer dizer que se algum dos nomes for alterado, a cosia pode parar de funcionar, mas deixando assim ta tudo beleza
quem carrega os controller aqui, é o ultimo bean definido: commonsAttributesHandlerMapping

bom, o negócio parece show de bola, mas tem um probleminha na versÉ£o atual do spring (1.1), os controllers sÉ£o carregados sempre utilizando auto wire by bype, isto quer dizer que só pode existir um bean de cada tipo no contexto, mas eu fiz uma pequena alteração e mandei para o pessoal do spring, e o Rod Johnson respondeu dizendo que iria incluir a alteração para a versÉ£o 1.1.3 corrigindo este problema. Atualmente to utilizando a minha versÉ£o alterada com autoWireByName, acho bem mais flexivel :D
bom, eu achei super legal este suporte para anotações, acho que vcs podem aproveitar também, qualquer duvida postem aqui nos comentários.

Se você gostou deste post, lembre-se de assinar o RSS feed do blog, para ser notificado de novos posts!