Skip to content

Estudo sobre a implementação do modelo conceitual. (Curso Projeto full stack completo! Java Spring Boot no back end e Ionic no front end do Prof. Dr. Nelio Alves)Seção 1: Implementação do modelo conceitual.

Notifications You must be signed in to change notification settings

AugustoMello09/Modelo-conceitual

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Objetivo geral:

  • Leitura e entendimento do diagrama de classes
  • Leitura e entendimento do diagrama de objetos
  • Associações Um para muitos / muitos para um , Um para um , Muitos para muitos comum e Muitos para muitos com classe de associação
  • Bidirecionais / direcionadas
  • Conceito independente / dependente
  • Classe de associação
  • Herança
  • Enumerações
  • Atributos Embedded (ItemPedidoPK)
  • Coleções ElementCollection (telefones de um cliente)

Modelo Conceitual

Estrutura de camadas do sistema

mvc

Objetivos específicos:

  1. Fazer uma implementação padrão do seguinte modelo conceitual:

modeloconceitual

Objetivos (continuação):

  1. Criar a seguinte instância do modelo conceitual:

Screenshot_1

Anotações de estudo

  • Na camada de controladores REST vai ficar nosso Resource.
  • Por padrão na hora de trabalhar na criação das classes de entidade colocar no pacote domain.
  • Service oferece operações e consulta para os controladores REST.
  • A camada de serviço não tem contato com nenhuma tecnologia específicas(Não tem contato com o Banco, REST e com tela).
  • A camada de serviço vai utilizar a camada de acesso a dados para realizar regras de negócio que por ventura ainda não foi implantado na camada domínio.
  • A camada de acesso a dados(Repository) tem o papel de conversar com o banco de dados, é nela que vamos realizar as operações de salvar, alterar, excluir e consultar(Tudo que envolva SQL).
  • Como não é uma boa prática colocar blocos de try catch no controladores REST, vamos fazer um Handler que é um objeto especial que vai interceptar e vai lançar a resposta Http correta.
  • Em teste realizados, o uso de @JsonManagedReference/@JsonBackRefence apresentou alguns problemas com o envio de dados Json em requisições . Assim, ao invés de usar @JsonManagedReference/@JsonBackRefence, vamos simplesmente utilizar o @JsonIgnore no lado da associação que não deve ser serializada.

Criando a classe de controle REST

começando pela categoria.

@RestController
@RequestMapping(value = "/categorias")
public class CategoriaResource {


  @RequestMapping(method = RequestMothod.GET)
  public String listar(){
    return "REST está funcionando";
  }

}

Criando nossa entidade Categoria

Criando nossa primeira entidade e colocando no pacote domain. Obs:Nela também acompanha Construtores, Getters, Setters e hashCode, mas não foi colocado na parte da documentação para não atrapalhar a visualização.

public class Categoria implements Serializable{
	private static final long serialVersionUID = 1L;

	private Integer id;
	private String nome;
}

Fazendo atualização na classe de controle REST.

Fazendo atualização no método de listar.

  @RequestMapping(method = RequestMothod.GET)
  public List<Categoria> listar(){
    Categoria cat1 = new Categoria(1, "Informática");
    Categoria cat2 = new Categoria(2,"Escritório");

    List<Categoria> lista = new ArrayList<>();
    lista.add(cat1);
    lista.add(cat2);

    return lista;
  }
  • Testando no navegador e no Postman se está funcioando a requisição.

nav

postam

Gerando tabela Categoria automaticamente no Banco de teste H2

colocando as Anotações na classe Categoria para gerar no Banco

@Entity
public class Categoria implements Serializable{
	private static final long serialVersionUID = 1L;

  @Id
  @GeneratedValue (strategy = GenerationType.IDENTITY)
  private Integer id;

  private String nome;
}  

h2

Criando a camada de acesso a dados(Repository)

Criando um Repository para acessar as categorias

@Repository
public interface CategoriaRepository extends JpaRepository<Categoria, Integer> {
}

Criando a camada Service

