Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

jpa board 과제 #1

Merged
merged 5 commits into from
Nov 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ plugins {
id 'java'
id 'org.springframework.boot' version '3.1.5'
id 'io.spring.dependency-management' version '1.1.3'
id 'org.asciidoctor.jvm.convert' version '3.3.2'
}

group = 'org.programmers'
Expand All @@ -21,18 +22,31 @@ repositories {
mavenCentral()
}

ext {
set('snippetsDir', file("build/generated-snippets"))
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
runtimeOnly 'com.mysql:mysql-connector-j'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'

}

tasks.named('bootBuildImage') {
builder = 'paketobuildpacks/builder-jammy-base:latest'
}

tasks.named('test') {
outputs.dir snippetsDir
useJUnitPlatform()
}

tasks.named('asciidoctor') {
inputs.dir snippetsDir
dependsOn test
}
54 changes: 54 additions & 0 deletions src/docs/asciidoc/index.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
:hardbreaks:
ifndef::snippets[]
:snippets: ../../../build/generated-snippets
endif::[]

== 포스트

=== 포스트 생성

==== /post

.Request
include::{snippets}/create-post/http-request.adoc[]
.Request Fields
include::{snippets}/create-post/request-fields.adoc[]
.Response
include::{snippets}/create-post/http-response.adoc[]
.Response Fields
include::{snippets}/create-post/response-body.adoc[]

=== 포스트 업데이트

==== /post/{id}

.Request
include::{snippets}/update-post/http-request.adoc[]
.Request Fields
include::{snippets}/update-post/request-fields.adoc[]
.Response
include::{snippets}/update-post/http-response.adoc[]
.Response Fields
include::{snippets}/update-post/response-body.adoc[]

=== 포스트 조회 (id 기반 단건)

==== /post/{id}

.Request
include::{snippets}/get-post-by-id/http-request.adoc[]
.Response
include::{snippets}/get-post-by-id/http-response.adoc[]
.Response Fields
include::{snippets}/get-post-by-id/response-fields.adoc[]

=== 포스트 전체 조회

==== /post

.Request
include::{snippets}/post-getAllPost/http-request.adoc[]
.Response
include::{snippets}/post-getAllPost/http-response.adoc[]
.Response Fields
include::{snippets}/post-getAllPost/response-fields.adoc[]
22 changes: 22 additions & 0 deletions src/main/java/org/programmers/dev/base/BaseEntity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.programmers.dev.base;

import jakarta.persistence.Column;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.MappedSuperclass;
import java.time.LocalDateTime;
import lombok.Getter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

