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

코드 리뷰~ #4

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.DS_Store
build/
out/
.gradle
.idea

src/main/resources/application-db.yml
src/main/resources/application.properties
src/main/resources/application.yml
18 changes: 18 additions & 0 deletions src/main/java/kr/where/backend/BackendApplication.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package kr.where.backend;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.retry.annotation.EnableRetry;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@EnableRetry
@SpringBootApplication
public class BackendApplication {

public static void main(String[] args) {
SpringApplication.run(BackendApplication.class, args);
}

}
16 changes: 16 additions & 0 deletions src/main/java/kr/where/backend/exception/CustomException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package kr.where.backend.exception;

import lombok.Getter;
import lombok.ToString;

@Getter
@ToString
public class CustomException extends RuntimeException{
private final int errorCode;
private final String errorMessage;

public <T extends Enum<T> & ErrorCode> CustomException(final T errorType) {
errorCode = errorType.getErrorCode();
errorMessage = errorType.getErrorMessage();
}
}
6 changes: 6 additions & 0 deletions src/main/java/kr/where/backend/exception/ErrorCode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package kr.where.backend.exception;

public interface ErrorCode {
int getErrorCode();
String getErrorMessage();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package kr.where.backend.exception;

import kr.where.backend.auth.authUser.exception.AuthUserException;
import kr.where.backend.exception.httpError.HttpResourceErrorCode;
import kr.where.backend.exception.httpError.HttpResourceException;
import kr.where.backend.group.exception.GroupException;
import kr.where.backend.group.exception.GroupMemberException;
import kr.where.backend.join.exception.JoinException;
import kr.where.backend.jwt.exception.JwtException;
import kr.where.backend.member.exception.MemberException;
import kr.where.backend.api.exception.JsonException;
import kr.where.backend.api.exception.RequestException;
import kr.where.backend.oauthtoken.exception.OAuthTokenException;
import kr.where.backend.search.exception.SearchException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
@Slf4j
public class ExceptionHandleController {

@ExceptionHandler({MemberException.NoMemberException.class, GroupException.NoGroupException.class})
public ResponseEntity<String> handleNoResultException(final CustomException e) {
log.info(e.toString());

return ResponseEntity.status(HttpStatus.NOT_FOUND).body(e.toString());
}

@ExceptionHandler({MemberException.DuplicatedMemberException.class, GroupException.DuplicatedGroupNameException.class,
GroupMemberException.class})
public ResponseEntity<String> handleDuplicatedException(final CustomException e) {
log.info(e.toString());

return ResponseEntity.status(HttpStatus.CONFLICT).body(e.toString());
}

@ExceptionHandler(GroupException.CannotModifyGroupException.class)
public ResponseEntity<String> handleCannotModifiedException(final CustomException e) {
log.info(e.toString());

return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.toString());
}

@ExceptionHandler(OAuthTokenException.class)
public ResponseEntity<String> handleOAuthTokenException(final CustomException e) {
log.info(e.toString());

return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(e.toString());
}

@ExceptionHandler(JwtException.class)
public ResponseEntity<String> handleJwtTokenException(final CustomException e) {
log.info(e.toString());

return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(e.toString());
}

@ExceptionHandler(RequestException.class)
public ResponseEntity<String> handleBadRequestException(final CustomException e) {
log.info(e.toString());

return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.toString());
}

@ExceptionHandler(JsonException.class)
public ResponseEntity<String> handleJsonException(final CustomException e) {
log.info(e.toString());

return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.toString());
}

@ExceptionHandler(JoinException.class)
public ResponseEntity<String> handleJoinException(final CustomException e) {
log.info(e.toString());

return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.toString());
}

@ExceptionHandler(SearchException.class)
public ResponseEntity<String> handleSearchException(final CustomException e) {
log.info(e.toString());

return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.toString());
}

@ExceptionHandler(AuthUserException.class)
public ResponseEntity<String> handleAuthUserException(final CustomException e) {
log.info(e.toString());

return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(e.toString());
}

@ExceptionHandler(MissingServletRequestParameterException.class)
public ResponseEntity<String> handleMissingParameterException() {
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body(HttpResourceException.of(HttpResourceErrorCode.NO_PARAMETERS));
}

@ExceptionHandler(HttpMessageNotReadableException.class)
public ResponseEntity<String> handleNoRequestBodyException() {
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body(HttpResourceException.of(HttpResourceErrorCode.NO_REQUEST_BODY));
}

@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public ResponseEntity<String> handleUnsupportedMethodException() {
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body(HttpResourceException.of(HttpResourceErrorCode.NO_SUPPORTED_METHOD));
}