A camada Service vai servir de operações e consultas para Categoria e implantado um serviço que busca uma Categoria.

@Service
public class CategoriaService {

	@Autowired/*A dependência e automaticamente instanciada pelo Spring */
	private CategoriaRepository repo;

	public Categoria find(Integer id) {
		Optional<Categoria> obj = repo.findById(id);
		return obj.orElse(null);
	}

}

Atualizando os controladores REST

Atualizando para os controladores serem capazes de buscar uma Categoria.

@RestController
@RequestMapping(value = "/categorias")
public class CategoriaResource {

	@Autowired
	private CategoriaService service;

	@RequestMapping(value ="/{id}", method = RequestMethod.GET)
	public ResponseEntity<?> find(@PathVariable Integer id) {
		Categoria obj = service.find(id);
		return ResponseEntity.ok().body(obj);

	}
}

Incluindo manualmente no banco teste H2

INSERT INTO CATEGORIA(NOME) VALUES ('Informática');
INSERT INTO CATEGORIA(NOME) VALUES ('Escritório');  

SELECT * FROM CATEGORIA

dbh2

  • Testando a requisição no Postman.

/categorias/1

cat1

/categorias/2

cat2

Instanciando CategoriaRepository

para não ter o trabalho de instanciar manualmente os objetos Categoria no banco de dados, vamos fazer isso automaticamente.

  @Autowired
	private CategoriaRepository categoriaRepository;

	public static void main(String[] args) {
		SpringApplication.run(EstudomcApplication.class, args);
	}

	@Override
	public void run(String... args) throws Exception {

		Categoria cat1 = new Categoria(null, "Informática");
		Categoria cat2 = new Categoria(null, "Escritório");

		categoriaRepository.saveAll(Arrays.asList(cat1, cat2));


	}

implementado a entidade Produto

Fazendo as associações entra elas e instanciar os objetos. Obs:Nela também acompanha Construtores, Getters, Setters e hashCode, mas não foi colocado na parte da documentação para não atrapalhar a visualização.

@Entity
public class Produto implements Serializable {
	private static final long serialVersionUID = 1L;

	@Id
	@GeneratedValue(strategy =GenerationType.IDENTITY)
	private Integer id;

	private String nome;
	private Double preco;

	@ManyToMany
	@JoinTable(name = "PRODUTO_CATEGORIA",
	joinColumns = @JoinColumn(name= "produto_id"),
	inverseJoinColumns = @JoinColumn(name = "categoria_id"))
	private List<Categoria> categorias = new ArrayList<>();
}
Criando ProdutoRepository
@Repository
public interface ProdutoRepository extends JpaRepository<Produto, Integer> {
}
Instanciando os objetos e Repository na classe de execução.
  @Autowired
	private ProdutoRepository produtoRepository;

  Produto p1 = new Produto(null, "Computador", 2000.00);
	Produto p2 = new Produto(null, "Impressora", 800.00);
	Produto p3 = new Produto(null, "Mouse", 80.00);

	cat1.getProdutos().addAll(Arrays.asList(p1, p2, p3));
	cat2.getProdutos().addAll(Arrays.asList(p2));

	p1.getCategorias().addAll(Arrays.asList(cat1));
	p2.getCategorias().addAll(Arrays.asList(cat1, cat2));
	p3.getCategorias().addAll(Arrays.asList(cat1));

  categoriaRepository.saveAll(Arrays.asList(cat1, cat2));
  produtoRepository.saveAll(Arrays.asList(p1, p2, p3));

Testando no H2 o relacionamento

select produtos

categoria

Protegendo da referência cítrica no Json

@JsonManagedReference
	@ManyToMany(mappedBy = "categorias")
	private List<Produto> produtos  = new ArrayList<>();
@JsonBackReference
	@ManyToMany
	@JoinTable(name = "PRODUTO_CATEGORIA",
	joinColumns = @JoinColumn(name= "produto_id"),
	inverseJoinColumns = @JoinColumn(name = "categoria_id"))
	private List<Categoria> categorias = new ArrayList<>();

Corrigindo erro de busca vazia

