Sistema de Gestão para Troca de Artigos Usados entre Estudantes Universitários com Funcionalidade de Item Gratuito Baseado em Java Spring Boot

Este sistema de gestão visa promover a reutilização e troca de itens usados dentro do ambiente universitário, com um módulo específico dedicado à troca de itens gratuitos. Desenvolvido sobre o framework Java Spring Boot, a plataforma facilita a publicação, navegação, troca e avaliação de itens que os estudantes desejam disponibilizar sem custo.

Arquitetura e Tecnologias Utilizadas

O desenvolvimento do sistema emprega uma pilha tecnológica moderna e robusta.

Backend com Spring Boot

O framework Spring Boot é utilizado como base para o desenvolvimento do backend. Sua configuração automática e suporte a servidores embutidos como Tomcat simplificam consideravelmente o processo de implantação e desenvolvimento. A integração nativa com módulos do ecossistema Spring, como Spring Security para autenticação e Spring Data para acesso a dados, permite a construção rápida de uma aplicação segura e escalável.

Frontend com Vue.js

A camada de apresentação é construída com o framework Vue.js. Sua abordagem reativa e baseada em componentes permite a criação de interfaces de usuário dinâmicas e responsivas. A utilização do Virtual DOM otimiza as operações de renderização, proporcionando uma experiência fluida ao usuário final, onde as alterações nos dados refletem-se automaticamente na interface.

Camada de Persistência com MyBatis-Plus

Para o mapeamento objeto-relacional (ORM), o sistema utiliza o MyBatis-Plus, uma extensão poderosa do MyBatis. Esta ferramenta reduz significativamente a necessidade de escrever código boilerplate SQL, oferecendo uma API avançada para operações CRUD, consultas dinâmicas e paginnação. O gerador de código integrado acelera ainda mais o desenvolvimento ao criar automaticamente as classes de entidade e interfaces de mapeamento.

Processo de Testes do Sistema

A fase de testes é crucial para assegurar a qualidade e confiabilidade da aplicação. O foco principal reside nos testes funcionais (caixa preta), verificando se cada módulo opera conforme as especificações.

Estratégia de Teste para Login

O cenário de autenticação é rigorosamente testado. Os casos de teste incluem a verificação de credenciais corretas, senhas incorretas, usuários inexistentes, campos obrigatórios vazios e validação de captcha. Os resultados são comparados com os outputs esperados para garantir a robustez do processo de login.

Estratégia de Teste para Gerenciamento de Usuários

As operações CRUD (Criar, Ler, Atualizar, Deletar) no módulo de usuários são alvo de testes específicos. Verifica-se a validação de campos únicos (como nome de usuário), a integridade das operações de edição e a confirmação em ações de remoção. O objetivo é garantir que todas as funcionalidades de gerenciamento operem corretamente e apresentem mensagens de erro claras ao usuário.

Conclui-se que uma suíte de testes bem elaborada é indispensável. Ela não apenas valida a aderência aos requisitos funcionais, como também simula cenários de uso real, elevando a qualidade final e a experiência do usuário com o sistema.

Exemplos de Implementação

A seguir, são apresentados trechos ilustrativos da implementação.

Endpoint de Autenticação (Login)


@IgnoreAuth
@PostMapping("/autenticar")
public Resposta autenticar(String loginUsuario, String senha, String captcha, HttpServletRequest requisicao) {
    EntidadeUsuario usuario = servicoUsuario.buscarUm(new EnvolucroEntidade<EntidadeUsuario>().eq("login", loginUsuario));
    if (usuario == null || !usuario.getSenha().equals(senha)) {
        return Resposta.erro("Credenciais inválidas");
    }
    String jwtToken = servicoToken.gerarToken(usuario.getId(), loginUsuario, "usuarios", usuario.getPapel());
    return Resposta.ok().colocar("token", jwtToken);
}