@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<String> handleMethodArgumentNotValidException() {
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body(HttpResourceException.of(HttpResourceErrorCode.NOT_METHOD_VALID_ARGUMENT));
}

@ExceptionHandler(RuntimeException.class)
public ResponseEntity<String> handleNoResourceException() {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("관리자에게 요청하세요.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package kr.where.backend.exception.httpError;

import kr.where.backend.exception.ErrorCode;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public enum HttpResourceErrorCode implements ErrorCode {

NO_PARAMETERS(1700, "파라미터가 없는 Api 요청입니다."),
NO_REQUEST_BODY(1701, "Request body가 없는 Api 요청입니다."),
NO_SUPPORTED_METHOD(1702, "지원하지 않는 Http Method 요청입니다."),
NOT_METHOD_VALID_ARGUMENT(1703, "Method에 맞는 arguments가 없습니다");

private final int errorCode;
private final String errorMessage;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package kr.where.backend.exception.httpError;

import kr.where.backend.exception.ErrorCode;

public class HttpResourceException {
public static String of(final ErrorCode errorCode) {
return "CustomException(errorCode=" + errorCode.getErrorCode() +
", " + "errorMessage=" +
errorCode.getErrorMessage() + ")";
}
}
111 changes: 111 additions & 0 deletions src/main/java/kr/where/backend/group/GroupController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package kr.where.backend.group;

import jakarta.validation.Valid;
import java.util.List;
import kr.where.backend.auth.authUser.AuthUser;
import kr.where.backend.auth.authUser.AuthUserInfo;
import kr.where.backend.group.dto.groupmember.*;
import kr.where.backend.group.dto.group.CreateGroupDTO;
import kr.where.backend.group.dto.group.ResponseGroupDTO;
import kr.where.backend.group.dto.group.UpdateGroupDTO;
import kr.where.backend.group.swagger.GroupApiDocs;
import lombok.AllArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/v3/group")
@AllArgsConstructor
public class GroupController implements GroupApiDocs {

private final GroupService groupService;
private final GroupMemberService groupMemberService;

@PostMapping("")
Copy link
Collaborator

Choose a reason for hiding this comment

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

어떻게 구글링 해봐야할지도 잘 모르겠어서 질문 남깁니다.
같은 url에 대해 어떤 종류의(post, get 등) 요청인지로 구분하는것이 지향해야할 방법인가요??

Copy link
Contributor Author

Choose a reason for hiding this comment

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

음 http의 method로 구별하기 때문에 굳이, get post 등의 url을 구분하는 것은 자원 낭비 라고 저희 팀은 생각했어요
그리고 restApi로 "post" v3/api/group 이렇게 요청하면, 아 그룹에서 변경점이 일어나는군 이라고 명시적으로 알 수 있는 장점도 있어서 구분하지 않았습니다.

Copy link

@namzisun namzisun Sep 25, 2024

Choose a reason for hiding this comment

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

REST API URI Naming Conventions

요 문서의 2.4번을 봐주세요!
저희가 모든 컨벤션을 따른것은 아닙니다만,

  1. request를 구성하는 요소는 url 하나가 아니라 HTTP request 전체이기 때문에 같은 자원에 대한 post/get/delete는 url이 아닌 method로 구별하는 것이 맞다고 판단했습니다.
  2. 또한 url가 너무 세분화되면 사용할때도, 만들때도 헷갈리더라구요! 때문에 최대한 간단하고 직관적으로 구성하려고 했습니다.

상기 이유로 동일 자원에 대한 url은 method로 구분했습니다. 다만 컨벤션 문서를 지금 다시 정독해보니 개발 후반부로 갈수록 컨벤션을 엄격하게 고려하지 않은 url도 있네요. 컨벤션은 컨벤션일 뿐이니 3기 기준에 맞지 않다고 판단되는 부분은 프론트와 협의 후 수정하시면 될 것 같습니다~!

public ResponseEntity<ResponseGroupDTO> createGroup(
@RequestBody @Valid final CreateGroupDTO request,
@AuthUserInfo final AuthUser authUser) {
final ResponseGroupDTO dto = groupService.createGroup(request, authUser);

return ResponseEntity.status(HttpStatus.CREATED).body(dto);
}
//완성

@GetMapping("")
public ResponseEntity<List<ResponseGroupMemberListDTO>> findAllGroups(@AuthUserInfo final AuthUser authUser) {
return ResponseEntity
.status(HttpStatus.OK)
.body(groupService.getGroupList(authUser));
}

@PostMapping("/name")
public ResponseEntity<ResponseGroupDTO> updateGroupName(
@RequestBody @Valid final UpdateGroupDTO dto,
@AuthUserInfo final AuthUser authUser) {
final ResponseGroupDTO responseGroupDto = groupService.updateGroup(dto, authUser);

return ResponseEntity.status(HttpStatus.OK).body(responseGroupDto);
}

@DeleteMapping("")
public ResponseEntity<ResponseGroupDTO> deleteGroup(
@RequestParam("groupId") final Long groupId,
@AuthUserInfo final AuthUser authUser) {
final ResponseGroupDTO responseGroupDto = groupService.deleteGroup(groupId, authUser);

return ResponseEntity.status(HttpStatus.OK).body(responseGroupDto);
}

@GetMapping("/info")
public ResponseEntity<List<ResponseGroupMemberDTO>> findGroupNames(@AuthUserInfo final AuthUser authUser) {
final List<ResponseGroupMemberDTO> dto = groupMemberService.findGroupsInfoByIntraId(authUser);

return ResponseEntity.status(HttpStatus.OK).body(dto);
}

@PostMapping("/groupmember")
public ResponseEntity<ResponseGroupMemberDTO> createGroupMember(
@RequestParam("intraId") final Integer intraId,
@AuthUserInfo final AuthUser authUser) {
final ResponseGroupMemberDTO dto = groupMemberService.createDefaultGroupMember(intraId, false, authUser);

return ResponseEntity.status(HttpStatus.CREATED).body(dto);
}

@PostMapping("/groupmember/not-ingroup")
public ResponseEntity<List<ResponseOneGroupMemberDTO>> findMemberListNotInGroup(
@RequestParam("groupId") final Long groupId,
@AuthUserInfo final AuthUser authUser) {
final List<ResponseOneGroupMemberDTO> groupMemberDTOS = groupMemberService.findMemberNotInGroup(groupId, authUser);

return ResponseEntity.status(HttpStatus.OK).body(groupMemberDTOS);
}

@PostMapping("/groupmember/members")
public ResponseEntity<List<ResponseOneGroupMemberDTO>> addFriendsToGroup(
@RequestBody @Valid final AddGroupMemberListDTO request,
@AuthUserInfo final AuthUser authUser) {
final List<ResponseOneGroupMemberDTO> response = groupMemberService.addFriendsList(request, authUser);

return ResponseEntity.status(HttpStatus.CREATED).body(response);
}

@GetMapping("/groupmember")
public ResponseEntity<List<ResponseOneGroupMemberDTO>> findAllGroupFriends(
@RequestParam("groupId") final Long groupId,
@AuthUserInfo final AuthUser authUser) {
final List<ResponseOneGroupMemberDTO> dto = groupMemberService.findGroupMemberByGroupId(groupId);

return ResponseEntity.status(HttpStatus.CREATED).body(dto);
}

@PutMapping ("/groupmember")
public ResponseEntity<List<ResponseGroupMemberDTO>> removeIncludeGroupFriends(
@RequestBody @Valid final DeleteGroupMemberListDTO request,
@AuthUserInfo final AuthUser authUser) {
final List<ResponseGroupMemberDTO> ResponseGroupMemberDTOs = groupMemberService.deleteFriendsList(request, authUser);

return ResponseEntity.status(HttpStatus.OK).body(ResponseGroupMemberDTOs);
}
}
28 changes: 28 additions & 0 deletions src/main/java/kr/where/backend/group/GroupMemberRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package kr.where.backend.group;

import java.util.List;
import kr.where.backend.group.entity.Group;
import kr.where.backend.group.entity.GroupMember;
import kr.where.backend.member.Member;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface GroupMemberRepository extends JpaRepository<GroupMember, Long> {

List<GroupMember> findGroupMembersByMemberAndIsOwner(Member member, Boolean isOwner);

List<GroupMember> findGroupMemberByGroup_GroupIdAndIsOwnerIsFalse(Long groupId);

List<GroupMember> findGroupMembersByGroup_GroupIdAndMember_IntraIdIn(Long groupId, List<Integer> MemberIntraId);

boolean existsByGroupAndMember(Group group, Member member);

long countByGroup_GroupIdAndMemberIn(Long groupId, List<Member> members);

List<GroupMember> findGroupMembersByMember_IntraIdAndIsOwner(Integer intraId, boolean isOwner);

List<GroupMember> findGroupMembersByGroup_GroupIdInAndMember_IntraIdIn(List<Long> groupIds, List<Integer> memberIds);

List<GroupMember> findGroupMemberByGroup_GroupId(Long defaultGroupId);
}
Loading