diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..01f7d07 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,9 @@ +FROM mcr.microsoft.com/openjdk/jdk:21-ubuntu + +WORKDIR /app + +COPY /build/libs/java.docker.day.2-0.0.1-SNAPSHOT.jar /app/java.docker.day.2-0.0.1-SNAPSHOT.jar + +EXPOSE 4000 + +ENTRYPOINT [ "java", "-jar", "java.docker.day.2-0.0.1-SNAPSHOT.jar" ] diff --git a/build.gradle b/build.gradle index fb070c4..fec067d 100644 --- a/build.gradle +++ b/build.gradle @@ -1,12 +1,17 @@ plugins { id 'java' - id 'org.springframework.boot' version '3.1.4' - id 'io.spring.dependency-management' version '1.1.3' + id 'org.springframework.boot' version '3.4.2' + id 'io.spring.dependency-management' version '1.1.7' } group = 'com.booleanuk' -version = '0.0.1' -sourceCompatibility = '17' +version = '0.0.1-SNAPSHOT' + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } +} configurations { compileOnly { @@ -23,11 +28,25 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' - implementation 'org.postgresql:postgresql:42.6.0' + runtimeOnly 'org.postgresql:postgresql' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + // https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-starter-webmvc-ui + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.3' } tasks.named('test') { useJUnitPlatform() } + +jar { + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + manifest { + attributes 'Main-Class': 'com.booleanuk.api.Main' + } + + from { + configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } + } +} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..9677f09 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,21 @@ +services: + app: + image: 'docker-day-2:latest' + container_name: app + depends_on: + - postgresdb + ports: + - '4000:4000' + environment: + - SPRING_DATASOURCE_URL=jdbc:postgresql://postgresdb:5432/postgres + - SPRING_DATASOURCE_USERNAME=postgres + - SPRING_DATASOURCE_PASSWORD=mypassword + - SPRING_JPA_HIBERNATE_DDL_AUTO=update + + postgresdb: + image: 'postgres:latest' + container_name: postgresdb + environment: + - POSTGRES_USER=postgres + - POSTGRES_DATABASE=postgres + - POSTGRES_PASSWORD=mypassword diff --git a/src/main/java/com/booleanuk/api/Main.java b/src/main/java/com/booleanuk/api/Main.java new file mode 100644 index 0000000..8e749e0 --- /dev/null +++ b/src/main/java/com/booleanuk/api/Main.java @@ -0,0 +1,11 @@ +package com.booleanuk.api; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Main { + public static void main(String[] args) { + SpringApplication.run(Main.class, args); + } +} diff --git a/src/main/java/com/booleanuk/api/controllers/PostController.java b/src/main/java/com/booleanuk/api/controllers/PostController.java new file mode 100644 index 0000000..c2ea832 --- /dev/null +++ b/src/main/java/com/booleanuk/api/controllers/PostController.java @@ -0,0 +1,76 @@ +package com.booleanuk.api.controllers; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.DeleteMapping; +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.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.server.ResponseStatusException; + +import com.booleanuk.api.models.Post; +import com.booleanuk.api.models.User; +import com.booleanuk.api.repositories.PostRepository; +import com.booleanuk.api.repositories.UserRepository; + +@RestController +@RequestMapping("posts") +public class PostController { + @Autowired + private PostRepository postRepository; + @Autowired + private UserRepository userRepository; + + @GetMapping + public List getAllPosts() { + return postRepository.findAll(); + } + + @GetMapping("{userId}") + public List getPostsByUser(@PathVariable int userId) { + List posts = new ArrayList<>(); + for (Post p : getAllPosts()) { + if (p.getUser().getId() == userId) { + posts.add(p); + } + } + + return posts; + } + + @PostMapping("{userId}") + public Post addPost(@PathVariable int userId, @RequestBody Post post) { + User user = userRepository.findById(userId).orElseThrow( + () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Could not find user with this id")); + post.setUser(user); + post.setCreatedAt(LocalDateTime.now().toString()); + + return postRepository.save(post); + } + + @PutMapping("{postId}") + public Post updatePost(@PathVariable int postId, @RequestBody Post post) { + Post postToUpdate = postRepository.findById(postId).orElseThrow( + () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Could not find post with this id")); + postToUpdate.setText(post.getText()); + + return postRepository.save(postToUpdate); + } + + @DeleteMapping("{postId}") + public Post deletePost(@PathVariable int postId) { + Post postToDelete = postRepository.findById(postId).orElseThrow( + () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Could not find post with this id")); + + postRepository.delete(postToDelete); + return postToDelete; + } +} diff --git a/src/main/java/com/booleanuk/api/controllers/UserController.java b/src/main/java/com/booleanuk/api/controllers/UserController.java new file mode 100644 index 0000000..3009391 --- /dev/null +++ b/src/main/java/com/booleanuk/api/controllers/UserController.java @@ -0,0 +1,54 @@ +package com.booleanuk.api.controllers; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.DeleteMapping; +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.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.server.ResponseStatusException; + +import com.booleanuk.api.repositories.UserRepository; +import com.booleanuk.api.models.User; + +@RestController +@RequestMapping("users") +public class UserController { + @Autowired + private UserRepository userRepository; + + @GetMapping + public List getAllUsers() { + return userRepository.findAll(); + } + + @PostMapping + public User addUser(@RequestBody User newUser) { + return userRepository.save(newUser); + } + + @PutMapping("{id}") + public User updateUser(@PathVariable int id, @RequestBody User user) { + User userToUpdate = userRepository.findById(id).orElseThrow( + () -> new ResponseStatusException(HttpStatus.NOT_FOUND)); + userToUpdate.setUsername(user.getUsername()); + userToUpdate.setAge(user.getAge()); + + return userRepository.save(userToUpdate); + } + + @DeleteMapping("{id}") + public User deleteUser(@PathVariable int id) { + User userToDelete = userRepository.findById(id).orElseThrow( + () -> new ResponseStatusException(HttpStatus.NOT_FOUND)); + userRepository.delete(userToDelete); + + return userToDelete; + } +} diff --git a/src/main/java/com/booleanuk/api/models/Post.java b/src/main/java/com/booleanuk/api/models/Post.java new file mode 100644 index 0000000..269947a --- /dev/null +++ b/src/main/java/com/booleanuk/api/models/Post.java @@ -0,0 +1,41 @@ +package com.booleanuk.api.models; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "posts") +public class Post { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + @Column + private String text; + @Column + private String createdAt; + + @ManyToOne + private User user; + + public Post(String text, String createdAt) { + this.text = text; + this.createdAt = createdAt; + } + + public Post(String text) { + this.text = text; + } +} diff --git a/src/main/java/com/booleanuk/api/models/User.java b/src/main/java/com/booleanuk/api/models/User.java new file mode 100644 index 0000000..963aafc --- /dev/null +++ b/src/main/java/com/booleanuk/api/models/User.java @@ -0,0 +1,42 @@ +package com.booleanuk.api.models; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "users") +public class User { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + @Column + private String username; + @Column + private int age; + + @OneToMany(mappedBy = "user") + @JsonIgnore + private List posts; + + public User(String username, int age) { + this.username = username; + this.age = age; + } +} diff --git a/src/main/java/com/booleanuk/api/repositories/PostRepository.java b/src/main/java/com/booleanuk/api/repositories/PostRepository.java new file mode 100644 index 0000000..1213f88 --- /dev/null +++ b/src/main/java/com/booleanuk/api/repositories/PostRepository.java @@ -0,0 +1,8 @@ +package com.booleanuk.api.repositories; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.booleanuk.api.models.Post; + +public interface PostRepository extends JpaRepository { +} diff --git a/src/main/java/com/booleanuk/api/repositories/UserRepository.java b/src/main/java/com/booleanuk/api/repositories/UserRepository.java new file mode 100644 index 0000000..4caa5ae --- /dev/null +++ b/src/main/java/com/booleanuk/api/repositories/UserRepository.java @@ -0,0 +1,7 @@ +package com.booleanuk.api.repositories; + +import org.springframework.data.jpa.repository.JpaRepository; +import com.booleanuk.api.models.User; + +public interface UserRepository extends JpaRepository { +}