diff --git a/src/main/java/com/rest/api/SpringRestApiApplication.java b/src/main/java/com/rest/api/SpringRestApiApplication.java index 46e02cc..43edbbd 100644 --- a/src/main/java/com/rest/api/SpringRestApiApplication.java +++ b/src/main/java/com/rest/api/SpringRestApiApplication.java @@ -6,10 +6,12 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory; import org.springframework.context.annotation.Bean; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; import org.springframework.security.crypto.factory.PasswordEncoderFactories; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.web.client.RestTemplate; +@EnableJpaAuditing @SpringBootApplication public class SpringRestApiApplication { public static void main(String[] args) { diff --git a/src/main/java/com/rest/api/advice/ExceptionAdvice.java b/src/main/java/com/rest/api/advice/ExceptionAdvice.java index 8f40cf5..3ff7860 100644 --- a/src/main/java/com/rest/api/advice/ExceptionAdvice.java +++ b/src/main/java/com/rest/api/advice/ExceptionAdvice.java @@ -26,7 +26,7 @@ public class ExceptionAdvice { @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) protected CommonResult defaultException(HttpServletRequest request, Exception e) { // 예외 처리의 메시지를 MessageSource에서 가져오도록 수정 - return responseService.getFailResult(Integer.valueOf(getMessage("unKnown.code")), getMessage("unKnown.msg")+"("+e.getMessage()+")"); + return responseService.getFailResult(Integer.valueOf(getMessage("unKnown.code")), getMessage("unKnown.msg") + "(" + e.getMessage() + ")"); } @ExceptionHandler(CUserNotFoundException.class) @@ -48,7 +48,7 @@ public class ExceptionAdvice { } @ExceptionHandler(AccessDeniedException.class) - @ResponseStatus(HttpStatus.UNAUTHORIZED) + @ResponseStatus(HttpStatus.FORBIDDEN) public CommonResult accessDeniedException(HttpServletRequest request, AccessDeniedException e) { return responseService.getFailResult(Integer.valueOf(getMessage("accessDenied.code")), getMessage("accessDenied.msg")); } @@ -65,10 +65,23 @@ public class ExceptionAdvice { return responseService.getFailResult(Integer.valueOf(getMessage("existingUser.code")), getMessage("existingUser.msg")); } + @ExceptionHandler(CNotOwnerException.class) + @ResponseStatus(HttpStatus.NON_AUTHORITATIVE_INFORMATION) + public CommonResult notOwnerException(HttpServletRequest request, CNotOwnerException e) { + return responseService.getFailResult(Integer.valueOf(getMessage("notOwner.code")), getMessage("notOwner.msg")); + } + + @ExceptionHandler(CResourceNotExistException.class) + @ResponseStatus(HttpStatus.NOT_FOUND) + public CommonResult resourceNotExistException(HttpServletRequest request, CResourceNotExistException e) { + return responseService.getFailResult(Integer.valueOf(getMessage("resourceNotExist.code")), getMessage("resourceNotExist.msg")); + } + // code정보에 해당하는 메시지를 조회합니다. private String getMessage(String code) { return getMessage(code, null); } + // code정보, 추가 argument로 현재 locale에 맞는 메시지를 조회합니다. private String getMessage(String code, Object[] args) { return messageSource.getMessage(code, args, LocaleContextHolder.getLocale()); diff --git a/src/main/java/com/rest/api/advice/exception/CNotOwnerException.java b/src/main/java/com/rest/api/advice/exception/CNotOwnerException.java new file mode 100644 index 0000000..34ecccb --- /dev/null +++ b/src/main/java/com/rest/api/advice/exception/CNotOwnerException.java @@ -0,0 +1,18 @@ +package com.rest.api.advice.exception; + +public class CNotOwnerException extends RuntimeException { + + private static final long serialVersionUID = 2241549550934267615L; + + public CNotOwnerException(String msg, Throwable t) { + super(msg, t); + } + + public CNotOwnerException(String msg) { + super(msg); + } + + public CNotOwnerException() { + super(); + } +} diff --git a/src/main/java/com/rest/api/advice/exception/CResourceNotExistException.java b/src/main/java/com/rest/api/advice/exception/CResourceNotExistException.java new file mode 100644 index 0000000..1cd44ee --- /dev/null +++ b/src/main/java/com/rest/api/advice/exception/CResourceNotExistException.java @@ -0,0 +1,15 @@ +package com.rest.api.advice.exception; + +public class CResourceNotExistException extends RuntimeException { + public CResourceNotExistException(String msg, Throwable t) { + super(msg, t); + } + + public CResourceNotExistException(String msg) { + super(msg); + } + + public CResourceNotExistException() { + super(); + } +} diff --git a/src/main/java/com/rest/api/config/security/CustomAccessDeniedHandler.java b/src/main/java/com/rest/api/config/security/CustomAccessDeniedHandler.java index 8b30ba8..e1cdff0 100644 --- a/src/main/java/com/rest/api/config/security/CustomAccessDeniedHandler.java +++ b/src/main/java/com/rest/api/config/security/CustomAccessDeniedHandler.java @@ -5,8 +5,6 @@ import org.springframework.security.access.AccessDeniedException; import org.springframework.security.web.access.AccessDeniedHandler; import org.springframework.stereotype.Component; -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @@ -16,9 +14,7 @@ import java.io.IOException; public class CustomAccessDeniedHandler implements AccessDeniedHandler { @Override - public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException exception) throws IOException, - ServletException { - RequestDispatcher dispatcher = request.getRequestDispatcher("/exception/accessdenied"); - dispatcher.forward(request, response); + public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException exception) throws IOException { + response.sendRedirect("/exception/accessdenied"); } -} +} \ No newline at end of file diff --git a/src/main/java/com/rest/api/config/security/CustomAuthenticationEntryPoint.java b/src/main/java/com/rest/api/config/security/CustomAuthenticationEntryPoint.java index 46d1b5b..1e898b5 100644 --- a/src/main/java/com/rest/api/config/security/CustomAuthenticationEntryPoint.java +++ b/src/main/java/com/rest/api/config/security/CustomAuthenticationEntryPoint.java @@ -5,8 +5,6 @@ import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.stereotype.Component; -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @@ -14,12 +12,8 @@ import java.io.IOException; @Slf4j @Component public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint { - @Override - public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException ex) throws IOException, - ServletException { -// RequestDispatcher dispatcher = request.getRequestDispatcher("/exception/entrypoint"); -// dispatcher.forward(request, response); + public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException ex) throws IOException { response.sendRedirect("/exception/entrypoint"); } -} +} \ No newline at end of file diff --git a/src/main/java/com/rest/api/config/security/SecurityConfiguration.java b/src/main/java/com/rest/api/config/security/SecurityConfiguration.java index 9d66841..fb46575 100644 --- a/src/main/java/com/rest/api/config/security/SecurityConfiguration.java +++ b/src/main/java/com/rest/api/config/security/SecurityConfiguration.java @@ -32,7 +32,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter { .and() .authorizeRequests() // 다음 리퀘스트에 대한 사용권한 체크 .antMatchers("/*/signin", "/*/signin/**", "/*/signup", "/*/signup/**", "/social/**").permitAll() // 가입 및 인증 주소는 누구나 접근가능 - .antMatchers(HttpMethod.GET, "/exception/**", "/helloworld/**","/actuator/health", "/v1/board/*", "/v1/board/*/posts").permitAll() // hellowworld로 시작하는 GET요청 리소스는 누구나 접근가능 + .antMatchers(HttpMethod.GET, "/exception/**", "/helloworld/**","/actuator/health", "/v1/board/**").permitAll() // hellowworld로 시작하는 GET요청 리소스는 누구나 접근가능 .anyRequest().hasRole("USER") // 그외 나머지 요청은 모두 인증된 회원만 접근 가능 .and() .exceptionHandling().accessDeniedHandler(new CustomAccessDeniedHandler()) diff --git a/src/main/java/com/rest/api/controller/HelloController.java b/src/main/java/com/rest/api/controller/HelloController.java index b9a8b7c..ed5538d 100644 --- a/src/main/java/com/rest/api/controller/HelloController.java +++ b/src/main/java/com/rest/api/controller/HelloController.java @@ -5,7 +5,6 @@ import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Slf4j diff --git a/src/main/java/com/rest/api/controller/v1/board/BoardController.java b/src/main/java/com/rest/api/controller/v1/board/BoardController.java index 7d3dc3e..cf93c2b 100644 --- a/src/main/java/com/rest/api/controller/v1/board/BoardController.java +++ b/src/main/java/com/rest/api/controller/v1/board/BoardController.java @@ -3,13 +3,18 @@ package com.rest.api.controller.v1.board; import com.rest.api.entity.board.Board; import com.rest.api.entity.board.Post; import com.rest.api.model.board.ParamsPost; +import com.rest.api.model.response.CommonResult; import com.rest.api.model.response.ListResult; import com.rest.api.model.response.SingleResult; import com.rest.api.service.ResponseService; import com.rest.api.service.board.BoardService; import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.*; import javax.validation.Valid; @@ -24,20 +29,54 @@ public class BoardController { private final ResponseService responseService; @ApiOperation(value = "게시판 정보 조회", notes = "게시판 정보를 조회한다.") - @GetMapping(value="/{boardName}") + @GetMapping(value = "/{boardName}") public SingleResult boardInfo(@PathVariable String boardName) { return responseService.getSingleResult(boardService.findBoard(boardName)); } - @ApiOperation(value = "게시판 포스트 조회", notes = "게시판의 포스팅 정보를 조회한다.") - @GetMapping(value="/{boardName}/posts") + @ApiOperation(value = "게시판 글 리스트", notes = "게시판의 포스팅 정보를 조회한다.") + @GetMapping(value = "/{boardName}/posts") public ListResult posts(@PathVariable String boardName) { return responseService.getListResult(boardService.findPosts(boardName)); } - @ApiOperation(value = "게시판 글쓰기", notes = "게시판에 글을 작성한다.") - @PostMapping(value="/{boardName}") - public SingleResult post(@PathVariable String boardName, @Valid ParamsPost post) { - return responseService.getSingleResult(boardService.writePost(boardName, post)); + @ApiImplicitParams({ + @ApiImplicitParam(name = "X-AUTH-TOKEN", value = "로그인 성공 후 access_token", required = true, dataType = "String", paramType = "header") + }) + @ApiOperation(value = "게시판 글 작성", notes = "게시판에 글을 작성한다.") + @PostMapping(value = "/{boardName}") + public SingleResult post(@PathVariable String boardName, @Valid @ModelAttribute ParamsPost post) { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + String uid = authentication.getName(); + return responseService.getSingleResult(boardService.writePost(uid, boardName, post)); + } + + @ApiOperation(value = "게시판 글 상세", notes = "게시판 글 상세정보를 조회한다.") + @GetMapping(value = "/post/{postId}") + public SingleResult post(@PathVariable long postId) { + return responseService.getSingleResult(boardService.getPost(postId)); + } + + @ApiImplicitParams({ + @ApiImplicitParam(name = "X-AUTH-TOKEN", value = "로그인 성공 후 access_token", required = true, dataType = "String", paramType = "header") + }) + @ApiOperation(value = "게시판 글 수정", notes = "게시판의 글을 수정한다.") + @PutMapping(value = "/post/{postId}") + public SingleResult post(@PathVariable long postId, @Valid @ModelAttribute ParamsPost post) { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + String uid = authentication.getName(); + return responseService.getSingleResult(boardService.updatePost(postId, uid, post)); + } + + @ApiImplicitParams({ + @ApiImplicitParam(name = "X-AUTH-TOKEN", value = "로그인 성공 후 access_token", required = true, dataType = "String", paramType = "header") + }) + @ApiOperation(value = "게시판 글 삭제", notes = "게시판의 글을 삭제한다.") + @DeleteMapping(value = "/post/{postId}") + public CommonResult deletePost(@PathVariable long postId) { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + String uid = authentication.getName(); + boardService.deletePost(postId, uid); + return responseService.getSuccessResult(); } } diff --git a/src/main/java/com/rest/api/entity/User.java b/src/main/java/com/rest/api/entity/User.java index 5156ad8..c2628a5 100644 --- a/src/main/java/com/rest/api/entity/User.java +++ b/src/main/java/com/rest/api/entity/User.java @@ -1,7 +1,11 @@ package com.rest.api.entity; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; @@ -18,10 +22,11 @@ import java.util.stream.Collectors; @NoArgsConstructor // 인자없는 생성자를 자동으로 생성합니다. @AllArgsConstructor // 인자를 모두 갖춘 생성자를 자동으로 생성합니다. @Table(name = "user") // 'user' 테이블과 매핑됨을 명시 +@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) public class User implements UserDetails { @Id // pk @GeneratedValue(strategy = GenerationType.IDENTITY) - private long msrl; + private Long msrl; @Column(nullable = false, unique = true, length = 50) private String uid; @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) diff --git a/src/main/java/com/rest/api/entity/board/Board.java b/src/main/java/com/rest/api/entity/board/Board.java index 21a0bcc..0039f1e 100644 --- a/src/main/java/com/rest/api/entity/board/Board.java +++ b/src/main/java/com/rest/api/entity/board/Board.java @@ -1,36 +1,20 @@ package com.rest.api.entity.board; -import lombok.Builder; +import com.rest.api.entity.common.CommonDateEntity; import lombok.Getter; import lombok.NoArgsConstructor; -import org.hibernate.annotations.CreationTimestamp; -import org.hibernate.annotations.UpdateTimestamp; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; -import java.time.LocalDateTime; @Entity @Getter @NoArgsConstructor -public class Board { +public class Board extends CommonDateEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; - @CreationTimestamp - private LocalDateTime createdAt; - @UpdateTimestamp - private LocalDateTime modifiedAt; - - @Builder - public Board(String name) { - this.name = name; - } - - public Post write(String author, String title, String content) { - return new Post(this, author, title, content); - } } diff --git a/src/main/java/com/rest/api/entity/board/Post.java b/src/main/java/com/rest/api/entity/board/Post.java index e7a6aa8..9d49ce2 100644 --- a/src/main/java/com/rest/api/entity/board/Post.java +++ b/src/main/java/com/rest/api/entity/board/Post.java @@ -1,34 +1,39 @@ package com.rest.api.entity.board; +import com.rest.api.entity.User; +import com.rest.api.entity.common.CommonDateEntity; import lombok.Getter; -import org.hibernate.annotations.CreationTimestamp; -import org.hibernate.annotations.UpdateTimestamp; +import lombok.NoArgsConstructor; import javax.persistence.*; -import java.time.LocalDateTime; @Entity @Getter -public class Post { +@NoArgsConstructor +public class Post extends CommonDateEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String author; private String title; private String content; - @CreationTimestamp - private LocalDateTime createdAt; - @UpdateTimestamp - private LocalDateTime modifiedAt; - @ManyToOne(fetch = FetchType.LAZY, optional = false) - private Board board; + private Long boardId; - protected Post() { - } + @ManyToOne(fetch = FetchType.LAZY) + private User user; - protected Post(Board board, String author, String title, String content) { + public Post(User user, Long boardId, String author, String title, String content) { + this.user = user; + this.boardId = boardId; this.author = author; this.title = title; this.content = content; } + + public Post setUpdate(String author, String title, String content) { + this.author = author; + this.title = title; + this.content = content; + return this; + } } diff --git a/src/main/java/com/rest/api/entity/common/CommonDateEntity.java b/src/main/java/com/rest/api/entity/common/CommonDateEntity.java new file mode 100644 index 0000000..3fb2ec8 --- /dev/null +++ b/src/main/java/com/rest/api/entity/common/CommonDateEntity.java @@ -0,0 +1,20 @@ +package com.rest.api.entity.common; + +import lombok.Getter; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import javax.persistence.EntityListeners; +import javax.persistence.MappedSuperclass; +import java.time.LocalDateTime; + +@Getter +@MappedSuperclass +@EntityListeners(AuditingEntityListener.class) +public abstract class CommonDateEntity { + @CreatedDate + private LocalDateTime createdAt; + @LastModifiedDate + private LocalDateTime modifiedAt; +} diff --git a/src/main/java/com/rest/api/model/board/ParamsPost.java b/src/main/java/com/rest/api/model/board/ParamsPost.java index 983fb2d..b4b7f38 100644 --- a/src/main/java/com/rest/api/model/board/ParamsPost.java +++ b/src/main/java/com/rest/api/model/board/ParamsPost.java @@ -1,6 +1,6 @@ package com.rest.api.model.board; -import lombok.Builder; +import io.swagger.annotations.ApiModelProperty; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -12,16 +12,12 @@ import javax.validation.constraints.NotEmpty; @NoArgsConstructor public class ParamsPost { @NotEmpty + @ApiModelProperty(value = "작성자명", required = true) private String author; @NotEmpty + @ApiModelProperty(value = "제목", required = true) private String title; @NotEmpty + @ApiModelProperty(value = "내용", required = true) private String content; - - @Builder - public ParamsPost(String author, String title, String content) { - this.author = author; - this.title = title; - this.content = content; - } } diff --git a/src/main/java/com/rest/api/repo/board/PostJpaRepo.java b/src/main/java/com/rest/api/repo/board/PostJpaRepo.java index 386c4e6..38ae636 100644 --- a/src/main/java/com/rest/api/repo/board/PostJpaRepo.java +++ b/src/main/java/com/rest/api/repo/board/PostJpaRepo.java @@ -1,11 +1,10 @@ package com.rest.api.repo.board; -import com.rest.api.entity.board.Board; import com.rest.api.entity.board.Post; import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; public interface PostJpaRepo extends JpaRepository { - List findByBoard(Board board); -} + List findByBoardId(Long boardId); +} \ No newline at end of file diff --git a/src/main/java/com/rest/api/service/board/BoardService.java b/src/main/java/com/rest/api/service/board/BoardService.java index 3e463e7..c6f8ba9 100644 --- a/src/main/java/com/rest/api/service/board/BoardService.java +++ b/src/main/java/com/rest/api/service/board/BoardService.java @@ -1,16 +1,23 @@ package com.rest.api.service.board; +import com.rest.api.advice.exception.CNotOwnerException; +import com.rest.api.advice.exception.CResourceNotExistException; +import com.rest.api.advice.exception.CUserNotFoundException; +import com.rest.api.entity.User; import com.rest.api.entity.board.Board; import com.rest.api.entity.board.Post; import com.rest.api.model.board.ParamsPost; +import com.rest.api.repo.UserJpaRepo; import com.rest.api.repo.board.BoardJpaRepo; import com.rest.api.repo.board.PostJpaRepo; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import javax.transaction.Transactional; import java.util.List; +@Slf4j @Service @Transactional @RequiredArgsConstructor @@ -18,6 +25,7 @@ public class BoardService { private final BoardJpaRepo boardJpaRepo; private final PostJpaRepo postJpaRepo; + private final UserJpaRepo userJpaRepo; public Board findBoard(String boardName) { return boardJpaRepo.findByName(boardName); @@ -25,16 +33,35 @@ public class BoardService { public List findPosts(String boardName) { Board board = findBoard(boardName); - return postJpaRepo.findByBoard(board); + return postJpaRepo.findByBoardId(board.getId()); } - private Post getPost(long postId) { - return postJpaRepo.findById(postId).orElse(null); + public Post getPost(long postId) { + return postJpaRepo.findById(postId).orElseThrow(CResourceNotExistException::new); } - public Post writePost(String boardName, ParamsPost paramsPost) { + public Post writePost(String uid, String boardName, ParamsPost paramsPost) { Board board = findBoard(boardName); - Post post = board.write(paramsPost.getAuthor(), paramsPost.getTitle(), paramsPost.getContent()); + Post post = new Post(userJpaRepo.findByUid(uid).orElseThrow(CUserNotFoundException::new), board.getId(), paramsPost.getAuthor(), paramsPost.getTitle(), paramsPost.getContent()); return postJpaRepo.save(post); } + + public Post updatePost(long postId, String uid, ParamsPost paramsPost) { + Post post = getPost(postId); + User user = post.getUser(); + if (!uid.equals(user.getUid())) + throw new CNotOwnerException(); + + post.setUpdate(paramsPost.getAuthor(), paramsPost.getTitle(), paramsPost.getContent()); + return postJpaRepo.save(post); + } + + public boolean deletePost(long postId, String uid) { + Post post = getPost(postId); + User user = post.getUser(); + if (!uid.equals(user.getUid())) + throw new CNotOwnerException(); + postJpaRepo.delete(post); + return true; + } } diff --git a/src/main/resources/i18n/exception_en.yml b/src/main/resources/i18n/exception_en.yml index ff111c2..11fc40f 100644 --- a/src/main/resources/i18n/exception_en.yml +++ b/src/main/resources/i18n/exception_en.yml @@ -18,4 +18,10 @@ communicationError: msg: "An error occurred during communication." existingUser: code: "-1005" - msg: "You are an existing member." \ No newline at end of file + msg: "You are an existing member." +notOwner: + code: "-1006" + msg: "You are not the owner of this resource." +resourceNotExist: + code: "-1007" + msg: "This resource does not exist." \ No newline at end of file diff --git a/src/main/resources/i18n/exception_ko.yml b/src/main/resources/i18n/exception_ko.yml index f94682d..cb6e423 100644 --- a/src/main/resources/i18n/exception_ko.yml +++ b/src/main/resources/i18n/exception_ko.yml @@ -18,4 +18,10 @@ communicationError: msg: "통신 중 오류가 발생하였습니다." existingUser: code: "-1005" - msg: "이미 가입한 회원입니다. 로그인을 해주십시오." \ No newline at end of file + msg: "이미 가입한 회원입니다. 로그인을 해주십시오." +notOwner: + code: "-1006" + msg: "해당 자원의 소유자가 아닙니다." +resourceNotExist: + code: "-1007" + msg: "요청하신 자원이 존재 하지 않습니다." \ No newline at end of file