diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 000000000..2632a73e6 Binary files /dev/null and b/.DS_Store differ diff --git a/README.md b/README.md index 053934033..00a33981e 100644 --- a/README.md +++ b/README.md @@ -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
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 파일 수정 시 자동으로 재시작 하기 \ No newline at end of file diff --git a/build.gradle b/build.gradle index d849a05b8..665cd9025 100644 --- a/build.gradle +++ b/build.gradle @@ -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") + } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f4d7b2bf6..bb20062f2 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -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 diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 000000000..c6efab4d9 Binary files /dev/null and b/src/.DS_Store differ diff --git a/src/main/.DS_Store b/src/main/.DS_Store new file mode 100644 index 000000000..e8321b619 Binary files /dev/null and b/src/main/.DS_Store differ diff --git a/src/main/java/techcourse/myblog/HelloWorldController.java b/src/main/java/techcourse/myblog/HelloWorldController.java index 0f5b5c3dd..9351ca1b3 100644 --- a/src/main/java/techcourse/myblog/HelloWorldController.java +++ b/src/main/java/techcourse/myblog/HelloWorldController.java @@ -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; } } diff --git a/src/main/java/techcourse/myblog/MyblogApplication.java b/src/main/java/techcourse/myblog/MyblogApplication.java index cd469756f..bc3ff5f71 100644 --- a/src/main/java/techcourse/myblog/MyblogApplication.java +++ b/src/main/java/techcourse/myblog/MyblogApplication.java @@ -5,7 +5,6 @@ @SpringBootApplication public class MyblogApplication { - public static void main(String[] args) { SpringApplication.run(MyblogApplication.class, args); } diff --git a/src/main/java/techcourse/myblog/application/converter/Converter.java b/src/main/java/techcourse/myblog/application/converter/Converter.java new file mode 100644 index 000000000..1bada2413 --- /dev/null +++ b/src/main/java/techcourse/myblog/application/converter/Converter.java @@ -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 { + private final Function fromDto; + private final Function fromEntity; + + public Converter(final Function fromDto, final Function 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 createFromDtos(final Collection dtos) { + return dtos.stream() + .map(this::convertFromDto) + .collect(Collectors.toList()); + } + + + public final List createFromEntities(final Collection entities) { + return entities.stream() + .map(this::convertFromEntity) + .collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/src/main/java/techcourse/myblog/application/converter/UserConverter.java b/src/main/java/techcourse/myblog/application/converter/UserConverter.java new file mode 100644 index 000000000..dc931affb --- /dev/null +++ b/src/main/java/techcourse/myblog/application/converter/UserConverter.java @@ -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 { + + 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(); + } +} \ No newline at end of file diff --git a/src/main/java/techcourse/myblog/application/dto/ArticleDto.java b/src/main/java/techcourse/myblog/application/dto/ArticleDto.java new file mode 100644 index 000000000..ecfc8937c --- /dev/null +++ b/src/main/java/techcourse/myblog/application/dto/ArticleDto.java @@ -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() + ); + } +} \ No newline at end of file diff --git a/src/main/java/techcourse/myblog/application/dto/CommentDto.java b/src/main/java/techcourse/myblog/application/dto/CommentDto.java new file mode 100644 index 000000000..a06c9c641 --- /dev/null +++ b/src/main/java/techcourse/myblog/application/dto/CommentDto.java @@ -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; + } +} \ No newline at end of file diff --git a/src/main/java/techcourse/myblog/application/dto/LoginDto.java b/src/main/java/techcourse/myblog/application/dto/LoginDto.java new file mode 100644 index 000000000..ed2d27edf --- /dev/null +++ b/src/main/java/techcourse/myblog/application/dto/LoginDto.java @@ -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; +} \ No newline at end of file diff --git a/src/main/java/techcourse/myblog/application/dto/UserDto.java b/src/main/java/techcourse/myblog/application/dto/UserDto.java new file mode 100644 index 000000000..c29a736a6 --- /dev/null +++ b/src/main/java/techcourse/myblog/application/dto/UserDto.java @@ -0,0 +1,40 @@ +package techcourse.myblog.application.dto; + + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import techcourse.myblog.domain.User; + +import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Pattern; + +@Getter +@Setter +@EqualsAndHashCode +public class UserDto { + @NotBlank(message = "이메일을 작성해주세요.") + @Email(message = "메일의 양식을 지켜주세요.") + private String email; + + @NotBlank(message = "이름을 작성해주세요.") + @Pattern(regexp = "^([A-Za-z가-힣]{2,10})$", message = "2~10자리 숫자, 글자만 입력가능합니다.") + private String name; + + @NotBlank(message = "비밀번호를 작성해주세요.") + @Pattern(regexp = "^([a-zA-Z0-9!@#$%^&*]{8,})$", message = "8자리 이상의 글자, 숫자, 특수문자를 입력해야합니다.") + private String password; + + public UserDto() { + } + + public static UserDto of(User user) { + UserDto userDto = new UserDto(); + userDto.setName(user.getName()); + userDto.setEmail(user.getEmail()); + userDto.setPassword(user.getPassword()); + + return userDto; + } +} \ No newline at end of file diff --git a/src/main/java/techcourse/myblog/application/service/ArticleService.java b/src/main/java/techcourse/myblog/application/service/ArticleService.java new file mode 100644 index 000000000..93eb16c6e --- /dev/null +++ b/src/main/java/techcourse/myblog/application/service/ArticleService.java @@ -0,0 +1,89 @@ +package techcourse.myblog.application.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import techcourse.myblog.application.dto.ArticleDto; +import techcourse.myblog.application.dto.UserDto; +import techcourse.myblog.application.service.exception.NotExistArticleIdException; +import techcourse.myblog.application.service.exception.NotMatchEmailException; +import techcourse.myblog.domain.Article; +import techcourse.myblog.domain.ArticleRepository; +import techcourse.myblog.domain.User; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +public class ArticleService { + + private final ArticleRepository articleRepository; + private final UserService userService; + + @Autowired + public ArticleService(ArticleRepository articleRepository, UserService userService) { + this.articleRepository = articleRepository; + this.userService = userService; + } + + @Transactional + public Long save(ArticleDto articleDto, String email) { + User user = userService.findUserByEmail(email); + Article article = new Article(articleDto.getTitle(), + articleDto.getCoverUrl(), + articleDto.getContents(), + user); + + return articleRepository.save(article).getId(); + } + + @Transactional(readOnly = true) + public ArticleDto findById(Long articleId) { + return ArticleDto.of(findArticleById(articleId)); + } + + @Transactional(readOnly = true) + public Article findArticleById(Long articleId) { + return articleRepository.findById(articleId) + .orElseThrow(() -> new NotExistArticleIdException("해당 게시물을 찾을 수 없습니다.")); + } + + @Transactional + public void removeById(Long articleId) { + articleRepository.deleteById(articleId); + } + + @Transactional + public void modify(Long articleId, ArticleDto articleDto, String email) { + User user = userService.findUserByEmail(email); + Article article = findArticleById(articleId); + + article.modify(new Article(articleDto.getTitle(), + articleDto.getCoverUrl(), + articleDto.getContents(), + user) + , user); + } + + @Transactional(readOnly = true) + public List findAll() { + return articleRepository.findAll().stream() + .map(ArticleDto::of) + .collect(Collectors.toList()); + } + + @Transactional(readOnly = true) + public void checkAuthor(Long articleId, String email) { + Article article = findArticleById(articleId); + if (!article.checkAuthor(email)) { + throw new NotMatchEmailException("작성자가 다릅니다."); + } + } + + @Transactional + public UserDto findAuthor(long articleId) { + User user = findArticleById(articleId) + .getUser(); + return UserDto.of(user); + } +} \ No newline at end of file diff --git a/src/main/java/techcourse/myblog/application/service/CommentService.java b/src/main/java/techcourse/myblog/application/service/CommentService.java new file mode 100644 index 000000000..46bfbdde2 --- /dev/null +++ b/src/main/java/techcourse/myblog/application/service/CommentService.java @@ -0,0 +1,66 @@ +package techcourse.myblog.application.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import techcourse.myblog.application.dto.CommentDto; +import techcourse.myblog.application.service.exception.NotExistCommentException; +import techcourse.myblog.domain.Article; +import techcourse.myblog.domain.Comment; +import techcourse.myblog.domain.CommentRepository; +import techcourse.myblog.domain.User; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +public class CommentService { + private CommentRepository commentRepository; + private UserService userService; + private ArticleService articleService; + + @Autowired + public CommentService(CommentRepository commentRepository, UserService userService, ArticleService articleService) { + this.commentRepository = commentRepository; + this.userService = userService; + this.articleService = articleService; + } + + @Transactional + public long save(CommentDto commentDto, String userEmail, long articleId) { + User user = userService.findUserByEmail(userEmail); + Article article = articleService.findArticleById(articleId); + + Comment comment = new Comment(commentDto.getContents(), user, article); + return commentRepository.save(comment).getId(); + } + + @Transactional(readOnly = true) + public List findAllByArticleId(Long articleId) { + List comments = commentRepository.findAllByArticleId(articleId); + return comments.stream() + .map(CommentDto::of) + .collect(Collectors.toList()); + } + + @Transactional + public void update(long commentId, CommentDto commentDto, String email) { + Comment comment = commentRepository.findById(commentId) + .orElseThrow(() -> new NotExistCommentException("해당 댓글이 존재하지 않습니다.")); + + userService.checkEmail(comment.getUser(), email); + + User user = userService.findUserByEmail(email); + + comment.modify(commentDto.getContents(), user); + } + + @Transactional + public void delete(Long commentId, String email) { + Comment comment = commentRepository.findById(commentId) + .orElseThrow(() -> new NotExistCommentException("해당 댓글이 존재하지 않습니다.")); + + userService.checkEmail(comment.getUser(), email); + commentRepository.deleteById(commentId); + } +} \ No newline at end of file diff --git a/src/main/java/techcourse/myblog/application/service/UserService.java b/src/main/java/techcourse/myblog/application/service/UserService.java new file mode 100644 index 000000000..1f151958e --- /dev/null +++ b/src/main/java/techcourse/myblog/application/service/UserService.java @@ -0,0 +1,90 @@ +package techcourse.myblog.application.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import techcourse.myblog.application.converter.UserConverter; +import techcourse.myblog.application.dto.LoginDto; +import techcourse.myblog.application.dto.UserDto; +import techcourse.myblog.application.service.exception.DuplicatedIdException; +import techcourse.myblog.application.service.exception.NotExistUserIdException; +import techcourse.myblog.application.service.exception.NotMatchEmailException; +import techcourse.myblog.application.service.exception.NotMatchPasswordException; +import techcourse.myblog.domain.User; +import techcourse.myblog.domain.UserRepository; + +import javax.validation.Valid; +import java.util.List; + +@Service +public class UserService { + private UserRepository userRepository; + private UserConverter userConverter; + + @Autowired + public UserService(UserRepository userRepository) { + this.userRepository = userRepository; + userConverter = UserConverter.getInstance(); + } + + @Transactional + public UserDto save(UserDto userDto) { + if (userRepository.existsByEmail(userDto.getEmail())) { + throw new DuplicatedIdException("이미 사용중인 이메일입니다."); + } + + User user = userConverter.convertFromDto(userDto); + return userConverter.convertFromEntity(userRepository.save(user)); + } + + @Transactional(readOnly = true) + public List findAll() { + return userConverter.createFromEntities(userRepository.findAll()); + } + + public UserDto findByEmail(String email) { + return userConverter.convertFromEntity(findUserByEmail(email)); + } + + @Transactional(readOnly = true) + protected User findUserByEmail(String email) { + return userRepository.findByEmail(email) + .orElseThrow(() -> new NotExistUserIdException("해당 이메일의 유저가 존재하지 않습니다.")); + } + + @Transactional(readOnly = true) + public void login(LoginDto loginDto) { + String requestPassword = loginDto.getPassword(); + User user = findUserByEmail(loginDto.getEmail()); + + checkPassword(user, requestPassword); + } + + @Transactional + public void modify(@Valid UserDto userDto, String email) { + User user = findUserByEmail(userDto.getEmail()); + checkEmail(user, email); + + user.modify(userConverter.convertFromDto(userDto)); + } + + @Transactional + public void removeById(UserDto userDto, String email) { + User user = findUserByEmail(userDto.getEmail()); + checkEmail(user, email); + + userRepository.delete(user); + } + + private void checkPassword(User user, String password) { + if (!user.checkPassword(password)) { + throw new NotMatchPasswordException("비밀번호가 일치하지 않습니다."); + } + } + + protected void checkEmail(User user, String email) { + if (!user.checkEmail(email)) { + throw new NotMatchEmailException("이메일이 일치하지 않습니다."); + } + } +} \ No newline at end of file diff --git a/src/main/java/techcourse/myblog/application/service/exception/DuplicatedIdException.java b/src/main/java/techcourse/myblog/application/service/exception/DuplicatedIdException.java new file mode 100644 index 000000000..183c6161a --- /dev/null +++ b/src/main/java/techcourse/myblog/application/service/exception/DuplicatedIdException.java @@ -0,0 +1,7 @@ +package techcourse.myblog.application.service.exception; + +public class DuplicatedIdException extends RuntimeException { + public DuplicatedIdException(String message) { + super(message); + } +} diff --git a/src/main/java/techcourse/myblog/application/service/exception/NotExistArticleIdException.java b/src/main/java/techcourse/myblog/application/service/exception/NotExistArticleIdException.java new file mode 100644 index 000000000..e55082ca2 --- /dev/null +++ b/src/main/java/techcourse/myblog/application/service/exception/NotExistArticleIdException.java @@ -0,0 +1,7 @@ +package techcourse.myblog.application.service.exception; + +public class NotExistArticleIdException extends RuntimeException { + public NotExistArticleIdException(String message) { + super(message); + } +} diff --git a/src/main/java/techcourse/myblog/application/service/exception/NotExistCommentException.java b/src/main/java/techcourse/myblog/application/service/exception/NotExistCommentException.java new file mode 100644 index 000000000..bc9ee39df --- /dev/null +++ b/src/main/java/techcourse/myblog/application/service/exception/NotExistCommentException.java @@ -0,0 +1,8 @@ +package techcourse.myblog.application.service.exception; + +public class NotExistCommentException extends RuntimeException { + public NotExistCommentException(String message) { + super(message); + } +} + diff --git a/src/main/java/techcourse/myblog/application/service/exception/NotExistUserIdException.java b/src/main/java/techcourse/myblog/application/service/exception/NotExistUserIdException.java new file mode 100644 index 000000000..ca9ab9d7c --- /dev/null +++ b/src/main/java/techcourse/myblog/application/service/exception/NotExistUserIdException.java @@ -0,0 +1,7 @@ +package techcourse.myblog.application.service.exception; + +public class NotExistUserIdException extends RuntimeException { + public NotExistUserIdException(String message) { + super(message); + } +} diff --git a/src/main/java/techcourse/myblog/application/service/exception/NotMatchEmailException.java b/src/main/java/techcourse/myblog/application/service/exception/NotMatchEmailException.java new file mode 100644 index 000000000..3ec4ed609 --- /dev/null +++ b/src/main/java/techcourse/myblog/application/service/exception/NotMatchEmailException.java @@ -0,0 +1,7 @@ +package techcourse.myblog.application.service.exception; + +public class NotMatchEmailException extends RuntimeException { + public NotMatchEmailException(String message) { + super(message); + } +} diff --git a/src/main/java/techcourse/myblog/application/service/exception/NotMatchPasswordException.java b/src/main/java/techcourse/myblog/application/service/exception/NotMatchPasswordException.java new file mode 100644 index 000000000..ff607bb3d --- /dev/null +++ b/src/main/java/techcourse/myblog/application/service/exception/NotMatchPasswordException.java @@ -0,0 +1,7 @@ +package techcourse.myblog.application.service.exception; + +public class NotMatchPasswordException extends RuntimeException { + public NotMatchPasswordException(String message) { + super(message); + } +} diff --git a/src/main/java/techcourse/myblog/config/LoginConfig.java b/src/main/java/techcourse/myblog/config/LoginConfig.java deleted file mode 100644 index 97c02b8d4..000000000 --- a/src/main/java/techcourse/myblog/config/LoginConfig.java +++ /dev/null @@ -1,24 +0,0 @@ -package techcourse.myblog.config; - -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.config.annotation.InterceptorRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import techcourse.myblog.interceptor.LoginInterceptor; - -@Configuration -public class LoginConfig implements WebMvcConfigurer { - @Override - public void addInterceptors(InterceptorRegistry registry) { - registry.addInterceptor(new LoginInterceptor()) - .addPathPatterns("/write") - .addPathPatterns("/articles/new") - .addPathPatterns("/articles/*/edit") - .addPathPatterns("/mypage") - .addPathPatterns("/mypage-edit") - .addPathPatterns("/withdrawal") - .addPathPatterns("/login") - .addPathPatterns("/signup") - .addPathPatterns("/users") - .addPathPatterns("/logout"); - } -} diff --git a/src/main/java/techcourse/myblog/domain/Article.java b/src/main/java/techcourse/myblog/domain/Article.java index 6e20aac6e..d2901d5b1 100644 --- a/src/main/java/techcourse/myblog/domain/Article.java +++ b/src/main/java/techcourse/myblog/domain/Article.java @@ -1,63 +1,53 @@ package techcourse.myblog.domain; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; -import java.util.Objects; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import techcourse.myblog.application.service.exception.NotExistUserIdException; +import javax.persistence.*; + +@Getter +@EqualsAndHashCode(of = "id") @Entity public class Article { @Id - @GeneratedValue - private Long articleId; + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(nullable = false) private String title; - private String coverUrl; - private String contents; - - public static Article of(String title, String coverUrl, String contents) { - Article article = new Article(); - article.title = title; - article.coverUrl = coverUrl; - article.contents = contents; - return article; - } - public void updateArticle(Article article) { - this.title = article.getTitle(); - this.coverUrl = article.getCoverUrl(); - this.contents = article.getContents(); - } + @Column(nullable = false) + private String coverUrl; - public Long getArticleId() { - return articleId; - } + @Lob + @Column(nullable = false) + private String contents; - public String getTitle() { - return title; - } + @ManyToOne + @JoinColumn(name = "user_id") + private User user; - public String getCoverUrl() { - return coverUrl; + private Article() { } - public String getContents() { - return contents; + public Article(String title, String coverUrl, String contents, User user) { + this.title = title; + this.coverUrl = coverUrl; + this.contents = contents; + this.user = user; } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Article article = (Article) o; - return Objects.equals(articleId, article.articleId) && - Objects.equals(title, article.title) && - Objects.equals(coverUrl, article.coverUrl) && - Objects.equals(contents, article.contents); + public void modify(Article article, User user) { + if (!this.user.equals(user)) { + throw new NotExistUserIdException("작성자가 아닙니다."); + } + this.title = article.title; + this.coverUrl = article.coverUrl; + this.contents = article.contents; } - @Override - public int hashCode() { - return Objects.hash(articleId, title, coverUrl, contents); + public boolean checkAuthor(String email) { + return user.checkEmail(email); } -} +} \ No newline at end of file diff --git a/src/main/java/techcourse/myblog/repository/ArticleRepository.java b/src/main/java/techcourse/myblog/domain/ArticleRepository.java similarity index 63% rename from src/main/java/techcourse/myblog/repository/ArticleRepository.java rename to src/main/java/techcourse/myblog/domain/ArticleRepository.java index cd967fcce..193dc5bf0 100644 --- a/src/main/java/techcourse/myblog/repository/ArticleRepository.java +++ b/src/main/java/techcourse/myblog/domain/ArticleRepository.java @@ -1,7 +1,7 @@ -package techcourse.myblog.repository; +package techcourse.myblog.domain; import org.springframework.data.jpa.repository.JpaRepository; -import techcourse.myblog.domain.Article; public interface ArticleRepository extends JpaRepository { -} + +} \ No newline at end of file diff --git a/src/main/java/techcourse/myblog/domain/Comment.java b/src/main/java/techcourse/myblog/domain/Comment.java new file mode 100644 index 000000000..0086cf401 --- /dev/null +++ b/src/main/java/techcourse/myblog/domain/Comment.java @@ -0,0 +1,51 @@ +package techcourse.myblog.domain; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; +import techcourse.myblog.application.service.exception.NotExistUserIdException; + +import javax.persistence.*; +import java.time.LocalDateTime; + +@EqualsAndHashCode(of = "id") +@Getter +@Entity +public class Comment { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + @CreationTimestamp + private LocalDateTime createDateTime; + + @UpdateTimestamp + private LocalDateTime updateDateTime; + + @Lob + private String contents; + + @ManyToOne + private User user; + + @ManyToOne + private Article article; + + protected Comment() { + } + + public Comment(String contents, User user, Article article) { + this.contents = contents; + this.user = user; + this.article = article; + } + + public void modify(String contents, User user) { + if (!this.user.equals(user)) { + throw new NotExistUserIdException("작성자가 아닙니다."); + } + this.contents = contents; + } +} \ No newline at end of file diff --git a/src/main/java/techcourse/myblog/domain/CommentRepository.java b/src/main/java/techcourse/myblog/domain/CommentRepository.java new file mode 100644 index 000000000..2ae520c80 --- /dev/null +++ b/src/main/java/techcourse/myblog/domain/CommentRepository.java @@ -0,0 +1,9 @@ +package techcourse.myblog.domain; + +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +public interface CommentRepository extends JpaRepository { + List findAllByArticleId(long articleId); +} \ No newline at end of file diff --git a/src/main/java/techcourse/myblog/domain/User.java b/src/main/java/techcourse/myblog/domain/User.java index e70710848..2b6a8a1e6 100644 --- a/src/main/java/techcourse/myblog/domain/User.java +++ b/src/main/java/techcourse/myblog/domain/User.java @@ -1,66 +1,59 @@ package techcourse.myblog.domain; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import java.util.Objects; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import techcourse.myblog.application.service.exception.NotExistUserIdException; +import javax.persistence.*; +import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Pattern; + + +@Getter @Entity +@EqualsAndHashCode(of = "id") public class User { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; + private long id; - private String name; + @NotBlank + @Email + @Column(unique = true) private String email; - private String password; - public static User of(String name, String email, String password) { - User user = new User(); - user.name = name; - user.email = email; - user.password = password; - return user; - } - - public void updateUser(String name) { - this.name = name; - } - - public boolean isEqualPassword(String password) { - return this.password.equals(password); - } + @NotBlank + @Pattern(regexp = "^([A-Za-z가-힣]{2,10})$") + private String name; - public Long getId() { - return id; - } + @NotBlank + @Pattern(regexp = "^([a-zA-Z0-9!@#$%^&*]{8,})$") + private String password; - public String getName() { - return name; + private User() { } - public String getEmail() { - return email; + public User(String email, String name, String password) { + this.email = email; + this.name = name; + this.password = password; } - public String getPassword() { - return password; + public void modify(User user) { + if (!this.equals(user)) { + throw new NotExistUserIdException("해당 유저가 아닙니다."); + } + this.password = user.password; + this.name = user.name; } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - User user = (User) o; - return Objects.equals(id, user.id) && - Objects.equals(name, user.name) && - Objects.equals(email, user.email) && - Objects.equals(password, user.password); + public boolean checkPassword(String password) { + return this.password.equals(password); } - @Override - public int hashCode() { - return Objects.hash(id, name, email, password); + public boolean checkEmail(String email) { + return this.email.equals(email); } -} +} \ No newline at end of file diff --git a/src/main/java/techcourse/myblog/repository/UserRepository.java b/src/main/java/techcourse/myblog/domain/UserRepository.java similarity index 72% rename from src/main/java/techcourse/myblog/repository/UserRepository.java rename to src/main/java/techcourse/myblog/domain/UserRepository.java index 8388aaca8..4a69555fd 100644 --- a/src/main/java/techcourse/myblog/repository/UserRepository.java +++ b/src/main/java/techcourse/myblog/domain/UserRepository.java @@ -1,10 +1,11 @@ -package techcourse.myblog.repository; +package techcourse.myblog.domain; import org.springframework.data.jpa.repository.JpaRepository; -import techcourse.myblog.domain.User; import java.util.Optional; public interface UserRepository extends JpaRepository { Optional findByEmail(String email); -} + + boolean existsByEmail(String email); +} \ No newline at end of file diff --git a/src/main/java/techcourse/myblog/dto/ArticleDto.java b/src/main/java/techcourse/myblog/dto/ArticleDto.java deleted file mode 100644 index f4ca7f939..000000000 --- a/src/main/java/techcourse/myblog/dto/ArticleDto.java +++ /dev/null @@ -1,31 +0,0 @@ -package techcourse.myblog.dto; - -public class ArticleDto { - private String title; - private String coverUrl; - private String contents; - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getCoverUrl() { - return coverUrl; - } - - public void setCoverUrl(String coverUrl) { - this.coverUrl = coverUrl; - } - - public String getContents() { - return contents; - } - - public void setContents(String contents) { - this.contents = contents; - } -} diff --git a/src/main/java/techcourse/myblog/dto/LoginDto.java b/src/main/java/techcourse/myblog/dto/LoginDto.java deleted file mode 100644 index 3e06ea7ab..000000000 --- a/src/main/java/techcourse/myblog/dto/LoginDto.java +++ /dev/null @@ -1,22 +0,0 @@ -package techcourse.myblog.dto; - -public class LoginDto { - private String email; - private String password; - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } -} diff --git a/src/main/java/techcourse/myblog/dto/UserDto.java b/src/main/java/techcourse/myblog/dto/UserDto.java deleted file mode 100644 index 7b22a5520..000000000 --- a/src/main/java/techcourse/myblog/dto/UserDto.java +++ /dev/null @@ -1,70 +0,0 @@ -package techcourse.myblog.dto; - -import javax.validation.constraints.Email; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.Pattern; -import javax.validation.constraints.Size; - -public class UserDto { - private static final int MIN_NAME_SIZE = 2; - private static final int MAX_NAME_SIZE = 10; - private static final String NAME_PATTERN = "^[가-힣a-zA-Z]+$"; - private static final String PASSWORD_PATTERN = "^(?=.*[A-Za-z])(?=.*[0-9])(?=.*[$@$!%*#?&])[A-Za-z[0-9]$@$!%*#?&]{8,}$"; - private static final String ERROR_MESSAGE_ABOUT_NAME_SIZE = "이름은 2글자 이상 10글자 이하이어야 합니다."; - private static final String ERROR_MESSAGE_ABOUT_NAME_PATTERN = "이름은 한글 또는 영어만 입력이 가능합니다."; - private static final String ERROR_MESSAGE_ABOUT_EMAIL = "이메일 형식이 아닙니다."; - private static final String ERROR_MESSAGE_ABOUT_PASSWORD_PATTERN = "비밀번호는 8글자 이상으로 특수문자, 숫자, 소문자, 대문자가 포함되어야 합니다."; - - @NotBlank - @Size(min = MIN_NAME_SIZE, max = MAX_NAME_SIZE, message = ERROR_MESSAGE_ABOUT_NAME_SIZE) - @Pattern(regexp = NAME_PATTERN, message = ERROR_MESSAGE_ABOUT_NAME_PATTERN) - private String name; - - @NotBlank - @Email(message = ERROR_MESSAGE_ABOUT_EMAIL) - private String email; - - @NotBlank - @Pattern(regexp = PASSWORD_PATTERN, message = ERROR_MESSAGE_ABOUT_PASSWORD_PATTERN) - private String password; - - @NotBlank - @Pattern(regexp = PASSWORD_PATTERN, message = ERROR_MESSAGE_ABOUT_PASSWORD_PATTERN) - private String passwordConfirm; - - public boolean isEqualInputPassword() { - return this.password.equals(this.passwordConfirm); - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - public String getPasswordConfirm() { - return passwordConfirm; - } - - public void setPasswordConfirm(String passwordConfirm) { - this.passwordConfirm = passwordConfirm; - } -} diff --git a/src/main/java/techcourse/myblog/dto/UserUpdateDto.java b/src/main/java/techcourse/myblog/dto/UserUpdateDto.java deleted file mode 100644 index 411b2d52f..000000000 --- a/src/main/java/techcourse/myblog/dto/UserUpdateDto.java +++ /dev/null @@ -1,24 +0,0 @@ -package techcourse.myblog.dto; - -import javax.validation.constraints.Pattern; -import javax.validation.constraints.Size; - -public class UserUpdateDto { - private static final int MIN_NAME_SIZE = 2; - private static final int MAX_NAME_SIZE = 10; - private static final String NAME_PATTERN = "^[가-힣a-zA-Z]+$"; - private static final String ERROR_MESSAGE_ABOUT_NAME_SIZE = "이름은 2글자 이상 10글자 이하이어야 합니다."; - private static final String ERROR_MESSAGE_ABOUT_NAME_PATTERN = "이름은 한글 또는 영어만 입력이 가능합니다."; - - @Size(min = MIN_NAME_SIZE, max = MAX_NAME_SIZE, message = ERROR_MESSAGE_ABOUT_NAME_SIZE) - @Pattern(regexp = NAME_PATTERN, message = ERROR_MESSAGE_ABOUT_NAME_PATTERN) - private String name; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } -} diff --git a/src/main/java/techcourse/myblog/exception/BlogExceptionHandler.java b/src/main/java/techcourse/myblog/exception/BlogExceptionHandler.java deleted file mode 100644 index daab75774..000000000 --- a/src/main/java/techcourse/myblog/exception/BlogExceptionHandler.java +++ /dev/null @@ -1,52 +0,0 @@ -package techcourse.myblog.exception; - -import org.springframework.ui.Model; -import org.springframework.validation.BindException; -import org.springframework.validation.BindingResult; -import org.springframework.validation.FieldError; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.servlet.mvc.support.RedirectAttributes; -import techcourse.myblog.dto.UserDto; -import techcourse.myblog.dto.UserUpdateDto; - -import javax.servlet.http.HttpSession; - -@ControllerAdvice -public class BlogExceptionHandler { - - @ExceptionHandler(CouldNotFindArticleIdException.class) - public String coultNotFIndArticleId() { - return "redirect:/"; - } - - @ExceptionHandler(BindException.class) - public String methodArgumentNotValid(BindException e, Model model, HttpSession session) { - BindingResult bindingResult = e.getBindingResult(); - FieldError fieldError = bindingResult.getFieldError(); - model.addAttribute("errorMessage", fieldError.getDefaultMessage()); - - String invalidClassName = bindingResult.getTarget().getClass().getName(); - if (invalidClassName.equals(UserDto.class.getName())) { - return "signup"; - } - if (invalidClassName.equals(UserUpdateDto.class.getName())) { - model.addAttribute("loginUser", session.getAttribute("loginUser")); - return "mypage-edit"; - } - - return "/"; - } - - @ExceptionHandler(DuplicateEmailException.class) - public String duplicateEmail(DuplicateEmailException e, RedirectAttributes redirectAttributes) { - redirectAttributes.addFlashAttribute("errorMessage", e.getMessage()); - return "signup"; - } - - @ExceptionHandler(UnequalPasswordException.class) - public String unequalPassword(UnequalPasswordException e, RedirectAttributes redirectAttributes) { - redirectAttributes.addAttribute("errorMessage", e.getMessage()); - return "signup"; - } -} diff --git a/src/main/java/techcourse/myblog/exception/CouldNotFindArticleIdException.java b/src/main/java/techcourse/myblog/exception/CouldNotFindArticleIdException.java deleted file mode 100644 index 504baadd3..000000000 --- a/src/main/java/techcourse/myblog/exception/CouldNotFindArticleIdException.java +++ /dev/null @@ -1,7 +0,0 @@ -package techcourse.myblog.exception; - -public class CouldNotFindArticleIdException extends IllegalArgumentException { - public CouldNotFindArticleIdException() { - super("게시글 ID를 찾을 수 없습니다"); - } -} diff --git a/src/main/java/techcourse/myblog/exception/CouldNotFindUserIdException.java b/src/main/java/techcourse/myblog/exception/CouldNotFindUserIdException.java deleted file mode 100644 index 4665dfacd..000000000 --- a/src/main/java/techcourse/myblog/exception/CouldNotFindUserIdException.java +++ /dev/null @@ -1,7 +0,0 @@ -package techcourse.myblog.exception; - -public class CouldNotFindUserIdException extends IllegalArgumentException { - public CouldNotFindUserIdException() { - super("유저 ID를 찾을 수 없습니다"); - } -} diff --git a/src/main/java/techcourse/myblog/exception/DuplicateEmailException.java b/src/main/java/techcourse/myblog/exception/DuplicateEmailException.java deleted file mode 100644 index c02f7f13d..000000000 --- a/src/main/java/techcourse/myblog/exception/DuplicateEmailException.java +++ /dev/null @@ -1,7 +0,0 @@ -package techcourse.myblog.exception; - -public class DuplicateEmailException extends IllegalArgumentException { - public DuplicateEmailException() { - super("해당 이메일은 존재하는 이메일 입니다."); - } -} diff --git a/src/main/java/techcourse/myblog/exception/InvalidDataFormException.java b/src/main/java/techcourse/myblog/exception/InvalidDataFormException.java deleted file mode 100644 index 33cb5c524..000000000 --- a/src/main/java/techcourse/myblog/exception/InvalidDataFormException.java +++ /dev/null @@ -1,7 +0,0 @@ -package techcourse.myblog.exception; - -public class InvalidDataFormException extends IllegalArgumentException { - public InvalidDataFormException(String message) { - super(message); - } -} diff --git a/src/main/java/techcourse/myblog/exception/NotFindUserEmailException.java b/src/main/java/techcourse/myblog/exception/NotFindUserEmailException.java deleted file mode 100644 index dce27fb99..000000000 --- a/src/main/java/techcourse/myblog/exception/NotFindUserEmailException.java +++ /dev/null @@ -1,7 +0,0 @@ -package techcourse.myblog.exception; - -public class NotFindUserEmailException extends IllegalArgumentException { - public NotFindUserEmailException() { - super("존재하지 않는 이메일 입니다."); - } -} diff --git a/src/main/java/techcourse/myblog/exception/UnequalPasswordException.java b/src/main/java/techcourse/myblog/exception/UnequalPasswordException.java deleted file mode 100644 index 9994aece4..000000000 --- a/src/main/java/techcourse/myblog/exception/UnequalPasswordException.java +++ /dev/null @@ -1,7 +0,0 @@ -package techcourse.myblog.exception; - -public class UnequalPasswordException extends IllegalArgumentException { - public UnequalPasswordException() { - super("비밀번호가 일치하지 않습니다."); - } -} diff --git a/src/main/java/techcourse/myblog/interceptor/LoginInterceptor.java b/src/main/java/techcourse/myblog/interceptor/LoginInterceptor.java deleted file mode 100644 index 3afeae8f5..000000000 --- a/src/main/java/techcourse/myblog/interceptor/LoginInterceptor.java +++ /dev/null @@ -1,51 +0,0 @@ -package techcourse.myblog.interceptor; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.web.servlet.HandlerInterceptor; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - -public class LoginInterceptor implements HandlerInterceptor { - private static final Logger log = LoggerFactory.getLogger(LoginInterceptor.class); - public static final String LOGIN_SESSION_KEY = "loginUser"; - - @Override - public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { - HttpSession session = request.getSession(); - String requestUri= request.getRequestURI(); - String requestMethod = request.getMethod(); - boolean login = session.getAttribute(LOGIN_SESSION_KEY) != null; - - if (login) { - if (isNeedLogin(requestUri, requestMethod)) { - log.debug("login error!"); - response.sendRedirect("/"); - return false; - } - return true; - } - - if (isNeedLogout(requestUri, requestMethod)) { - log.debug("logout error!"); - response.sendRedirect("/login"); - return false; - } - - return true; - } - - private boolean isNeedLogin(String requestUri, String requestMethod) { - return requestUri.contains("/login") - || requestUri.contains("/signup") - || (requestUri.contains("/users") && requestMethod.equals("POST")); - } - - private boolean isNeedLogout(String requestUri, String requestMethod) { - return !requestUri.contains("/login") - && (!requestUri.contains("/users") && !requestMethod.equals("POST")) - && !requestUri.contains("/signup"); - } -} diff --git a/src/main/java/techcourse/myblog/presentation/config/WebMvcConfig.java b/src/main/java/techcourse/myblog/presentation/config/WebMvcConfig.java new file mode 100644 index 000000000..d40895dd9 --- /dev/null +++ b/src/main/java/techcourse/myblog/presentation/config/WebMvcConfig.java @@ -0,0 +1,21 @@ +package techcourse.myblog.presentation.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import techcourse.myblog.presentation.interceptor.LoginCheckInterceptor; + +@Configuration +public class WebMvcConfig implements WebMvcConfigurer { + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(new LoginCheckInterceptor()) + .addPathPatterns("/mypage") + .addPathPatterns("/mypage/edit") + .addPathPatterns("/logout") + .addPathPatterns("/writing") + .addPathPatterns("/articles/*") + .addPathPatterns("/articles/*/edit"); + } +} \ No newline at end of file diff --git a/src/main/java/techcourse/myblog/presentation/controller/ArticleController.java b/src/main/java/techcourse/myblog/presentation/controller/ArticleController.java new file mode 100644 index 000000000..9ba1d0a0e --- /dev/null +++ b/src/main/java/techcourse/myblog/presentation/controller/ArticleController.java @@ -0,0 +1,79 @@ +package techcourse.myblog.presentation.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.view.RedirectView; +import techcourse.myblog.application.dto.ArticleDto; +import techcourse.myblog.application.dto.CommentDto; +import techcourse.myblog.application.service.ArticleService; +import techcourse.myblog.application.service.CommentService; +import techcourse.myblog.application.service.UserService; + +import javax.servlet.http.HttpSession; +import java.util.List; + +@RequestMapping("/articles") +@Controller +public class ArticleController { + private final ArticleService articleService; + private final CommentService commentService; + private final UserService userService; + + @Autowired + public ArticleController(final ArticleService articleService, CommentService commentService, UserService userService) { + this.articleService = articleService; + this.commentService = commentService; + this.userService = userService; + } + + @PostMapping("") + public RedirectView createArticles(HttpSession httpSession, ArticleDto article) { + String email = (String) httpSession.getAttribute("email"); + Long id = articleService.save(article, email); + + return new RedirectView("/articles/" + id); + } + + @GetMapping("/{articleId}") + public ModelAndView readArticlePageByArticleId(@PathVariable Long articleId) { + ModelAndView modelAndView = new ModelAndView("/article"); + modelAndView.addObject("article", articleService.findById(articleId)); + modelAndView.addObject("user", articleService.findAuthor(articleId)); + + List commentDtos = commentService.findAllByArticleId(articleId); + modelAndView.addObject("comments", commentDtos); + return modelAndView; + } + + @PutMapping("/{articleId}") + public RedirectView updateArticle(HttpSession httpSession, @PathVariable Long articleId, ArticleDto article) { + String email = (String) httpSession.getAttribute("email"); + articleService.checkAuthor(articleId, email); + articleService.modify(articleId, article, email); + + return new RedirectView("/articles/" + articleId); + } + + @DeleteMapping("/{articleId}") + public RedirectView deleteArticle(HttpSession httpSession, @PathVariable Long articleId) { + String email = (String) httpSession.getAttribute("email"); + articleService.checkAuthor(articleId, email); + + articleService.removeById(articleId); + return new RedirectView("/"); + } + + @GetMapping("/{articleId}/edit") + public ModelAndView readArticleEditPage(HttpSession httpSession, @PathVariable Long articleId) { + String email = (String) httpSession.getAttribute("email"); + articleService.checkAuthor(articleId, email); + + ModelAndView modelAndView = new ModelAndView("/article-edit"); + modelAndView.addObject("article", articleService.findById(articleId)); + modelAndView.addObject("method", "put"); + + return modelAndView; + } +} \ No newline at end of file diff --git a/src/main/java/techcourse/myblog/presentation/controller/CommentController.java b/src/main/java/techcourse/myblog/presentation/controller/CommentController.java new file mode 100644 index 000000000..5a6929342 --- /dev/null +++ b/src/main/java/techcourse/myblog/presentation/controller/CommentController.java @@ -0,0 +1,44 @@ +package techcourse.myblog.presentation.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.view.RedirectView; +import techcourse.myblog.application.dto.CommentDto; +import techcourse.myblog.application.service.CommentService; + +import javax.servlet.http.HttpSession; + +@RequestMapping("/articles") +@Controller +public class CommentController { + + private CommentService commentService; + + public CommentController(CommentService commentService) { + this.commentService = commentService; + } + + @PostMapping("/{articleId}") + public RedirectView create(HttpSession httpSession, CommentDto commentDto, @PathVariable Long articleId) { + String email = (String) httpSession.getAttribute("email"); + + commentService.save(commentDto, email, articleId); + return new RedirectView("/articles/" + articleId); + } + + @DeleteMapping("/{articleId}/{commentId}") + public RedirectView delete(HttpSession httpSession, @PathVariable Long articleId, @PathVariable Long commentId) { + String email = (String) httpSession.getAttribute("email"); + + commentService.delete(commentId, email); + return new RedirectView("/articles/" + articleId); + } + + @PutMapping("/{articleId}/comment-edit/{commentId}") + public RedirectView update(HttpSession httpSession, CommentDto commentDto, @PathVariable Long articleId, @PathVariable Long commentId) { + String email = (String) httpSession.getAttribute("email"); + + commentService.update(commentId, commentDto, email); + return new RedirectView("/articles/" + articleId); + } +} \ No newline at end of file diff --git a/src/main/java/techcourse/myblog/presentation/controller/MainController.java b/src/main/java/techcourse/myblog/presentation/controller/MainController.java new file mode 100644 index 000000000..4aa973d82 --- /dev/null +++ b/src/main/java/techcourse/myblog/presentation/controller/MainController.java @@ -0,0 +1,48 @@ +package techcourse.myblog.presentation.controller; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import techcourse.myblog.application.service.ArticleService; + +import javax.servlet.http.HttpSession; + +@Controller +public class MainController { + private static final Logger log = LoggerFactory.getLogger(MainController.class); + + private final ArticleService articleService; + + public MainController(final ArticleService articleService) { + this.articleService = articleService; + } + + @GetMapping("/") + public String readHomePage(HttpSession httpSession, Model model) { + model.addAttribute("articles", articleService.findAll()); + + if (httpSession.getAttribute("email") != null) { + model.addAttribute("email", httpSession.getAttribute("email")); + } + + return "/index"; + } + + @GetMapping("/writing") + public String readWritingPage(Model model) { + model.addAttribute("method", "post"); + return "/article-edit"; + } + + @GetMapping("/login") + public String readLoginPage() { + return "login"; + } + + @GetMapping("/signup") + public String readSignUpPage() { + return "signup"; + } +} \ No newline at end of file diff --git a/src/main/java/techcourse/myblog/presentation/controller/UserController.java b/src/main/java/techcourse/myblog/presentation/controller/UserController.java new file mode 100644 index 000000000..64bdde8ef --- /dev/null +++ b/src/main/java/techcourse/myblog/presentation/controller/UserController.java @@ -0,0 +1,94 @@ +package techcourse.myblog.presentation.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.view.RedirectView; +import techcourse.myblog.application.dto.LoginDto; +import techcourse.myblog.application.dto.UserDto; +import techcourse.myblog.application.service.UserService; + +import javax.servlet.http.HttpSession; +import javax.validation.Valid; + +@Controller +public class UserController { + private final UserService userService; + + @Autowired + public UserController(UserService userService) { + this.userService = userService; + } + + @PostMapping("/users") + public RedirectView createUser(@Valid UserDto user) { + userService.save(user); + + return new RedirectView("/login"); + } + + @GetMapping("/users") + public ModelAndView readUsers() { + ModelAndView modelAndView = new ModelAndView("user-list"); + modelAndView.addObject("users", userService.findAll()); + return modelAndView; + } + + @PostMapping("/login") + public RedirectView login(HttpSession httpSession, LoginDto loginDto) { + userService.login(loginDto); + httpSession.setAttribute("email", loginDto.getEmail()); + httpSession.setMaxInactiveInterval(600); + + return new RedirectView("/"); + } + + @GetMapping("/logout") + public RedirectView logout(HttpSession httpSession) { + httpSession.invalidate(); + + return new RedirectView("/"); + } + + @GetMapping("/mypage") + public ModelAndView readMyPage(HttpSession httpSession) { + ModelAndView modelAndView = new ModelAndView(); + String email = (String) httpSession.getAttribute("email"); + + modelAndView.setViewName("mypage"); + modelAndView.addObject("user", userService.findByEmail(email)); + + return modelAndView; + } + + @GetMapping("/mypage/edit") + public ModelAndView readMyPageEdit(HttpSession httpSession) { + ModelAndView modelAndView = new ModelAndView(); + String email = (String) httpSession.getAttribute("email"); + modelAndView.setViewName("mypage-edit"); + modelAndView.addObject("user", userService.findByEmail(email)); + + return modelAndView; + } + + @PutMapping("/mypage/edit") + public RedirectView updateUser(HttpSession httpSession, @Valid UserDto user) { + String email = (String) httpSession.getAttribute("email"); + userService.modify(user, email); + + return new RedirectView("/mapage"); + } + + @DeleteMapping("/users") + public RedirectView deleteUser(HttpSession httpSession, @Valid UserDto user) { + String email = (String) httpSession.getAttribute("email"); + userService.removeById(user, email); + httpSession.invalidate(); + + return new RedirectView("/"); + } +} \ No newline at end of file diff --git a/src/main/java/techcourse/myblog/presentation/controller/UserExceptionHandler.java b/src/main/java/techcourse/myblog/presentation/controller/UserExceptionHandler.java new file mode 100644 index 000000000..15622a8ea --- /dev/null +++ b/src/main/java/techcourse/myblog/presentation/controller/UserExceptionHandler.java @@ -0,0 +1,60 @@ +package techcourse.myblog.presentation.controller; + +import org.springframework.context.support.DefaultMessageSourceResolvable; +import org.springframework.validation.BindException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; +import org.springframework.web.servlet.view.RedirectView; +import techcourse.myblog.application.service.exception.*; + +import java.util.stream.Collectors; + +@ControllerAdvice +public class UserExceptionHandler { + + @ExceptionHandler(DuplicatedIdException.class) + public RedirectView handleDuplicatedIdError(RedirectAttributes redirectAttributes, DuplicatedIdException e) { + redirectAttributes.addFlashAttribute("errormessage", e.getMessage()); + + return new RedirectView("/signup"); + } + + @ExceptionHandler(NotExistUserIdException.class) + public RedirectView handleNotExistIdError(RedirectAttributes redirectAttributes, NotExistUserIdException e) { + redirectAttributes.addFlashAttribute("errormessage", e.getMessage()); + + return new RedirectView("/login"); + } + + @ExceptionHandler(NotMatchPasswordException.class) + public RedirectView handleNotMatchPasswordError(RedirectAttributes redirectAttributes, NotMatchPasswordException e) { + redirectAttributes.addFlashAttribute("errormessage", e.getMessage()); + + return new RedirectView("/login"); + } + + @ExceptionHandler(BindException.class) + public RedirectView handleBindError(RedirectAttributes redirectAttributes, BindException e) { + String errorMessages = e.getFieldErrors().stream() + .map(DefaultMessageSourceResolvable::getDefaultMessage) + .collect(Collectors.joining("\n")); + + redirectAttributes.addFlashAttribute("errormessage", errorMessages); + return new RedirectView("signup"); + } + + @ExceptionHandler(NotExistCommentException.class) + public RedirectView handleNotMatchCommentUserError(RedirectAttributes redirectAttributes, NotExistCommentException e) { + redirectAttributes.addFlashAttribute("errormessage", e.getMessage()); + + return new RedirectView("/"); + } + + @ExceptionHandler(NotMatchEmailException.class) + public RedirectView handleNotMatchEmailError(RedirectAttributes redirectAttributes, NotMatchEmailException e) { + redirectAttributes.addFlashAttribute("errormessage", e.getMessage()); + + return new RedirectView("/"); + } +} \ No newline at end of file diff --git a/src/main/java/techcourse/myblog/presentation/interceptor/LoginCheckInterceptor.java b/src/main/java/techcourse/myblog/presentation/interceptor/LoginCheckInterceptor.java new file mode 100644 index 000000000..9b54e690f --- /dev/null +++ b/src/main/java/techcourse/myblog/presentation/interceptor/LoginCheckInterceptor.java @@ -0,0 +1,26 @@ +package techcourse.myblog.presentation.interceptor; + +import org.springframework.web.servlet.FlashMap; +import org.springframework.web.servlet.FlashMapManager; +import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; +import org.springframework.web.servlet.support.RequestContextUtils; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class LoginCheckInterceptor extends HandlerInterceptorAdapter { + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + if(request.getSession().getAttribute("email") == null){ + response.sendRedirect("/login"); + FlashMap flashMap = new FlashMap(); + flashMap.put("errormessage", "로그인이 필요합니다."); + FlashMapManager flashMapManager = RequestContextUtils.getFlashMapManager(request); + flashMapManager.saveOutputFlashMap(flashMap, request, response); + return false; + } + + return true; + } +} diff --git a/src/main/java/techcourse/myblog/service/ArticleService.java b/src/main/java/techcourse/myblog/service/ArticleService.java deleted file mode 100644 index cd2c8eded..000000000 --- a/src/main/java/techcourse/myblog/service/ArticleService.java +++ /dev/null @@ -1,53 +0,0 @@ -package techcourse.myblog.service; - -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.ui.Model; -import techcourse.myblog.domain.Article; -import techcourse.myblog.dto.ArticleDto; -import techcourse.myblog.exception.CouldNotFindArticleIdException; -import techcourse.myblog.repository.ArticleRepository; - -@Service -public class ArticleService { - private final ArticleRepository articleRepository; - - public ArticleService(ArticleRepository articleRepository) { - this.articleRepository = articleRepository; - } - - public Article save(ArticleDto articleDto) { - Article article = Article.of(articleDto.getTitle(), - articleDto.getCoverUrl(), - articleDto.getContents() - ); - - return articleRepository.save(article); - } - - public Article findArticleById(Long articleId) { - return articleRepository.findById(articleId) - .orElseThrow(CouldNotFindArticleIdException::new); - } - - @Transactional - public Article update(Long articleId, ArticleDto articleDto) { - Article findArticle = findArticleById(articleId); - - findArticle.updateArticle( - Article.of(articleDto.getTitle(), articleDto.getCoverUrl(), articleDto.getContents()) - ); - - return findArticle; - } - - public Long deleteById(Long articleId) { - articleRepository.deleteById(articleId); - return articleId; - } - - public void setActionOfArticle(Model model, String actionRoute, String formMethod) { - model.addAttribute("actionRoute", actionRoute); - model.addAttribute("formMethod", formMethod); - } -} diff --git a/src/main/java/techcourse/myblog/service/LoginService.java b/src/main/java/techcourse/myblog/service/LoginService.java deleted file mode 100644 index 18f9ef8a0..000000000 --- a/src/main/java/techcourse/myblog/service/LoginService.java +++ /dev/null @@ -1,31 +0,0 @@ -package techcourse.myblog.service; - -import org.springframework.stereotype.Service; -import techcourse.myblog.domain.User; -import techcourse.myblog.dto.LoginDto; -import techcourse.myblog.exception.NotFindUserEmailException; -import techcourse.myblog.exception.UnequalPasswordException; -import techcourse.myblog.repository.UserRepository; - -@Service -public class LoginService { - private final UserRepository userRepository; - - public LoginService(UserRepository userRepository) { - this.userRepository = userRepository; - } - - public User findUser(LoginDto loginDto) { - User findUser = userRepository.findByEmail(loginDto.getEmail()) - .orElseThrow(NotFindUserEmailException::new); - - checkEqualPassword(findUser, loginDto.getPassword()); - return findUser; - } - - private void checkEqualPassword(User findUser, String inputPassword) { - if (!findUser.isEqualPassword(inputPassword)) { - throw new UnequalPasswordException(); - } - } -} diff --git a/src/main/java/techcourse/myblog/service/UserService.java b/src/main/java/techcourse/myblog/service/UserService.java deleted file mode 100644 index e3fb5efa2..000000000 --- a/src/main/java/techcourse/myblog/service/UserService.java +++ /dev/null @@ -1,58 +0,0 @@ -package techcourse.myblog.service; - -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import techcourse.myblog.domain.User; -import techcourse.myblog.dto.UserDto; -import techcourse.myblog.dto.UserUpdateDto; -import techcourse.myblog.exception.DuplicateEmailException; -import techcourse.myblog.exception.UnequalPasswordException; -import techcourse.myblog.repository.UserRepository; - -import javax.servlet.http.HttpSession; -import java.util.List; - -@Service -public class UserService { - private static final String LOGIN_SESSION_KEY = "loginUser"; - - private final UserRepository userRepository; - - public UserService(UserRepository userRepository) { - this.userRepository = userRepository; - } - - public void save(UserDto userDto) { - checkEqualPassword(userDto); - checkDuplicateEmail(userDto.getEmail()); - User user = User.of(userDto.getName(), userDto.getEmail(), userDto.getPassword()); - userRepository.save(user); - } - - private void checkEqualPassword(UserDto userDto) { - if (!userDto.isEqualInputPassword()) { - throw new UnequalPasswordException(); - } - } - - private void checkDuplicateEmail(String email) { - if (userRepository.findByEmail(email).isPresent()) { - throw new DuplicateEmailException(); - } - } - - @Transactional - public void update(User user, UserUpdateDto userUpdateDto) { - user.updateUser(userUpdateDto.getName()); - } - - public void delete(HttpSession session) { - Long userId = ((User) session.getAttribute(LOGIN_SESSION_KEY)).getId(); - userRepository.deleteById(userId); - session.removeAttribute(LOGIN_SESSION_KEY); - } - - public List getUserList() { - return userRepository.findAll(); - } -} diff --git a/src/main/java/techcourse/myblog/web/ArticleController.java b/src/main/java/techcourse/myblog/web/ArticleController.java deleted file mode 100644 index cc14d1f00..000000000 --- a/src/main/java/techcourse/myblog/web/ArticleController.java +++ /dev/null @@ -1,72 +0,0 @@ -package techcourse.myblog.web; - -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.*; -import techcourse.myblog.domain.Article; -import techcourse.myblog.dto.ArticleDto; -import techcourse.myblog.service.ArticleService; - -import javax.servlet.http.HttpSession; - -@Controller -public class ArticleController { - private static final String LOGIN_SESSION_KEY = "loginUser"; - private final ArticleService articleService; - - public ArticleController(ArticleService articleService) { - this.articleService = articleService; - } - - @PostMapping("/write") - public String createArticle(ArticleDto articleDto) { - Article article = articleService.save(articleDto); - return "redirect:/articles/" + article.getArticleId(); - } - - @GetMapping("/articles/new") - public String editNewArticleView(HttpSession session, Model model) { - model.addAttribute(LOGIN_SESSION_KEY, session.getAttribute(LOGIN_SESSION_KEY)); - articleService.setActionOfArticle(model, - "/write", - "post" - ); - - return "article-edit"; - } - - @GetMapping("/articles/{articleId}/edit") - public String editArticleView(@PathVariable Long articleId, HttpSession session, Model model) { - model.addAttribute(LOGIN_SESSION_KEY, session.getAttribute(LOGIN_SESSION_KEY)); - Article findArticle = articleService.findArticleById(articleId); - articleService.setActionOfArticle(model, - "/articles/" + articleId, - "put" - ); - - model.addAttribute("article", findArticle); - return "article-edit"; - } - - @GetMapping("/articles/{articleId}") - public String searchArticleView(@PathVariable Long articleId, HttpSession session, Model model) { - model.addAttribute(LOGIN_SESSION_KEY, session.getAttribute(LOGIN_SESSION_KEY)); - Article findArticle = articleService.findArticleById(articleId); - model.addAttribute("article", findArticle); - return "article"; - } - - @PutMapping("/articles/{articleId}") - public String updateArticle(@PathVariable Long articleId, ArticleDto articleDto) { - Article updateArticle = articleService.update(articleId, articleDto); - - return "redirect:/articles/" + updateArticle.getArticleId(); - } - - @DeleteMapping("/articles/{articleId}") - public String deleteArticle(@PathVariable Long articleId) { - articleService.deleteById(articleId); - - return "redirect:/"; - } -} diff --git a/src/main/java/techcourse/myblog/web/ControllerUtil.java b/src/main/java/techcourse/myblog/web/ControllerUtil.java deleted file mode 100644 index b7ae9aaa0..000000000 --- a/src/main/java/techcourse/myblog/web/ControllerUtil.java +++ /dev/null @@ -1,15 +0,0 @@ -package techcourse.myblog.web; - -import org.springframework.ui.Model; - -import javax.servlet.http.HttpSession; - -public class ControllerUtil { - private static final String LOGIN_SESSION_KEY = "loginUser"; - - public static void putLoginUser(HttpSession session, Model model) { - if (session.getAttribute(LOGIN_SESSION_KEY) != null) { - model.addAttribute(LOGIN_SESSION_KEY, session.getAttribute(LOGIN_SESSION_KEY)); - } - } -} diff --git a/src/main/java/techcourse/myblog/web/IndexController.java b/src/main/java/techcourse/myblog/web/IndexController.java deleted file mode 100644 index 4941e3d37..000000000 --- a/src/main/java/techcourse/myblog/web/IndexController.java +++ /dev/null @@ -1,30 +0,0 @@ -package techcourse.myblog.web; - -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.GetMapping; -import techcourse.myblog.domain.Article; -import techcourse.myblog.repository.ArticleRepository; - -import javax.servlet.http.HttpSession; -import java.util.List; - -import static techcourse.myblog.web.ControllerUtil.putLoginUser; - -@Controller -public class IndexController { - private final ArticleRepository articleRepository; - - public IndexController(ArticleRepository articleRepository) { - this.articleRepository = articleRepository; - } - - @GetMapping("/") - public String indexView(HttpSession session, Model model) { - putLoginUser(session, model); - List
articles = articleRepository.findAll(); - - model.addAttribute("articles", articles); - return "index"; - } -} diff --git a/src/main/java/techcourse/myblog/web/LoginController.java b/src/main/java/techcourse/myblog/web/LoginController.java deleted file mode 100644 index ddcc9dd8a..000000000 --- a/src/main/java/techcourse/myblog/web/LoginController.java +++ /dev/null @@ -1,43 +0,0 @@ -package techcourse.myblog.web; - -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import techcourse.myblog.domain.User; -import techcourse.myblog.dto.LoginDto; -import techcourse.myblog.service.LoginService; - -import javax.servlet.http.HttpSession; - -@Controller -public class LoginController { - private final LoginService loginService; - - public LoginController(LoginService loginService) { - this.loginService = loginService; - } - - @PostMapping("/login") - public String postLogin(LoginDto loginDto, Model model, HttpSession session) { - try { - User loginUser = loginService.findUser(loginDto); - session.setAttribute("loginUser", loginUser); - return "redirect:/"; - } catch (IllegalArgumentException e) { - model.addAttribute("errorMessage", e.getMessage()); - return "login"; - } - } - - @GetMapping("/login") - public String loginView() { - return "login"; - } - - @GetMapping("/logout") - public String logoutView(HttpSession session) { - session.removeAttribute("loginUser"); - return "redirect:/login"; - } -} diff --git a/src/main/java/techcourse/myblog/web/UserController.java b/src/main/java/techcourse/myblog/web/UserController.java deleted file mode 100644 index 879ca67a4..000000000 --- a/src/main/java/techcourse/myblog/web/UserController.java +++ /dev/null @@ -1,71 +0,0 @@ -package techcourse.myblog.web; - -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import techcourse.myblog.domain.User; -import techcourse.myblog.dto.UserDto; -import techcourse.myblog.dto.UserUpdateDto; -import techcourse.myblog.service.UserService; - -import javax.servlet.http.HttpSession; -import javax.validation.Valid; - -import static techcourse.myblog.web.ControllerUtil.putLoginUser; - -@Controller -public class UserController { - private static final String LOGIN_SESSION_KEY = "loginUser"; - - private final UserService userService; - - public UserController(UserService userService) { - this.userService = userService; - } - - @PostMapping("/users") - public String createUser(@Valid UserDto userDto) { - userService.save(userDto); - return "redirect:/login"; - } - - @GetMapping("/signup") - public String signUpView() { - return "signup"; - } - - @GetMapping("/users") - public String userListView(HttpSession session, Model model) { - putLoginUser(session, model); - model.addAttribute("userList", userService.getUserList()); - return "user-list"; - } - - @GetMapping("/mypage") - public String myPageView(HttpSession session, Model model) { - model.addAttribute(LOGIN_SESSION_KEY, session.getAttribute(LOGIN_SESSION_KEY)); - return "mypage"; - } - - @GetMapping("/mypage-edit") - public String editMyPageView(HttpSession session, Model model) { - model.addAttribute(LOGIN_SESSION_KEY, session.getAttribute(LOGIN_SESSION_KEY)); - return "mypage-edit"; - } - - @PutMapping("/mypage-edit") - public String updateUser(@Valid UserUpdateDto userUpdateDto, HttpSession session) { - User user = (User) session.getAttribute(LOGIN_SESSION_KEY); - userService.update(user, userUpdateDto); - return "redirect:/mypage"; - } - - @DeleteMapping("/withdrawal") - public String withdrawalUser(HttpSession session) { - userService.delete(session); - return "redirect:/"; - } -} diff --git a/src/main/resources/.DS_Store b/src/main/resources/.DS_Store new file mode 100644 index 000000000..373e593c8 Binary files /dev/null and b/src/main/resources/.DS_Store differ diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties old mode 100644 new mode 100755 index 0134f5508..8c0fee5a2 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,14 +1,16 @@ +spring.thymeleaf.prefix=classpath:/templates/ +spring.thymeleaf.cache=false spring.devtools.livereload.enabled=true -spring.datasource.url=jdbc:mysql://localhost/jwp_blog?allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=UTC +spring.datasource.url=jdbc:mysql://localhost:3306/blog_db?characterEncoding=UTF-8&serverTimezone=UTC&allowPublicKeyRetrieval=true&useSSL=false spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver -spring.datasource.username=root -spring.datasource.password=0000 -spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect +spring.datasource.username=zino +spring.datasource.password=1234 -spring.jpa.properties.hibernate.show_sql=true -spring.jpa.properties.hibernate.format_sql=true -spring.jpa.properties.hibernate.use_sql_comments=true +spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect + +spring.h2.console.enabled=true +spring.h2.console.path=/h2-console spring.jpa.generate-ddl=true -hibernate.hbm2ddl.auto=create +hibernate.hbm2ddl.auto=create \ No newline at end of file diff --git a/src/main/resources/logback-access.xml b/src/main/resources/logback-access.xml old mode 100644 new mode 100755 diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml old mode 100644 new mode 100755 index 2d6866bcc..2bf922f81 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -8,9 +8,11 @@ - + + + + - diff --git a/src/main/resources/static/css/app.css b/src/main/resources/static/css/app.css old mode 100644 new mode 100755 diff --git a/src/main/resources/static/css/article-edit.css b/src/main/resources/static/css/article-edit.css old mode 100644 new mode 100755 diff --git a/src/main/resources/static/css/article.css b/src/main/resources/static/css/article.css old mode 100644 new mode 100755 diff --git a/src/main/resources/static/css/customize.css b/src/main/resources/static/css/customize.css old mode 100644 new mode 100755 diff --git a/src/main/resources/static/css/index.css b/src/main/resources/static/css/index.css old mode 100644 new mode 100755 diff --git a/src/main/resources/static/css/main.css b/src/main/resources/static/css/main.css old mode 100644 new mode 100755 diff --git a/src/main/resources/static/css/mypage.css b/src/main/resources/static/css/mypage.css old mode 100644 new mode 100755 diff --git a/src/main/resources/static/images/default/bg.jpg b/src/main/resources/static/images/default/bg.jpg old mode 100644 new mode 100755 diff --git a/src/main/resources/static/images/logo/favicon.ico b/src/main/resources/static/images/logo/favicon.ico old mode 100644 new mode 100755 diff --git a/src/main/resources/static/images/logo/logo_full_dark.png b/src/main/resources/static/images/logo/logo_full_dark.png old mode 100644 new mode 100755 diff --git a/src/main/resources/static/images/logo/logo_full_white.png b/src/main/resources/static/images/logo/logo_full_white.png old mode 100644 new mode 100755 diff --git a/src/main/resources/static/images/logo/logo_small_dark.png b/src/main/resources/static/images/logo/logo_small_dark.png old mode 100644 new mode 100755 diff --git a/src/main/resources/static/images/logo/logo_small_white.png b/src/main/resources/static/images/logo/logo_small_white.png old mode 100644 new mode 100755 diff --git a/src/main/resources/static/images/logo/logo_thumnail_bg.jpg b/src/main/resources/static/images/logo/logo_thumnail_bg.jpg old mode 100644 new mode 100755 diff --git a/src/main/resources/static/images/pages/index/bg.jpg b/src/main/resources/static/images/pages/index/bg.jpg old mode 100644 new mode 100755 diff --git a/src/main/resources/static/images/pages/index/study.jpg b/src/main/resources/static/images/pages/index/study.jpg old mode 100644 new mode 100755 diff --git a/src/main/resources/static/js/index.js b/src/main/resources/static/js/index.js old mode 100644 new mode 100755 diff --git a/src/main/resources/templates/article-edit.html b/src/main/resources/templates/article-edit.html old mode 100644 new mode 100755 index 15f167192..5b53602b0 --- a/src/main/resources/templates/article-edit.html +++ b/src/main/resources/templates/article-edit.html @@ -1,35 +1,85 @@ - + + + + + - - + + + +
- -
- + +
+ +
+
+ + + + + - + diff --git a/src/main/resources/templates/article.html b/src/main/resources/templates/article.html old mode 100644 new mode 100755 index 0a57987e2..e23e684e0 --- a/src/main/resources/templates/article.html +++ b/src/main/resources/templates/article.html @@ -1,14 +1,57 @@ - + + + + + - - + + + +
- + +
@@ -20,13 +63,15 @@

