Skip to content

Commit

Permalink
Merge pull request #20 from Ewha-thon-Melting-Pot/feat/post
Browse files Browse the repository at this point in the history
[feat] 게시물 CRU
  • Loading branch information
hannah0226 authored Mar 17, 2024
2 parents 2623ca9 + eb0049d commit 1fdc01b
Show file tree
Hide file tree
Showing 22 changed files with 769 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,4 @@ public abstract class BaseTimeEntity {
@CreatedDate
@Column(updatable = false)
private LocalDateTime createdDate;

@LastModifiedDate
@Column(insertable=false)
private LocalDateTime updatedDate;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package melting_pot.ewha_sinmungo.global.apiResponse;


import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import lombok.AllArgsConstructor;
import lombok.Getter;
import melting_pot.ewha_sinmungo.global.apiResponse.code.status.SuccessStatus;

@Getter
@AllArgsConstructor
@JsonPropertyOrder({"isSuccess", "code", "message", "result"})
public class ApiResponse<T> {

@JsonProperty("isSuccess")
private final Boolean isSuccess;
private final String code;
private final String message;
@JsonInclude(JsonInclude.Include.NON_NULL)
private T result;


// 성공한 경우 응답 생성

public static <T> ApiResponse<T> onSuccess(T result){
return new ApiResponse<>(true, SuccessStatus._OK.getCode() , SuccessStatus._OK.getMessage(), result);
}
//
// public static <T> ApiResponse<T> of(BaseCode code, T result){
// return new ApiResponse<>(true, code.getReasonHttpStatus().getCode() , code.getReasonHttpStatus().getMessage(), result);
// }


// 실패한 경우 응답 생성
public static <T> ApiResponse<T> onFailure(String code, String message, T data){
return new ApiResponse<>(false, code, message, data);
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package melting_pot.ewha_sinmungo.global.apiResponse;

import lombok.Builder;
import lombok.Data;
import lombok.ToString;

@ToString
@Data
public class Message {

private String message;
@Builder
public Message(String message) {
this.message = message;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package melting_pot.ewha_sinmungo.global.apiResponse.code;

public interface BaseCode {

public ReasonDTO getReason();

public ReasonDTO getReasonHttpStatus();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package melting_pot.ewha_sinmungo.global.apiResponse.code;

public interface BaseErrorCode {

public ErrorReasonDTO getReason();

public ErrorReasonDTO getReasonHttpStatus();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package melting_pot.ewha_sinmungo.global.apiResponse.code;

import lombok.Builder;
import lombok.Getter;
import org.springframework.http.HttpStatus;

@Getter
@Builder
public class ErrorReasonDTO {

private HttpStatus httpStatus;

private final boolean isSuccess;
private final String code;
private final String message;

public boolean getIsSuccess(){return isSuccess;}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package melting_pot.ewha_sinmungo.global.apiResponse.code;

import lombok.Builder;
import lombok.Getter;
import org.springframework.http.HttpStatus;

@Getter
@Builder
public class ReasonDTO {

private HttpStatus httpStatus;

private final boolean isSuccess;
private final String code;
private final String message;

public boolean getIsSuccess(){return isSuccess;}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package melting_pot.ewha_sinmungo.global.apiResponse.code.status;


import lombok.AllArgsConstructor;
import lombok.Getter;
import melting_pot.ewha_sinmungo.global.apiResponse.code.BaseErrorCode;
import melting_pot.ewha_sinmungo.global.apiResponse.code.ErrorReasonDTO;
import org.springframework.http.HttpStatus;


@Getter
@AllArgsConstructor
public enum ErrorStatus implements BaseErrorCode {

// 가장 일반적인 응답
_INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "COMMON500", "서버 에러, 관리자에게 문의 바랍니다."),
_BAD_REQUEST(HttpStatus.BAD_REQUEST,"COMMON400","잘못된 요청입니다."),
_UNAUTHORIZED(HttpStatus.UNAUTHORIZED,"COMMON401","인증이 필요합니다."),
_FORBIDDEN(HttpStatus.FORBIDDEN, "COMMON403", "금지된 요청입니다."),


// 멤버 관련 에러
MEMBER_NOT_FOUND(HttpStatus.BAD_REQUEST, "MEMBER4001", "사용자가 없습니다."),
INVALID_REFRESH_TOKEN(HttpStatus.BAD_REQUEST, "MEMBER4005", "유효하지 않은 리프레시 토큰 입니다."),
// 게시물 관련 에러
ARTICLE_NOT_FOUND(HttpStatus.NOT_FOUND, "ARTICLE4001", "게시글이 없습니다."),
PAGE_FORMAT_BAD_REQUEST(HttpStatus.BAD_REQUEST,"PAGE4001","잘못된 페이지 번호 형식입니다");

private final HttpStatus httpStatus;
private final String code;
private final String message;

@Override
public ErrorReasonDTO getReason() {
return ErrorReasonDTO.builder()
.message(message)
.code(code)
.isSuccess(false)
.build();
}

@Override
public ErrorReasonDTO getReasonHttpStatus() {
return ErrorReasonDTO.builder()
.message(message)
.code(code)
.isSuccess(false)
.httpStatus(httpStatus)
.build()
;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package melting_pot.ewha_sinmungo.global.apiResponse.code.status;
import lombok.AllArgsConstructor;
import lombok.Getter;
import melting_pot.ewha_sinmungo.global.apiResponse.code.BaseCode;
import melting_pot.ewha_sinmungo.global.apiResponse.code.ReasonDTO;
import org.springframework.http.HttpStatus;


@Getter
@AllArgsConstructor
public enum SuccessStatus implements BaseCode {

// 일반적인 응답
_OK(HttpStatus.OK, "COMMON200", "성공입니다.");

// 멤버 관련 응답

// ~~~ 관련 응답

private final HttpStatus httpStatus;
private final String code;
private final String message;

@Override
public ReasonDTO getReason() {
return ReasonDTO.builder()
.message(message)
.code(code)
.isSuccess(true)
.build();
}

@Override
public ReasonDTO getReasonHttpStatus() {
return ReasonDTO.builder()
.message(message)
.code(code)
.isSuccess(true)
.httpStatus(httpStatus)
.build()
;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package melting_pot.ewha_sinmungo.global.apiResponse.exception;


import lombok.Getter;
import melting_pot.ewha_sinmungo.global.apiResponse.code.BaseErrorCode;
import melting_pot.ewha_sinmungo.global.apiResponse.code.ErrorReasonDTO;

@Getter
public class GeneralException extends RuntimeException {

private BaseErrorCode code;
private String sourceClass;
private String sourceMethod;
private String sourcePackage;
private String sourceAddress;

public GeneralException(BaseErrorCode errorCode) {
extractSourceInfo();
this.code = errorCode;
}
public ErrorReasonDTO getErrorReason() {
return this.code.getReason();
}

public ErrorReasonDTO getErrorReasonHttpStatus(){
return this.code.getReasonHttpStatus();
}
private void extractSourceInfo() {
StackTraceElement[] stackTrace = this.getStackTrace();
if (stackTrace.length > 1) {
StackTraceElement element = stackTrace[1]; // [0]는 현재 생성자, [1]은 CustomException을 발생시킨 메서드
this.sourceClass = element.getClassName();
this.sourceMethod = element.getMethodName();

// 패키지 정보는 클래스 이름에서 추출
int lastDotIndex = this.sourceClass.lastIndexOf('.');
if (lastDotIndex > 0) {
this.sourcePackage = this.sourceClass.substring(0, lastDotIndex);
} else {
this.sourcePackage = "Unknown";
}
}
this.sourceAddress = sourcePackage+"."+sourceClass+"."+sourceMethod;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package melting_pot.ewha_sinmungo.global.apiResponse.exception.handler;


import melting_pot.ewha_sinmungo.global.apiResponse.code.BaseErrorCode;
import melting_pot.ewha_sinmungo.global.apiResponse.exception.GeneralException;

public class ErrorHandler extends GeneralException {

public ErrorHandler(BaseErrorCode errorCode) {
super(errorCode);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package melting_pot.ewha_sinmungo.post.controller;

import lombok.RequiredArgsConstructor;
import melting_pot.ewha_sinmungo.global.apiResponse.ApiResponse;
import melting_pot.ewha_sinmungo.post.dto.requestDto.PostRequestDTO;
import melting_pot.ewha_sinmungo.post.dto.responseDto.PostResponseDTO;
import melting_pot.ewha_sinmungo.post.entity.Category;
import melting_pot.ewha_sinmungo.post.entity.Status;
import melting_pot.ewha_sinmungo.post.service.PostService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;

@RestController
@RequiredArgsConstructor
public class PostController {
private final PostService postService;

@PostMapping("/article")
public String postPost (@RequestBody @Valid PostRequestDTO.PostSaveDto request) {
postService.createPost(request);
return "Success";
}

@GetMapping("/article/{postId}")
public ApiResponse<PostResponseDTO.PostEntityDto> getPost (@PathVariable Long postId){
return ApiResponse.onSuccess(postService.getPostInfo(postId));
}

@GetMapping("/article/previews/{category}/{status}/newest")
public ApiResponse<Page<PostResponseDTO.PostPreviewDto>> getPostPreviewByCategoryNewest(@PathVariable Category category, @PathVariable Status status, Pageable pageable) {
Page<PostResponseDTO.PostPreviewDto> previews = postService.getPostPreviewByCategoryNewest(category, status, pageable);
return ApiResponse.onSuccess(previews);
}
@GetMapping("/article/previews/{category}/{status}/oldest")
public ApiResponse<Page<PostResponseDTO.PostPreviewDto>> getPostPreviewByCategoryOldest(@PathVariable Category category, @PathVariable Status status, Pageable pageable) {
Page<PostResponseDTO.PostPreviewDto> previews = postService.getPostPreviewByCategoryOldest(category, status, pageable);
return ApiResponse.onSuccess(previews);
}
@GetMapping("/article/previews/{category}/{status}/hot")
public ApiResponse<Page<PostResponseDTO.PostPreviewDto>> getPostPreviewByCategoryHot(@PathVariable Category category, @PathVariable Status status, Pageable pageable) {
Page<PostResponseDTO.PostPreviewDto> previews = postService.getPostPreviewByCategoryNewest(category, status, pageable);
return ApiResponse.onSuccess(previews);
}
@GetMapping("/article/previews/{category}/newest")
public ApiResponse<Page<PostResponseDTO.PostPreviewDto>> getPostPreviewNewest(@PathVariable Status status, Pageable pageable) {
Page<PostResponseDTO.PostPreviewDto> previews = postService.getPostPreviewNewest(status, pageable);
return ApiResponse.onSuccess(previews);
}
@GetMapping("/article/previews/{category}/oldest")
public ApiResponse<Page<PostResponseDTO.PostPreviewDto>> getPostPreviewOldest( @PathVariable Status status, Pageable pageable) {
Page<PostResponseDTO.PostPreviewDto> previews = postService.getPostPreviewOldest(status, pageable);
return ApiResponse.onSuccess(previews);
}
@GetMapping("/article/previews/{category}/hot")
public ApiResponse<Page<PostResponseDTO.PostPreviewDto>> getPostPreviewHot(@PathVariable Status status, Pageable pageable) {
Page<PostResponseDTO.PostPreviewDto> previews = postService.getPostPreviewHot(status, pageable);
return ApiResponse.onSuccess(previews);
}

@PutMapping("/article/{postId}/vote/enable")
public ApiResponse<Boolean> enablePostLike(@PathVariable Long postId){
postService.enablePostLike(postId);
return ApiResponse.onSuccess(Boolean.TRUE);
}

@PutMapping("/article/{postId}/vote/disable")
public ApiResponse<Boolean> disablePostLike(@PathVariable Long postId){
postService.disablePostLike(postId);
return ApiResponse.onSuccess(Boolean.TRUE);
}

}
Loading

0 comments on commit 1fdc01b

Please sign in to comment.