Skip to content

Commit

Permalink
REFACTOR(wrapper) :: ResponseEntity -> 공통 Response로 처리
Browse files Browse the repository at this point in the history
  • Loading branch information
Woongbin06 committed Nov 18, 2024
1 parent 4e337cc commit b6c8686
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 34 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
package com.woongeya.zoing.domain.post.presetation;

import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.woongeya.zoing.domain.auth.annotation.LoginRequired;
import com.woongeya.zoing.domain.auth.service.implementation.AuthReader;
import com.woongeya.zoing.domain.post.presetation.dto.request.CreatePostRequest;
import com.woongeya.zoing.domain.post.presetation.dto.response.PostResponse;
Expand All @@ -10,12 +21,9 @@
import com.woongeya.zoing.domain.post.service.qeury.QueryPostOneService;
import com.woongeya.zoing.domain.post.service.qeury.QueryPostService;
import com.woongeya.zoing.domain.post.service.qeury.QuerySearchPostService;
import com.woongeya.zoing.domain.user.domain.User;

import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequiredArgsConstructor
Expand All @@ -28,43 +36,42 @@ public class PostController {
private final QuerySearchPostService querySearchPostService;
private final UpdatePostService updatePostService;
private final DeletePostService deletePostService;
private final AuthReader authReader;

@PostMapping()
@LoginRequired
@Operation(summary = "게시글 생성")
public ResponseEntity<Void> create(@RequestBody CreatePostRequest request) {
createPostService.execute(request);
return ResponseEntity.noContent().build();
public void create(@RequestBody CreatePostRequest request) {
createPostService.execute(authReader.getCurrentUser(), request);
}

@GetMapping()
@GetMapping
@Operation(summary = "게시글 전체 조회")
public ResponseEntity<PostResponseList> getAll() {
return ResponseEntity.ok(queryPostService.execute());
public PostResponseList getAll() {
return queryPostService.execute();
}

@GetMapping("/{id}")
@Operation(summary = "게시글 상세 조회")
public ResponseEntity<PostResponse> getOne(@PathVariable Long id) {
return ResponseEntity.ok(queryPostOneService.execute(id));
public PostResponse getOne(@PathVariable Long id) {
return queryPostOneService.execute(id);
}

@GetMapping("/search")
@Operation(summary = "게시글 검색")
public ResponseEntity<PostResponseList> search(@RequestParam(name = "q") String q) {
return ResponseEntity.ok(querySearchPostService.execute(q));
public PostResponseList search(@RequestParam(name = "q") String q) {
return querySearchPostService.execute(q);
}

@PutMapping("/{id}")
@Operation(summary = "게시글 수정")
public ResponseEntity<Void> update(@PathVariable Long id, @RequestBody CreatePostRequest request) {
public void update(@PathVariable Long id, @RequestBody CreatePostRequest request) {
updatePostService.execute(id, request);
return ResponseEntity.noContent().build();
}

@DeleteMapping("/{id}")
@Operation(summary = "게시글 삭제")
public ResponseEntity<Void> delete(@PathVariable Long id) {
public void delete(@PathVariable Long id) {
deletePostService.execute(id);
return ResponseEntity.noContent().build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.woongeya.zoing.domain.auth.repository.AuthRepository;
import com.woongeya.zoing.domain.post.domain.repository.PostRepository;
import com.woongeya.zoing.domain.post.presetation.dto.request.CreatePostRequest;
import com.woongeya.zoing.domain.user.domain.User;
Expand All @@ -15,11 +14,9 @@
@Transactional
public class CreatePostService {

private final AuthRepository authRepository;
private final PostRepository postRepository;

public void execute(CreatePostRequest request) {
User user = authRepository.getCurrentUser();
public void execute(User user, CreatePostRequest request) {
postRepository.save(request.toEntity(user));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.woongeya.zoing.global.converter;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;

import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.stereotype.Component;
import org.springframework.util.StreamUtils;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.woongeya.zoing.global.converter.exception.NotSupportedException;
import com.woongeya.zoing.global.wraper.response.CommonResponse;

import lombok.RequiredArgsConstructor;

@Component
@RequiredArgsConstructor
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CommonHttpsMessageConverter extends AbstractHttpMessageConverter<CommonResponse<Object>> {

private final ObjectMapper objectMapper;

@Override
public List<MediaType> getSupportedMediaTypes() {
return Collections.singletonList(MediaType.APPLICATION_JSON);
}

@Override
protected boolean supports(Class<?> clazz) {
return clazz.equals(String.class);
}

@Override
protected CommonResponse<Object> readInternal(Class<? extends CommonResponse<Object>> clazz,
HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
throw new NotSupportedException();
}

@Override
protected void writeInternal(CommonResponse<Object> resultMessage, HttpOutputMessage outputMessage) throws
IOException,
HttpMessageNotWritableException {
String responseMessage = this.objectMapper.writeValueAsString(resultMessage);
StreamUtils.copy(responseMessage.getBytes(StandardCharsets.UTF_8), outputMessage.getBody());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.woongeya.zoing.global.converter.exception;

import org.springframework.http.HttpStatus;

import com.woongeya.zoing.global.exception.JJoingException;

public class NotSupportedException extends JJoingException {

public NotSupportedException() {
super(HttpStatus.INTERNAL_SERVER_ERROR, "지원하지 않는 형식입니다.");
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
package com.woongeya.zoing.global.exception;

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class ErrorResponse {

private int status;
private String message;
import org.springframework.http.HttpStatus;

public record ErrorResponse (
HttpStatus status,
String message
) {
@Override
public String toString() {
return "{\n" +
"\t\"status\": " + status +
"\nt\"status\": " + status +
",\n\t\"message\": \"" + message + '\"' +
"\n}";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class GlobalExceptionHandler {
public ResponseEntity<ErrorResponse> handleDefineException(JJoingException e) {
log.warn(e.getMessage() + "\n \t {}", e);
return ResponseEntity.status(e.getStatus())
.body(new ErrorResponse(e.getStatus().value(), e.getMessage()));
.body(new ErrorResponse(e.getStatus(), e.getMessage()));
}

@ExceptionHandler({MethodArgumentNotValidException.class})
Expand All @@ -34,13 +34,13 @@ public ErrorResponse handleDefineException(MethodArgumentNotValidException e) {
message = e.getFieldError().getDefaultMessage();
}

return new ErrorResponse(400, message);
return new ErrorResponse(BAD_REQUEST, message);
}

@ExceptionHandler(Exception.class)
@ResponseStatus(INTERNAL_SERVER_ERROR)
public ErrorResponse handleDefineException(Exception e) {
log.error(e.getMessage() + "\n \t {}", e);
return new ErrorResponse(500, "서버에서 알 수 없는 에러가 발생했습니다.");
return new ErrorResponse(INTERNAL_SERVER_ERROR, "서버에서 알 수 없는 에러가 발생했습니다.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.woongeya.zoing.global.wraper;

import org.springframework.core.MethodParameter;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import com.woongeya.zoing.global.exception.ErrorResponse;
import com.woongeya.zoing.global.wraper.response.CommonResponse;

@RestControllerAdvice
public class ResponseWrapper implements ResponseBodyAdvice<Object> {

@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}

@Override
public Object beforeBodyWrite(Object body,
MethodParameter returnType,
MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType,
ServerHttpRequest request,
ServerHttpResponse response
) {
if (body instanceof ErrorResponse errorResponse) {
response.setStatusCode(errorResponse.status());
return CommonResponse.error(errorResponse.status(), errorResponse.message());
}

return CommonResponse.success(HttpStatus.OK, body);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.woongeya.zoing.global.wraper.response;

import java.time.LocalDateTime;

import org.springframework.http.HttpStatus;

public record CommonResponse<T> (
HttpStatus state,
T body,
LocalDateTime timeStamp,
String message
) {

public static <T> CommonResponse<T> error(HttpStatus state, String message) {
return new CommonResponse<>(state, null, LocalDateTime.now(), message);
}

public static <T> CommonResponse<T> success(HttpStatus state, T body) {
return new CommonResponse<>(state, body, LocalDateTime.now(), "");
}
}

0 comments on commit b6c8686

Please sign in to comment.