├── .gitignore ├── .travis.yml ├── README.md ├── app-build-deploy.bat ├── pom.xml ├── src └── main │ ├── java │ └── com │ │ └── kaluzny │ │ ├── Application.java │ │ ├── domain │ │ ├── Book.java │ │ └── BookRepository.java │ │ └── web │ │ └── BookRestController.java │ └── resources │ ├── Request.http │ ├── application.yml │ └── body.json └── travis-ci.bat /.gitignore: -------------------------------------------------------------------------------- 1 | # Maven 2 | target 3 | 4 | # Eclipse 5 | .project 6 | .settings 7 | .classpath 8 | 9 | # IntelliJ IDEA 10 | .idea 11 | *.iml 12 | 13 | /app-build-deploy.bat 14 | /travis-ci.bat 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | 3 | jdk: 4 | oraclejdk8 5 | dist: trusty 6 | sudo: 7 | required -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Plain REST API CRUD with Spring Boot 3 and PostgreSQL. 2 | 3 | [![Build Status](https://travis-ci.org/OKaluzny/spring-boot-rest-api-postgresql.svg?branch=master)](https://travis-ci.org/OKaluzny/spring-boot-rest-api-postgresql) 4 | 5 | ### Technology stack: 6 | 7 | * Spring Boot 3; 8 | * Spring Web; 9 | * Spring Data; 10 | * PostgreSQL database; 11 | * Hibernate; 12 | * Lombok; 13 | * Spring Security (as basic authentication). 14 | 15 | #### To run this application use: 16 | 17 | ```bash 18 | mvn spring-boot:run 19 | ``` 20 | 21 | ### The view in the Postman: 22 | [http://localhost:8080/api/books](http://localhost:8080/api/books) 23 | -------------------------------------------------------------------------------- /app-build-deploy.bat: -------------------------------------------------------------------------------- 1 | mvn spring-boot:run 2 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.kaluzny 7 | spring-boot2-rest-api-postgresql 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | 12 | UTF-8 13 | ${project.encoding} 14 | ${project.encoding} 15 | 16 | 17 17 | 3.1.1 18 | 1.18.28 19 | 42.2.8 20 | 21 | 22 | 23 | 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-web 28 | ${spring.boot.version} 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-starter-data-rest 33 | ${spring.boot.version} 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-starter-data-jpa 38 | ${spring.boot.version} 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-starter-test 43 | ${spring.boot.version} 44 | test 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter-security 49 | ${spring.boot.version} 50 | 51 | 52 | 53 | org.postgresql 54 | postgresql 55 | ${postgreSQL.version} 56 | runtime 57 | 58 | 59 | 60 | javax.inject 61 | javax.inject 62 | 1 63 | 64 | 65 | org.projectlombok 66 | lombok 67 | ${lombok.version} 68 | provided 69 | 70 | 71 | 72 | 73 | 74 | 75 | org.apache.maven.plugins 76 | maven-compiler-plugin 77 | 78 | 79 | ${java.version} 80 | ${java.version} 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /src/main/java/com/kaluzny/Application.java: -------------------------------------------------------------------------------- 1 | package com.kaluzny; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Application { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Application.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/kaluzny/domain/Book.java: -------------------------------------------------------------------------------- 1 | package com.kaluzny.domain; 2 | 3 | import jakarta.persistence.*; 4 | import lombok.*; 5 | 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | @Entity 11 | @Getter 12 | @Setter 13 | @NoArgsConstructor 14 | @AllArgsConstructor 15 | @EqualsAndHashCode 16 | @ToString 17 | public class Book { 18 | 19 | @Id 20 | @GeneratedValue(strategy = GenerationType.SEQUENCE) 21 | private Long id; 22 | 23 | private String name; 24 | 25 | private String description; 26 | 27 | @ElementCollection(fetch = FetchType.EAGER) 28 | @CollectionTable(name = "tag") 29 | @Column(name = "Value") 30 | private List tags = new ArrayList<>(); 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/kaluzny/domain/BookRepository.java: -------------------------------------------------------------------------------- 1 | package com.kaluzny.domain; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | import org.springframework.data.rest.core.annotation.RepositoryRestResource; 5 | 6 | import java.util.List; 7 | 8 | @RepositoryRestResource 9 | public interface BookRepository extends JpaRepository { 10 | List findByName(String name); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/kaluzny/web/BookRestController.java: -------------------------------------------------------------------------------- 1 | package com.kaluzny.web; 2 | 3 | import com.kaluzny.domain.Book; 4 | import com.kaluzny.domain.BookRepository; 5 | import jakarta.persistence.EntityNotFoundException; 6 | import lombok.RequiredArgsConstructor; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.springframework.http.HttpStatus; 9 | import org.springframework.http.MediaType; 10 | import org.springframework.web.bind.annotation.*; 11 | 12 | 13 | import java.util.Collection; 14 | 15 | @RestController 16 | @RequestMapping(value = "/api", produces = MediaType.APPLICATION_JSON_VALUE) 17 | @RequiredArgsConstructor 18 | @Slf4j 19 | public class BookRestController { 20 | 21 | private final BookRepository repository; 22 | 23 | @PostMapping("/books") 24 | @ResponseStatus(HttpStatus.CREATED) 25 | public Book saveBook(@RequestBody Book book) { 26 | log.info("saveBook() - start: book = {}", book); 27 | Book savedBook = repository.save(book); 28 | log.info("saveBook() - end: savedBook = {}", savedBook.getId()); 29 | return savedBook; 30 | } 31 | 32 | @GetMapping("/books") 33 | @ResponseStatus(HttpStatus.OK) 34 | public Collection getAllBooks() { 35 | log.info("getAllBooks() - start"); 36 | Collection collection = repository.findAll(); 37 | log.info("getAllBooks() - end"); 38 | return collection; 39 | } 40 | 41 | @GetMapping("/books/{id}") 42 | @ResponseStatus(HttpStatus.OK) 43 | public Book getBookById(@PathVariable Long id) { 44 | log.info("getBookById() - start: id = {}", id); 45 | Book receivedBook = repository.findById(id) 46 | .orElseThrow(() -> new EntityNotFoundException("Entity with id = Not found")); 47 | log.info("getBookById() - end: book = {}", receivedBook.getId()); 48 | return receivedBook; 49 | } 50 | 51 | @GetMapping(value = "/books", params = {"name"}) 52 | @ResponseStatus(HttpStatus.OK) 53 | public Collection findBookByName(@RequestParam(value = "name") String name) { 54 | log.info("findBookByName() - start: name = {}", name); 55 | Collection collection = repository.findByName(name); 56 | log.info("findBookByName() - end: collection = {}", collection); 57 | return collection; 58 | } 59 | 60 | @PutMapping("/books/{id}") 61 | @ResponseStatus(HttpStatus.OK) 62 | public Book refreshBook(@PathVariable("id") long id, @RequestBody Book book) { 63 | log.info("refreshBook() - start: id = {}, book = {}", id, book); 64 | Book updatedBook = repository.findById(id) 65 | .map(entity -> { 66 | entity.setName(book.getName()); 67 | entity.setDescription(book.getDescription()); 68 | entity.setTags(book.getTags()); 69 | return repository.save(entity); 70 | }) 71 | .orElseThrow(() -> new EntityNotFoundException("Book with id = Not found")); 72 | log.info("refreshBook() - end: updatedBook = {}", updatedBook); 73 | return updatedBook; 74 | } 75 | 76 | @DeleteMapping("/books/{id}") 77 | @ResponseStatus(HttpStatus.NO_CONTENT) 78 | public void removeBookById(@PathVariable Long id) { 79 | log.info("removeBookById() - start: id = {}", id); 80 | repository.deleteById(id); 81 | log.info("removeBookById() - end: id = {}", id); 82 | } 83 | 84 | @DeleteMapping("/books") 85 | @ResponseStatus(HttpStatus.NO_CONTENT) 86 | public void removeAllBooks() { 87 | log.info("removeAllBooks() - start"); 88 | repository.deleteAll(); 89 | log.info("removeAllBooks() - end"); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/resources/Request.http: -------------------------------------------------------------------------------- 1 | # For a quick start check out our HTTP Requests collection (Tools|HTTP Client|Open HTTP Requests Collection) or 2 | # paste cURL into the file and request will be converted to HTTP Request format. 3 | # 4 | # Following HTTP Request Live Templates are available: 5 | # * 'gtrp' and 'gtr' create a GET request with or without query parameters; 6 | # * 'ptr' and 'ptrp' create a POST request with a simple or parameter-like body; 7 | # * 'mptr' and 'fptr' create a POST request to submit a form with a text or file field (multipart/form-data); 8 | 9 | ### Send POST request with json body 10 | POST http://localhost:8080/api/books 11 | Accept: application/json 12 | Authorization: Basic dXNlcjp1c2Vy 13 | Content-Type: application/json 14 | 15 | { 16 | "name": "Java", 17 | "description": "Programming", 18 | "tags": [ 19 | "#lambdaexpressions, #streams, #functionalprogramming" 20 | ] 21 | } 22 | 23 | ### -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | # Spring Boot configuration 2 | spring: 3 | profiles: 4 | active: development 5 | # Security configuration 6 | security: 7 | user: 8 | name: user 9 | password: user 10 | # Database 11 | datasource: 12 | driver-class-name: org.postgresql.Driver 13 | url: jdbc:postgresql://localhost:5432/book_db 14 | username: postgres 15 | password: postgres 16 | # JPA properties 17 | jpa: 18 | hibernate: 19 | ddl-auto: update # When you launch the application for the first time - switch "none" at "create" 20 | show-sql: true 21 | database: postgresql 22 | database-platform: org.hibernate.dialect.PostgreSQLDialect 23 | open-in-view: false 24 | generate-ddl: true 25 | # Logger configuration 26 | logging: 27 | pattern: 28 | console: "%d %-5level %logger : %msg%n" 29 | level: 30 | org.springframework: info 31 | org.hibernate: debug 32 | # Server configuration 33 | server: 34 | port: 8080 #set your port 35 | -------------------------------------------------------------------------------- /src/main/resources/body.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Java", 3 | "description": "Programming", 4 | "tags": [ 5 | "#lambdaexpressions, #streams, #functionalprogramming" 6 | ] 7 | } -------------------------------------------------------------------------------- /travis-ci.bat: -------------------------------------------------------------------------------- 1 | mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V 2 | --------------------------------------------------------------------------------