Introdução
Este artigo apresenta o desenvolvimento de um sistema completo de e-commerce para petshop, utilizando uma arquitetura moderna baseada em SpringBoot para o backend, Vue.js para o frontend web e UniApp para aplicações móveis. O sistema oferece funcionalidades completas de gerenciametno de produtos, carrinho de compras, controle de usuários e administração do sistema.
Arquitetura do Sistema
A arquitetura proposta segue o padrão MVC (Model-View-Controller) separando claramente as responsabilidades entre as camadas de apresentação, negócio e persistência. O backend utiliza o framework SpringBoot que oferece configuração automática e servidor embarcado, enquanto o frontend Vue.js proporciona uma experiência reactiva e responsiva ao usuário.
Backend com SpringBoot
O SpringBoot representa uma evolução significativa no desenvolvimento de aplicações Java empresariais. Este framework elimina a necessidade de configuração manual de servidores como Tomcat ou Jetty, pois já inclui um servidor embarcado. A funcionalidade de auto-configuração detecta automaticamente as dependências presentes no projeto e configura os componentes necessários, reduzindo drasticamente o tempo de desenvolvimento.
Além disso, o SpringBoot integra-se perfeitamante com projetos como Spring Data para acesso a dados, Spring Security para autenticação e autorização, além de oferecer excelente suporte para testes unitários e de integração.
A seguir, apresentamos um exemplo de configuração básica de uma aplicação SpringBoot:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
public class PetshopApplication {
public static void main(String[] args) {
SpringApplication.run(PetshopApplication.class, args);
}
@GetMapping("/api/saudacao")
public String obterSaudacao() {
return "Bem-vindo ao Sistema de Petshop!";
}
}
Este código demonstra a estrutura básica de um endpoint RESTful utilizando as anotações do SpringBoot. A anotação @SpringBootApplication combina as funcionalidades de @Configuration, @EnableAutoConfiguration e @ComponentScan, enquanto @RestController indica que esta classe menangani requisições HTTP e retorna dados diretamente no corpo da resposta.
Frontend com Vue.js
O Vue.js destaca-se no desenvolvimento de interfaces web modernas devido ao seu sistema de reatividade automatizada. Quando o estado dos dados muda, a interface é automaticamente atualizada sem necessidade de manipulação manual do DOM. O Virtual DOM permite atualizações eficientes minimizando operações custosas no DOM real.
A arquitetura baseada em componentes do Vue.js facilita a reutilização de código e a manutenção do sistema. Cada componente encapsula sua própria lógica, estilos e estrutura, tornando o desenvolvimento mais organizado e escalável.
Exemplo de implementação básica com Vue.js:
<html>
<head>
<title>Loja de Petshop</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<h2>{{ mensagem }}</h2>
<button @click="alterarMensagem">Atualizar</button>
</div>
<script>
var aplicacao = new Vue({
el: '#app',
data: {
mensagem: 'Bem-vindo à nossa Loja de Petshop!'
},
methods: {
alterarMensagem: function() {
this.mensagem = 'Obrigado por visitar nossa loja!';
}
}
});
</script>
</body>
</html>
Camada de Persistência com MyBatis
O MyBatis constitui um framework de mapeamento objeto-relacional que simplifica significativamente a interação com bancos de dados relacionais. Diferente de outros frameworks ORM, o MyBatis permite escrever SQL puro mantendo total controle sobre as consultas exectuadas.
As principais vantagens do MyBatis incluem:
- Separação clara entre código SQL e lógica de negócio
- Suporte a SQL dinâmico para construção de queries condicionais
- Cache de primeira e segunda nível para otimização de performance
- Arquitetura de plugins extensível
Modelo de Dados
A estrutura do banco de dados para o sistema de petshop foi projetada considerando escalabilidade e normalização adequada. A tabela de produtos exemplifica esta estrutura:
-- Estrutura da tabela de produtos
DROP TABLE IF EXISTS `produto`;
CREATE TABLE `produto` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'Identificador único',
`nome` varchar(100) NOT NULL COMMENT 'Nome do produto',
`preco` decimal(10, 2) NOT NULL COMMENT 'Preço do produto',
`descricao` varchar(200) DEFAULT NULL COMMENT 'Descrição detalhada',
`quantidade_estoque` int(11) NOT NULL COMMENT 'Quantidade disponível',
`data_criacao` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`data_atualizacao` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
Esta tabela armazena informações essenciais sobre cada produto disponível na loja, incluindo controle de datas de criação e atualização automática.
Sistema de Autenticação e Autorização
O sistema implementa autenticação baseada em tokens JWT para garantir segurança nas requisições. O processo de login valida as credenciais do usuário e gera um token de acesso temporário:
// Anotação para ignorar validação de autenticação
@IgnoreAuth
@PostMapping(value = "/autenticar")
public R autenticar(String username, String password, String captcha, HttpServletRequest request) {
// Consultar informações do usuário
UsuarioEntity usuario = usuarioService.selecionarUm(new EntityWrapper<UsuarioEntity>().eq("nome_usuario", username));
// Validar existência e senha
if(usuario == null || !usuario.getSenha().equals(password)) {
return R.erro("Credenciais inválidas");
}
// Gerar token de acesso
String token = tokenService.gerarToken(usuario.getId(), username, "usuarios", usuario.getFuncao());
return R.ok().put("token", token);
}
// Método para geração de token
@Override
public String gerarToken(Long idUsuario, String nomeUsuario, String nomeTabela, String funcao) {
// Verificar token existente
TokenEntity tokenExistente = this.selecionarUm(new EntityWrapper<TokenEntity>()
.eq("idusuario", idUsuario).eq("funcao", funcao));
// Criar token aleatório
String token = CommonUtil.gerarStringAleatoria(32);
// Configurar expiração para 1 hora
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
cal.add(Calendar.HOUR_OF_DAY, 1);
if(tokenExistente != null) {
// Atualizar token existente
tokenExistente.setToken(token);
tokenExistente.setDataExpiracao(cal.getTime());
this.atualizarPorId(tokenExistente);
} else {
// Inserir novo registro de token
this.inserir(new TokenEntity(idUsuario, nomeUsuario, nomeTabela, funcao, token, cal.getTime()));
}
return token;
}
O interceptor de autorização valida automaticamente cada requisição verificando a presença e validade do token nos cabeçalhos HTTP:
/**
* Interceptor para validação de autenticação
*/
@Component
public class InterceptadorAutorizacao implements HandlerInterceptor {
public static final String CHAVE_TOKEN = "Token";
@Autowired
private ServicoToken servicoToken;
@Override
public boolean preHandle(HttpServletRequest requisicao, HttpServletResponse resposta, Object manipulador) {
// Configurar cabeçalhos CORS
resposta.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
resposta.setHeader("Access-Control-Max-Age", "3600");
resposta.setHeader("Access-Control-Allow-Credentials", "true");
resposta.setHeader("Access-Control-Allow-Headers", "x-requested-with,request-source,Token, Origin");
// Tratar requisição OPTIONS para CORS
if (requisicao.getMethod().equals(RequestMethod.OPTIONS.name())) {
resposta.setStatus(HttpStatus.OK.value());
return false;
}
// Verificar anotação de exemptionsão de autenticação
AnotacaoIgnorarAuth anotacao;
if (manipulador instanceof HandlerMethod) {
anotacao = ((HandlerMethod) manipulador).getMethodAnnotation(AnotacaoIgnorarAuth.class);
} else {
return true;
}
// Recuperar token do cabeçalho
String token = requisicao.getHeader(CHAVE_TOKEN);
// Permitir acesso sem autenticação quando especificado
if(anotacao != null) {
return true;
}
// Validar token
EntidadeToken entidadeToken = null;
if(StringUtils.isNotBlank(token)) {
entidadeToken = servicoToken.obterEntidadeToken(token);
}
if(entidadeToken != null) {
// Armazenar informações do usuário na sessão
requisicao.getSession().setAttribute("idUsuario", entidadeToken.getIdUsuario());
requisicao.getSession().setAttribute("funcao", entidadeToken.getFuncao());
requisicao.getSession().setAttribute("nomeTabela", entidadeToken.getNomeTabela());
requisicao.getSession().setAttribute("nomeUsuario", entidadeToken.getNomeUsuario());
return true;
}
// Retornar erro de autenticação
resposta.setCharacterEncoding("UTF-8");
resposta.setContentType("application/json; charset=utf-8");
PrintWriter writer = null;
try {
writer = resposta.getWriter();
writer.print(JSONObject.toJSONString(R.erro(401, "Autenticação necessária")));
} finally {
if(writer != null) {
writer.close();
}
}
return false;
}
}
Testes do Sistema
A fase de testes garante que todas as funcionalidades implementadas atendam aos requisitos estabelecidos. O processo de teste inclui verificação de funcionalidades, validação de dados de entrada e confirmação de respostas do sistema.
Os testes de funcionalidade verificam se cada módulo opera conforme esperado. Para o módulo de autenticação, por exemplo, são testados cenários como credenciais corretas, senha incorreta, código de verificação inválido e campos obrigatórios não preenchidos.
Os casos de teste para autenticação demonstram a validação completa do processo:
| Entrada | Resultado Esperado | Resultado Obtido |
|---|---|---|
| Usuário: admin, Senha: 123456, Código: válido | Login bem-sucedido | Login realizado com sucesso |
| Usuário: admin, Senha: senha123, Código: válido | Erro de senha | Mensagem de senha incorreta |
| Usuário: admin, Senha: 123456, Código: inválido | Erro de verificação | Mensagem de código incorreto |
| Usuário: vazio, Senha: 123456, Código: válido | Campo obrigatório | Mensagem informando campo obrigatório |
Conclusão
O sistema de e-commerce para petshop desenvolvido demonstra a integração eficaz de tecnologias modernas como SpringBoot, Vue.js e UniApp. A arquitetura proposta oferece escalabilidade, manutenibilidade e performance adequadas para aplicações comerciais. Os testes realizados confirmam que o sistema atende aos requisitos funcionais e não-funcionais estabelecidos, proporcionando uma experiência confiável para os usuários finais.