diff --git a/.gitignore b/.gitignore index 549e00a..3ce7ebf 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,7 @@ build/ ### VS Code ### .vscode/ + +.mvn +target + diff --git a/pom.xml b/pom.xml index f4e27e4..d7ace11 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.springframework.boot spring-boot-starter-parent 2.6.0 - + br.com.codar receitas @@ -33,7 +33,6 @@ org.springframework.boot spring-boot-starter-web - com.h2database h2 diff --git a/src/main/java/br/com/codar/receitas/ReceitasApplication.java b/src/main/java/br/com/codar/receitas/ReceitasApplication.java index 15af552..bb45467 100644 --- a/src/main/java/br/com/codar/receitas/ReceitasApplication.java +++ b/src/main/java/br/com/codar/receitas/ReceitasApplication.java @@ -2,10 +2,29 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.MessageSource; +import org.springframework.context.annotation.Bean; +import org.springframework.context.support.ReloadableResourceBundleMessageSource; +import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; @SpringBootApplication public class ReceitasApplication { + @Bean + public MessageSource messageSource() { + ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource(); + messageSource.setBasename("classpath:messages"); + messageSource.setDefaultEncoding("UTF-8"); + return messageSource; + } + + @Bean + public LocalValidatorFactoryBean validator() { + LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean(); + bean.setValidationMessageSource(messageSource()); + return bean; + } + public static void main(String[] args) { SpringApplication.run(ReceitasApplication.class, args); } diff --git a/src/main/java/br/com/codar/receitas/controller/ReceitasController.java b/src/main/java/br/com/codar/receitas/controller/ReceitasController.java new file mode 100644 index 0000000..ad7fe6d --- /dev/null +++ b/src/main/java/br/com/codar/receitas/controller/ReceitasController.java @@ -0,0 +1,79 @@ +package br.com.codar.receitas.controller; + +import br.com.codar.receitas.controller.dto.DetalheReceitaDto; +import br.com.codar.receitas.controller.dto.ListaReceitaDto; +import br.com.codar.receitas.controller.form.IngredienteForm; +import br.com.codar.receitas.controller.form.ReceitaForm; +import br.com.codar.receitas.model.Receita; + +import br.com.codar.receitas.repository.IngredienteRepository; +import br.com.codar.receitas.repository.ReceitaRepository; +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.*; + +import javax.validation.Valid; +import java.util.List; +import java.util.Optional; + +@Controller +@RequestMapping(value = "/receitas", produces = "application/json") +public class ReceitasController { + + @Autowired + private ReceitaRepository receitaRepository; + + @Autowired + private IngredienteRepository ingredienteRepository; + + @GetMapping( + value = "/nova", + produces="application/json" + ) + public String nova(Model model){ + model.addAttribute("receitaForm", new ReceitaForm()); + return "receitas/nova"; + } + + @GetMapping("/lista") + public String listaReceita(Model model){ + List receitas = receitaRepository.findByRevisarFalseAndOrderByDateDesc(); + + model.addAttribute("receitas", ListaReceitaDto.converter(receitas)); + return "receitas/lista"; + } + + @PostMapping + public String cadastrar(@Valid ReceitaForm receitaForm, BindingResult resultReceitaForm, Model model) { + + if(resultReceitaForm.hasErrors()) { + model.addAttribute("sucesso", false); + return "receitas/nova"; + } + + Receita receita = receitaForm.converter(ingredienteRepository); + receitaRepository.save(receita); + + model.addAttribute("sucesso", "Receita inserida com sucesso!"); + ReceitaForm receitaFormNovo = new ReceitaForm(); + model.addAttribute("receitaForm", receitaFormNovo); + return "receitas/nova"; + } + + @GetMapping("/detalhe/{id}") + public String detalhar(@PathVariable Long id, Model model) { + Optional receita = receitaRepository.findById(id); + if (!receita.isEmpty()) { + model.addAttribute("receita", new DetalheReceitaDto(receita.get())); + return "receitas/detalhe"; + } + return "receitas/lista"; + } + + @ExceptionHandler(IllegalArgumentException.class) + public String onError() { + return "redirect:/receitas/lista"; + } +} diff --git a/src/main/java/br/com/codar/receitas/controller/dto/DetalheReceitaDto.java b/src/main/java/br/com/codar/receitas/controller/dto/DetalheReceitaDto.java new file mode 100644 index 0000000..3d5e245 --- /dev/null +++ b/src/main/java/br/com/codar/receitas/controller/dto/DetalheReceitaDto.java @@ -0,0 +1,63 @@ +package br.com.codar.receitas.controller.dto; + +import br.com.codar.receitas.model.Receita; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class DetalheReceitaDto { + private Long id; + private String nome; + private String linkFoto; + private Integer tempoPreparo; + private Integer rendimento; + private String modoPreparo; + private List ingredientes; + private LocalDateTime dataPublicacao; + + public DetalheReceitaDto(Receita receita) { + this.id = receita.getId(); + this.nome = receita.getNome(); + this.linkFoto = receita.getLinkFoto(); + this.tempoPreparo = receita.getTempoPreparo(); + this.rendimento = receita.getRendimento(); + this.modoPreparo = receita.getModoPreparo(); + this.ingredientes = new ArrayList<>(); + this.ingredientes.addAll(receita.getIngredientes().stream().map(IngredienteDto::new).collect(Collectors.toList())); + this.dataPublicacao = receita.getDataPublicacao(); + } + + public Long getId() { + return id; + } + + public String getNome() { + return nome; + } + + public String getLinkFoto() { + return linkFoto; + } + + public Integer getTempoPreparo() { + return tempoPreparo; + } + + public Integer getRendimento() { + return rendimento; + } + + public String getModoPreparo() { + return modoPreparo; + } + + public List getIngredientes() { + return ingredientes; + } + + public LocalDateTime getDataPublicacao() { + return dataPublicacao; + } +} diff --git a/src/main/java/br/com/codar/receitas/controller/dto/IngredienteDto.java b/src/main/java/br/com/codar/receitas/controller/dto/IngredienteDto.java new file mode 100644 index 0000000..87139ba --- /dev/null +++ b/src/main/java/br/com/codar/receitas/controller/dto/IngredienteDto.java @@ -0,0 +1,40 @@ +package br.com.codar.receitas.controller.dto; + +import br.com.codar.receitas.model.Ingrediente; +import br.com.codar.receitas.model.Medida; + +public class IngredienteDto { + private String nome; + private Integer quantidade; + private Medida medida; + + public IngredienteDto(Ingrediente ingrediente) { + this.nome = ingrediente.getNome(); + this.quantidade = ingrediente.getQuantidade(); + this.medida = ingrediente.getMedida(); + } + + public String getNome() { + return nome; + } + + public void setNome(String nome) { + this.nome = nome; + } + + public Integer getQuantidade() { + return quantidade; + } + + public void setQuantidade(Integer quantidade) { + this.quantidade = quantidade; + } + + public Medida getMedida() { + return medida; + } + + public void setMedida(Medida medida) { + this.medida = medida; + } +} diff --git a/src/main/java/br/com/codar/receitas/controller/dto/ListaReceitaDto.java b/src/main/java/br/com/codar/receitas/controller/dto/ListaReceitaDto.java new file mode 100644 index 0000000..9e81a39 --- /dev/null +++ b/src/main/java/br/com/codar/receitas/controller/dto/ListaReceitaDto.java @@ -0,0 +1,54 @@ +package br.com.codar.receitas.controller.dto; + +import br.com.codar.receitas.model.Receita; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; + +public class ListaReceitaDto { + + private Long id; + private String nome; + private String linkFoto; + private Integer tempoPreparo; + private Integer rendimento; + private LocalDateTime dataPublicacao; + + public ListaReceitaDto(Receita receita){ + this.id = receita.getId(); + this.nome = receita.getNome(); + this.linkFoto = receita.getLinkFoto(); + this.tempoPreparo = receita.getTempoPreparo(); + this.rendimento = receita.getRendimento(); + this.dataPublicacao = receita.getDataPublicacao(); + } + + public Long getId() { + return id; + } + + public String getNome() { + return nome; + } + + public String getLinkFoto() { + return linkFoto; + } + + public Integer getTempoPreparo() { + return tempoPreparo; + } + + public Integer getRendimento() { + return rendimento; + } + + public LocalDateTime getDataPublicacao() { + return dataPublicacao; + } + + public static List converter(List receitas) { + return receitas.stream().map(ListaReceitaDto::new).collect(Collectors.toList()); + } +} diff --git a/src/main/java/br/com/codar/receitas/controller/form/IngredienteForm.java b/src/main/java/br/com/codar/receitas/controller/form/IngredienteForm.java new file mode 100644 index 0000000..ff1acfc --- /dev/null +++ b/src/main/java/br/com/codar/receitas/controller/form/IngredienteForm.java @@ -0,0 +1,54 @@ +package br.com.codar.receitas.controller.form; + +import br.com.codar.receitas.model.Ingrediente; +import br.com.codar.receitas.model.Medida; + +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.validation.constraints.*; + +public class IngredienteForm { + @NotBlank(message = "{nomeIngrediente.NotBlank}") + private String nome; + @NotNull(message = "{quantidadeIngrediente.NotNull}") @Min(value = 1, message = "{quantidadeIngrediente.MinMax}") @Max(value = 1000, message = "{quantidadeIngrediente.MinMax}") + private Integer quantidade; + @NotNull(message = "{medidaIngrediente.NotNull}") @Enumerated(EnumType.STRING) + private Medida medida; + + public IngredienteForm() { + } + + public IngredienteForm(String nome, Integer quantidade, Medida medida) { + this.nome = nome; + this.quantidade = quantidade; + this.medida = medida; + } + + public String getNome() { + return nome; + } + + public Integer getQuantidade() { + return quantidade; + } + + public Medida getMedida() { + return medida; + } + + public void setNome(String nome) { + this.nome = nome; + } + + public void setQuantidade(Integer quantidade) { + this.quantidade = quantidade; + } + + public void setMedida(Medida medida) { + this.medida = medida; + } + + public Ingrediente converter() { + return new Ingrediente(this.nome, this.quantidade, this.medida); + } +} 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..e73f77f --- /dev/null +++ b/src/main/java/br/com/codar/receitas/controller/form/ReceitaForm.java @@ -0,0 +1,96 @@ +package br.com.codar.receitas.controller.form; + +import br.com.codar.receitas.model.Ingrediente; +import br.com.codar.receitas.model.Receita; +import br.com.codar.receitas.repository.IngredienteRepository; +import org.hibernate.validator.constraints.Length; + +import javax.validation.Valid; +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.*; +import java.util.ArrayList; +import java.util.List; + +public class ReceitaForm { + + @NotBlank(message = "{nomeReceita.NotBlank}") + private String nome; + private String linkFoto; + @NotNull(message = "{tempoPreparo.NotNull}") @Min(value = 10, message = "{tempoPreparo.MinMax}") @Max(value = 360, message = "{tempoPreparo.MinMax}") + private Integer tempoPreparo; + @NotNull(message = "{rendimento.NotNull}") @Min(value = 1, message = "{rendimento.MinMax}") @Max(value = 50, message = "{rendimento.MinMax}") + private Integer rendimento; + @NotBlank(message = "{modoPreparo.NotBlank}") @Length(min = 20, message = "{modoPreparo.Length}") + private String modoPreparo; + private Boolean revisar; + @NotNull(message = "{listaIngrediente.NotNull}") @Valid + private List ingredientes; + + public ReceitaForm() { + } + + public String getNome() { + return nome; + } + + public void setNome(String nome) { + this.nome = nome; + } + + public String getLinkFoto() { + return linkFoto; + } + + public void setLinkFoto(String linkFoto) { + this.linkFoto = linkFoto; + } + + public Integer getTempoPreparo() { + return tempoPreparo; + } + + public void setTempoPreparo(Integer tempoPreparo) { + this.tempoPreparo = tempoPreparo; + } + + public Integer getRendimento() { + return rendimento; + } + + public void setRendimento(Integer rendimento) { + this.rendimento = rendimento; + } + + public String getModoPreparo() { + return modoPreparo; + } + + public void setModoPreparo(String modoPreparo) { + this.modoPreparo = modoPreparo; + } + + public Boolean getRevisar() { + return revisar; + } + + public void setRevisar(Boolean revisar) { + this.revisar = revisar; + } + + public List getIngredientes() { + return ingredientes; + } + + public void setIngredientes(List ingredientes) { + this.ingredientes = ingredientes; + } + + public Receita converter(IngredienteRepository ingredienteRepository) { + List listaIngredientes = new ArrayList<>(); + this.ingredientes.forEach(i -> listaIngredientes.add(i.converter())); + listaIngredientes.forEach(i -> ingredienteRepository.save(i)); + return new Receita(this.nome, this.linkFoto, this.tempoPreparo, this.rendimento, this.modoPreparo, this.revisar, listaIngredientes); + } + +} diff --git a/src/main/java/br/com/codar/receitas/model/Ingrediente.java b/src/main/java/br/com/codar/receitas/model/Ingrediente.java new file mode 100644 index 0000000..20986d0 --- /dev/null +++ b/src/main/java/br/com/codar/receitas/model/Ingrediente.java @@ -0,0 +1,40 @@ +package br.com.codar.receitas.model; + +import javax.persistence.*; + +@Entity +@Table(name = "ingredientes") +public class Ingrediente { + + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String nome; + private Integer quantidade; + @Enumerated(EnumType.STRING) + private Medida medida; + + public Ingrediente() { + } + + public Ingrediente(String nome, Integer quantidade, Medida medida) { + this.nome = nome; + this.quantidade = quantidade; + this.medida = medida; + } + + public Long getId() { + return id; + } + + public String getNome() { + return nome; + } + + public Integer getQuantidade() { + return quantidade; + } + + public Medida getMedida() { + return 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..b1a82d7 --- /dev/null +++ b/src/main/java/br/com/codar/receitas/model/Medida.java @@ -0,0 +1,5 @@ +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..0d299be --- /dev/null +++ b/src/main/java/br/com/codar/receitas/model/Receita.java @@ -0,0 +1,67 @@ +package br.com.codar.receitas.model; + +import javax.persistence.*; +import java.time.LocalDateTime; +import java.util.List; + +@Entity +@Table(name = "receitas") +public class Receita { + + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String nome; + private String linkFoto; + private Integer tempoPreparo; + private Integer rendimento; + private String modoPreparo; + private Boolean revisar; + @OneToMany + private List ingredientes; + private LocalDateTime dataPublicacao = LocalDateTime.now(); + + public Receita() { + } + + public Receita(String nome, String linkFoto, Integer tempoPreparo, Integer rendimento, String modoPreparo, Boolean revisar, List ingredientes) { + this.nome = nome; + this.linkFoto = linkFoto; + this.tempoPreparo = tempoPreparo; + this.rendimento = rendimento; + this.modoPreparo = modoPreparo; + this.revisar = revisar; + this.ingredientes = ingredientes; + } + + public Long getId() { + return id; + } + + public String getNome() { + return nome; + } + + public String getLinkFoto() { + return linkFoto; + } + + public Integer getTempoPreparo() { + return tempoPreparo; + } + + public Integer getRendimento() { + return rendimento; + } + + public String getModoPreparo() { + return modoPreparo; + } + + public List getIngredientes() { + return ingredientes; + } + + public LocalDateTime getDataPublicacao() { + return dataPublicacao; + } +} diff --git a/src/main/java/br/com/codar/receitas/repository/IngredienteRepository.java b/src/main/java/br/com/codar/receitas/repository/IngredienteRepository.java new file mode 100644 index 0000000..ef4a585 --- /dev/null +++ b/src/main/java/br/com/codar/receitas/repository/IngredienteRepository.java @@ -0,0 +1,7 @@ +package br.com.codar.receitas.repository; + +import br.com.codar.receitas.model.Ingrediente; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface IngredienteRepository extends JpaRepository { +} 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..43d8ef4 --- /dev/null +++ b/src/main/java/br/com/codar/receitas/repository/ReceitaRepository.java @@ -0,0 +1,14 @@ +package br.com.codar.receitas.repository; + +import br.com.codar.receitas.model.Receita; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +import java.util.List; + +public interface ReceitaRepository extends JpaRepository { + + @Query(value = "SELECT * FROM RECEITAS r WHERE r.REVISAR = FALSE ORDER BY r.DATA_PUBLICACAO DESC", + nativeQuery = true) + List findByRevisarFalseAndOrderByDateDesc(); +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 3469e0c..e8f4b46 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,10 +1,20 @@ # Datasource (H2 em memória) -spring.datasource.url=jdbc:h2:mem:testdb +spring.datasource.url=jdbc:h2:mem:livrodereceitas spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password=password +spring.h2.console.enabled=true +spring.h2.console.path=/h2-console + +spring.jpa.defer-datasource-initialization=true # JPA / Hibernate spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=update +spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.ImproveNamingStrategy spring.jpa.database-platform=org.hibernate.dialect.H2Dialect + +spring.thymeleaf.cache=false +spring.thymeleaf.enabled=true +spring.thymeleaf.prefix=classpath:/templates/ +spring.thymeleaf.suffix=.html \ No newline at end of file diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql new file mode 100644 index 0000000..9b873bc --- /dev/null +++ b/src/main/resources/data.sql @@ -0,0 +1,45 @@ +INSERT INTO INGREDIENTES +(nome, quantidade, medida) +VALUES +('Chocolate', 200, 'GRAMA'), +('Farinha', 500, 'GRAMA'), +('Ovos', 2, 'UNIDADE'), +('Leite', 100, 'MILILITRO'), +('Açucar', 100, 'GRAMA'), +('Massa para lasanha', 500, 'GRAMA'), +('Molho', 200, 'MILILITRO'), +('Carne moída', 400, 'GRAMA'), +('Queijo', 300, 'GRAMA'); + + +INSERT INTO RECEITAS +(nome, link_foto, tempo_preparo, rendimento, modo_preparo, +revisar, data_publicacao) +VALUES('Brownie de chocolate', +'https://img.estadao.com.br/fotos/crop/1200x1200/resources/jpg/7/0/1519841184607.jpg', +40, +8, +'Em uma tigela coloque os ovos e o açúcar e bata com a ajuda de fouet ou garfo, em seguida adicione chocolate e depois adicione a farinha até que fique homogênea; Despeje a massa em uma forma untada e asse em forno pré-aquecido a 180ºC por 35 minutos.', +FALSE, +TO_DATE('17/12/2015', 'DD/MM/YYYY')), +('Lasanha', +'https://i.ytimg.com/vi/FrdumyhYaZY/maxresdefault.jpg', +40, +8, +'Cozinhe a massa da lasanha e o molho. Em uma forma coloque uma camada de massa, uma camada de molho, uma camada de carne moída e uma camada de queijo até acabarem os ingredientes, finalize com queijo e asse por 20 minutos.', +FALSE, +CURRENT_TIMESTAMP); + +INSERT INTO RECEITAS_INGREDIENTES +(receita_id, ingredientes_id) +VALUES +(1,1), +(1,2), +(1,3), +(1,4), +(1,5), +(2,6), +(2,7), +(2,8), +(2,9); + diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties new file mode 100644 index 0000000..e1d470d --- /dev/null +++ b/src/main/resources/messages.properties @@ -0,0 +1,12 @@ +nomeReceita.NotBlank=O campo nome da receita é obrigatório +tempoPreparo.NotNull=O campo tempo de preparo é obrigatório +tempoPreparo.MinMax=O campo tempo de preparo deve estar entre 1 e 360 minutos +rendimento.NotNull=O campo rendimento é obrigatório +rendimento.MinMax=O campo rendimento deve estar entre 1 e 50 porções +modoPreparo.NotBlank=O campo modo de preparo é obrigatório +modoPreparo.Length=O campo modo de preparo precisa ter no mínimo 20 caracteres +listaIngrediente.NotNull=É obrigatório pelo menos um ingrediente +nomeIngrediente.NotBlank=O campo nome do ingrediente é obrigatório +quantidadeIngrediente.NotNull=O campo quantidade do ingrediente é obrigatório +quantidadeIngrediente.MinMax=O campo quantidade deve estar entre 1 e 1000 +medidaIngrediente.NotNull=O campo medida do ingrediente é obrigatório \ No newline at end of file diff --git a/src/main/resources/templates/cadastro-receita.html b/src/main/resources/templates/cadastro-receita.html deleted file mode 100644 index 1f981f1..0000000 --- a/src/main/resources/templates/cadastro-receita.html +++ /dev/null @@ -1,165 +0,0 @@ - - - Cadastro de Receita - - - - - - -
- -
- -
- - - -
- - - -
- -
- - -
- -
-
- -
- -
- minutos -
-
- -
- - -
- -
- -
- porções -
-
- - -
-
- -
- Ingredientes - -
-
- - - - - - - - - - - - - - - -
NomeQuantidadeMedida
- -
- -
- -
- -
- - - -
- -
- - -
- -
- -
- -
- - - - - - - - - - \ No newline at end of file diff --git a/src/main/resources/templates/detalhe-receita.html b/src/main/resources/templates/receitas/detalhe.html similarity index 99% rename from src/main/resources/templates/detalhe-receita.html rename to src/main/resources/templates/receitas/detalhe.html index 5f14783..77007ab 100644 --- a/src/main/resources/templates/detalhe-receita.html +++ b/src/main/resources/templates/receitas/detalhe.html @@ -5,6 +5,7 @@ + diff --git a/src/main/resources/templates/lista-receitas.html b/src/main/resources/templates/receitas/lista.html similarity index 100% rename from src/main/resources/templates/lista-receitas.html rename to src/main/resources/templates/receitas/lista.html diff --git a/src/main/resources/templates/receitas/nova.html b/src/main/resources/templates/receitas/nova.html new file mode 100644 index 0000000..0cf3b4e --- /dev/null +++ b/src/main/resources/templates/receitas/nova.html @@ -0,0 +1,164 @@ + + + Cadastro de Receita + + + + + + +
+ +
+ +
+ + +
+ + + +
+ +
+ + +
+ +
+
+ +
+ +
+ minutos +
+
+ +
+ + +
+ +
+ +
+ porções +
+
+ + +
+
+ +
+ Ingredientes + +
+
+ + + + + + + + + + + + + + + +
NomeQuantidadeMedida
+ +
+ +
+ +
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ + + + + + + + + + \ No newline at end of file