Incluindo um tratamento de Exceções, agora o método de serviço ele lança uma exceção caso o Id não exista.

código que não existe

public Categoria find(Integer id) {
		 Optional<Categoria> obj = repo.findById(id);
		return obj.orElseThrow(() -> new ObjectNotFoundException(
		 "Objeto não encontrado! Id: " + id + ", Tipo: " + Categoria.class.getName()));
		}
Criando um Hendler para lançar o erro

Como não é uma boa prática colocar blocos de try catch no controladores REST, vamos fazer um Handler que é um objeto especial que vai interceptar e vai lançar a resposta Http correta.

ResourceExceptionHandler
@ControllerAdvice
public class ResourceExceptionHandler  {

  @ExceptionHandler(ObjectNotFoundException.class)
  public ResponseEntity<StandardError> objectNotFound(ObjectNotFoundException e, HttpServletRequest request){

		StandardError err = new StandardError(HttpStatus.NOT_FOUND.value(), e.getMessage(), System.currentTimeMillis());
		return ResponseEntity.status(HttpStatus.NOT_FOUND).body(err);
	}
}
StandardError
public class StandardError implements Serializable {

	private static final long serialVersionUID = 1L;

	private Integer status;
	private String msg;
	private Long timeStamp;
}

erro

implementado a entidade Cidade

Com o relacionamento de muitos para um. Obs:Nela também acompanha Construtores, Getters, Setters e hashCode, mas não foi colocado na parte da documentação para não atrapalhar a visualização.

@Entity
public class Cidade implements Serializable {
	private static final long serialVersionUID = 1L;

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Integer id;
	private String nome;

	@ManyToOne
	@JoinColumn(name ="estado_id")
	private Estado estado;

}
Criando CidadeRepository
@Repository
public interface CidadeRepository extends JpaRepository<Cidade, Integer> {
}
Instanciando os objetos e Repository na classe de execução.
@Autowired
private CidadeRepository cidadeRepository;

Cidade c1 = new Cidade(null, "Uberlândia", est1);
Cidade c2 = new Cidade(null, "São Paulo", est2);
Cidade c3 = new Cidade(null, "Campinas", est2);

cidadeRepository.saveAll(Arrays.asList(c1, c2, c3));

implementado a entidade Estado

Com o relacionamento de um para muitos. Obs:Nela também acompanha Construtores, Getters, Setters e hashCode, mas não foi colocado na parte da documentação para não atrapalhar a visualização.

@Entity
public class Estado implements Serializable {
	private static final long serialVersionUID = 1L;

		@Id
		@GeneratedValue(strategy = GenerationType.IDENTITY)
		private Integer id;

		private String nome;

		@OneToMany(mappedBy = "estado")
		private List<Cidade> cidade = new ArrayList<>();

}
Criando EstadoRepository
@Repository
public interface EstadoRepository extends JpaRepository<Estado, Integer> {
}
Instanciando os objetos e Repository na classe de execução.
@Autowired
private EstadoRepository estadoRepository;

Estado est1 = new Estado(null, "Minas Gerais");
Estado est2 = new Estado(null, "São Paulo");

// Adicionando cada cidade em seu estado
est1.getCidade().addAll(Arrays.asList(c1));
est2.getCidade().addAll(Arrays.asList(c2, c3));

estadoRepository.saveAll(Arrays.asList(est1, est2));

Testando no banco teste H2

estado

cidade

Criando um enumerado de TipoCliente

public enum TipoCliente {
	PESSOAFISICA(1, "Pessoa Física"),
	PESSOAJURIDICA(2, "Pessoa Jurídica");

	private int cod;
	private String descricao;

	private TipoCliente(int cod, String descricao) {
		this.cod = cod;
		this.descricao = descricao;
	}

	public int getCod() {
		return cod;
	}

	public String getDescricao() {
		return descricao;
	}

	public static TipoCliente toEnum(Integer cod) {

		if (cod == null) {
			return null;
		}

		for (TipoCliente x : TipoCliente.values()) {
			if (cod.equals(x.getCod())) {
				return x;
			}
		}

		throw new IllegalArgumentException("Id inválido: " + cod);

	}

}