@Override
public String gerarToken(Long idUsuario, String nomeUsuario, String tabelaPapel, String papel) {
    EntidadeToken tokenExistente = this.buscarUm(new EnvolucroEntidade<EntidadeToken>().eq("id_usuario", idUsuario).eq("papel", papel));
    String novoToken = UtilidadeComum.gerarStringAleatoria(32);
    Calendar calendario = Calendar.getInstance();
    calendario.add(Calendar.HOUR_OF_DAY, 1); // Expira em 1 hora
    Date dataExpiracao = calendario.getTime();

    if (tokenExistente != null) {
        tokenExistente.setToken(novoToken);
        tokenExistente.setDataExpiracao(dataExpiracao);
        this.atualizarPorId(tokenExistente);
    } else {
        this.inserir(new EntidadeToken(idUsuario, nomeUsuario, tabelaPapel, papel, novoToken, dataExpiracao));
    }
    return novoToken;
}

Interceptor de Autorização


@Component
public class InterceptorAutorizacao implements HandlerInterceptor {

    private static final String CABECALHO_TOKEN = "Authorization";

    @Autowired
    private ServicoToken servicoToken;

    @Override
    public boolean preHandle(HttpServletRequest requisicao, HttpServletResponse resposta, Object manipulador) throws Exception {
        // Configuração de CORS
        resposta.setHeader("Access-Control-Allow-Origin", requisicao.getHeader("Origin"));
        resposta.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        resposta.setHeader("Access-Control-Allow-Headers", CABECALHO_TOKEN + ", Content-Type");
        resposta.setHeader("Access-Control-Allow-Credentials", "true");

        // Pré-voo CORS (OPTIONS)
        if ("OPTIONS".equalsIgnoreCase(requisicao.getMethod())) {
            resposta.setStatus(HttpServletResponse.SC_OK);
            return false;
        }

        // Verificar anotação @IgnoreAuth
        if (manipulador instanceof HandlerMethod) {
            IgnoreAuth anotacao = ((HandlerMethod) manipulador).getMethodAnnotation(IgnoreAuth.class);
            if (anotacao != null) {
                return true; // Ignora a autenticação
            }
        }

        // Extrair e validar o token
        String tokenCabecalho = requisicao.getHeader(CABECALHO_TOKEN);
        if (StringUtils.isNotBlank(tokenCabecalho)) {
            EntidadeToken tokenValido = servicoToken.validarToken(tokenCabecalho);
            if (tokenValido != null) {
                // Define atributos na requisição para uso nos controllers
                requisicao.setAttribute("idUsuarioLogado", tokenValido.getIdUsuario());
                requisicao.setAttribute("papelUsuario", tokenValido.getPapel());
                return true;
            }
        }

        // Resposta de erro de autenticação
        resposta.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        resposta.setContentType("application/json;charset=UTF-8");
        resposta.getWriter().write("{\"erro\": \"Autenticação necessária\"}");
        return false;
    }
}

Estrutura de Banco de Dados para Tokens


-- Tabela para armazenar tokens de autenticação
CREATE TABLE tokens_auth (
    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT 'Chave primária',
    id_usuario BIGINT NOT NULL COMMENT 'ID do usuário associado',
    nome_usuario VARCHAR(100) NOT NULL COMMENT 'Nome de login do usuário',
    tabela_papel VARCHAR(100) COMMENT 'Tabela de referência do papel (ex: usuarios, alunos)',
    papel VARCHAR(50) COMMENT 'Papel do usuário no sistema',
    token VARCHAR(255) NOT NULL UNIQUE COMMENT 'Token JWT gerado',
    criado_em TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 'Data de criação',
    expira_em TIMESTAMP NOT NULL COMMENT 'Data e hora de expiração do token',
    INDEX idx_token (token),
    INDEX idx_usuario_papel (id_usuario, papel)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Tabela de gerenciamento de tokens de sessão';

Tags: Spring Boot Vue.js MyBatis-Plus jwt autenticacao

Publicado em 6-29 23:23