- - - - + + + + - +
@@ -37,7 +82,7 @@

- Brown / gracefulBrown@woowahan.com +

백엔드 개발자: 설계.테스트.생산성.클린코드.멘토링에 관심이 많음
Woowahantechcourse Organizer / Coach / Husband @@ -60,37 +105,74 @@

댓글 - 2 +
-
    -
  • - -
    - Jun - - - 6 min ago - -

    3주라는 짧은 기간에 효과적으로 연습하도록 하기 위해 의식적인 연습을 기반으로 미션을 진행하도록 설계했다. 교육자로 살다 보니 효과적인 학습 방법에 대한 관심이 높아졌다. 효과적인 학습 방법을 찾던 중 “1만 시간의 재발견”이라는 책을 통해 의식적인 연습의 중요성을 느낄 수 있는 계기가 되었다.

    -
    -
  • - -
  • - -
    - Jun - - - 6 min ago - -

    브라운 멋져

    -
    -
  • - +
      +
      +
    • + +
      + Jun + + + + + + + + + + + +
      + + + + +
      +
      + + + + + +
      +

      +
      +
    • +
    -
    +
    + +
    + +
    +
@@ -98,28 +180,39 @@

- - - + \ No newline at end of file diff --git a/src/main/resources/templates/comment-edit.html b/src/main/resources/templates/comment-edit.html new file mode 100644 index 000000000..e3b34be76 --- /dev/null +++ b/src/main/resources/templates/comment-edit.html @@ -0,0 +1,10 @@ + + + + + Title + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/error/error-page.html b/src/main/resources/templates/error/error-page.html new file mode 100755 index 000000000..244cb5968 --- /dev/null +++ b/src/main/resources/templates/error/error-page.html @@ -0,0 +1,12 @@ + + + + + + 우아한테크코스 기술블로그 + + + + +홈으로 + \ No newline at end of file diff --git a/src/main/resources/templates/fragments/article/styles.html b/src/main/resources/templates/fragments/article/styles.html deleted file mode 100644 index a0f21ff2b..000000000 --- a/src/main/resources/templates/fragments/article/styles.html +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/src/main/resources/templates/fragments/body.html b/src/main/resources/templates/fragments/body.html new file mode 100755 index 000000000..6316a6e22 --- /dev/null +++ b/src/main/resources/templates/fragments/body.html @@ -0,0 +1,13 @@ + + + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/fragments/meta.html b/src/main/resources/templates/fragments/head.html old mode 100644 new mode 100755 similarity index 54% rename from src/main/resources/templates/fragments/meta.html rename to src/main/resources/templates/fragments/head.html index 1027c4c76..05df9f863 --- a/src/main/resources/templates/fragments/meta.html +++ b/src/main/resources/templates/fragments/head.html @@ -1,6 +1,5 @@ - + 우아한테크코스 기술블로그 @@ -17,3 +16,10 @@ + + + + + + + diff --git a/src/main/resources/templates/fragments/header.html b/src/main/resources/templates/fragments/header.html deleted file mode 100644 index e2cbfd54f..000000000 --- a/src/main/resources/templates/fragments/header.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/src/main/resources/templates/fragments/scripts.html b/src/main/resources/templates/fragments/scripts.html deleted file mode 100644 index 17ae5f297..000000000 --- a/src/main/resources/templates/fragments/scripts.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - \ No newline at end of file diff --git a/src/main/resources/templates/fragments/styles.html b/src/main/resources/templates/fragments/styles.html deleted file mode 100644 index e942dd3bb..000000000 --- a/src/main/resources/templates/fragments/styles.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html old mode 100644 new mode 100755 index 84cac1611..3aa9d783c --- a/src/main/resources/templates/index.html +++ b/src/main/resources/templates/index.html @@ -1,14 +1,37 @@ - - + + + + +
+ -
@@ -35,45 +58,39 @@

