Spring MVC e jQuery, simples e rápido
Autor: Rafael | Publicado: 2011-09-15T05:08:00-03:00

O objetivo é criar uma aplicação web tão simples e rápida quanto possível, assim iremos mostrar como desenvolver uma pequena aplicação web, usando Spring MVC como backend, jQuery como biblioteca javascript/ajax e&nbsp; retornar alguns dados no formato JSON, que o Spring já tem suporte, usando a biblioteca Jackson JSON.






Overview

Nossa aplicação terá um Home e um pequeno Cadastro de Item, que deixaremos os dados em memória. Utilizaremos JSPs para as views e algumas classes Java pra serem controllers e services, resultando em um fluxo:

Requisição &gt; Controller &gt; Service, View

- Uma requisição é enviada.
- O Controller recebe.
- O Controller opcionalmente chama um Service para executar alguma lógica de negócio.
- O Controller cria um ModelAndView e coloca os dados necessários da view dentro do Model.
- O Controller dispacha para alguma view JSP usando JSTL ou retorna dados JSON.
- A JSP mostra as informações. 

Home:



Listagem de Item:

 

Formulário de Item:




Configuração 

Primeiro, precisaremos configurar o Spring MVC para receber nossas requisições. Inclua a servlet DispatcherServlet dentro do web.xml:

web.xml


&nbsp;&nbsp;&nbsp; &lt;servlet&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;servlet-name&gt;example&lt;/servlet-name&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;servlet-class&gt;org.springframework.web.servlet.DispatcherServlet&lt;/servlet-class&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;init-param&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;param-value&gt;classpath*:META-INF/applicationContext.xml&lt;/param-value&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/init-param&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;
&nbsp;&nbsp;&nbsp; &lt;/servlet&gt;

