- Visão Geral do Projeto: Uma Base Sólida para Sua Defesa de TCC
Ao orientar projetos de conclusão de curso, percebo que muitos alunos optam por sistemas de logística, mas acabam apresentando soluções superficiais. Este projeto, no entanto, foi concebido para ser uma base robusta, capaz de suportar questionamentos técnicos detalhados durante a defesa. Ele transcende um simples "demo funcional", oferecendo uma estrutura que reflete boas práticas de desenvolvimento de software corporativo.
Os diferenciais incluem a granularidade no controle de permissões de usuário (administrador, despachante, estoquista), o design transacional para alterações de status de transporte (garantindo atomicidade entre criação de pedido, baixa de estoque e emissão de nota fiscal) e otimizações de banco de dados, como a criação de índices compostos na tabela de logs de status de pedido. Estes pontos são cruciais para demonstrar um entendimento aprofundado do ciclo de vida do desenvolvimento em Java Web.
A escolha de tecnologias como Spring Boot e MyBatis não é apenas uma questão de popularidade, mas sim uma integração estratégica. O uso de @SelectProvider no MyBatis para consultas dinâmicas complexas, a fragmentação de layout em Thymeleaf com th:fragment e a configuração específica do pool de conexões HikariCP (maximumPoolSize) demonstram uma atenção aos detalhes que diferencia um projeto acadêmico de um projeto de software real. O objetivo é fornecer aos estudantes uma referência clara sobre como implementar um sistema corporativo de ponta a ponta, abordando desde a autenticação até a lógica de negócios específica da logística.
- Arquitetura e Tecnologias: A Lógica por Trás das Escolhas
2.1 Versão do Framework: Estabilidade e Compatibilidade
A escolha pelo Spring Boot 2.x (especificamente 2.7.x) em detrimento da versão 3.x foi uma decisão pragmática. O Spring Boot 2.x possui excelente compatibilidade com JDK 8 e MySQL 5.7, ambientes comuns em laboratórios e máquinas de estudantes. A atualização para o Spring Boot 3.x exigiria JDK 17+ e migração para Jakarta EE 9+, o que poderia consumir um tempo valioso do projeto em questões de compatibilidade e configuração de ambiente, em vez de focar na lógica de negócios.
As dependências no pom.xml são explicitamente definidas e bloqueadas para evitar conflitos:
<properties>
<java.version>1.8</java.version>
<spring-boot.version>2.7.18</spring-boot.version>
<mybatis-spring-boot-starter.version>2.2.2</mybatis-spring-boot-starter.version>
</properties>
Essa configuração garante que o projeto possa ser compilado e executado em diferentes sistemas operacionais e IDEs, desde que o JDK 8 e o MySQL 5.7 estejam instalados.
2.2 Camada de Persistência: MyBatis como Ferramenta Pedagógica
Optou-se pelo MyBatis em vez do Spring Data JPA por razões pedagógicas. Enquanto o JPA abstrai grande parte da escrita de SQL, o MyBatis exige que o desenvolvedor escreva as consultas explicitamente. Isso é vantajoso para o aprendizado, pois força a compreensão de conceitos como otimização de SQL, identificação de consultas N+1 e níveis de isolamento de transação.
Um exemplo é a consulta de mercadorias por múltiplos critérios:
<!-- src/main/resources/mapper/GoodsMapper.xml -->
<select id="selectByConditions" resultType="com.example.logistics.entity.Goods">
SELECT id, name, type, weight, volume, warehouse_id, status, create_time
FROM goods
WHERE status = 1
<if test="type != null and type != ''">
AND type LIKE CONCAT('%', #{type}, '%')
</if>
<if test="startTime != null">
AND create_time >= #{startTime}
</if>
</select>
Este trecho demonstra o uso de SQL dinâmico com <if> para evitar injeção de SQL (usando #{} em vez de ${}) e a lógica de "soft delete" (filtrando por status = 1).
2.3 Frontend: Thymeleaf como Solução Eficiente
A combinação Thymeleaf + HTML foi escolhida pela sua simplicidade de configuração e integração direta com o Spring Boot. Diferente de frameworks como Vue.js ou React, o Thymeleaf não exige um ambiente de build separado (Node.js, npm, webpack), permitindo que a aplicação seja iniciada rapidamente. A renderização do lado do servidor simplifica a separação de responsabilidades entre frontend e backend, alinhado com o padrão MVC.
Recursos como th:each para iteração de listas e th:fragment para reutilização de componentes de template tornam o desenvolvimento mais organizado e eficiente.
2.4 Banco de Dados: MySQL 5.7 como Padrão Acessível
A exigência de MySQL 5.7+ visa garantir a compatibilidade com a maioria dos ambientes de desenvolvimento e laboratórios acadêmicos. O MySQL 8.0 introduziu o plugin de autenticação caching\_sha2\_password, que pode causar problemas de compatibilidade com drivers JDBC mais antigos. O projeto utiliza o driver mysql-connector-java:8.0.28, que suporta ambas as versões.
A escolha de VARCHAR(255) para o campo address na tabela warehouse em vez de TEXT (em versões mais antigas do MySQL) e o uso de TINYINT(2) para códigos de status em vez de ENUM são exemplos de considerações práticas para otimizar o desempenho e a compatibilidade.
- Módulos Principais e Pontos de Atenção
3.1 Autenticação e Autorização: Controle de Acesso Baseado em Sessão
O módulo de login implementa autenticação via formulário com validação de senha criptografada usando BCryptPasswordEncoder. As permissões são gerenciadas através de atributos na sessão HTTP (session.setAttribute("role", user.getRole())). Controllers subsequentes verificam o papel do usuário na sessão para determinar o acesso a funcionalidades específicas.
@PostMapping("/login")
public String login(@RequestParam String username, @RequestParam String password, Model model) {
User user = userService.findByUsername(username);
if (user != null && passwordEncoder.matches(password, user.getPassword())) {
session.setAttribute("user", user);
session.setAttribute("role", user.getRole()); // Armazena o papel do usuário
return "redirect:/dashboard";
}
model.addAttribute("error", "Usuário ou senha inválidos");
return "login";
}
@GetMapping("/create")
public String createOrder(Model model, HttpSession session) {
String role = (String) session.getAttribute("role");
// Verifica se o usuário tem permissão para criar pedidos
if (!"admin".equals(role) && !"scheduler".equals(role)) {
return "redirect:/unauthorized"; // Redireciona para página de acesso não autorizado
}
model.addAttribute("warehouses", warehouseService.findAll());
return "order/create";
}
Essa abordagem baseada em sessão é adequada para aplicações monolíticas e simplifica a demonstração do controle de acesso em um contexto acadêmico.
3.2 Gestão de Mercadorias e Armazéns: Integridade Referencial e Lógica de Negócios
A relação entre mercadorias e armazéns é gerenciada através de uma chave estrangeira (warehouse\_id). A exclusão de um armazém é implementada como "soft delete" (atualizando o status para inativo) para preservar o histórico das mercadorias associadas. A criação de mercadorias exige que o armazém esteja ativo e exista, garantindo a integridade dos dados.
@Transactional
public void saveGoods(Goods goods) {
Warehouse warehouse = warehouseService.findById(goods.getWarehouseId());
if (warehouse == null || warehouse.getStatus() != 1) {
throw new RuntimeException("Armazém inexistente ou inativo");
}
goods.setStatus(1); // Mercadoria ativa por padrão
goods.setCreateTime(new Date());
goodsMapper.insert(goods);
}
A anotação @Transactional garante a atomicidade das operações de verificação de armazém e inserção de mercadoria.
3.3 Ciclo de Vida do Pedido: Gerenciamento Transacional e Rastreabilidade
O sistema gerencia o ciclo de vida completo de um pedido, incluindo criação, atualização de status e rastreamento. Tabelas separadas para order (informações principais) e order\_status\_log (histórico de status) garantem rastreabilidade e evitam contenção em atualizações de status.
A criação de um pedido envolve a dedução de estoque (com bloqueio pessimista SELECT ... FOR UPDATE para evitar overselling), a inserção do pedido principal e o registro do status inicial.
@Transactional
public Order createOrder(Order order, List<OrderItem> items) {
// Deduz o estoque com bloqueio pessimista
goodsMapper.decreaseStock(order.getGoodsId(), order.getQuantity());
// Cria o registro principal do pedido
orderMapper.insert(order);
// Cria os itens do pedido
orderItemMapper.insertBatch(items);
// Registra o status inicial
statusLogMapper.insert(new StatusLog(order.getId(), "Pendente", "Sistema"));
return order;
}
Atualizações de status incluem validação de transição (garantindo que o status avance logicamente) e registro no log.
3.4 Rastreamento de Transporte: Abordagem de Polling para Simplicidade
Em vez de implementar soluções complexas como WebSockets, o rastreamento de transporte utiliza uma abordagem de polling (requisições AJAX periódicas). O frontend consulta o backend a cada 10 segundos para obter as atualizações mais recentes do log de status.
// No frontend (JavaScript)
function loadTrackData() {
fetch('/order/track?id=' + orderId)
.then(response => response.json())
.then(data => {
// Atualiza a lista de logs no HTML
// ...
});
}
setInterval(loadTrackData, 10000); // Refresca a cada 10 segundos
// No backend (OrderController)
@GetMapping("/track")
@ResponseBody
public List<StatusLog> getTrack(@RequestParam Long id) {
return statusLogMapper.selectByOrderId(id);
}
Essa abordagem simplificada é ideal para projetos acadêmicos, priorizando a funcionalidade e a facilidade de implementação.
- Implantação Local e Debugging
4.1 Preparação do Ambiente
JDK 8: Certifique-se de que a variável de ambiente JAVA\_HOME aponta para o diretório JDK (não JRE) e que o PATH inclui %JAVA\_HOME%\\bin.
MySQL 5.7: Configure o banco de dados e as tabelas para usar utf8mb4 como character set padrão para evitar problemas com caracteres especiais.
IDE (IntelliJ IDEA/Eclipse): Importe o projeto como um projeto Maven existente, selecionando o pom.xml e certificando-se de que o SDK do projeto está configurado corretamente (JDK 8).
4.2 Inicialização do Banco de Dados
Execute os scripts SQL localizados em src/main/resources/sql/ na seguinte ordem: init.sql (criação de tabelas) e, em seguida, data.sql (inserção de dados básicos).
4.3 Execução e Debugging
Inicie a aplicação usando o comando Maven wrapper: ./mvnw spring-boot:run (Linux/Mac) ou mvnw.cmd spring-boot:run (Windows).
Para debugging, utilize os recursos da IDE definindo breakpoints em pontos chave do fluxo de execução (Controllers, Services, Mappers) para entender o fluxo de dados.
- Perguntas Frequentes e Solução de Problemas
- Erro de porta ocupada: Altere a porta no arquivo
application.ymlou finalize o processo que está usando a porta 8080. - Falha na conexão com o banco de dados: Verifique as credenciais (usuário, senha), URL do banco e se o serviço MySQL está em execução. Confirme também o character set do MySQL.
- Erro ao encontrar templates Thymeleaf: Verifique se os arquivos HTML estão no diretório correto (
src/main/resources/templates) e se os nomes coincidem exatamente (sensível a maiúsculas/minúsculas).
- Sugestões para Evolução do Projeto
Para transformar este projeto de referência em um trabalho original, considere:
- Visualização de Dados: Integrar bibliotecas como ECharts ou Chart.js para criar dashboards com gráficos (ex: volume de pedidos por hora, distribuição de mercadorias por armazém).
- Permissões Granulares: Implementar controle de acesso baseado em atributos (ABAC) para permitir que usuários vejam apenas os dados relevantes para sua função (ex: um estoquista só visualiza mercadorias do seu próprio armazém).
- Monitoramento: Adicionar o Spring Boot Actuator para expor métricas de saúde, uso de memória e contagem de requisições HTTP, facilitando o monitoramento em ambiente de produção.