implementado a entidade Cliente

Obs:Nela também acompanha Construtores, Getters, Setters e hashCode, mas não foi colocado na parte da documentação para não atrapalhar a visualização.

@Entity
public class Cliente implements Serializable {
	private static final long serialVersionUID = 1L;

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Integer id;

	private String nome;
	private String email;
	private String cpfOuCnpj;
	private Integer tipo;

	@OneToMany(mappedBy = "cliente")
	private List<Endereco> enderecos = new ArrayList<>();

	@ElementCollection
	@CollectionTable(name ="TELEFONE")
	private Set<String> telefones = new HashSet<>();
}
Criando ClienteRepository
@Repository
public interface ClienteRepository extends JpaRepository<Cliente, Integer> {
}
Instanciando os objetos e Repository na classe de execução.
@Autowired
private ClienteRepository clienteRepository;

Cliente cli1 = new Cliente(null, "Maria Silva", "maria@gmail.com", "36378912377", TipoCliente.PESSOAFISICA);

// Salvando os dois telefones
cli1.getTelefones().addAll(Arrays.asList("27363323", "93838393"));

//Salvando os endereços
cli1.getEnderecos().addAll(Arrays.asList(e1, e2));

clienteRepository.saveAll(Arrays.asList(cli1));

implementado a entidade Endereco

Obs:Nela também acompanha Construtores, Getters, Setters e hashCode, mas não foi colocado na parte da documentação para não atrapalhar a visualização.

@Entity
public class Endereco implements Serializable {
	private static final long serialVersionUID = 1L;

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Integer id;

	private String logradouro;
	private String numero;
	private String complemento;
	private String bairro;
	private String cep;

	@ManyToOne
	@JoinColumn (name ="cliente_id")
	private Cliente cliente;

	@ManyToOne
	@JoinColumn (name ="cidade_id")
	private Cidade cidade;

}
Criando ClienteRepository
@Repository
public interface EnderocoRepository extends JpaRepository<Endereco, Integer> {
}
Instanciando os objetos e Repository na classe de execução.
@Autowired
private EnderecoRepository enderecoRepository;

Endereco e1 = new Endereco(null, "Rua Flores", "360", "Apto 303", "Jardim", "38220834", cli1, c1);
Endereco e2 = new Endereco(null, "Avenida Matos", "105", "Sala 800", "Centro", "38777012", cli1, c2);

enderecoRepository.saveAll(Arrays.asList(e1, e2));

maria

teleclient1

endereco

Criando o Endpoint Clientes/id

@RestController
@RequestMapping(value = "/clientes")
public class ClienteResource {

	@Autowired
	private ClienteService service;

	@RequestMapping(value ="/{id}", method = RequestMethod.GET)
	public ResponseEntity<?> find(@PathVariable Integer id) {
		Cliente obj = service.find(id);
		return ResponseEntity.ok().body(obj);

	}
}

Protegendo da referência cítrica no Json

Cliente

@JsonManagedReference
	@OneToMany(mappedBy = "cliente")
	private List<Endereco> enderecos = new ArrayList<>();

Endereço

@JsonBackReference
	@ManyToOne
	@JoinColumn (name ="cliente_id")
	private Cliente cliente;

Cidade

@JsonManagedReference
	@ManyToOne
	@JoinColumn(name ="estado_id")
	private Estado estado;

Estado

@JsonBackReference
		@OneToMany(mappedBy = "estado")
		private List<Cidade> cidade = new ArrayList<>();

Criando ClienteService

@Service
public class ClienteService {

	@Autowired
	private ClienteRepository repo;

	public Cliente find(Integer id) {
		 Optional<Cliente> obj = repo.findById(id);
		return obj.orElseThrow(() -> new ObjectNotFoundException(
		 "Objeto não encontrado! Id: " + id + ", Tipo: " + Cliente.class.getName()));
		}

}

Testando o Endpoint no Postman (clientes/{id})