Welcome Brown!

-
-
-
- -
-
-
-
-
- + + - + - + \ No newline at end of file diff --git a/src/main/resources/templates/login.html b/src/main/resources/templates/login.html old mode 100644 new mode 100755 index 327e39090..a9d85c0ef --- a/src/main/resources/templates/login.html +++ b/src/main/resources/templates/login.html @@ -1,8 +1,11 @@ - - + + + + +
@@ -35,10 +38,10 @@

로그인

- +
- +
@@ -47,7 +50,6 @@

로그인

-
@@ -70,6 +72,7 @@

로그인

- + + - + \ No newline at end of file diff --git a/src/main/resources/templates/mypage-edit.html b/src/main/resources/templates/mypage-edit.html old mode 100644 new mode 100755 index 2df96ddb8..8e831d809 --- a/src/main/resources/templates/mypage-edit.html +++ b/src/main/resources/templates/mypage-edit.html @@ -1,14 +1,55 @@ - - - - + + + + + + +
- + +
@@ -17,98 +58,87 @@
- -
-
+
+
-
-

profile

- -
-
-
-
-

Name

-
-
- -
-
-
-

- -

+ + +
+

profile

+
-
-
-
-

Email

-
-
-

-
-
-
-
-
-

Avatar

+
+
+
+

Name

+
+
+ +
-
-
- +
+
+
+

Email

+
+
+

+
-
-
-
-
-

SNS

+
+
+
+

Password

+
+
+ +
-
-
-
- - - +
+
+
+

SNS

+
+
+
+
+ + + + - - Github -
-
- + Github +
+
+ +
-
-
-
-
- - - +
+
+
+ + + + - - Facebook -
-
- + Facebook +
+
+ +
-
+
-
- - +
- + - + \ No newline at end of file diff --git a/src/main/resources/templates/mypage.html b/src/main/resources/templates/mypage.html old mode 100644 new mode 100755 index 3227ab659..eeae57e02 --- a/src/main/resources/templates/mypage.html +++ b/src/main/resources/templates/mypage.html @@ -1,14 +1,55 @@ - - - - + + + + + + +
- + +
@@ -23,7 +64,7 @@

profile

- +
@@ -33,7 +74,7 @@

profile

Name

-

+


@@ -42,20 +83,10 @@

profile

Email

-

+


-
-
-

Avatar

-
-
-
- -
-
-

@@ -64,11 +95,11 @@

profile

- - - + + + + - Github
@@ -78,11 +109,11 @@

profile


- - - + + + + - Facebook
@@ -90,14 +121,16 @@

profile


-
-
-
+
+
+ - + +
+
@@ -107,6 +140,6 @@

profile

- + diff --git a/src/main/resources/templates/signup.html b/src/main/resources/templates/signup.html old mode 100644 new mode 100755 index 14aea16c6..a1653af71 --- a/src/main/resources/templates/signup.html +++ b/src/main/resources/templates/signup.html @@ -1,8 +1,11 @@ - - + + + + +
@@ -20,7 +23,7 @@