diff --git a/.DS_Store b/.DS_Store index cbbe98a..6e59327 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.gitattributes.txt b/.gitattributes.txt deleted file mode 100644 index 2125666..0000000 --- a/.gitattributes.txt +++ /dev/null @@ -1 +0,0 @@ -* text=auto \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8e69e07 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/.idea + diff --git a/.idea/GDSC_SERVER_STUDY.iml b/.idea/GDSC_SERVER_STUDY.iml new file mode 100644 index 0000000..f959fa3 --- /dev/null +++ b/.idea/GDSC_SERVER_STUDY.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..275d26c --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ServerStudyPractice/.idea/gradle.xml b/.idea/gradle.xml similarity index 58% rename from ServerStudyPractice/.idea/gradle.xml rename to .idea/gradle.xml index 0ead08a..618fedd 100644 --- a/ServerStudyPractice/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -1,14 +1,12 @@ - - - + - + diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..fdc392f --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ServerStudyPractice/.idea/misc.xml b/.idea/misc.xml similarity index 59% rename from ServerStudyPractice/.idea/misc.xml rename to .idea/misc.xml index 8917924..611a919 100644 --- a/ServerStudyPractice/.idea/misc.xml +++ b/.idea/misc.xml @@ -2,9 +2,9 @@ - + - + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..d0e3016 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..c94dc45 --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1696582016004 + + + 1696582016004 + + + + + + + + \ No newline at end of file diff --git a/ServerStudyPractice/.idea/.gitignore b/ServerStudyPractice/.idea/.gitignore deleted file mode 100644 index 13566b8..0000000 --- a/ServerStudyPractice/.idea/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml diff --git a/ServerStudyPractice/settings.gradle b/ServerStudyPractice/settings.gradle deleted file mode 100644 index 4ce9650..0000000 --- a/ServerStudyPractice/settings.gradle +++ /dev/null @@ -1,2 +0,0 @@ -rootProject.name = 'ServerStudyPractice' - diff --git a/suucong/.DS_Store b/suucong/.DS_Store new file mode 100644 index 0000000..80a1e4a Binary files /dev/null and b/suucong/.DS_Store differ diff --git a/ServerStudyPractice/.gitignore b/suucong/SpringBoot/SpringBootPractice/.gitignore similarity index 100% rename from ServerStudyPractice/.gitignore rename to suucong/SpringBoot/SpringBootPractice/.gitignore diff --git a/ServerStudyPractice/build.gradle b/suucong/SpringBoot/SpringBootPractice/build.gradle similarity index 78% rename from ServerStudyPractice/build.gradle rename to suucong/SpringBoot/SpringBootPractice/build.gradle index 6e4b62d..b5da408 100644 --- a/ServerStudyPractice/build.gradle +++ b/suucong/SpringBoot/SpringBootPractice/build.gradle @@ -28,10 +28,13 @@ repositories { dependencies { implementation('org.springframework.boot:spring-boot-starter-web') - testImplementation('org.springframework.boot:spring-boot-starter-test') - testImplementation('junit:junit:4.12') // Junit 4.12 라이브러리 추가 implementation('org.projectlombok:lombok') annotationProcessor('org.projectlombok:lombok') + implementation('org.springframework.boot:spring-boot-starter-data-jpa') + implementation('com.h2database:h2') + testImplementation('org.springframework.boot:spring-boot-starter-test') + testImplementation('junit:junit:4.12') // Junit 4.12 라이브러리 추가 + implementation ('org.springframework.boot:spring-boot-starter-mustache') // mustache starter 라이브러리 추가 } test { diff --git a/ServerStudyPractice/gradle/wrapper/gradle-wrapper.jar b/suucong/SpringBoot/SpringBootPractice/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from ServerStudyPractice/gradle/wrapper/gradle-wrapper.jar rename to suucong/SpringBoot/SpringBootPractice/gradle/wrapper/gradle-wrapper.jar diff --git a/ServerStudyPractice/gradle/wrapper/gradle-wrapper.properties b/suucong/SpringBoot/SpringBootPractice/gradle/wrapper/gradle-wrapper.properties similarity index 80% rename from ServerStudyPractice/gradle/wrapper/gradle-wrapper.properties rename to suucong/SpringBoot/SpringBootPractice/gradle/wrapper/gradle-wrapper.properties index 768277e..ee38219 100644 --- a/ServerStudyPractice/gradle/wrapper/gradle-wrapper.properties +++ b/suucong/SpringBoot/SpringBootPractice/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Sun Sep 17 21:41:43 KST 2023 +#Mon Oct 02 08:27:41 KST 2023 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/ServerStudyPractice/gradlew b/suucong/SpringBoot/SpringBootPractice/gradlew similarity index 100% rename from ServerStudyPractice/gradlew rename to suucong/SpringBoot/SpringBootPractice/gradlew diff --git a/ServerStudyPractice/gradlew.bat b/suucong/SpringBoot/SpringBootPractice/gradlew.bat similarity index 100% rename from ServerStudyPractice/gradlew.bat rename to suucong/SpringBoot/SpringBootPractice/gradlew.bat diff --git a/suucong/SpringBoot/SpringBootPractice/settings.gradle b/suucong/SpringBoot/SpringBootPractice/settings.gradle new file mode 100644 index 0000000..40d2fc5 --- /dev/null +++ b/suucong/SpringBoot/SpringBootPractice/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'SpringBootPractice' + diff --git a/ServerStudyPractice/src/main/java/com/sujin/book/springboot/Application.java b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/Application.java similarity index 83% rename from ServerStudyPractice/src/main/java/com/sujin/book/springboot/Application.java rename to suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/Application.java index 91d2bda..86fddbb 100644 --- a/ServerStudyPractice/src/main/java/com/sujin/book/springboot/Application.java +++ b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/Application.java @@ -1,7 +1,9 @@ package com.sujin.book.springboot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +@EnableJpaAuditing // JPA Auditing 어노테이션을 모두 활성화 할 수 있도록 함. @SpringBootApplication // 스프링부트의 자동 설정, 스프링 Bean 읽기와 생성을 모두 자동으로 설정. 이 어노테이션이 있는 위치부터 설정을 읽어가기 떄문에 이 클래스는 항상 프로젝트 최상단에 위치해야함. public class Application { public static void main(String[] args) { diff --git a/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/domain/BaseTimeEntity.java b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/domain/BaseTimeEntity.java new file mode 100644 index 0000000..3960be1 --- /dev/null +++ b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/domain/BaseTimeEntity.java @@ -0,0 +1,23 @@ +package com.sujin.book.springboot.domain; + +import jakarta.persistence.EntityListeners; +import jakarta.persistence.MappedSuperclass; +import lombok.Getter; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import java.time.LocalDateTime; + +@Getter +@MappedSuperclass // JPA 엔타티 클래스들이 이 클래스를 상속할 경우 필드들(createdDate, modifiedDate)도 칼럼으로 인식하도록 한다. +@EntityListeners(AuditingEntityListener.class) // 이 클래스에 Auditing 기능을 포함시킨다. JPA Auditing 기능은 데이타베이스 엔티티의 변경 이력을 추적하고 기록하는 기능 +public abstract class BaseTimeEntity { // 모든 Entity의 상위 클래스가 되어 Entity들의 createdDate, modifiedDate를 자동으로 관리하는 역할 + + @CreatedDate // Entity가 생성되어 저장될 때 시간이 자동 저장 + private LocalDateTime createdDate; + + @LastModifiedDate // 조회한 Entity의 값을 변경할 때 시간이 자동 저장. + private LocalDateTime modifiedDate; + +} diff --git a/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/domain/posts/Posts.java b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/domain/posts/Posts.java new file mode 100644 index 0000000..432aa41 --- /dev/null +++ b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/domain/posts/Posts.java @@ -0,0 +1,41 @@ +package com.sujin.book.springboot.domain.posts; + +import com.sujin.book.springboot.domain.BaseTimeEntity; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; + +@Getter +@NoArgsConstructor +@Entity +public class Posts extends BaseTimeEntity { // BaseTimeEntity 클래스를 상속받음. + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(length = 500, nullable = false) + private String title; + + @Column(columnDefinition = "TEXT", nullable = false) + private String content; + + private String author; + + @Builder + public Posts(String title, String content, String author) { + this.title = title; + this.content = content; + this.author = author; + } + + public void update(String title, String content) { + this.title = title; + this.content = content; + } +} diff --git a/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/domain/posts/PostsRepository.java b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/domain/posts/PostsRepository.java new file mode 100644 index 0000000..03f55af --- /dev/null +++ b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/domain/posts/PostsRepository.java @@ -0,0 +1,14 @@ +package com.sujin.book.springboot.domain.posts; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +import java.util.List; + +public interface PostsRepository extends JpaRepository{ + + // SpringDataJpa에서 제공하는 기본 메서드만으로 해결 가능하지만. Query가 + // 가독성이 좋기 때문에 선택해서 사용하면 된다. + @Query("SELECT p FROM Posts p ORDER BY p.id DESC") + List findAllDesc(); +} diff --git a/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/domain/products/Products.java b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/domain/products/Products.java new file mode 100644 index 0000000..a4bb681 --- /dev/null +++ b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/domain/products/Products.java @@ -0,0 +1,42 @@ +package com.sujin.book.springboot.domain.products; + +import jakarta.persistence.*; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +@Entity +public class Products { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long productNum; + + @Column(length = 200, nullable = false) + private String name; + + @Column(nullable = false) + private Long price; + + @Column(nullable = false) + private Long stock; + + @Column(length = 200, nullable = false) + private String category; + + @Builder + public Products(String name, Long price, Long stock, String category) { + this.name = name; + this.price = price; + this.stock = stock; + this.category = category; + } + + public void update(String name, Long price, Long stock, String category) { + this.name = name; + this.price = price; + this.stock = stock; + this.category = category; + } +} diff --git a/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/domain/products/ProductsRepository.java b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/domain/products/ProductsRepository.java new file mode 100644 index 0000000..3fd3e99 --- /dev/null +++ b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/domain/products/ProductsRepository.java @@ -0,0 +1,6 @@ +package com.sujin.book.springboot.domain.products; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ProductsRepository extends JpaRepository { +} diff --git a/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/service/posts/PostsService.java b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/service/posts/PostsService.java new file mode 100644 index 0000000..d0b98ad --- /dev/null +++ b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/service/posts/PostsService.java @@ -0,0 +1,60 @@ +package com.sujin.book.springboot.service.posts; + +import com.sujin.book.springboot.domain.posts.Posts; +import com.sujin.book.springboot.domain.posts.PostsRepository; +import com.sujin.book.springboot.web.dto.PostsListResponseDto; +import com.sujin.book.springboot.web.dto.PostsResponseDto; +import com.sujin.book.springboot.web.dto.PostsSaveRequestDto; +import com.sujin.book.springboot.web.dto.PostsUpdateRequestDto; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.stream.Collectors; + +@RequiredArgsConstructor +@Service +public class PostsService { + private final PostsRepository postsRepository; + + @Transactional + public Long save(PostsSaveRequestDto requestDto) { + return postsRepository.save(requestDto.toEntity()).getId(); + } + + @Transactional + public Long update(Long id, PostsUpdateRequestDto requestDto) { + Posts posts = postsRepository.findById(id) + .orElseThrow(() -> new IllegalArgumentException("해당 게시글이 없습니다. id=" + id)); + posts.update(requestDto.getTitle(), requestDto.getContent()); + + return id; + } + + @Transactional + public PostsResponseDto findById(Long id) { + Posts entity = postsRepository.findById(id) + .orElseThrow(() -> new IllegalArgumentException("해당 게시글이 없습니다. id=" + id)); + + return new PostsResponseDto(entity); + } + + @Transactional(readOnly = true) // readOnly = true를 주면 트랜잭션 범위는 유지하되, 조회 기능만 남겨두어 조회 속도가 개선. + public List findAllDesc() { + return postsRepository.findAllDesc().stream() + // .map(posts -> new PostsListResponseDto(posts)) 와 같다. + // postsRepository의 결과로 넘어온 Posts의 Stream을 map을 통해 + // PostsListResponseDto로 변환 -> List로 반환하는 클래스 + .map(PostsListResponseDto::new) + .collect(Collectors.toList()); + } + + @Transactional + public void delete (Long id) { + Posts posts = postsRepository.findById(id) + .orElseThrow(() -> new IllegalArgumentException("해당 게시글이 없습니다. id = " + id)); + + postsRepository.delete(posts); + } +} diff --git a/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/service/products/ProductsService.java b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/service/products/ProductsService.java new file mode 100644 index 0000000..b7afd8a --- /dev/null +++ b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/service/products/ProductsService.java @@ -0,0 +1,53 @@ +package com.sujin.book.springboot.service.products; + +import com.sujin.book.springboot.domain.products.Products; +import com.sujin.book.springboot.domain.products.ProductsRepository; +import com.sujin.book.springboot.web.dto.ProductsResponseDto; +import com.sujin.book.springboot.web.dto.ProductsSaveRequestDto; +import com.sujin.book.springboot.web.dto.ProductsUpdateRequestDto; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@RequiredArgsConstructor +@Service +public class ProductsService { + + private final ProductsRepository productsRepository; + + // 상품 저장 + @Transactional + public Long save(ProductsSaveRequestDto requestDto) { + return productsRepository.save(requestDto.toEntity()).getProductNum(); + } + + // 상품 정보 수정 + @Transactional + public Long update(Long productNum, ProductsUpdateRequestDto requestDto) { + Products products = productsRepository.findById(productNum) + .orElseThrow(() -> new IllegalArgumentException("해당 상품이 없습니다. productNum=" + productNum)); + products.update(requestDto.getName(), requestDto.getPrice(), requestDto.getStock(), requestDto.getCategory()); + + return productNum; + } + + // 상품 조회 + @Transactional + public ProductsResponseDto findByProductNum(Long productNum) { + Products products = productsRepository.findById(productNum) + .orElseThrow(() -> new IllegalArgumentException("해당 상품이 없습니다. productNum=" + productNum)); + + return new ProductsResponseDto(products); + } + + // 상품 삭제 + @Transactional + public Long delete(Long productNum) { + Products products = productsRepository.findById(productNum) + .orElseThrow(() -> new IllegalArgumentException("해당 상품이 없습니다. productNum=" + productNum)); + productsRepository.delete(products); + + return productNum; + } + +} diff --git a/ServerStudyPractice/src/main/java/com/sujin/book/springboot/web/HelloController.java b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/HelloController.java similarity index 99% rename from ServerStudyPractice/src/main/java/com/sujin/book/springboot/web/HelloController.java rename to suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/HelloController.java index 39b0319..a4fbafa 100644 --- a/ServerStudyPractice/src/main/java/com/sujin/book/springboot/web/HelloController.java +++ b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/HelloController.java @@ -1,5 +1,6 @@ package com.sujin.book.springboot.web; import com.sujin.book.springboot.web.dto.HelloResponseDto; + import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; diff --git a/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/IndexController.java b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/IndexController.java new file mode 100644 index 0000000..5669a2c --- /dev/null +++ b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/IndexController.java @@ -0,0 +1,35 @@ +package com.sujin.book.springboot.web; + +import com.sujin.book.springboot.service.posts.PostsService; +import com.sujin.book.springboot.web.dto.PostsResponseDto; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; + +@RequiredArgsConstructor +@Controller +public class IndexController { + + private final PostsService postsService; + + @GetMapping("/") + public String index(Model model) { + model.addAttribute("posts", postsService.findAllDesc()); + return "index"; + } + + @GetMapping("/posts/save") + public String postsSave() { + return "posts-save"; + } + + @GetMapping("/posts/update/{id}") + public String postsUpdate(@PathVariable Long id, Model model) { + PostsResponseDto dto = postsService.findById(id); + model.addAttribute("post", dto); + + return "posts-update"; + } +} diff --git a/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/PostsApiController.java b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/PostsApiController.java new file mode 100644 index 0000000..b038c6e --- /dev/null +++ b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/PostsApiController.java @@ -0,0 +1,37 @@ +package com.sujin.book.springboot.web; + +import com.sujin.book.springboot.service.posts.PostsService; +import com.sujin.book.springboot.web.dto.PostsResponseDto; +import com.sujin.book.springboot.web.dto.PostsSaveRequestDto; +import com.sujin.book.springboot.web.dto.PostsUpdateRequestDto; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +@RequiredArgsConstructor +@RestController +public class PostsApiController { + + private final PostsService postsService; + + @PostMapping("/api/v1/posts") + public Long save(@RequestBody PostsSaveRequestDto requestDto) { + return postsService.save(requestDto); + } + + @PutMapping("/api/v1/posts/{id}") + public Long update(@PathVariable Long id, @RequestBody PostsUpdateRequestDto requestDto) { + return postsService.update(id, requestDto); + } + + @GetMapping("/api/v1/posts/{id}") + public PostsResponseDto findById(@PathVariable Long id) { + return postsService.findById(id); + } + + @DeleteMapping("/api/v1/posts/{id}") + public Long delete(@PathVariable Long id) { + postsService.delete(id); + + return id; + } +} diff --git a/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/ProductsApiController.java b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/ProductsApiController.java new file mode 100644 index 0000000..32de494 --- /dev/null +++ b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/ProductsApiController.java @@ -0,0 +1,35 @@ +package com.sujin.book.springboot.web; + +import com.sujin.book.springboot.service.products.ProductsService; +import com.sujin.book.springboot.web.dto.ProductsResponseDto; +import com.sujin.book.springboot.web.dto.ProductsSaveRequestDto; +import com.sujin.book.springboot.web.dto.ProductsUpdateRequestDto; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +@RequiredArgsConstructor +@RestController +public class ProductsApiController { + + private final ProductsService productsService; + + @PostMapping("/api/v1/save/products") + public Long save(@RequestBody ProductsSaveRequestDto requestDto) { + return productsService.save(requestDto); + } + + @PutMapping("/api/v1/update/products/{productNum}") + public Long update(@PathVariable Long productNum, @RequestBody ProductsUpdateRequestDto requestDto) { + return productsService.update(productNum, requestDto); + } + + @GetMapping("/api/v1/get/products/{productNum}") + public ProductsResponseDto getProducts(@PathVariable Long productNum) { + return productsService.findByProductNum(productNum); + } + + @DeleteMapping("/api/v1/delete/products/{productNum}") + public Long deleteProducts(@PathVariable Long productNum) { + return productsService.delete(productNum); + } +} diff --git a/ServerStudyPractice/src/main/java/com/sujin/book/springboot/web/dto/HelloResponseDto.java b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/dto/HelloResponseDto.java similarity index 100% rename from ServerStudyPractice/src/main/java/com/sujin/book/springboot/web/dto/HelloResponseDto.java rename to suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/dto/HelloResponseDto.java diff --git a/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/dto/PostsListResponseDto.java b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/dto/PostsListResponseDto.java new file mode 100644 index 0000000..509bc9a --- /dev/null +++ b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/dto/PostsListResponseDto.java @@ -0,0 +1,21 @@ +package com.sujin.book.springboot.web.dto; + +import com.sujin.book.springboot.domain.posts.Posts; +import lombok.Getter; + +import java.time.LocalDateTime; + +@Getter +public class PostsListResponseDto { + private Long id; + private String title; + private String author; + private LocalDateTime modifiedDate; + + public PostsListResponseDto(Posts entity) { + this.id = entity.getId(); + this.title = entity.getTitle(); + this.author = entity.getAuthor(); + this.modifiedDate = entity.getModifiedDate(); + } +} diff --git a/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/dto/PostsResponseDto.java b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/dto/PostsResponseDto.java new file mode 100644 index 0000000..40406dc --- /dev/null +++ b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/dto/PostsResponseDto.java @@ -0,0 +1,20 @@ +package com.sujin.book.springboot.web.dto; + +import com.sujin.book.springboot.domain.posts.Posts; +import lombok.Getter; + +@Getter +public class PostsResponseDto { + + private Long id; + private String title; + private String content; + private String author; + + public PostsResponseDto(Posts entity) { + this.id = entity.getId(); + this.title = entity.getTitle(); + this.content = entity.getContent(); + this.author = entity.getAuthor(); + } +} diff --git a/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/dto/PostsSaveRequestDto.java b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/dto/PostsSaveRequestDto.java new file mode 100644 index 0000000..106288c --- /dev/null +++ b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/dto/PostsSaveRequestDto.java @@ -0,0 +1,29 @@ +package com.sujin.book.springboot.web.dto; + +import com.sujin.book.springboot.domain.posts.Posts; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +public class PostsSaveRequestDto { + private String title; + private String content; + private String author; + + @Builder + public PostsSaveRequestDto(String title, String content, String author) { + this.title = title; + this.content = content; + this.author = author; + } + + public Posts toEntity() { + return Posts.builder() + .title(title) + .content(content) + .author(author) + .build(); + } +} diff --git a/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/dto/PostsUpdateRequestDto.java b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/dto/PostsUpdateRequestDto.java new file mode 100644 index 0000000..45d7d4c --- /dev/null +++ b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/dto/PostsUpdateRequestDto.java @@ -0,0 +1,19 @@ +package com.sujin.book.springboot.web.dto; + +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +public class PostsUpdateRequestDto { + + private String title; + private String content; + + @Builder + public PostsUpdateRequestDto(String title, String content) { + this.title = title; + this.content = content; + } +} diff --git a/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/dto/ProductsResponseDto.java b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/dto/ProductsResponseDto.java new file mode 100644 index 0000000..aff3ce7 --- /dev/null +++ b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/dto/ProductsResponseDto.java @@ -0,0 +1,22 @@ +package com.sujin.book.springboot.web.dto; + +import com.sujin.book.springboot.domain.products.Products; +import lombok.Getter; + +@Getter +public class ProductsResponseDto { + private Long productNum; + private String name; + private Long price; + private Long stock; + private String category; + + public ProductsResponseDto(Products products) { + this.productNum = products.getProductNum(); + this.name = products.getName(); + this.price = products.getProductNum(); + this.stock = products.getStock(); + this.category = products.getCategory(); + } + +} diff --git a/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/dto/ProductsSaveRequestDto.java b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/dto/ProductsSaveRequestDto.java new file mode 100644 index 0000000..73d1ff4 --- /dev/null +++ b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/dto/ProductsSaveRequestDto.java @@ -0,0 +1,34 @@ +package com.sujin.book.springboot.web.dto; + +import com.sujin.book.springboot.domain.products.Products; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@NoArgsConstructor +@Getter +public class ProductsSaveRequestDto { + + private String name; + private Long price; + private Long stock; + private String category; + + @Builder + public ProductsSaveRequestDto(String name, Long price, Long stock, String category) { + this.name = name; + this.price = price; + this.stock = stock; + this.category = category; + } + + public Products toEntity() { + return Products.builder() + .name(name) + .price(price) + .stock(stock) + .category(category) + .build(); + } + +} diff --git a/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/dto/ProductsUpdateRequestDto.java b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/dto/ProductsUpdateRequestDto.java new file mode 100644 index 0000000..666c028 --- /dev/null +++ b/suucong/SpringBoot/SpringBootPractice/src/main/java/com/sujin/book/springboot/web/dto/ProductsUpdateRequestDto.java @@ -0,0 +1,24 @@ +package com.sujin.book.springboot.web.dto; + +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +public class ProductsUpdateRequestDto { + + private String name; + private Long price; + private Long stock; + private String category; + + @Builder + public ProductsUpdateRequestDto(String name, Long price, Long stock, String category) { + this.name = name; + this.price = price; + this.stock = stock; + this.category = category; + } + +} diff --git a/suucong/SpringBoot/SpringBootPractice/src/main/resources/application.properties b/suucong/SpringBoot/SpringBootPractice/src/main/resources/application.properties new file mode 100644 index 0000000..2f6e8c1 --- /dev/null +++ b/suucong/SpringBoot/SpringBootPractice/src/main/resources/application.properties @@ -0,0 +1,7 @@ +spring.jpa.show-sql=true +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect +spring.jpa.properties.hibernate.dialect.storage_engine=innodb +spring.h2.console.path=/h2-console +spring.datasource.hikari.jdbc-url=jdbc:h2:mem://localhost/~/testdb;MODE=MYSQL;DB_CLOSE_ON_EXIT=FALSE +spring.h2.console.enabled=true +server.servlet.encoding.force-response=true \ No newline at end of file diff --git a/suucong/SpringBoot/SpringBootPractice/src/main/resources/static/js/app/index.js b/suucong/SpringBoot/SpringBootPractice/src/main/resources/static/js/app/index.js new file mode 100644 index 0000000..3f54520 --- /dev/null +++ b/suucong/SpringBoot/SpringBootPractice/src/main/resources/static/js/app/index.js @@ -0,0 +1,76 @@ +var main = { + init : function () { + var _this = this; + $('#btn-save').on('click', function () { + _this.save(); + }); + + $('#btn-update').on('click', function () { + _this.update(); + }); + + $('#btn-delete').on('click', function () { + _this.delete(); + }); + }, + save : function () { + var data = { + title: $('#title').val(), + author: $('#author').val(), + content: $('#content').val() + }; + + $.ajax({ + type: 'POST', + url: '/api/v1/posts', + dataType: 'json', + contentType:'application/json; charset=utf-8', + data: JSON.stringify(data) + }).done(function() { + alert('글이 등록되었습니다.'); + // 글 등록이 성공하면 메인페이지로 이동 + window.location.href = '/'; + }).fail(function (error) { + alert(JSON.stringify(error)); + }); + }, + update : function () { + var data = { + title: $('#title').val(), + content: $('#content').val() + }; + + var id = $('#id').val(); + + $.ajax({ + type: 'PUT', + url: '/api/v1/posts/'+id, + dataType: 'json', + contentType:'application/json; charset=utf-8', + data: JSON.stringify(data) + }).done(function() { + alert('글이 수정되었습니다.'); + window.location.href = '/'; + }).fail(function (error) { + alert(JSON.stringify(error)); + }); + }, + delete : function () { + var id = $('#id').val(); + + $.ajax({ + type: 'DELETE', + url: '/api/v1/posts/'+id, + dataType: 'json', + contentType:'application/json; charset=utf-8' + }).done(function() { + alert('글이 삭제되었습니다.'); + window.location.href = '/'; + }).fail(function (error) { + alert(JSON.stringify(error)); + }); + } + +}; + +main.init(); \ No newline at end of file diff --git a/suucong/SpringBoot/SpringBootPractice/src/main/resources/templates/index.mustache b/suucong/SpringBoot/SpringBootPractice/src/main/resources/templates/index.mustache new file mode 100644 index 0000000..9d025c1 --- /dev/null +++ b/suucong/SpringBoot/SpringBootPractice/src/main/resources/templates/index.mustache @@ -0,0 +1,56 @@ + + + + + + + + + + + + +{{>layout/header}} + +스프링부트로 시작하는 웹 서비스 Ver.2 + + + + 글 등록 + {{#userName}} + Logged in as: {{userName}} + Logout + {{/userName}} + {{^userName}} + Google Login + Naver Login + {{/userName}} + + + + + + + + 게시글번호 + 제목 + 작성자 + 최종수정일 + + + + + {{#posts}} + + + {{id}} + {{title}} + {{author}} + {{modifiedDate}} + + {{/posts}} + + + + +{{>layout/footer}} \ No newline at end of file diff --git a/suucong/SpringBoot/SpringBootPractice/src/main/resources/templates/layout/footer.mustache b/suucong/SpringBoot/SpringBootPractice/src/main/resources/templates/layout/footer.mustache new file mode 100644 index 0000000..2e8c833 --- /dev/null +++ b/suucong/SpringBoot/SpringBootPractice/src/main/resources/templates/layout/footer.mustache @@ -0,0 +1,9 @@ + + + + + + + +