Skip to content

Commit

Permalink
태그 api 구현 (#69)
Browse files Browse the repository at this point in the history
* [#31] Implement domain layer
- Add domain `Post`
- Add domain `Tag`

* [#31] Obey to checkstyle

* [#develop] add other content api

* [#62] add tag-api module settings

* [#62] Implement tag api

* [#62] delete duplicated settings

* [#62] refactor codes

* [#62] add custom exception and exception controller
- TagNotFoundException.java
- ExceptionController.java

* [#62] delete unused statement

* [#62] add Tag tests

* [#62] add TagContent tests

* [#62] fix variable name
- 'tableContent' to 'contentType'

* [#62] add tagContent test

* [#62] change tagContent api

* [#62] add TagService test

* [#62] add TagController test

* [#62] add tag test fixture

* [#62] fix service
- list to page

* [#62] add restdocs

Co-authored-by: Jiwoo,Kim <[email protected]>
  • Loading branch information
jiwookim5757 and jiwooo-kim authored Jul 23, 2020
1 parent cbb209c commit 185ea82
Show file tree
Hide file tree
Showing 24 changed files with 907 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.kiworkshop.community.content.simplelife.exception;

import org.kiworkshop.community.common.dto.ApiError;
import org.kiworkshop.community.common.exception.CommonExceptionController;
import org.kiworkshop.community.content.simplelife.article.exception.SimpleArticleNotFoundException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

@ControllerAdvice
@ResponseBody
public class ExceptionController extends CommonExceptionController {
@Override
@ExceptionHandler(SimpleArticleNotFoundException.class)
public ApiError handleNotFound(RuntimeException e) {
return super.handleNotFound(e);
}
}
27 changes: 27 additions & 0 deletions tag-api/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
plugins {
id 'java'
}

group 'org.kiworkshop'
version '0.0.1-SNAPSHOT'

sourceCompatibility = 11

repositories {
mavenCentral()
}

dependencies {
implementation project(':common')

implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
runtimeOnly 'com.h2database:h2'
}

asciidoctor {
inputs.dir snippetsDir
sourceDir 'docs'
outputDir = file('build/docs')
dependsOn test
}
5 changes: 5 additions & 0 deletions tag-api/docs/docinfo.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<style>
body {
font-family: "Noto Serif","DejaVu Serif","Apple SD Gothic Neo",serif;
}
</style>
42 changes: 42 additions & 0 deletions tag-api/docs/index.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
= Kiworkshop community Mother-API Docs
:doctype: book
:icons: font
:source-highlighter: highlightjs
:toc: left
:toclevels: 2
:sectlinks:

[[overview]]
= Overview

[[overview-http-verbs]]
== HTTP verbs
[cols="20%,80%"]
|===
| Verb | Usage

| `GET`
| Used to retrieve a resource

| `POST`
| Used to create a new resource

| `PUT`
| Used to update an existing resource, full updates only

| `DELETE`
| Used to delete an existing resource
|===

= Resources

[[resources-notice]]
== Notice API

[[resource-myangPost-notice]]

=== Read a notice
A `GET` request to read a notice.

operation::/tags/create-a-tag[snippets='http-request,path-parameters,http-response,response-fields']

14 changes: 14 additions & 0 deletions tag-api/src/main/java/community/exception/ExceptionController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package community.exception;

import community.common.dto.ApiError;
import community.common.exception.CommonExceptionController;
import community.tag.exception.TagNotFoundException;
import org.springframework.web.bind.annotation.ExceptionHandler;

public class ExceptionController extends CommonExceptionController {
@Override
@ExceptionHandler(TagNotFoundException.class)
protected ApiError handleNotFound(RuntimeException e) {
return super.handleNotFound(e);
}
}
11 changes: 11 additions & 0 deletions tag-api/src/main/java/community/tag/TagApplication.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package community.tag;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class TagApplication {
public static void main(String[] args) {
SpringApplication.run(TagApplication.class, args);
}
}
51 changes: 51 additions & 0 deletions tag-api/src/main/java/community/tag/api/TagController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package community.tag.api;

import community.tag.api.dto.TagContentRequestDto;
import community.tag.api.dto.TagContentResponseDto;
import community.tag.api.dto.TagRequestDto;
import community.tag.api.dto.TagResponseDto;
import community.tag.service.TagService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;

@CrossOrigin
@RequiredArgsConstructor
@RestController
@RequestMapping("/tags")
public class TagController {
private final TagService tagService;

@GetMapping
public Page<TagResponseDto> readTagPage(
@PageableDefault(sort = "id", direction = Sort.Direction.DESC) Pageable pageable
) {
return tagService.readTagPage(pageable);
}

@PostMapping
public Long create(@RequestBody @Valid TagRequestDto tagRequestDto) {
return tagService.createTagIfAbsent(tagRequestDto);
}

@GetMapping("/{contentType}/{contentId}")
public List<TagResponseDto> readTags(@PathVariable String contentType, @PathVariable Long contentId) {
return tagService.readTagsByTagContent(contentType, contentId);
}

@GetMapping("/{tagName}")
public List<TagContentResponseDto> readTagContents(@PathVariable String tagName) {
return tagService.readTagContentsByTag(tagName);
}

@PostMapping("/tagContents")
public List<Long> createTagContents(@RequestBody @Valid TagContentRequestDto tagContentRequestDto) {
return tagService.createTagContents(tagContentRequestDto);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package community.tag.api.dto;

import lombok.Getter;

import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;

@Getter
public class TagContentRequestDto {
private @NotEmpty List<@NotEmpty String> tagNames;
private @NotEmpty String contentType;
private @NotNull Long contentId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package community.tag.api.dto;

import community.tag.domain.TagContent;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
public class TagContentResponseDto {
private String contentType;
private Long contentId;

private TagContentResponseDto(TagContent tagContent) {
this.contentType = tagContent.getContentType();
this.contentId = tagContent.getContentId();
}

public static TagContentResponseDto from(TagContent tagContent) {
return new TagContentResponseDto(tagContent);
}
}
10 changes: 10 additions & 0 deletions tag-api/src/main/java/community/tag/api/dto/TagRequestDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package community.tag.api.dto;

import lombok.Getter;

import javax.validation.constraints.NotEmpty;

@Getter
public class TagRequestDto {
private @NotEmpty String name;
}
19 changes: 19 additions & 0 deletions tag-api/src/main/java/community/tag/api/dto/TagResponseDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package community.tag.api.dto;

import community.tag.domain.Tag;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
public class TagResponseDto {
private String name;

private TagResponseDto(Tag tag) {
this.name = tag.getName();
}

public static TagResponseDto from(Tag tag) {
return new TagResponseDto(tag);
}
}
31 changes: 31 additions & 0 deletions tag-api/src/main/java/community/tag/domain/Tag.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package community.tag.domain;

import community.common.model.BaseEntity;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.util.Assert;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Getter
@Entity
@NoArgsConstructor
public class Tag extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;

private Tag(String name) {
Assert.hasLength(name, "name should not be empty");

this.name = name;
}

public static Tag of(String name) {
return new Tag(name);
}
}
38 changes: 38 additions & 0 deletions tag-api/src/main/java/community/tag/domain/TagContent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package community.tag.domain;

import community.common.model.BaseEntity;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.util.Assert;

import javax.persistence.*;

@Getter
@Entity
@NoArgsConstructor
public class TagContent extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "tag_id")
private Tag tag;
private String contentType;
private Long contentId;

@Builder
private TagContent(
Tag tag,
String contentType,
Long contentId
) {
Assert.notNull(tag, "tag should not be null.");
Assert.hasLength(contentType, "contentType should not be empty.");
Assert.notNull(contentId, "contentId should not be null.");

this.tag = tag;
this.contentType = contentType;
this.contentId = contentId;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package community.tag.domain;

import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface TagContentRepository extends JpaRepository<TagContent, Long> {

List<TagContent> findByContentTypeAndContentId(String contentType, Long contentId);

List<TagContent> findByTag(Tag tag);
}
11 changes: 11 additions & 0 deletions tag-api/src/main/java/community/tag/domain/TagRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package community.tag.domain;

import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface TagRepository extends JpaRepository<Tag, Long> {
boolean existsTagByName(String name);

Optional<Tag> findByName(String name);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package community.tag.exception;

import javax.persistence.EntityNotFoundException;

public class TagNotFoundException extends EntityNotFoundException {
public TagNotFoundException(String name) {
super("post id " + name + " has not been found");
}
}
Loading

0 comments on commit 185ea82

Please sign in to comment.