diff --git a/pom.xml b/pom.xml index f4e27e4..1d0c559 100644 --- a/pom.xml +++ b/pom.xml @@ -44,6 +44,11 @@ spring-boot-starter-test test + + org.projectlombok + lombok + true + diff --git a/src/main/java/br/com/codar/receitas/controller/NotFoundController.java b/src/main/java/br/com/codar/receitas/controller/NotFoundController.java new file mode 100644 index 0000000..777d4bf --- /dev/null +++ b/src/main/java/br/com/codar/receitas/controller/NotFoundController.java @@ -0,0 +1,15 @@ +package br.com.codar.receitas.controller; + +import org.springframework.boot.web.servlet.error.ErrorController; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; + +@Controller +public class NotFoundController implements ErrorController { + @RequestMapping("/error") + public String notFound(RedirectAttributes redirectAttributes) { + redirectAttributes.addFlashAttribute("messageError404", "Página não encontrada!"); + return "redirect:/receitas/lista"; + } +} diff --git a/src/main/java/br/com/codar/receitas/controller/ReceitaController.java b/src/main/java/br/com/codar/receitas/controller/ReceitaController.java new file mode 100644 index 0000000..5b3f455 --- /dev/null +++ b/src/main/java/br/com/codar/receitas/controller/ReceitaController.java @@ -0,0 +1,50 @@ +package br.com.codar.receitas.controller; +import br.com.codar.receitas.controller.form.ReceitaForm; +import br.com.codar.receitas.model.Receita; +import br.com.codar.receitas.service.ReceitaService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; + +import javax.validation.Valid; + +@Controller +@RequestMapping("receitas") +public class ReceitaController { + @Autowired + private ReceitaService receitaService; + + @GetMapping("lista") + public String lista(Model model) { + model.addAttribute("receitas", receitaService.listarSortData()); + return "lista-receitas"; + } + + @GetMapping("nova") + public String nova(ReceitaForm receitaForm) { + return "cadastro-receita"; + } + + @PostMapping + public String salvar(@Valid ReceitaForm receitaForm, BindingResult result, RedirectAttributes attributes) { + if (result.hasErrors()) { + return "cadastro-receita"; + } + Receita receitaSalva = receitaService.salvar(receitaForm.converter()); + attributes.addFlashAttribute("sucesso", "Receita salva com sucesso!"); + return "redirect:/receitas/nova"; + } + + @GetMapping("detalhe/{id}") + public String detalhe(@PathVariable(value = "id") Long id, Model model) { + model.addAttribute("receita", receitaService.buscarPorId(id)); + return "detalhe-receita"; + } + +} diff --git a/src/main/java/br/com/codar/receitas/controller/form/ReceitaForm.java b/src/main/java/br/com/codar/receitas/controller/form/ReceitaForm.java new file mode 100644 index 0000000..3f01b82 --- /dev/null +++ b/src/main/java/br/com/codar/receitas/controller/form/ReceitaForm.java @@ -0,0 +1,36 @@ +package br.com.codar.receitas.controller.form; + +import br.com.codar.receitas.model.Ingredientes; +import br.com.codar.receitas.model.Receita; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.*; +import java.util.List; + +@Data +@NoArgsConstructor +public class ReceitaForm { + @NotNull @NotEmpty + private String nome; + + private String linkFoto; + + @NotNull @Min(10) @Max(360) + private Integer tempoPreparo; + + @NotNull @Min(1) @Max(50) + private Integer rendimento; + + @NotEmpty + private List ingredientes; + + @NotNull @Size(min = 20, max = 1000) + private String modoPreparo; + private Boolean revisar; + + public Receita converter() { + return new Receita(nome, linkFoto, tempoPreparo, rendimento, ingredientes, modoPreparo, revisar); + } + +} diff --git a/src/main/java/br/com/codar/receitas/model/Ingredientes.java b/src/main/java/br/com/codar/receitas/model/Ingredientes.java new file mode 100644 index 0000000..ef8e81e --- /dev/null +++ b/src/main/java/br/com/codar/receitas/model/Ingredientes.java @@ -0,0 +1,32 @@ +package br.com.codar.receitas.model; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.*; +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Entity +@Data +@NoArgsConstructor +public class Ingredientes { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @NotNull @NotEmpty + private String nome; + @Min(1) @Max(1000) + private Integer quantidade; + @NotNull + @Enumerated(EnumType.STRING) + private Medida medida; + + public Ingredientes(String nome, Integer quantidade, Medida medida) { + setNome(nome); + setQuantidade(quantidade); + setMedida(medida); + } +} diff --git a/src/main/java/br/com/codar/receitas/model/Medida.java b/src/main/java/br/com/codar/receitas/model/Medida.java new file mode 100644 index 0000000..3d8f0eb --- /dev/null +++ b/src/main/java/br/com/codar/receitas/model/Medida.java @@ -0,0 +1,7 @@ +package br.com.codar.receitas.model; + +public enum Medida { + GRAMA, + MILILITRO, + UNIDADE; +} diff --git a/src/main/java/br/com/codar/receitas/model/Receita.java b/src/main/java/br/com/codar/receitas/model/Receita.java new file mode 100644 index 0000000..847d345 --- /dev/null +++ b/src/main/java/br/com/codar/receitas/model/Receita.java @@ -0,0 +1,39 @@ +package br.com.codar.receitas.model; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.*; +import java.time.LocalDateTime; +import java.util.List; + +@Entity +@Data +@NoArgsConstructor +public class Receita { + @Id + @GeneratedValue(strategy = javax.persistence.GenerationType.IDENTITY) + private Long id; + private String nome; + @Lob + private String linkFoto; + private Integer tempoPreparo; + private Integer rendimento; + @OneToMany(cascade = CascadeType.ALL) + private List ingredientes; + private LocalDateTime dataPublicacao = LocalDateTime.now(); + @Column(length = 1000) + private String modoPreparo; + private Boolean revisar; + + public Receita (String nome, String linkFoto, Integer tempoPreparo, Integer rendimento, List ingredientes, String modoPreparo, Boolean revisar) { + setNome(nome); + setLinkFoto(linkFoto); + setTempoPreparo(tempoPreparo); + setRendimento(rendimento); + setIngredientes(ingredientes); + setModoPreparo(modoPreparo); + setRevisar(revisar); + } + +} diff --git a/src/main/java/br/com/codar/receitas/repository/ReceitaRepository.java b/src/main/java/br/com/codar/receitas/repository/ReceitaRepository.java new file mode 100644 index 0000000..49f0654 --- /dev/null +++ b/src/main/java/br/com/codar/receitas/repository/ReceitaRepository.java @@ -0,0 +1,12 @@ +package br.com.codar.receitas.repository; + +import br.com.codar.receitas.model.Receita; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface ReceitaRepository extends JpaRepository { + List findAllByOrderByDataPublicacaoDesc(); +} diff --git a/src/main/java/br/com/codar/receitas/service/ReceitaService.java b/src/main/java/br/com/codar/receitas/service/ReceitaService.java new file mode 100644 index 0000000..5c1d331 --- /dev/null +++ b/src/main/java/br/com/codar/receitas/service/ReceitaService.java @@ -0,0 +1,26 @@ +package br.com.codar.receitas.service; + +import br.com.codar.receitas.model.Receita; +import br.com.codar.receitas.repository.ReceitaRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class ReceitaService { + @Autowired + private ReceitaRepository repository; + + public List listarSortData() { + return repository.findAllByOrderByDataPublicacaoDesc(); + } + + public Receita salvar(Receita receita) { + return repository.save(receita); + } + + public Receita buscarPorId(Long id) { + return repository.findById(id).get(); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 3469e0c..be2bb65 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -2,9 +2,12 @@ spring.datasource.url=jdbc:h2:mem:testdb spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa -spring.datasource.password=password +spring.datasource.password= # JPA / Hibernate spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=update spring.jpa.database-platform=org.hibernate.dialect.H2Dialect +spring.h2.console.enabled=true +spring.h2.console.path=/h2 +spring.jpa.defer-datasource-initialization=true diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql new file mode 100644 index 0000000..a8d9099 --- /dev/null +++ b/src/main/resources/data.sql @@ -0,0 +1,32 @@ +INSERT INTO INGREDIENTES (NOME, QUANTIDADE, MEDIDA) VALUES +('Lata de Leite Condensado', 1, 'UNIDADE'), +('Lata de Creme de Leite', 1, 'UNIDADE'), +('Feijão', 500, 'GRAMA'), +('Toucinho', 200, 'GRAMA'), +('Cebola média picada', 1, 'UNIDADE'), +('Dentes de alho', 4, 'UNIDADE'), +('Colher (sopa) de sal com alho', 1, 'UNIDADE'), +('Cheiro-verde a gosto', 1, 'UNIDADE'), +('Farinha de mandioca', 200, 'GRAMA'), +('Café solúvel', 50, 'GRAMA'), +('Xícaras de açúcar refinado', 2, 'UNIDADE'), +('Xícara de água', 1, 'UNIDADE'); + +INSERT INTO RECEITA (NOME, LINK_FOTO, TEMPO_PREPARO, RENDIMENTO, DATA_PUBLICACAO, MODO_PREPARO, REVISAR) VALUES +('MOUSSE DE LIMÃO', 'https://img.itdg.com.br/tdg/images/recipes/000/001/621/38640/38640_original.jpg?mode=crop&width=710&height=400', 10, 10, '2021-11-01 17:02:28.636254', 'Coloque no liquidificador o creme de leite (com soro mesmo) e o leite condensado. Bata um pouco e depois vá acrescentando o suco do limão, aos poucos. Ele vai ficar bem consistente, leve à geladeira.', FALSE), +('FEIJÃO TROPEIRO', 'https://img.itdg.com.br/tdg/images/recipes/000/000/961/327805/327805_original.jpg?mode=crop&width=540&height=400', 60, 6, '2021-11-05 07:32:28.636254', 'Coloque o óleo em uma panela e doure a cebola, acrescente o bacon e frite bem. Adicione o alho, sal e os ovos, misturando com cuidado para que não se despedacem muito. Refogue o feijão, baixe o fogo, misture a farinha aos poucos e o cheiro-verde.', FALSE), +('CAFÉ CREMOSO', 'https://img.itdg.com.br/tdg/images/recipes/000/011/486/140396/140396_original.jpg?mode=crop&width=710&height=400', 15, 15, '2021-12-01 15:16:28.636254', 'Junte todos os ingredientes e bata na batedeira durante 15 minutos até ficar um creme. Guarde no congelador em pote fechado. Este creme é para ser servido do seguinte modo: 1 colher de sobremesa em 1 xícara de café quente (já pronto) ou 2 colheres de sobremesa em 1 xícara de leite fervendo. Está pronta uma deliciosa bebida cremosa para aquecer as noites frias de inverno.', FALSE); + +INSERT INTO RECEITA_INGREDIENTES (RECEITA_ID, INGREDIENTES_ID) VALUES +(1, 1), +(1, 2), +(2, 3), +(2, 4), +(2, 5), +(2, 6), +(2, 7), +(2, 8), +(2, 9), +(3, 10), +(3, 11), +(3, 12); \ No newline at end of file diff --git a/src/main/resources/static/js/receita-ingrediente.js b/src/main/resources/static/js/receita-ingrediente.js index 2fb06e0..eaabcb0 100644 --- a/src/main/resources/static/js/receita-ingrediente.js +++ b/src/main/resources/static/js/receita-ingrediente.js @@ -10,7 +10,7 @@ function adicionarIngrediente() { let medida = $("#ingredientesMedida").val(); let deleteButton = "×" - if(nome && quantidade && medida) { + if(isValid(nome, quantidade, medida)) { let linha = "" + getCelula(nome, 'nome') + getCelula(quantidade, 'quantidade') + @@ -21,9 +21,16 @@ function adicionarIngrediente() { $("#tabelaIngredientes").append(linha); $('#ingredienteForm').trigger("reset"); $('#modalIngrediente').modal('hide'); + } else { + alert("Preencha todos os campos!"); } } + +function isValid(nome, quantidade, medida) { + return nome != "" && nome != null && quantidade >= 1 && quantidade <= 1000 && medida != "Selecione um tipo de medida..."; +} + function removerIngrediente(el) { $(el).closest("tr").remove(); } \ No newline at end of file diff --git a/src/main/resources/templates/cadastro-receita.html b/src/main/resources/templates/cadastro-receita.html index 1f981f1..668a2ef 100644 --- a/src/main/resources/templates/cadastro-receita.html +++ b/src/main/resources/templates/cadastro-receita.html @@ -8,15 +8,11 @@ - - Nova Receita - - Bem vindo, Usuário - + - + @@ -50,7 +46,6 @@ - Rendimento diff --git a/src/main/resources/templates/data.html b/src/main/resources/templates/data.html new file mode 100644 index 0000000..a1cf562 --- /dev/null +++ b/src/main/resources/templates/data.html @@ -0,0 +1,8 @@ + + +Receitas + Lista + Cadastro + + Bem vindo, Usuário + + \ No newline at end of file diff --git a/src/main/resources/templates/detalhe-receita.html b/src/main/resources/templates/detalhe-receita.html index 5f14783..30f1c2e 100644 --- a/src/main/resources/templates/detalhe-receita.html +++ b/src/main/resources/templates/detalhe-receita.html @@ -9,8 +9,7 @@ - - Receita - + diff --git a/src/main/resources/templates/lista-receitas.html b/src/main/resources/templates/lista-receitas.html index d419d1f..48fbc14 100644 --- a/src/main/resources/templates/lista-receitas.html +++ b/src/main/resources/templates/lista-receitas.html @@ -9,18 +9,25 @@ - - Portal de Receitas + + + + + + × + + + Nenhuma receita cadastrada! Receitas + th:each="receita : ${receitas}" th:if="${receita.revisar != true}">