├── src └── main │ ├── java │ └── com │ │ └── project │ │ └── bootcamp │ │ ├── exceptions │ │ ├── BusinessException.java │ │ ├── NotFoundException.java │ │ ├── ExceptionResponse.java │ │ └── ExceptionsHandler.java │ │ ├── util │ │ └── MessageUtils.java │ │ ├── repository │ │ └── StockRepository.java │ │ ├── mapper │ │ └── StockMapper.java │ │ ├── BootcampApplication.java │ │ ├── model │ │ ├── Stock.java │ │ └── dto │ │ │ └── StockDTO.java │ │ ├── controller │ │ └── StockController.java │ │ └── service │ │ └── StockService.java │ └── resources │ └── application.yml ├── README.md ├── .gitignore └── pom.xml /src/main/java/com/project/bootcamp/exceptions/BusinessException.java: -------------------------------------------------------------------------------- 1 | package com.project.bootcamp.exceptions; 2 | 3 | public class BusinessException extends RuntimeException{ 4 | 5 | public BusinessException(String message){ 6 | super(message); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/project/bootcamp/util/MessageUtils.java: -------------------------------------------------------------------------------- 1 | package com.project.bootcamp.util; 2 | 3 | public abstract class MessageUtils { 4 | 5 | public static final String NO_RECORDS_FOUND = "No records found"; 6 | public static final String ACTIVE_ALREADY_EXISTS = "Stock already exists in the database"; 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/project/bootcamp/exceptions/NotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.project.bootcamp.exceptions; 2 | 3 | import com.project.bootcamp.util.MessageUtils; 4 | 5 | public class NotFoundException extends RuntimeException{ 6 | 7 | public NotFoundException(){ 8 | super(MessageUtils.NO_RECORDS_FOUND); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/project/bootcamp/exceptions/ExceptionResponse.java: -------------------------------------------------------------------------------- 1 | package com.project.bootcamp.exceptions; 2 | 3 | public class ExceptionResponse { 4 | 5 | private String message; 6 | 7 | public ExceptionResponse(String message){ 8 | this.message = message; 9 | } 10 | 11 | public String getMessage() { 12 | return message; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bootcamp Santander: Java + Angular 2 | 3 | 1. Instalação do Ambiente Java 4 | 1. Criando o Projeto Base Java 5 | 1. Criando sua Primeira API 6 | 1. Aplicando Validações de Dados 7 | 1. Configurando o Banco de Dados 8 | 1. Criando a Camada Service e Exceptions Handlers 9 | 1. Publicando nossa API na Nuvem 10 | 11 | URL da API no Heroku: https://bootcamp-dio.herokuapp.com/bootcamp/swagger-ui.html 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8080 3 | servlet: 4 | context-path: /bootcamp 5 | 6 | spring: 7 | datasource: 8 | driver-class-name: org.postgresql.Driver 9 | #url: jdbc:postgresql://localhost:5432/postgres 10 | url: postgres://pesvogdpexfcao:2093eec9faf80060e65a50fdc4459c426b06dbaaadd15f088b4e48906b0ee11f@ec2-23-22-191-232.compute-1.amazonaws.com:5432/d8es2j2epdm0c1 11 | #username: postgres 12 | username: pesvogdpexfcao 13 | #password: 123456 14 | password: 2093eec9faf80060e65a50fdc4459c426b06dbaaadd15f088b4e48906b0ee11f 15 | jpa: 16 | show-sql: true 17 | database-platform: org.hibernate.dialect.PostgreSQLDialect 18 | generate-ddl: true 19 | hibernate: 20 | ddl-auto: none 21 | 22 | application: 23 | description: Projeto criado para o bootcamp DIO - Santander -------------------------------------------------------------------------------- /src/main/java/com/project/bootcamp/repository/StockRepository.java: -------------------------------------------------------------------------------- 1 | package com.project.bootcamp.repository; 2 | 3 | import java.time.LocalDate; 4 | import java.util.List; 5 | import java.util.Optional; 6 | 7 | import org.springframework.data.jpa.repository.JpaRepository; 8 | import org.springframework.data.jpa.repository.Query; 9 | import org.springframework.stereotype.Repository; 10 | 11 | import com.project.bootcamp.model.Stock; 12 | 13 | @Repository 14 | public interface StockRepository extends JpaRepository { 15 | 16 | public Optional findByNameAndDate(String name, LocalDate date); 17 | 18 | @Query("SELECT stock FROM Stock stock WHERE stock.name = :name AND stock.date = :date AND stock.id <> :id ") 19 | public Optional findByName(String name, Long id, LocalDate date); 20 | 21 | @Query("SELECT stock FROM Stock stock WHERE stock.date = CURRENT_DATE ") 22 | Optional> findByCurrentDate(); 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/project/bootcamp/mapper/StockMapper.java: -------------------------------------------------------------------------------- 1 | package com.project.bootcamp.mapper; 2 | 3 | import com.project.bootcamp.model.Stock; 4 | import com.project.bootcamp.model.dto.StockDTO; 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.util.List; 8 | import java.util.stream.Collectors; 9 | 10 | @Component 11 | public class StockMapper { 12 | 13 | public Stock toEntity(StockDTO dto) { 14 | Stock stock = new Stock(); 15 | stock.setId(dto.getId()); 16 | stock.setName(dto.getName()); 17 | stock.setDate(dto.getDate()); 18 | stock.setPrice(dto.getPrice()); 19 | stock.setVariation(dto.getVariation()); 20 | return stock; 21 | } 22 | 23 | public StockDTO toDto(Stock active) { 24 | StockDTO stockDTO = new StockDTO(); 25 | stockDTO.setId(active.getId()); 26 | stockDTO.setName(active.getName()); 27 | stockDTO.setDate(active.getDate()); 28 | stockDTO.setPrice(active.getPrice()); 29 | stockDTO.setVariation(active.getVariation()); 30 | return stockDTO; 31 | } 32 | 33 | public List toDto(List list) { 34 | return list.stream().map(this::toDto).collect(Collectors.toList()); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/project/bootcamp/BootcampApplication.java: -------------------------------------------------------------------------------- 1 | package com.project.bootcamp; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.beans.factory.annotation.Value; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.boot.info.BuildProperties; 8 | import org.springframework.context.annotation.Bean; 9 | 10 | import io.swagger.v3.oas.models.OpenAPI; 11 | import io.swagger.v3.oas.models.info.Info; 12 | import io.swagger.v3.oas.models.info.License; 13 | 14 | @SpringBootApplication 15 | public class BootcampApplication { 16 | 17 | @Autowired 18 | private BuildProperties buildProps; 19 | 20 | public static void main(String[] args) { 21 | SpringApplication.run(BootcampApplication.class, args); 22 | } 23 | 24 | @Bean 25 | public OpenAPI customOpenAPI(@Value("${application.description}") String description) { 26 | return new OpenAPI() 27 | .info(new Info() 28 | .title(description) 29 | .version(buildProps.getVersion()) 30 | .termsOfService("http://swagger.io/terms/") 31 | .license(new License().name("Apache 2.0").url("http://springdoc.org"))); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/project/bootcamp/exceptions/ExceptionsHandler.java: -------------------------------------------------------------------------------- 1 | package com.project.bootcamp.exceptions; 2 | 3 | import org.springframework.http.HttpStatus; 4 | import org.springframework.http.ResponseEntity; 5 | import org.springframework.web.bind.annotation.ControllerAdvice; 6 | import org.springframework.web.bind.annotation.ExceptionHandler; 7 | import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; 8 | 9 | 10 | @ControllerAdvice 11 | public class ExceptionsHandler extends ResponseEntityExceptionHandler { 12 | 13 | @ExceptionHandler(NotFoundException.class) 14 | protected ResponseEntity handleSecurity(NotFoundException ex) { 15 | return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ExceptionResponse(ex.getMessage())); 16 | } 17 | 18 | @ExceptionHandler(BusinessException.class) 19 | protected ResponseEntity handleSecurity(BusinessException ex) { 20 | return ResponseEntity.status(HttpStatus.UNPROCESSABLE_ENTITY).body(new ExceptionResponse(ex.getMessage())); 21 | } 22 | 23 | @ExceptionHandler(Exception.class) 24 | protected ResponseEntity handleSecurity(Exception ex) { 25 | return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new ExceptionResponse(ex.getMessage())); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/project/bootcamp/model/Stock.java: -------------------------------------------------------------------------------- 1 | package com.project.bootcamp.model; 2 | 3 | import java.time.LocalDate; 4 | 5 | import javax.persistence.Column; 6 | import javax.persistence.Entity; 7 | import javax.persistence.GeneratedValue; 8 | import javax.persistence.GenerationType; 9 | import javax.persistence.Id; 10 | import javax.persistence.Table; 11 | 12 | @Entity 13 | @Table(name = "tb_stock") 14 | public class Stock { 15 | 16 | @Id 17 | @GeneratedValue(strategy = GenerationType.AUTO) 18 | @Column(name = "id") 19 | private Long id; 20 | 21 | @Column(name = "name") 22 | private String name; 23 | 24 | @Column(name = "price") 25 | private Double price; 26 | 27 | @Column(name = "variation") 28 | private Double variation; 29 | 30 | @Column(name = "date") 31 | private LocalDate date; 32 | 33 | public Long getId() { 34 | return id; 35 | } 36 | 37 | public void setId(Long id) { 38 | this.id = id; 39 | } 40 | 41 | public String getName() { 42 | return name; 43 | } 44 | 45 | public void setName(String name) { 46 | this.name = name; 47 | } 48 | 49 | public Double getPrice() { 50 | return price; 51 | } 52 | 53 | public void setPrice(Double price) { 54 | this.price = price; 55 | } 56 | 57 | public Double getVariation() { 58 | return variation; 59 | } 60 | 61 | public void setVariation(Double variation) { 62 | this.variation = variation; 63 | } 64 | 65 | public LocalDate getDate() { 66 | return date; 67 | } 68 | 69 | public void setDate(LocalDate date) { 70 | this.date = date; 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/com/project/bootcamp/model/dto/StockDTO.java: -------------------------------------------------------------------------------- 1 | package com.project.bootcamp.model.dto; 2 | 3 | import java.time.LocalDate; 4 | 5 | import javax.validation.constraints.DecimalMin; 6 | import javax.validation.constraints.Digits; 7 | import javax.validation.constraints.NotNull; 8 | 9 | import com.fasterxml.jackson.annotation.JsonFormat; 10 | 11 | public class StockDTO { 12 | 13 | private Long id; 14 | 15 | @NotNull 16 | private String name; 17 | 18 | @NotNull 19 | @DecimalMin(value = "0.00") 20 | @Digits(integer = 6, fraction = 2) 21 | private Double price; 22 | 23 | @NotNull 24 | @Digits(integer = 3, fraction = 2) 25 | private Double variation; 26 | 27 | @NotNull 28 | @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd/MM/yyyy") 29 | private LocalDate date; 30 | 31 | public Long getId() { 32 | return id; 33 | } 34 | 35 | public void setId(Long id) { 36 | this.id = id; 37 | } 38 | 39 | public String getName() { 40 | return name; 41 | } 42 | 43 | public void setName(String name) { 44 | this.name = name; 45 | } 46 | 47 | public Double getPrice() { 48 | return price; 49 | } 50 | 51 | public void setPrice(Double price) { 52 | this.price = price; 53 | } 54 | 55 | public Double getVariation() { 56 | return variation; 57 | } 58 | 59 | public void setVariation(Double variation) { 60 | this.variation = variation; 61 | } 62 | 63 | public LocalDate getDate() { 64 | return date; 65 | } 66 | 67 | public void setDate(LocalDate date) { 68 | this.date = date; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.springframework.boot 8 | spring-boot-starter-parent 9 | 2.4.5 10 | 11 | 12 | com.project 13 | bootcamp 14 | 0.0.1-SNAPSHOT 15 | bootcamp 16 | Demo project for Spring Boot 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-data-jpa 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-web 30 | 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter-validation 35 | 36 | 37 | 38 | org.springdoc 39 | springdoc-openapi-ui 40 | 1.2.32 41 | 42 | 43 | 44 | org.postgresql 45 | postgresql 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-maven-plugin 55 | 56 | 57 | 58 | build-info 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /src/main/java/com/project/bootcamp/controller/StockController.java: -------------------------------------------------------------------------------- 1 | package com.project.bootcamp.controller; 2 | 3 | import com.project.bootcamp.model.dto.StockDTO; 4 | import com.project.bootcamp.service.StockService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.http.MediaType; 7 | import org.springframework.http.ResponseEntity; 8 | import org.springframework.web.bind.annotation.*; 9 | 10 | import javax.validation.Valid; 11 | import java.util.List; 12 | 13 | @CrossOrigin 14 | @RestController 15 | @RequestMapping(value = "/stock") 16 | public class StockController { 17 | 18 | @Autowired 19 | private StockService service; 20 | 21 | @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) 22 | public ResponseEntity save(@Valid @RequestBody StockDTO dto) { 23 | return ResponseEntity.ok(service.save(dto)); 24 | } 25 | 26 | @PutMapping(consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) 27 | public ResponseEntity update(@Valid @RequestBody StockDTO dto) { 28 | return ResponseEntity.ok(service.update(dto)); 29 | } 30 | 31 | @DeleteMapping(value = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE) 32 | public ResponseEntity delete(@PathVariable(value = "id") Long id) { 33 | return ResponseEntity.ok(service.delete(id)); 34 | } 35 | 36 | @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) 37 | public ResponseEntity> findAll() { 38 | return ResponseEntity.ok(service.findAll()); 39 | } 40 | 41 | @GetMapping(value = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE) 42 | public ResponseEntity findById(@PathVariable(value = "id") Long id) { 43 | return ResponseEntity.ok(service.findById(id)); 44 | } 45 | 46 | @GetMapping(value = "/today", produces = MediaType.APPLICATION_JSON_VALUE) 47 | public ResponseEntity> findByCurrentDate() { 48 | return ResponseEntity.ok(service.findByCurrentDate()); 49 | } 50 | 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/project/bootcamp/service/StockService.java: -------------------------------------------------------------------------------- 1 | package com.project.bootcamp.service; 2 | 3 | import com.project.bootcamp.exceptions.BusinessException; 4 | import com.project.bootcamp.exceptions.NotFoundException; 5 | import com.project.bootcamp.mapper.StockMapper; 6 | import com.project.bootcamp.model.Stock; 7 | import com.project.bootcamp.model.dto.StockDTO; 8 | import com.project.bootcamp.repository.StockRepository; 9 | import com.project.bootcamp.util.MessageUtils; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Service; 12 | import org.springframework.transaction.annotation.Propagation; 13 | import org.springframework.transaction.annotation.Transactional; 14 | 15 | import java.util.List; 16 | import java.util.Optional; 17 | 18 | @Service 19 | public class StockService { 20 | 21 | @Autowired 22 | private StockMapper mapper; 23 | 24 | @Autowired 25 | private StockRepository repository; 26 | 27 | @Transactional 28 | public StockDTO save(StockDTO dto) { 29 | Optional optionalEntity = repository.findByNameAndDate(dto.getName(), dto.getDate()); 30 | if (optionalEntity.isPresent()) { 31 | throw new BusinessException(MessageUtils.ACTIVE_ALREADY_EXISTS); 32 | } 33 | Stock active = mapper.toEntity(dto); 34 | repository.save(active); 35 | return mapper.toDto(active); 36 | } 37 | 38 | @Transactional 39 | public StockDTO update(StockDTO dto) { 40 | Optional optionalEntity = repository.findByName(dto.getName(), dto.getId(), dto.getDate()); 41 | if (optionalEntity.isPresent()) { 42 | throw new BusinessException(MessageUtils.ACTIVE_ALREADY_EXISTS); 43 | } 44 | Stock active = mapper.toEntity(dto); 45 | repository.save(active); 46 | return mapper.toDto(active); 47 | } 48 | 49 | @Transactional 50 | public StockDTO delete(Long id) { 51 | StockDTO activeDTO = findById(id); 52 | repository.deleteById(activeDTO.getId()); 53 | return activeDTO; 54 | } 55 | 56 | @Transactional(readOnly = true, propagation = Propagation.SUPPORTS) 57 | public List findAll() { 58 | List list = repository.findAll(); 59 | if (list.isEmpty()) { 60 | throw new NotFoundException(); 61 | } 62 | return mapper.toDto(list); 63 | } 64 | 65 | @Transactional(readOnly = true, propagation = Propagation.SUPPORTS) 66 | public StockDTO findById(Long id) { 67 | return repository.findById(id) 68 | .map(mapper::toDto) 69 | .orElseThrow(NotFoundException::new); 70 | } 71 | 72 | @Transactional(readOnly = true, propagation = Propagation.SUPPORTS) 73 | public List findByCurrentDate() { 74 | return repository.findByCurrentDate() 75 | .map(mapper::toDto) 76 | .orElseThrow(NotFoundException::new); 77 | } 78 | } 79 | --------------------------------------------------------------------------------