Skip to content

Commit

Permalink
[댓글 기능] 효오 미션 제출합니다. (#154)
Browse files Browse the repository at this point in the history
* revert: Project revert

* [게시글 생성/조회/수정/삭제] 지노 미션 제출합니다. (#45)

* feat: thymeleaf 추가, html 파일 templates 디렉토리로 이동

* feat: Test 주석추가

* feat: ArticleController 추가

* feat: Article 클래스 추가

* feat: 게시글 수정, 삭제 기능 구현

* refactor: 코드 리팩토링

* refactor: 함수명 수정

* refactor: Controller 메서드명 수정

* refactor: 코드 리팩토링

* refactor: 매서드 위치 수정

* refactor: 리뷰 반영

* refactor: 리뷰 반영 : setter 메서드명 번경

* refactor: 리뷰 반영, ArticleRepository.class update 메서드 삭제

* refactor: 리뷰 반영, ArticleRepository.class 수정에 따른 테스트 코드 삭제

* refactor: 리뷰 반영, controller ModelAnvView 메서드 내부에서 수정

* refactor: 테스트 코드 수정

* refactor 피드백 반영

* refactor 피드백 반영

* [게시판 회원 기능] 지노 미션 제출합니다. (#79)

* feat: thymeleaf 추가, html 파일 templates 디렉토리로 이동

* feat: Test 주석추가

* feat: ArticleController 추가

* feat: Article 클래스 추가

* [DOCS] Add README.md

* [ADD] Add dependencies

* [ADD] Add properties

* [MOVE] Move views to templates directory

* [ADD] Add properties

* [FEATURE] Implement redirection to article writing page

* [FEATURE] Implement methods for read and create article

* [FEATURE] Implement methods for read article edit page

* [FEATURE] Implement methods for update article

* [FEATURE] implement methods for delete article

* feat: 게시글 수정, 삭제 기능 구현

* [FEATURE] Implement methods for read all articles

* [FEATURE] Apply template to article page

* refactor: 코드 리팩토링

* refactor: 함수명 수정

* refactor: Controller 메서드명 수정

* [REFACTOR] adjust put method to article edit page

- 메소드 타입에 따른 해당 메소드 뷰 적용

* [REFACTOR] replace response from rendering to redirection

* [ADD] Update css and html for bug fix

* [FEATURE] Apply delete specific article

* [REFACTOR] management role from Article to ArticleRepository

* [REFACTOR] update for redirection tests

* [REFACTOR] remove duplicated html

* [REMOVE] unnecessary class and test

* [FEATURE] Create and apply error pages

* [REFACTOR] Move and rename Main controller

* [REFACTOR] Modify controller name

* [REFACTOR] Modify new article id from 0 to 1

* [REFACTOR] Modify repository method name to remove correlation with db

* [REFACTOR] Modify int to AtomicInteger

* [REFACTOR] Apply code alignment

* [REFACTOR] Modify field dependency injection to constructor dependency injection

* [REFACTOR] Modify constructor

세터 제거 및 생성자 private으로 변경.

* refactor: 코드 리팩토링

* refactor: 매서드 위치 수정

* refactor: 리뷰 반영

* refactor: 리뷰 반영 : setter 메서드명 번경

* [REFACTOR] Remove of() static factory method

* [FIX] add id attribute

* [REFACTOR] Apply constant at auto-increment value

* refactor: 리뷰 반영, ArticleRepository.class update 메서드 삭제

* refactor: 리뷰 반영, ArticleRepository.class 수정에 따른 테스트 코드 삭제

* [REFACTOR] Apply code alignment

* refactor: 리뷰 반영, controller ModelAnvView 메서드 내부에서 수정

* refactor: 테스트 코드 수정

* [REFACTOR] Remove console logs

* [REFACTOR] Remove modifyArticle method

* [REFACTOR] Modify Setter name

* [REFACTOR] Modify save method

modify method가 필요없도록 수정

* [REFACTOR] Modify id from int to Long

* [FIX] Fix typing error

* [REFACTOR] Change update request

findArticle(id) 후 해당 Article을 수정하도록 변경

* refactor 피드백 반영

* refactor 피드백 반영

* [ADD] Add db for test

프로덕트 코드에 MySQL, 테스트 코드에 H2 적용

* [FEATURE] Apply JPA

Repository에 CrudRepository 상속받도록 적용.

* [ADD] Add dto for Article Domain Model

* [FEATURE] Implements create and read user

* [FEATURE] Implements login

* [FEATURE] Implement modify user

* [FEATURE] Implement delete user

* [FEATURE] Add logback dependency

* [FEATURE] Implement interceptor for session

* [FEATURE] Implement logout

* [FEATURE] Implement exception handler

* [FEATURE] Implement login dto and exception

* [FEATURE] Test Controller

* [REFACTOR] Move WebMvcConfig Class to config package

* [ADD] Add User Entity Tests

* [ADD] Add Article Service

* [REFACTOR] Remove unnecessary classes

* [REFACTOR] Remove unnecessary classes

* [ADD] Add static factory method at UserDto

* [ADD] Add tests for UserService

* [REFACTOR] remove duplicates

* [REFACTOR] remove unnecessary exceptions

* [ADD] Add error message for session interceptor

* Revert "[게시글 생성/조회/수정/삭제] 지노 미션 제출합니다. (#45)"

This reverts commit 72e0dc0.

* refactor

* refactor 피드백 반영

* refactor 피드백 반영

* [add] comment 클래스

* refactor

* refactor

* refactor

* add articles user 관계 추가

* delete ArticleConverter 삭제

* add 작성자만 글 수정 삭제 기능 추가

* add comment 추가 삭제 수정 기능 추가

* refactor 주석 제거, 어노테이션 추가

* refactor 불 필요 코드 제거

* refactor NotExistUserIdException class 수정

* add NotExistCommentIdException class 수정

* fix 예외처리 클래스 수정

* refactor 접근제어자 변경

* add comment 작성자만 추가, 삭제, 수정 기능 추가

* add comment test 작성중..

* refactor

* refactor

* refactor 예외 누락된 부분 custom exception 적용

* refactor Transactional 공통된 부분 적용

* refactor redirect 리팩토링

* refactor Path 중복제거

* refactor

* refactor 불필요한 부분 제거

* refactor 댓글 생성 테스트 추가

* refactor

* refactor Service

* refactor 도메인 리팩토링

* refactor 변수명 rename

* refactor controller 리팩토링

* refactor 모든 테스트 추가
  • Loading branch information
hyojaekim authored and 이동규 committed Aug 4, 2019
1 parent 68dd4dc commit d6bc333
Show file tree
Hide file tree
Showing 114 changed files with 2,180 additions and 2,096 deletions.
Binary file added .DS_Store
Binary file not shown.
113 changes: 37 additions & 76 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,77 +1,38 @@
# 나만의 블로그 만들기

## 게시글 관련 기능 구현 요구사항

- `/`: 메인 페이지(`index.html`)
- [x] 게시글 생성 버튼을 누르면 `/writing`으로 GET 요청을 보낸다.
- [x] 작성된 게시글 목록이 노출된다.
- [x] 게시글을 클릭하면 게시글 페이지(`/articles/{articleId}`)로 이동한다.

- `/write`: 게시글 작성 페이지(`article-edit.html`)
- [x] 저장 버튼을 누르면 `/articles`로 POST 요청을 보낸다.
- [x] X 버튼을 누르면 메인 페이지로 이동한다.
- [x] request받은 게시글을 ArticleRespository에 저장한다.

- `/articles/{articleId}`: 게시글 페이지(`article.html`)
- [x] 수정 버튼을 누르면 게시글 수정 페이지(`/articles/{articleId}/edit`)로 이동
- [x] 삭제 버튼을 누르면 `articles/{articleId}`로 DELETE 요청을 보낸다.
- [x] 요청이 처리되면 메인 페이지(`/`)로 리다이렉트한다.

- `/articles/{articleId}/edit`: 게시글 수정 페이지(`article-edit.html`)
- [x] 수정을 완료하면 `/articles/{articleId}`로 PUT 요청을 보낸다.
- [x] 요청이 처리되면 게시글 페이지(`/article/{articleId}`)로 리다이렉트한다.

- 기타
- [x] 정적 파일 수정시 재시작하지 않고 변경사항 바로 반영되게 한다.
- [x] class파일 수정시 자동으로 서버 재기동 되도록 한다.

### 2주차 요구사항 - 회원 관리

#### 1단계: 등록/조회

- [x] 기존에 구현한 내용을 Mysql로 옮긴다.
- [x] 실행 쿼리를 볼 수 있도록 설정한다.

- `/signup`: 회원가입 페이지(`signup.html`)
- [x] '가입하기' 버튼을 누르면 `/users`로 POST 요청을 보낸다.
- [x] Spring Data JPA를 이용하여 DB에 사용자 정보를 저장한다.
- [x] 생성된 후에 로그인 화면(`/login`)으로 이동한다.
- [x] 입력 정보는 다음 규칙을 따르며, 위반 시 사용자에게 알린다.
- [x] 동일한 email로 중복 가입 불가능.
- [x] 이름은 2~10글자이며, 숫자와 특수문자가 포함될 수 없다.
- [x] 비밀번호는 8글자 이상 소문자, 대문자, 숫자, 특수문자 조합이어야 한다.
- [x] 비밀번호 확인 기능이 기능이 동작해야 한다.
- [x] 회원 등록 실패 시 에러 메시지를 `Model`에 담아서 페이지에 노출한다 - 부트스트랩의 Alerts를 이용
- [x] 프론트엔드에서도 유효성을 체크할 수 있도록 한다.
- [x] HTML5에서 제공하는 form validation 기능을 최대한 활용한다.

- `/users`: 회원 목록 페이지(`user-list.html`)
- [x] DB에 저장된 회원 정보를 노출한다.

#### 2단계: 로그인

- `/login`: 로그인 페이지(`login.html`)
- [x] 로그인 성공 시 메인 페이지(`/`)로 이동하고 우측 상단에 사용자 이름을 띄운다.
- [x] 로그인 실패 시 상황에 맞는 메시지를 띄운다.
- 이메일이 없는 경우
- 비밀번호가 틀린 경우
- [x] 로그아웃 시 메인 페이지로 이동한다.
- [x] 로그인된 사용자가 로그인/회원가입 화면에 접근할 경우 메인 페이지로 이동한다.

- `/mypage`: 마이페이지(사용자 정보 확인, `mypage.html`)
- [x] 로그인된 사용자 정보가 보여진다.
- [x] 로그인 여부를 판단하여 다른 사람이 접근하는 경우를 제한한다.
- [x] 수정 아이콘을 클릭하면 수정 페이지(`/mypage-edit`)로 이동한다.
- [x] 탈퇴 버튼을 추가한다.

#### 3단계: 회원정보 수정 및 탈퇴

- `/mypage-edit`: 마이페이지(사용자 정보 수정, `mypage-edit.html`)
- [x] 수정 버튼을 클릭하면 사용자 정보를 새로 수정한다.
- [x] 로그인 여부를 판단하여 다른 사람이 접근하는 경우를 제한한다.
- [x] 잘못된 이름을 입력하면 에러 메시지를 띄웁니다.

- `/withdrawal`: 사용자 탈퇴(별도 페이지 없음)
- [x] 사용자 정보를 DB에서 제거한다.
- [x] 로그인 여부를 판단하여 다른 사람이 접근하는 경우를 제한한다.
## 나만의 블로그 서비스 (1주차)

### 기능 요구사항
- 게시글 생성
- 게시글 작성 페이지 이동
- 메인페이지(index.html)에서 게시글 생성 버튼을 누르기
- GET /writing 으로 요청
- 작성 페이지(article-edit.html)로 이동
- 게시글 작성
- POST /articles 으로 요청
- 게시글 생성 시 게시글은 ArticleRepository의 List<Article> articles에 저장한다.
- 게시글 페이지(article.html)로 이동
- 게시글 목록 조회
- 메인 페이지 이동
- GET / 으로 요청으로 이동 시 메인 페이지에 게시글 목록이 노출
- 게시글 조회
- 게시글 페이지 이동
- 메인페이지(index.html)에서 게시글을 클릭 시 게시글 페이지(article.html)으로 이동
- GET /articles/{articleId} 으로 요청

- 게시글 수정
- 게시글 수정 페이지 이동
- 게시글 페이지(article.html)에서 수정 버튼 누르기
- GET /articles/{articleId}/edit 으로 요청
- 게시글 수정 페이지(article-edit.html)로 이동
- 게시글 수정
- PUT /articles/{articleId} 으로 요청
- 게시글 페이지(article.html)로 이동
- 게시글 삭제
- 게시글 페이지(article.html)에서 삭제 버튼 누르기
- DELETE /articles/{articleId} 으로 요청
- 게시글 목록 조회 페이지(index.html)로 이동


### 제약조건
- HTML 중복제거
- 정적 파일 수정 시 재시작 하지 않고 변경사항 반영하기
- class 파일 수정 시 자동으로 재시작 하기
40 changes: 25 additions & 15 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,29 +1,39 @@
plugins {
id 'org.springframework.boot' version '2.1.6.RELEASE'
id 'java'
id 'org.springframework.boot' version '2.1.6.RELEASE'
id 'java'
}

apply plugin: 'io.spring.dependency-management'
apply plugin: 'org.springframework.boot'

group = 'techcourse'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
targetCompatibility = 1.8

bootJar {
baseName = 'gs-accessing-data-mysql'
version = '0.1.0'
}

repositories {
mavenCentral()
mavenCentral()
}

dependencies {
runtimeOnly 'net.rakugakibox.spring.boot:logback-access-spring-boot-starter:2.7.1'
implementation 'mysql:mysql-connector-java:8.0.16'
implementation 'com.h2database:h2'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-devtools'
testImplementation 'org.junit.jupiter:junit-jupiter-api'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'junit'
}
testImplementation 'org.springframework.boot:spring-boot-starter-webflux'
annotationProcessor 'org.projectlombok:lombok:1.18.8'
compileOnly 'org.projectlombok:lombok:1.18.8'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'com.h2database:h2'
implementation 'mysql:mysql-connector-java'
runtimeOnly 'net.rakugakibox.spring.boot:logback-access-spring-boot-starter:2.7.1'
testImplementation 'org.junit.jupiter:junit-jupiter-api'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'junit'
}
testImplementation 'org.springframework.boot:spring-boot-starter-webflux'
testImplementation("org.springframework.boot:spring-boot-devtools")

}
3 changes: 2 additions & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#Wed Jul 10 14:33:33 KST 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
Binary file added src/.DS_Store
Binary file not shown.
Binary file added src/main/.DS_Store
Binary file not shown.
15 changes: 7 additions & 8 deletions src/main/java/techcourse/myblog/HelloWorldController.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
package techcourse.myblog;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@Controller
@RestController
public class HelloWorldController {

@ResponseBody
@GetMapping("/helloworld")
public String helloWord(@RequestParam String blogName) {
public String temp(String blogName) {
return blogName;
}

@ResponseBody
@PostMapping("/helloworld")
public String helloWord2(@RequestBody String blogName) {
public String asd(@RequestBody String blogName) {
return blogName;
}
}
1 change: 0 additions & 1 deletion src/main/java/techcourse/myblog/MyblogApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

@SpringBootApplication
public class MyblogApplication {

public static void main(String[] args) {
SpringApplication.run(MyblogApplication.class, args);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package techcourse.myblog.application.converter;

import java.util.Collection;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

public class Converter<T, U> {
private final Function<T, U> fromDto;
private final Function<U, T> fromEntity;

public Converter(final Function<T, U> fromDto, final Function<U, T> fromEntity) {
this.fromDto = fromDto;
this.fromEntity = fromEntity;
}

public final U convertFromDto(final T dto) {
return fromDto.apply(dto);
}

public final T convertFromEntity(final U entity) {
return fromEntity.apply(entity);
}

public final List<U> createFromDtos(final Collection<T> dtos) {
return dtos.stream()
.map(this::convertFromDto)
.collect(Collectors.toList());
}


public final List<T> createFromEntities(final Collection<U> entities) {
return entities.stream()
.map(this::convertFromEntity)
.collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package techcourse.myblog.application.converter;

import techcourse.myblog.application.dto.UserDto;
import techcourse.myblog.domain.User;

public class UserConverter extends Converter<UserDto, User> {

private UserConverter() {
super(userDto -> new User(
userDto.getEmail(),
userDto.getName(),
userDto.getPassword()),
UserDto::of);
}

public static UserConverter getInstance() {
return UserConverterHolder.INSTANCE;
}

private static class UserConverterHolder {
private static final UserConverter INSTANCE = new UserConverter();
}
}
32 changes: 32 additions & 0 deletions src/main/java/techcourse/myblog/application/dto/ArticleDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package techcourse.myblog.application.dto;

import lombok.Getter;
import lombok.Setter;
import techcourse.myblog.domain.Article;

@Getter
@Setter
public class ArticleDto {
private long id;
private String title;
private String coverUrl;
private String contents;

public ArticleDto() {
}

public ArticleDto(long id, String title, String coverUrl, String contents) {
this.id = id;
this.title = title;
this.coverUrl = coverUrl;
this.contents = contents;
}

public static ArticleDto of(Article article) {
return new ArticleDto(article.getId(),
article.getTitle(),
article.getCoverUrl(),
article.getContents()
);
}
}
28 changes: 28 additions & 0 deletions src/main/java/techcourse/myblog/application/dto/CommentDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package techcourse.myblog.application.dto;

import lombok.Getter;
import lombok.Setter;
import techcourse.myblog.domain.Comment;

import java.time.LocalDateTime;

@Getter
@Setter
public class CommentDto {
private long id;
private String contents;
private String userName;
private LocalDateTime createDateTime;
private LocalDateTime updateDateTime;

public static CommentDto of(Comment comment) {
CommentDto commentDto = new CommentDto();
commentDto.setId(comment.getId());
commentDto.setContents(comment.getContents());
commentDto.setUserName(comment.getUser().getName());
commentDto.setCreateDateTime(comment.getCreateDateTime());
commentDto.setUpdateDateTime(comment.getCreateDateTime());

return commentDto;
}
}
20 changes: 20 additions & 0 deletions src/main/java/techcourse/myblog/application/dto/LoginDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package techcourse.myblog.application.dto;

import lombok.Getter;
import lombok.Setter;

import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;

@Getter
@Setter
public class LoginDto {
@NotBlank(message = "이메일을 작성해주세요.")
@Email(message = "메일의 양식을 지켜주세요.")
private String email;

@NotBlank(message = "비밀번호를 작성해주세요.")
@Pattern(regexp = "^([a-zA-Z0-9!@#$%^&*]{8,})$", message = "8자리 이상의 글자, 숫자, 특수문자를 입력해야합니다.")
private String password;
}
Loading

0 comments on commit d6bc333

Please sign in to comment.