@MappedSuperclass
@Getter
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseEntity {

@CreatedDate
@Column(name = "created_at", nullable = false, columnDefinition = "TIMESTAMP", updatable = false)
protected LocalDateTime createdAt;

@Column(name = "created_by", nullable = false, updatable = false)
protected String createdBy;
}
10 changes: 10 additions & 0 deletions src/main/java/org/programmers/dev/config/JpaConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.programmers.dev.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@Configuration
@EnableJpaAuditing
public class JpaConfig {
// 추가적인 JPA 관련 구성이 필요한 경우 여기에 작성
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.programmers.dev.domain.post.application;

import java.util.List;
import lombok.RequiredArgsConstructor;
import org.programmers.dev.domain.post.controller.dto.CreatePostDto;
import org.programmers.dev.domain.post.controller.dto.PostResponse;
import org.programmers.dev.domain.post.controller.dto.UpdatePostDto;
import org.programmers.dev.domain.post.domain.entity.Post;
import org.programmers.dev.domain.post.infrastructure.PostRepository;
import org.programmers.dev.exception.PostNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class PostService {

private final PostRepository postRepository;

public List<PostResponse> getAll() {
return postRepository.findAll().stream().map(PostResponse::from).toList();
}

public PostResponse findById(Long id) {
return PostResponse.from(postRepository.findById(id).orElseThrow(
() -> new PostNotFoundException(id.toString())
));
}

@Transactional
public Long create(CreatePostDto createPostDto) {
Post post = createPostDto.of();
return postRepository.save(post).getId();
}

@Transactional
public Long update(Long id, UpdatePostDto updatePostDto) {
Post post = postRepository.findById(id).orElseThrow(
() -> new PostNotFoundException(id.toString())
);

post.updateTitle(updatePostDto.getTitle());
post.updateContent(updatePostDto.getContent());
return id;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package org.programmers.dev.domain.post.controller;

import java.util.List;
import lombok.RequiredArgsConstructor;
import org.programmers.dev.domain.post.application.PostService;
import org.programmers.dev.domain.post.controller.dto.CreatePostDto;
import org.programmers.dev.domain.post.controller.dto.PostResponse;
import org.programmers.dev.domain.post.controller.dto.UpdatePostDto;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

@RequiredArgsConstructor
@RestController
@RequestMapping("posts")
public class PostController {

private final PostService postService;

@GetMapping("")
public List<PostResponse> getAll() {
return postService.getAll();
}

@GetMapping("/{id}")
public PostResponse findById(@PathVariable Long id) {
return postService.findById(id);
}

@ResponseStatus(HttpStatus.CREATED)
@PostMapping("")
public Long create(@RequestBody CreatePostDto createPostDto) {
return postService.create(createPostDto);
}

@PatchMapping("/{id}")
public Long update(@PathVariable Long id, @RequestBody UpdatePostDto updatePostDto) {
return postService.update(id, updatePostDto);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.programmers.dev.domain.post.controller.dto;

import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.programmers.dev.domain.post.domain.entity.Post;

@NoArgsConstructor
@Data
public class CreatePostDto {

private String title;
private String content;

@Builder
private CreatePostDto(String title, String content) {
this.title = title;
this.content = content;
}

public Post of() {
return Post.builder()
.title(this.title)
.content(this.content)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.programmers.dev.domain.post.controller.dto;

import java.time.LocalDateTime;
import lombok.Builder;
import lombok.Data;
import org.programmers.dev.domain.post.domain.entity.Post;
import org.programmers.dev.domain.user.UserResponse;

@Data
public class PostResponse {

private Long id;
private String title;
private String content;
private LocalDateTime createdAt;
private String createdBy;
private UserResponse user;

@Builder
private PostResponse(
Long id, String title, String content, UserResponse user, LocalDateTime createdAt,
String createdBy
) {
this.id = id;
this.title = title;
this.content = content;
this.createdBy = createdBy;
this.createdAt = createdAt;
this.user = user;
}

public static PostResponse from(Post post) {
return PostResponse.builder()
.id(post.getId())
.title(post.getTitle())
.content(post.getContent())
.createdAt(post.getCreatedAt())
.createdBy(post.getCreatedBy())
.user(UserResponse.from(post.getUser()))
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.programmers.dev.domain.post.controller.dto;

import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@NoArgsConstructor
@Data
public class UpdatePostDto {

private String title;
private String content;

@Builder
private UpdatePostDto(String title, String content) {
this.title = title;
this.content = content;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package org.programmers.dev.domain.post.domain.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import java.time.LocalDateTime;
import java.util.Objects;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.programmers.dev.base.BaseEntity;
import org.programmers.dev.domain.user.domain.entity.User;
import org.programmers.dev.exception.PostValidationException;

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Post extends BaseEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;

@Column(nullable = false, length = 50)
private String title;

@Column(name = "content", nullable = false, length = 1000)
private String content;

@ManyToOne
@JoinColumn(name = "user_id", updatable = false, nullable = false)
private User user;

@Builder
private Post(Long id, String title, String content, User user, LocalDateTime createdAt) {
this.id = id;
this.title = title;
this.content = content;
this.createdBy = user.getName();
this.createdAt = createdAt;
setUser(user);
}

public void updateTitle(String title) {
if (title.length() > 50) {
throw new PostValidationException("제목은 50자를 넘을 수 없습니다.");
}
this.title = title;
}

public void updateContent(String content) {
if (content.length() > 1000) {
throw new PostValidationException("내용은 1000자를 넘을 수 없습니다.");
}
this.content = content;
}

private void setUser(User user) {
if (Objects.nonNull(this.user)) {
this.user.getPosts().remove(this);
}
this.user = user;
user.getPosts().add(this);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.programmers.dev.domain.post.infrastructure;

import org.programmers.dev.domain.post.domain.entity.Post;
import org.springframework.data.jpa.repository.JpaRepository;

public interface PostRepository extends JpaRepository<Post, Long> {

}
Loading