testeEndpoint

terminotest1

Criando a entidade Pedidos

Obs:Nela também acompanha Construtores, Getters, Setters e hashCode, mas não foi colocado na parte da documentação para não atrapalhar a visualização.

@Entity
public class Pedido implements Serializable {
	private static final long serialVersionUID = 1L;

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Integer id;
	private Date instante;

	@OneToOne(cascade=CascadeType.ALL, mappedBy ="pedido")
	private Pagamento pagamento;

	@ManyToOne
	@JoinColumn(name="cliente_id")
	private Cliente cliente;

	@ManyToOne
	@JoinColumn(name="endereco_de_entrega_id")
	private Endereco enderecoDeEntrega;
}  

Criando a classe Pagamento

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Pagamento implements Serializable {
	private static final long serialVersionUID = 1L;

	@Id
	private Integer id;
	private Integer estado;

	@OneToOne
	@JoinColumn(name ="pedido_id")
	@MapsId
	private Pedido pedido;
}  

Criando um enumerado de EstadoPagamento

public enum EstadoPagamento {
	PENDENTE(1, "Pendente"),
	QUITADO(2, "Quitado"),
	CANCELADO(3, "Cancelado");

	private int cod;
	private String descricao;

	private EstadoPagamento(int cod, String descricao) {
		this.cod = cod;
		this.descricao = descricao;
	}

	public int getCod() {
		return cod;
	}

	public String getDescricao() {
		return descricao;
	}

	public static EstadoPagamento toEnum(Integer cod) {

		if (cod == null) {
			return null;
		}

		for (EstadoPagamento x : EstadoPagamento.values()) {
			if (cod.equals(x.getCod())) {
				return x;
			}
		}

		throw new IllegalArgumentException("Id inválido: " + cod);

	}

}

Criando as SubClasses de pagamento

Pagamento com Boleto
@Entity
public class PagamentoComBoleto  extends Pagamento{

	private static final long serialVersionUID = 1L;
	private Date dataVencimento;
	private Date dataPagamento;
}
Pagamento com Cartão
@Entity
public class PagamentoComCartao  extends Pagamento {

	private static final long serialVersionUID = 1L;

	private Integer numeroDeParcelas;
}

mapeamento OneToOne nos Pedidos

@OneToOne
	@JoinColumn(name ="pedido_id")
	@MapsId
	private Pedido pedido;

  @OneToOne(cascade=CascadeType.ALL, mappedBy ="pedido")
	private Pagamento pagamento;
Criando PagamentoRepository
@Repository
public interface PagamentoRepository extends JpaRepository<Pagamento, Integer> {		
}
Criando PedidoRepository
@Repository
public interface PedidoRepository extends JpaRepository<Pedido, Integer> {		
}
Instanciando os objetos e Repository na classe de execução.
@Autowired
private PagamentoRepository pagamentoRepository;

@Autowired
private PedidoRepository pedidoRepository;

SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm");

Pedido ped1 = new Pedido(null, sdf.parse("30/09/2017 10:32"), cli1, e1);
Pedido ped2 = new Pedido(null, sdf.parse("10/10/2017 19:35"), cli1, e2);

Pagamento pagto1 = new PagamentoComCartao(null, EstadoPagamento.QUITADO, ped1, 6);
ped1.setPagamento(pagto1);

Pagamento pagto2 = new PagamentoComBoleto(null, EstadoPagamento.PENDENTE, ped2, sdf.parse("20/10/2017 00:00"),null);
ped2.setPagamento(pagto2);

cli1.getPedidos().addAll(Arrays.asList(ped1, ped2));

pedidoRepository.saveAll(Arrays.asList(ped1, ped2));
pagamentoRepository.saveAll(Arrays.asList(pagto1, pagto2));

Testando no bando de dados H2

pagamento

pagamentoboleto

pagamentoCartão

pedido

Entidade ItemPedido

Obs:Nela também acompanha Construtores, Getters, Setters e hashCode, mas não foi colocado na parte da documentação para não atrapalhar a visualização.

