Entendendo os Tipos de Retorno do Controller no SpringMVC
Neste artigo, exploraremos os sete principais tipos de retorno de métodos em controladores SpringMVC, demonstrando com exemplos práticos em um projeto Maven Web chamado SpringMVC04. O objetivo é entender profundamente o mecanismo de resposta do SpringMVC.
Estrutura do Projeto
O projeto SpringMVC04 segue uma estrutura Maven com o pacote base com.qcby. Abaixo está a estrutura do diretório:
SpringMVC04
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── qcby
│ │ │ ├── controller
│ │ │ │ └── UsuarioController.java
│ │ │ └── modelo
│ │ │ └── Usuario.java
│ │ ├── resources
│ │ │ └── springmvc.xml
│ │ └── webapp
│ │ ├── paginas
│ │ │ └── sucesso.jsp
│ │ ├── js
│ │ │ └── jquery.min.js
│ │ ├── index.jsp
│ │ └── WEB-INF
│ │ └── web.xml
Configure os diretórios java e resources como Sources Root e Resources Root, respectivamente.
Dependências no pom.xml
As dependências principais incluem Spring, Jackson para JSON e suporte a Servlet/JSP:
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!-- Jackson para JSON -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
<!-- Servlet e JSP -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
Configurações do SpringMVC
No web.xml, configuramos o DispatcherServlet e o filtro de codificação UTF-8:
<filter>
<filter-name>filtroCodificacao</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>filtroCodificacao</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>controladorCentral</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>controladorCentral</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
No springmvc.xml, configuramos o scan de componentes, o resolvedor de visualização e recursos estáticos:
<context:component-scan base-package="com.qcby"/>
<bean id="resolvedorVisualizacao" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/paginas/"/>
<property name="suffix" value=".jsp"/>
</bean>
<mvc:annotation-driven/>
<mvc:resources location="/css/" mapping="/css/**"/>
<mvc:resources location="/js/" mapping="/js/**"/>
Entidade de Exemplo: Usuario.java
package com.qcby.modelo;
import java.io.Serializable;
public class Usuario implements Serializable {
private static final long serialVersionUID = 1L;
private String nome;
private Integer idade;
public Usuario() {}
public String getNome() { return nome; }
public void setNome(String nome) { this.nome = nome; }
public Integer getIdade() { return idade; }
public void setIdade(Integer idade) { this.idade = idade; }
@Override
public String toString() {
return "Usuario{nome='" + nome + "', idade=" + idade + "}";
}
}
JSP de Exemplo: sucesso.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Página de Sucesso</title>
</head>
<body>
<h1>Operação bem-sucedida!</h1>
<h3>Mensagem: ${msg}</h3>
</body>
</html>
Exemplos de Métodos no Controller
1. Retorno String – Nome da Visualização Lógica
@RequestMapping("/salvar1.do")
public String salvar1() {
System.out.println("Método executado - String");
return "sucesso";
}
2. Retorno void – Sem Retorno
@RequestMapping("/salvar2.do")
public void salvar2(HttpServletRequest req, HttpServletResponse res) throws IOException {
res.getWriter().print("<h1>Resposta direta - void</h1>");
}
3. Retorno String com forward:
@RequestMapping("/salvar4.do")
public String salvar4() {
return "forward:/paginas/sucesso.jsp";
}
4. Retorno String com redirect:
@RequestMapping("/salvar5.do")
public String salvar5() {
return "redirect:/paginas/sucesso.jsp";
}
5. Retorno ModelAndView
@RequestMapping("/salvar3.do")
public ModelAndView salvar3() {
ModelAndView mv = new ModelAndView();
mv.addObject("msg", "Usuário já existe");
mv.setViewName("sucesso");
return mv;
}
6. Retorno Model + String
@RequestMapping("/salvar7.do")
public String salvar7(Model model) {
model.addAttribute("msg", "Dados passados via Model");
return "sucesso";
}
7. Retorno com @ResponseBody para JSON
@RequestMapping("/salvar6.do")
@ResponseBody
public Usuario salvar6(@RequestBody Usuario usuario) {
usuario.setNome("ola");
usuario.setIdade(100);
return usuario;
}
Comparação dos Tipos de Retorno
| Tipo de Retorno | Uso Principal | Passagem de Dados | Cenário Comum |
|---|---|---|---|
| String (view name) | Nome lógico da visualização | Com Model |
Páginas com dados dinâmicos |
| void | Controle manual de resposta | Usando HttpServletResponse |
Resposta direta ou redirecionamento manual |
| String (forward) | Redirecionamento interno | Com request.setAttribute |
Dados compartilhados no request |
| String (redircet) | Redirecionamento externo | Não compartilha dados do request | Evitar reenvio de formulário |
| ModelAndView | Modelo e visualização comibnados | Com addObject |
Exemplos simples e rápidos |
| Model + String | Separar dados e visualização | Com addAttribute |
Padrão mais usado em projetos reais |
| @ResponseBody | Retornar JSON/XML | Serialização automática | Chamadas AJAX ou APIs REST |