Skip to content

Commit 8ca29db

Browse files
authored
Merge pull request #7 from Im-D/question-api
API Interface 구성하기
2 parents c352e8c + 4d64cf2 commit 8ca29db

File tree

12 files changed

+452
-55
lines changed

12 files changed

+452
-55
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.imd.yourvoice.common;
2+
3+
import org.springframework.context.annotation.Configuration;
4+
import org.springframework.web.filter.OncePerRequestFilter;
5+
import org.springframework.web.util.ContentCachingRequestWrapper;
6+
import org.springframework.web.util.ContentCachingResponseWrapper;
7+
8+
import javax.servlet.FilterChain;
9+
import javax.servlet.ServletException;
10+
import javax.servlet.http.HttpServletRequest;
11+
import javax.servlet.http.HttpServletResponse;
12+
import java.io.IOException;
13+
14+
@Configuration
15+
public class CachingBodyPerRequestFilter extends OncePerRequestFilter {
16+
17+
@Override
18+
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
19+
ContentCachingRequestWrapper cachingRequestWrapper = new ContentCachingRequestWrapper(request);
20+
ContentCachingResponseWrapper cachingResponseWrapper = new ContentCachingResponseWrapper(response);
21+
22+
filterChain.doFilter(cachingRequestWrapper, cachingResponseWrapper);
23+
cachingResponseWrapper.copyBodyToResponse();
24+
}
25+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.imd.yourvoice.common;
2+
3+
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import lombok.SneakyThrows;
5+
import org.springframework.http.HttpStatus;
6+
import org.springframework.http.converter.HttpMessageNotReadableException;
7+
import org.springframework.web.bind.MethodArgumentNotValidException;
8+
import org.springframework.web.bind.annotation.ExceptionHandler;
9+
import org.springframework.web.bind.annotation.ResponseStatus;
10+
import org.springframework.web.bind.annotation.RestControllerAdvice;
11+
import org.springframework.web.util.ContentCachingRequestWrapper;
12+
13+
import java.util.HashMap;
14+
import java.util.Map;
15+
16+
@RestControllerAdvice
17+
public class CommonExceptionHandler {
18+
19+
@ResponseStatus(HttpStatus.BAD_REQUEST)
20+
@ExceptionHandler(MethodArgumentNotValidException.class)
21+
public ResponseDTO<Map<String, Object>> methodArgumentNotValidExceptionHandler(ContentCachingRequestWrapper request) {
22+
return ResponseDTO.<Map<String, Object>>builder()
23+
.data(getRequestBodyAt(request))
24+
.message("Validation Error")
25+
.isSuccess("fail")
26+
.build();
27+
}
28+
29+
@ResponseStatus(HttpStatus.BAD_REQUEST)
30+
@ExceptionHandler(HttpMessageNotReadableException.class)
31+
public ResponseDTO<Map<String, Object>> httpMessageNotReadableExceptionHandler(ContentCachingRequestWrapper request) {
32+
return ResponseDTO.<Map<String, Object>>builder()
33+
.data(getRequestBodyAt(request))
34+
.message("UnknownRequestProperties Error")
35+
.isSuccess("fail")
36+
.build();
37+
}
38+
39+
@SneakyThrows
40+
private Map<String, Object> getRequestBodyAt(ContentCachingRequestWrapper request) {
41+
return new ObjectMapper().readValue(request.getContentAsByteArray(), HashMap.class);
42+
}
43+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.imd.yourvoice.common;
2+
3+
import java.time.format.DateTimeFormatter;
4+
5+
public class Const {
6+
public static final String DATE_TIME_FORMAT_STRING = "yyyy-MM-dd'T'HH:mm:ss";
7+
public static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
8+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.imd.yourvoice.common;
2+
3+
import lombok.*;
4+
5+
@Data
6+
@Builder
7+
@NoArgsConstructor(access = AccessLevel.PRIVATE)
8+
@AllArgsConstructor(access = AccessLevel.PRIVATE)
9+
public class ResponseDTO<T> {
10+
private T data;
11+
private String isSuccess;
12+
private String message;
13+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.imd.yourvoice.question;
2+
3+
import com.imd.yourvoice.common.ResponseDTO;
4+
import com.imd.yourvoice.question.model.QuestionDTO;
5+
import org.springframework.web.bind.annotation.PostMapping;
6+
import org.springframework.web.bind.annotation.RequestBody;
7+
import org.springframework.web.bind.annotation.RestController;
8+
9+
import javax.validation.Valid;
10+
11+
@RestController
12+
public class QuestionController {
13+
@PostMapping("/question")
14+
public ResponseDTO<QuestionDTO> createQuestion(@RequestBody @Valid QuestionDTO.CreateRequest questionDTO) {
15+
return ResponseDTO.<QuestionDTO>builder()
16+
.data(questionDTO.toEntity().toDTO())
17+
.isSuccess("success")
18+
.message("CREATE SUCCESSFUL")
19+
.build();
20+
}
21+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.imd.yourvoice.question.model;
2+
3+
import lombok.*;
4+
import org.hibernate.annotations.GenericGenerator;
5+
6+
import javax.persistence.*;
7+
import java.time.LocalDateTime;
8+
import java.util.List;
9+
import java.util.UUID;
10+
import java.util.stream.Collectors;
11+
12+
@Builder
13+
@NoArgsConstructor(access = AccessLevel.PROTECTED)
14+
@AllArgsConstructor(access = AccessLevel.PRIVATE)
15+
@Getter
16+
@ToString
17+
@Entity
18+
public class Question {
19+
@Id
20+
@GeneratedValue(generator = "uuid2")
21+
@GenericGenerator(name = "uuid2", strategy = "uuid2")
22+
@Column(columnDefinition = "BINARY(16)")
23+
private UUID id;
24+
25+
private Long indexNumber;
26+
27+
private String contents;
28+
29+
private String emoji;
30+
31+
private LocalDateTime createDateTime;
32+
33+
@OneToMany(mappedBy = "question")
34+
private List<QuestionLike> questionLikes;
35+
36+
public QuestionDTO toDTO() {
37+
return QuestionDTO.builder()
38+
.id(id)
39+
.indexNumber(indexNumber)
40+
.contents(contents)
41+
.emoji(emoji)
42+
.createDateTime(createDateTime)
43+
.questionLikeDTOs(questionLikes.stream().map(QuestionLike::toDTO).collect(Collectors.toList()))
44+
.build();
45+
}
46+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package com.imd.yourvoice.question.model;
2+
3+
import com.fasterxml.jackson.annotation.JsonFormat;
4+
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
5+
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
6+
import lombok.*;
7+
8+
import javax.validation.constraints.NotEmpty;
9+
import javax.validation.constraints.Size;
10+
import java.time.LocalDateTime;
11+
import java.util.Collections;
12+
import java.util.List;
13+
import java.util.UUID;
14+
import java.util.stream.Collectors;
15+
16+
import static com.imd.yourvoice.common.Const.*;
17+
18+
@Data
19+
@Builder
20+
@NoArgsConstructor(access = AccessLevel.PRIVATE)
21+
@AllArgsConstructor(access = AccessLevel.PRIVATE)
22+
public class QuestionDTO {
23+
private UUID id;
24+
25+
private Long indexNumber;
26+
27+
private String contents;
28+
29+
private String emoji;
30+
31+
@JsonSerialize(using = LocalDateTimeSerializer.class)
32+
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DATE_TIME_FORMAT_STRING)
33+
private LocalDateTime createDateTime;
34+
35+
private List<QuestionLikeDTO> questionLikeDTOs;
36+
37+
public Question toEntity() {
38+
return Question.builder()
39+
.id(id)
40+
.indexNumber(indexNumber)
41+
.contents(contents)
42+
.emoji(emoji)
43+
.createDateTime(createDateTime)
44+
.questionLikes(questionLikeDTOs.stream().map(QuestionLikeDTO::toEntity).collect(Collectors.toList()))
45+
.build();
46+
}
47+
48+
@Data
49+
@Builder
50+
@NoArgsConstructor(access = AccessLevel.PRIVATE)
51+
@AllArgsConstructor(access = AccessLevel.PRIVATE)
52+
public static class CreateRequest {
53+
@NotEmpty
54+
@Size(max = 140)
55+
private String contents;
56+
57+
private String emoji;
58+
59+
@JsonSerialize(using = LocalDateTimeSerializer.class)
60+
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DATE_TIME_FORMAT_STRING)
61+
private LocalDateTime createDateTime;
62+
63+
public Question toEntity() {
64+
return Question.builder()
65+
.id(null)
66+
.indexNumber(null)
67+
.contents(contents)
68+
.emoji(emoji)
69+
.createDateTime(createDateTime)
70+
.questionLikes(Collections.emptyList())
71+
.build();
72+
}
73+
}
74+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.imd.yourvoice.question.model;
2+
3+
import lombok.*;
4+
5+
import javax.persistence.*;
6+
import java.time.LocalDateTime;
7+
8+
@Builder
9+
@NoArgsConstructor(access = AccessLevel.PROTECTED)
10+
@AllArgsConstructor(access = AccessLevel.PRIVATE)
11+
@Getter
12+
@ToString
13+
@Entity
14+
public class QuestionLike {
15+
@Id
16+
private Long id;
17+
18+
@ManyToOne
19+
private Question question;
20+
21+
private LocalDateTime createDateTime;
22+
23+
public QuestionLikeDTO toDTO() {
24+
return QuestionLikeDTO.builder()
25+
.id(id)
26+
.question(question)
27+
.createDateTime(createDateTime)
28+
.build();
29+
}
30+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.imd.yourvoice.question.model;
2+
3+
import lombok.*;
4+
5+
import java.time.LocalDateTime;
6+
7+
@Data
8+
@Builder
9+
@NoArgsConstructor(access = AccessLevel.PRIVATE)
10+
@AllArgsConstructor(access = AccessLevel.PRIVATE)
11+
public class QuestionLikeDTO {
12+
private Long id;
13+
private Question question;
14+
private LocalDateTime createDateTime;
15+
16+
public QuestionLike toEntity() {
17+
return QuestionLike.builder()
18+
.id(id)
19+
.question(question)
20+
.createDateTime(createDateTime)
21+
.build();
22+
}
23+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
spring.jackson.deserialization.fail-on-unknown-properties=true

0 commit comments

Comments
 (0)