@Entity
public class ItemPedido implements Serializable {
	private static final long serialVersionUID = 1L;

	@EmbeddedId
	private ItemPedidoPK id = new ItemPedidoPK();

	private Double desconto;
	private Integer quantida;
	private Double preco;
}  
Classe ItemPedidoPK

Obs:Nela também acompanha Construtores, Getters, Setters e hashCode, mas não foi colocado na parte da documentação para não atrapalhar a visualização.

@Embeddable
public class ItemPedidoPK implements Serializable {

	private static final long serialVersionUID = 1L;

	@ManyToOne
	@JoinColumn(name="pedido_id")
	private Pedido pedido;

	@ManyToOne
	@JoinColumn(name ="produto_id")
	private Produto produto;
}
Criando ItemPedidoRepository
@Repository
public interface PedidoRepository extends JpaRepository<ItemPedido, Integer> {		
}
Instanciando os objetos e Repository na classe de execução.
@Autowired
private ItemPedidoRepository itemPedidoRepository;

ItemPedido ip1 = new ItemPedido(ped1, p1, 0.00, 1, 2000.00);
ItemPedido ip2 = new ItemPedido(ped1, p3, 0.00, 2, 80.00);
ItemPedido ip3 = new ItemPedido(ped2, p2, 100.00, 1, 800.00);

ped1.getItens().addAll(Arrays.asList(ip1, ip2));
ped2.getItens().addAll(Arrays.asList(ip3));

p1.getItens().addAll(Arrays.asList(ip1));
p2.getItens().addAll(Arrays.asList(ip3));
p3.getItens().addAll(Arrays.asList(ip2));

itemPedidoRepository.saveAll(Arrays.asList(ip1, ip2, ip3));

Testando no bando de dados H2

itempedido

Criando o Endpoint pedidos/id

@RestController
@RequestMapping(value = "/pedidos")
public class PedidoResource {

	@Autowired
	private PedidoService service;

	@RequestMapping(value ="/{id}", method = RequestMethod.GET)
	public ResponseEntity<?> find(@PathVariable Integer id) {
		Pedido obj = service.find(id);
		return ResponseEntity.ok().body(obj);

	}
}

Criando PedidoService

@Service
public class PedidoService {

	@Autowired
	private PedidoRepository repo;

	public Pedido find(Integer id) {
		 Optional<Pedido> obj = repo.findById(id);
		return obj.orElseThrow(() -> new ObjectNotFoundException(
		 "Objeto não encontrado! Id: " + id + ", Tipo: " + Pedido.class.getName()));
		}

}

Testando o Endpoint no Postman (pedidos/{id})

pedidos1

pedidos2

pediso3

pedidos4

Atualizacao: utilizando somente JsonIgnore

Em teste realizados, o uso de @JsonManagedReference/@JsonBackRefence apresentou alguns problemas com o envio de dados Json em requisições . Assim, ao invés de usar @JsonManagedReference/@JsonBackRefence, vamos simplesmente utilizar o @JsonIgnore no lado da associação que não deve ser serializada. Para isto faça:

  • Para cada classe de domínio:
  • Apague as anotações @JsonManagedReference existentes
  • Troque as anotações @JsonBackRefence por @JsonIgnore

Curso Projeto full stack completo! Java Spring Boot no back end e Ionic no front end.

Seção 1: Implementação do modelo conceitual

  • Prof. Dr. Nelio Alves

Ferramentas e Tecnologias usadas nesse repositório 🌐


Augusto-Java Augusto-SpringBoot Augusto-SpringBoot

Teste o projeto 👁‍🗨

Download do projeto para testar em sua máquina: https://github.com/AugustoMello09/Modelo-conceitual/archive/refs/heads/master.zip

Entre em contato comigo através dos canais abaixo e desde já, agradeço a atenção. 🤝

About

Estudo sobre a implementação do modelo conceitual. (Curso Projeto full stack completo! Java Spring Boot no back end e Ionic no front end do Prof. Dr. Nelio Alves)Seção 1: Implementação do modelo conceitual.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages