Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[Starve + Kyu] Mission5 - XHR과 AJAX #138

Open
wants to merge 20 commits into
base: Jiwon-JJW
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ dependencies {
implementation group: 'com.h2database', name: 'h2', version: '1.4.200'
runtimeOnly 'com.h2database:h2'
implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.3'

implementation group: 'io.springfox', name: 'springfox-swagger2', version: '2.9.2'
implementation group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.9.2'
Comment on lines +27 to +28
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

swagger를 사용하는 이유를 한 번 생각해보세요!


testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
Comment on lines +30 to +32
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spring Boot 2.4 버전부터는 vintage engine이 기본적으로 포함되어있지 않아서
exclude 사용해주지 않으셔도 됩니다!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그리고 위에 이미 존재합니다.

}

test {
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/codessquad/qna/QnaApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@SpringBootApplication
@EnableJpaAuditing
public class QnaApplication {

public static void main(String[] args) {
Expand Down
41 changes: 41 additions & 0 deletions src/main/java/com/codessquad/qna/SwaggerConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.codessquad.qna;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.util.ArrayList;

@Configuration
@EnableSwagger2
public class SwaggerConfig {

@Bean
public Docket apiV2() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

왜 v2인가요?

return new Docket(DocumentationType.SWAGGER_2)
.groupName("greetings")
.apiInfo(apiInfo())
.select()
.paths(PathSelectors.ant("/api/**"))
.build();

}

private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Spring REST Sample with Swagger")
.description("Spring REST Sample with Swagger")
.termsOfServiceUrl("http://www-03.ibm.com/software/sla/sladb.nsf/sla/bm?Open")
.license("Apache License Version 2.0")
.licenseUrl("https://github.com/IBM-Bluemix/news-aggregator/blob/master/LICENSE")
Comment on lines +35 to +37
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

라이선스까지 있군요?

.version("2.0")
.build();
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

통행금지 표시가 있네요!
codesquad-members-2021/java-chess#9 (comment)
여기 참고해서 수정해주세요!

82 changes: 82 additions & 0 deletions src/main/java/com/codessquad/qna/domain/AbstractEntity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package com.codessquad.qna.domain;

import com.fasterxml.jackson.annotation.JsonProperty;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Objects;

@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class AbstractEntity {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Abstract라는 키워드를 적어주기보다는 저는 Base를 선호합니다~

private static final DateTimeFormatter DATE_TIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@JsonProperty
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JsonProperty를 따로 붙여주신 이유가 있나요?

private Long id;

@CreatedDate
private LocalDateTime createDate;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

데이터 형식은 LocalDateTime이므로 createDateTime으로 만들어주시는 것을 추천합니다.


@LastModifiedDate
private LocalDateTime modifiedDate;

private boolean deleted;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

모든 DB 컬럼들이 softdelete로 구현되는건가요?



public Long getId() {
return id;
}

public String getFormattedDateTime() {
return getFormattedDate(createDate);
}

public String getFormattedModifiedDate() {
return getFormattedDate(modifiedDate);
}

public String getFormattedDate(LocalDateTime dateTime) {
return dateTime.format(DATE_TIME_FORMAT);
}
Comment on lines +36 to +46
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기 네이밍도 위의 피드백과 함께 고쳐주세요~



public boolean isMatchingId(long id) {
return this.id == id;
}

public void deleted() {
this.deleted = true;
}
Comment on lines +53 to +55
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete가 맞겠죠?


public boolean isDeleted() {
return this.deleted;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AbstractEntity that = (AbstractEntity) o;
return Objects.equals(id, that.id);
}

@Override
public int hashCode() {
return Objects.hash(id);
}
Comment on lines +61 to +72
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

자... 잘 생각해봅시다.
AbstractEntity의 id가 같으면 같은 것으로 본다는 것인데
User와 Question이 id가 같다면 어떻게 될까요?


@Override
public String toString() {
return "AbstractEntity{" +
"id=" + id +
", createDate=" + createDate +
", modifiedDate=" + modifiedDate +
'}';
}
}
69 changes: 11 additions & 58 deletions src/main/java/com/codessquad/qna/domain/Answer.java
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
package com.codessquad.qna.domain;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;

import javax.persistence.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Objects;

@Entity
public class Answer {
private static final DateTimeFormatter DATE_TIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
@Id
@GeneratedValue
private Long id;

public class Answer extends AbstractEntity {
@ManyToOne
@JsonProperty
@JoinColumn(foreignKey = @ForeignKey(name = "fk_answer_writer"))
private User writer;

@ManyToOne
@JsonProperty
@JoinColumn(foreignKey = @ForeignKey(name = "fk_answer_to_question"))
private Question question;

@Lob
@JsonProperty
private String contents;
private LocalDateTime createdDateTime = LocalDateTime.now();

public Answer() {
}
Expand All @@ -33,66 +33,19 @@ public Answer(User writer, Question question, String contents) {
this.contents = contents;
}

public Long getId() {
return id;
}

public User getWriter() {
return writer;
}

public void setWriter(User writer) {
this.writer = writer;
public boolean isSameWriter(User loginUser) {
return loginUser.equals(this.writer);
}

public Question getQuestion() {
return question;
}

public void setQuestion(Question question) {
this.question = question;
}

public String getContents() {
return contents;
}

public void setContents(String contents) {
this.contents = contents;
}

public LocalDateTime getCreatedDateTime() {
return createdDateTime;
}

public void setCreatedDateTime(LocalDateTime createdDateTime) {
this.createdDateTime = createdDateTime;
}

public String getFormattedDateTime() {
return createdDateTime.format(DATE_TIME_FORMAT);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Answer answer = (Answer) o;
return Objects.equals(id, answer.id);
}

@Override
public int hashCode() {
return Objects.hash(id);
}

@Override
public String toString() {
return "Answer{" +
"id=" + id +
super.toString() +
", writer=" + writer +
", contents='" + contents + '\'' +
", createdDateTime=" + createdDateTime +
'}';
", contents='" + contents + '\'';
}
}
78 changes: 31 additions & 47 deletions src/main/java/com/codessquad/qna/domain/Question.java
Original file line number Diff line number Diff line change
@@ -1,96 +1,80 @@
package com.codessquad.qna.domain;

import com.fasterxml.jackson.annotation.JsonProperty;

import javax.persistence.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Entity
public class Question {
private static final DateTimeFormatter DATE_TIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
public class Question extends AbstractEntity {

@ManyToOne
@JsonProperty
@JoinColumn(foreignKey = @ForeignKey(name = "fk_question_writer"))
private User writer;

@JsonProperty
private String title;

@OneToMany(mappedBy = "question")
@OrderBy("id ASC")
private List<Answer> answers;
private List<Answer> answers = new ArrayList<>();

@Lob
@JsonProperty
private String contents;
private LocalDateTime createdDateTime = LocalDateTime.now();

private boolean deleted;
@JsonProperty
private int answerCount = 0;

public Long getId() {
return id;
}
public Question() {

public User getWriter() {
return writer;
}

public void setWriter(User writer) {
public Question(User writer, String title, String contents) {
this.writer = writer;
}

public String getTitle() {
return title;
}

public void setTitle(String title) {
this.title = title;
}

public String getContents() {
return contents;
}

public void setContents(String contents) {
this.contents = contents;
}

public LocalDateTime getCreatedDateTime() {
return createdDateTime;
}

public String getFormattedDateTime() {
return createdDateTime.format(DATE_TIME_FORMAT);
}

public List<Answer> getAnswers() {
return answers;
public boolean isMatchingWriter(User loginUser) {
return this.writer.equals(loginUser);
}

public void delete() {
this.deleted = true;
public void update(String updateTitle, String updateContents) {
this.title = updateTitle;
this.contents = updateContents;
}

public void addAnswer(Answer answer) {
answers.add(answer);
answerCount++;
}

public boolean isMatchingWriter(User loginUser) {
return this.writer.equals(loginUser);
public void deleteAnswer(Answer answer) {
if (answers.contains(answer)) {
answer.deleted();
answerCount--;
}
}
Comment on lines 52 to 62
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

강의를 따라하신 거겠죠?
저는 이런식의 구현이 좋은지 잘 모르겠네요 ㅎㅎ


public void update(Question updateQuestion) {
this.title = updateQuestion.title;
this.contents = updateQuestion.contents;
public List<Answer> getAnswers() {
return answers.stream()
.filter(answer -> !answer.isDeleted())
.collect(Collectors.toList());
Comment on lines +64 to +67
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

처음 가져올 때, answers가 필터링 되어서 가져와지는게 좋겠죠?

}

@Override
public String toString() {
return "Qna{" +
super.toString() +
"writer='" + writer + '\'' +
", title='" + title + '\'' +
", contents='" + contents + '\'' +
'}';
}

}
Loading