Apesar da aplicação estar funcionando isso não significa que temos um bom código criado. O código atual possui diversas responsabilidades, como por exemplo, a validação dos dados, a persistência dos dados e a exibição dos dados. Isso é um problema, pois dificulta a manutenção e a evolução da aplicação. Além de que, quando trabalhamos com código trabalhamos em equipe, ou seja, outras pessoas precisarão entender o código e fazer alterações. Por isso, é importante que o código seja bem organizado e cada parte do código tenha sua responsabilidade bem definida.
A primeira parte é com relação ao Controller criado. Atualmente ele tem muitas responsabilidades. Ele está responsável por manipular a fonte de dados da aplicação - a lista de produtos, receber as requisições e enviar os dados para a visão. Isso é um problema grave.
A primeira modificação importante é que a manipulação da fonte de dados não deve ser realizada pelo controlador. Por enquanto nossa fonte de dados é apenas uma lista, mas em uma aplicação real a fonte de dados pode ser um banco de dados, um arquivo, uma API, etc. Por isso, é importante que a manipulação da fonte de dados seja realizada por uma camada específica para isso. Essa camada é chamada de repositório.
O repositório é uma classe que possui a responsabilidade de manipular a fonte de dados da aplicação. Para isso, ele possui métodos para adicionar, remover, atualizar e buscar os dados. Esses métodos são conhecidos pelo acrônimo CRUD de Create, Read, Update e Delete.
Não esqueça: O repositório é o responsável por realizar as operações CRUD na fonte de dados da aplicação.
Para criar o repositório, crie uma nova classe chamada ProductRepository
. Aproveite para separar os diferentes tipos de arquivos em suas respectivas pastas. Crie o repositório dentro de uma pasta repository
.
Essa classe deve possuir um atributo privado do tipo List<Product>
que será a fonte de dados da aplicação. Além disso, a classe deve possuir os métodos CRUD para manipular os objetos dessa lista.
1public class ProductRepository {2
3 private List<Product> products = new ArrayList<>();4
5 public List<Product> findAll() {6 return products;7 }8
9 public void save(Product product) {10 products.add(product);11 }12
13 public void update(Product product) {14 Product productToUpdate = findById(product.getId());15 productToUpdate.setName(product.getName());16 productToUpdate.setPrice(product.getPrice());17 productToUpdate.setDescription(product.getDescription());18 }19
20 public void delete(String id) {21 Product productToDelete = findById(id);22 products.remove(productToDelete);23 }24
25 public Product findById(String id) {26 for (Product product : products) {27 if (product.getId().equals(id)) {28 return product;29 }30 }31 return null;32 }33
34}
No total foram criados 5 métodos. O método findAll
retorna todos os produtos da lista. O método save
adiciona um novo produto na lista. O método update
atualiza um produto existente na lista. O método delete
remove um produto da lista. E o método findById
busca um produto pelo seu id. Perceba que toda a manipulação da lista é feita dentro do repositório. O controlador não precisa e nem deve se preocupar com isso.
Agora que o repositório foi criado, é necessário utilizá-lo no controlador. Para isso, é necessário criar um atributo do tipo ProductRepository
no controlador e inicializá-lo no construtor. Além disso, é necessário alterar os métodos do controlador para que eles utilizem o repositório para manipular a fonte de dados.
1@Controller2public class ProductController {3
4 private ProductRepository productRepository = new ProductRepository();5
6 @GetMapping("/products")7 public String index(Model model) {8 model.addAttribute("products", productRepository.findAll());9 return "list";10 }11
12 @GetMapping("/products/create")13 public String create(Model model) {14 Product product = new Product();15 model.addAttribute("product", product);16 return "create";17 }18
19 @PostMapping("/products/store")20 public String store(@Valid Product product, BindingResult result) {21 if (result.hasErrors()) { return "create"; }22 productRepository.save(product);23 return "redirect:/products";24 }25
26 @GetMapping("/products/show")27 public String show(Model model, @RequestParam("id") String id){28 Product product = productRepository.findById(id);29 model.addAttribute("product", product);30 return "show";31 }32
33 @GetMapping("/products/edit")34 public String edit(Model model, @RequestParam("id") String id){35 Product product = productRepository.findById(id);36 model.addAttribute("product", product);37 return "edit";38 }39
40 @PostMapping("/products/update")41 public String update(Product product){42 productRepository.update(product);43 return "redirect:/products";44 }45
46 @GetMapping("/products/delete")47 public String delete(@RequestParam("id") String id){48 productRepository.delete(id);49 return "redirect:/products";50 }51
52}
Três grandes modificações foram feitas no controlador. Primeiramente foi criado o atributo productRepository
que é inicializado no construtor. Depois, todos os métodos que manipulavam a lista de produtos foram alterados para que utilizem os métodos implementados no repositório. Por fim o método findProductById
foi movido para o repositório. Perceba que o controlador ficou mais simples e com menos responsabilidades.
O controlador não deve se preocupar com a manipulação da fonte de dados. Ele deve ser responsável apenas por receber as requisições e enviar os dados para a visão.
Por fim teste a aplicação e certifique-se que ela continua funcionando.