&nbsp;&nbsp;&nbsp; &lt;servlet-mapping&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;servlet-name&gt;example&lt;/servlet-name&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;url-pattern&gt;/app/*&lt;/url-pattern&gt;
&nbsp;&nbsp;&nbsp; &lt;/servlet-mapping&gt;

Depois, crie o arquivo applicationContext.xml dentro da pasta META-INF do seu source, conforme a configuração do valor do parametro contextConfigLocation do web.xml:

Aqui colocamos o mapeamento da servlet para /app/*, ou seja, todas as URLs com esse prefixo, serão direcionadas para a servlet do Spring. Outras URLs como /js, /css, /img, não serão direcionadas.

applicationContext.xml

&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;beans xmlns="http://www.springframework.org/schema/beans" 
&nbsp;&nbsp;&nbsp; xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
&nbsp;&nbsp;&nbsp; xmlns:p="http://www.springframework.org/schema/p" 
&nbsp;&nbsp;&nbsp; xmlns:context="http://www.springframework.org/schema/context"
&nbsp;&nbsp;&nbsp; xmlns:mvc="http://www.springframework.org/schema/mvc"
&nbsp;&nbsp;&nbsp; xsi:schemaLocation="
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; http://www.springframework.org/schema/beans 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; http://www.springframework.org/schema/context 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; http://www.springframework.org/schema/context/spring-context-3.0.xsd
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; http://www.springframework.org/schema/mvc
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; http://www.springframework.org/schema/mvc/spring-mvc.xsd"&gt;

&nbsp;&nbsp;&nbsp; &lt;mvc:annotation-driven /&gt;
&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp; &lt;context:component-scan base-package="com.naskar.springmvc"/&gt;
&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp; &lt;bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/&gt;
&nbsp;&nbsp;&nbsp; &nbsp; &lt;property name="prefix" value="/WEB-INF/jsp/"/&gt;
&nbsp;&nbsp;&nbsp; &nbsp; &lt;property name="suffix" value=".jsp"/&gt;
&nbsp; &nbsp;&nbsp;&nbsp; &lt;/bean&gt;
&nbsp; 
&lt;/beans&gt;

A configuração do parametro&nbsp;context:component-scan base-package diz ao Spring para procurar por todas as classes anotadas com @Controller e @Service dentro dos pacotes e subpacotes com.naskar.springmvc.

Depois disto, temos a configuração do InternalResourceViewResolver, que estamos direcionando para um diretório dentro de WEB-INF, assim as JSPs não estarão disponíveis diretamente para o usuário e todas as requisições terão sempre que passar por algum Controller para serem exibidas.

Se você estiver usando maven, inclua as seguintes dependências no seu arquivo pom.xml:


&nbsp;&nbsp;&nbsp; &lt;dependencies&gt;

&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;dependency&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;groupId&gt;org.springframework&lt;/groupId&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;spring-webmvc&lt;/artifactId&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;version&gt;3.0.5.RELEASE&lt;/version&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/dependency&gt;

&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;dependency&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;groupId&gt;org.codehaus.jackson&lt;/groupId&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;jackson-mapper-asl&lt;/artifactId&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;version&gt;1.8.0-SNAPSHOT&lt;/version&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/dependency&gt;

&nbsp;&nbsp;&nbsp; &lt;/dependencies&gt;


&nbsp;&nbsp;&nbsp; &lt;repositories&gt;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;repository&gt;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;id&gt;codehaus-snapshots&lt;/id&gt;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;url&gt;http://snapshots.repository.codehaus.org&lt;/url&gt;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/repository&gt;
&nbsp;&nbsp; &nbsp;&lt;/repositories&gt;

Caso não, veja as referências abaixo para efetuar o download das bibliotecas.
Jackson será necessário somente se você quiser usar JSON. 


Home

Agora vamos criar o HomeController, que irá receber as requisições para as URLs do tipo /app/home:

HomeController.java

@Controller
public class HomeController {
&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp; @RequestMapping("/home")
&nbsp;&nbsp;&nbsp; public ModelAndView home() {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ModelAndView mav = new ModelAndView();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mav.setViewName("home");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return mav;
&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp; @RequestMapping("/home/welcome")
&nbsp;&nbsp;&nbsp; public ModelAndView welcome() {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ModelAndView mav = new ModelAndView();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mav.setViewName("welcome");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mav.addObject("message", "Bem vindo!!!");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return mav;
&nbsp;&nbsp;&nbsp; }

}

Para todas as classes que iremos usar como controllers, precisamos anotá-las com @Controller, e para cada URL que queremos disponibilizar, utilizaremos a anotação @RequestMapping, para fazer o mapeamento entre o path e o método a ser executado. Assim, temos:

/app/home
Será executado o método home() e dispachada a requisição para a página WEB-INF/jsp/home.jsp.

/app/home/welcome
Será executado o método welcome() e dispachada a requisição para a página WEB-INF/jsp/welcome.jsp.

home.jsp:

&lt;%@page deferredSyntaxAllowedAsLiteral="true"%&gt;
&lt;html&gt;
&nbsp;&nbsp;&nbsp; &lt;head&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;link type="text/css" href="/springmvc/css/pepper-grinder/jquery-ui-1.8.16.custom.css" rel="stylesheet" /&gt;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;script type="text/javascript" src="/springmvc/js/jquery-1.6.2.min.js"&gt;&lt;/script&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;script type="text/javascript" src="/springmvc/js/jquery-ui-1.8.16.custom.min.js"&gt;&lt;/script&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;script&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; $(function() {
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; // add the itens to content
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; $("#HomeBtn").button().click(function() {
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; $("#content").load("home/welcome");
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; });
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; // add the itens to content
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; $("#itemBtn").button().click(function() {
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; $("#content").load("item");
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; });
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; // init
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; $("#content").load("home/welcome");
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; });&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/script&gt;
&nbsp;&nbsp;&nbsp; &lt;/head&gt;
&nbsp;&nbsp;&nbsp; &lt;body&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;div id="menu" class="ui-widget"&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;div&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;input type="button" id="HomeBtn" value="Home" /&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;input type="button" id="itemBtn" value="Item" /&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/div&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/div&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;div id="content" style="margin: 10px;"&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/div&gt;
&nbsp;&nbsp;&nbsp; &lt;/body&gt;
&lt;/html&gt;

Podemos vê que a página é simples e clara. Usaremos jQuery para carregar as outras páginas dentro do DIV content, usando a seguinte função load:


$("#content").load("item");

Isso faz com o jQuery procure algum element com o id content, que no nosso caso é um elemento DIV, e carregue o conteúdo da URL /app/item dentro do DIV.

Logo acima, temos a adição dos eventos click() dos botões para executar os carregamentos das páginas.


Dados para view

Um detalhe que precisamos perceber é que podemos passar dados para a view, utilizando o método addObject da classe ModelAndView, como é feito para a view welcome.

Logo que a página é carregada, é executado um load para a URL welcome, que mostrará uma mensagem "Bem vindo!!!", essa incluída durante a execução do HomeController:

welcome.jsp

&lt;div id="welcome_conteudo"&gt;

&nbsp;&nbsp;&nbsp; &lt;div id="welcome_conteudo" class="ui-dialog ui-widget ui-widget-content ui-corner-all undefined ui-resizable"&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &lt;div class="ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix"&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;span id="ui-dialog-title-dialog" class="ui-dialog-title"&gt;Home&lt;/span&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &lt;/div&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &lt;div style="height: 200px; width: auto;" class="ui-dialog-content ui-widget-content" id="dialog"&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;p&gt;${message}&lt;/p&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &lt;/div&gt;
&nbsp;&nbsp;&nbsp; &lt;/div&gt;
&nbsp;&nbsp;&nbsp; 
&lt;/div&gt;

Podemos perceber também, que dentro da JSP welcome.jsp só é necessário um framento de página que será incluído dentro do DIV content.


Item

Agora veremos o cadastro de item, que utiliza uma classe ItemService para armazenar os Items em memória que serão cadastrados.

ItemController.java


@Controller
public class ItemController {
&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp; @Autowired
&nbsp;&nbsp;&nbsp; private ItemService itemService;
&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp; @RequestMapping("/item")
&nbsp;&nbsp;&nbsp; public ModelAndView list() {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ModelAndView mav = new ModelAndView();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mav.setViewName("item/list");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mav.addObject("items", itemService.getItems());
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return mav;
&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp; @RequestMapping("/item/add")
&nbsp;&nbsp;&nbsp; public ModelAndView add() {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ModelAndView mav = new ModelAndView();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mav.setViewName("item/form");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return mav;
&nbsp;&nbsp;&nbsp; }

...
}

ItemServiceImpl.java

@Service
public class ItemServiceImpl implements ItemService {
&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp; private List&lt;Item&gt; items;
&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp; public ItemServiceImpl() {
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; items = new ArrayList&lt;Item&gt;();
&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp; public List&lt;Item&gt; getItems() {
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return items;
&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp; public void save(Item item) {
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(items.contains(item)) {
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; items.remove(item);
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; items.add(item);
&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp; public void remove(Item item) {
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; items.remove(item);
&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp; public Item load(Integer itemId) {
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; int i = items.indexOf(new Item(itemId, ""));
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(i &gt; -1)
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return items.get(i);
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; else 
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return null;
&nbsp;&nbsp;&nbsp; }

}

Podemos vê que ao tentarmos acessar a URL /app/item, temos um mapeamento para o métod list(), que executará o método getItems() da classe ItemService.

Depois disso, o ItemController, adiciona ao ModelAndView uma propriedade items com a lista de itens e dispacha para a view item/list. O viewResolver, que vimos no applicationContext, irá dispachar para a JSP /WEB-INF/jsp/item/list.jsp, que mostrará os dados.

list.jsp


&lt;%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %&gt;
&lt;%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %&gt;
&lt;div id="item_content"&gt;
&nbsp;&nbsp;&nbsp; &lt;script type="text/javascript"&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; $(function(){
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; $("#item_add")
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; .click(function() {
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; $('#item_content').load("item/add");
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; });
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; });
&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; function loadAction(action) {
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; $('#item_content').load(action);
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp; &lt;/script&gt;
&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp; &lt;div class="ui-dialog ui-widget ui-widget-content ui-corner-all undefined ui-resizable"&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &lt;div class="ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix"&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;span id="ui-dialog-title-dialog" class="ui-dialog-title"&gt;Item&lt;/span&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &lt;/div&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &lt;div style="height: 200px; width: auto;" class="ui-dialog-content ui-widget-content" id="dialog"&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;div&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;c:forEach var="message" items="${messages}"&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ${message}&lt;br /&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/c:forEach&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;br /&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/div&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;div&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;a id="item_add" href="#"&gt;Novo&lt;/a&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/div&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;div&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;table&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;thead&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;tr&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;td&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ID
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/td&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;td&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Descricao
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/td&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/tr&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/thead&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;tbody&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;c:forEach var="item" items="${items}"&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;tr&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;td&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ${item.id}
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/td&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;td&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ${item.description}
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/td&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;td&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;a id="item_edit" href="javascript:loadAction('item/edit/${item.id}');"&gt;#editar&lt;/a&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/td&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;td&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;a id="item_remove" href="javascript:loadAction('item/remove/${item.id}');"&gt;#excluir&lt;/a&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/td&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/tr&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/c:forEach&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/tbody&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/table&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/div&gt;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &lt;/div&gt;
&nbsp;&nbsp;&nbsp; &lt;/div&gt;


&lt;/div&gt;


Novamente, temos somente um pequeno framento de código que será carregado dentro do DIV content.

Aqui também, já podemos vê a utilização de uma URL para efetuar a exclusão de um Item:

/app/item/remove/${item.id}

Para efetuar o cadastro das informações temos o seguintes mapeamentos:


@RequestMapping("/item/edit/{itemId}")
&nbsp;&nbsp;&nbsp; public ModelAndView editar(@PathVariable Integer itemId) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ModelAndView mav = new ModelAndView();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mav.setViewName("item/form");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mav.addObject("item", itemService.load(itemId));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return mav;
&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp; @RequestMapping("/item/remove/{itemId}")
&nbsp;&nbsp;&nbsp; public ModelAndView remove(@PathVariable Integer itemId) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ModelAndView mav = new ModelAndView();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mav.setViewName("forward:/app/item");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; itemService.remove(new Item(itemId, ""));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List&lt;String&gt; messages = new ArrayList&lt;String&gt;();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; messages.add("Item removido com sucesso.");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mav.addObject("item", itemService.getItems());
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mav.addObject("messages", messages);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return mav;
&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp; @RequestMapping(value = "/item/save")
&nbsp;&nbsp;&nbsp; public ModelAndView save(Item item) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ModelAndView mav = new ModelAndView();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mav.setViewName("forward:");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; itemService.save(item);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List&lt;String&gt; messages = new ArrayList&lt;String&gt;();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; messages.add("Item salvo com sucesso.");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mav.addObject("item", itemService.getItems());
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mav.addObject("messages", messages);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return mav;
&nbsp;&nbsp;&nbsp; }

A diferença aqui está somente na utilização da anotação @PathVariable, que mapea um parametro do método para a URL.


@RequestMapping("/item/remove/{itemId}")

public ModelAndView remove(@PathVariable Integer itemId)

Outra característica interessante do Spring MVC é utilizar a String "forward:" para fazer um redirecionamento utilizando todos os dados do model anterior.


mav.setViewName("forward:/app/item");


JSON

Para finalizar, veremos agora como retornar alguns dados no formato JSON, que utilizando Spring MVC é realmente muito simples. Incluiremos mais esse mapeamento dentro da classe ItemController:


@RequestMapping(value = "/item/list.json")
&nbsp;&nbsp;&nbsp; public @ResponseBody List&lt;Item&gt; listjson() {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return itemService.getItems();
&nbsp;&nbsp;&nbsp; }

A anotação @ResponseBody fará com que, caso a biblioteca Jackson esteja no classpath, o Spring converta o List&lt;Item&gt; para o formato JSON. Para fazermos o teste podemos utilizar o navegador ou uma ferramenta chamada curl:

Se fizermos uma requisição para a URL:

/app/item/list.json 

Teremos o seguinte retorno:


[{"id":1,"description":"item1"},{"id":2,"description":"item2"}]

Aqui vemos o log do curl:


curl -v -i -H "Accept: application/json" -X POST -d "" "http://localhost:8080/springmvc/app/item/list.json"

* About to connect() to localhost port 8080 (#0)
*&nbsp;&nbsp; Trying 127.0.0.1... connected
* Connected to localhost (127.0.0.1) port 8080 (#0)
&gt; POST /springmvc/app/item/list.json HTTP/1.1
&gt; User-Agent: curl/7.19.3 
&gt; Host: localhost:8080
&gt; Accept: application/json
&gt; Content-Length: 0
&gt; Content-Type: application/x-www-form-urlencoded
&gt;
&lt; HTTP/1.1 200 OK
HTTP/1.1 200 OK
&lt; Content-Type: application/json
Content-Type: application/json
&lt; Transfer-Encoding: chunked
Transfer-Encoding: chunked
&lt; Server: Jetty(8.0.1.v20110908)
Server: Jetty(8.0.1.v20110908)

&lt;
[{"id":1,"description":"item1"},{"id":2,"description":"item2"}]* Connection #0 t
o host localhost left intact
* Closing connection #0

Para deixarmos a aplicação mais exuta, podemos ao invés de retornarmos framentos de página usando JSP, podemos retornar somente JSON, e fazermos todo o tratamento no cliente usando Javascript e componentes como datatables, calendars, etc, auxiliados pela função $.getJSON() do jQuery.


Considerações


Arquiteturas exutas

Aplicações para web, onde há uma grande necessidade de performance, podem se beneficiar de arquiteturas mais exutas, evitado o uso de frameworks pesados como JSF, na qual são baseados em componentes. Aqui, mostramos um modelo baseado em actions.

Largura de banda

O carregamento dos dados sob demanda e em pequenos framentos também economiza uma grande largura de banda, como também de processo de renderização da página.

Usabilidade

Outra questão importante, é a usabilidade da aplicação que aumenta de forma consideralmente, já que com a nova versão do HTML versão 5, temos mais opções disponíveis e podemos considerar o descarte de frameworks de componentes java.

Cases

Há vários casos de utilização desse modelo em sites com um número grande de acessos. Um exemplo clássico é o facebook que utiliza PHP como backend e javascript intensamente, e até desenvolveu um compilador para PHP, para suportar a quantidade enorme de acessos.

Simplificação do protocolo

Nessa abordagem, temos também o ganho da abstração do backend utilizado, já que, o que são enviados para o servidor, são somente GET/POST ou dados no formato JSON, que é mais exuto que a utilização de XML com SOAP, podendo ser uma ótíma opção para exposição de webservices.

Dados de Sessão

A maioria das aplicações usam cookies para armazenar dados de sessão no backend. Uma boa opção é usar banco de dados não estruturados ou orientados a documentos, onde eles só armazenam dados na forma de chave/valor, com uma alta performance de replicação e disponibilidade, exemplos são CouchDB, MongoDB.


Conclusão

Por mais que JSF seja o padrão JEE, não quer dizer que precisamos usá-lo sempre. A arquitetura de um sistema depende de três fatores principais: atributos de qualidade (escalabilidade, performance, etc..), ambiente (experiência da equipe, ferramentas, etc) e experiência do arquiteto. Assim, nós como arquitetos, temos que nos abastecermos da maior quantidade de experiências para escolhermos a melhor solução para cada caso, independente da tecnologia ou plataforma, seja Java, PHP ou .NET.


Referências

jQuery e Spring MVC: http://blog.springsource.com/2010/01/25/ajax-simplifications-in-spring-3-0/
Jackson: http://jackson.codehaus.org/
CounchDB: http://couchdb.apache.org/
MongoDB: http://www.mongodb.org/
cURL: http://curl.haxx.se/download.html

Os fontes desse exemplo estão disponiveis no googlecode:

http://code.google.com/p/com-naskar-springmvc/downloads/list
http://code.google.com/p/com-naskar-springmvc/source/browse/