Skip to content

Commit 002ac18

Browse files
authored
Merge pull request #17 from codej99/feature/board
Feature/board
2 parents 0bcbc81 + c259842 commit 002ac18

22 files changed

+379
-30
lines changed

‎src/main/java/com/rest/api/SpringRestApiApplication.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
77
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
88
import org.springframework.context.annotation.Bean;
9+
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
910
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
1011
import org.springframework.security.crypto.password.PasswordEncoder;
1112
import org.springframework.web.client.RestTemplate;
1213

14+
@EnableJpaAuditing
1315
@SpringBootApplication
1416
public class SpringRestApiApplication {
1517
public static void main(String[] args) {

‎src/main/java/com/rest/api/advice/ExceptionAdvice.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public class ExceptionAdvice {
2626
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
2727
protected CommonResult defaultException(HttpServletRequest request, Exception e) {
2828
// 예외 처리의 메시지를 MessageSource에서 가져오도록 수정
29-
return responseService.getFailResult(Integer.valueOf(getMessage("unKnown.code")), getMessage("unKnown.msg"));
29+
return responseService.getFailResult(Integer.valueOf(getMessage("unKnown.code")), getMessage("unKnown.msg") + "(" + e.getMessage() + ")");
3030
}
3131

3232
@ExceptionHandler(CUserNotFoundException.class)
@@ -48,7 +48,7 @@ public CommonResult authenticationEntryPointException(HttpServletRequest request
4848
}
4949

5050
@ExceptionHandler(AccessDeniedException.class)
51-
@ResponseStatus(HttpStatus.UNAUTHORIZED)
51+
@ResponseStatus(HttpStatus.FORBIDDEN)
5252
public CommonResult accessDeniedException(HttpServletRequest request, AccessDeniedException e) {
5353
return responseService.getFailResult(Integer.valueOf(getMessage("accessDenied.code")), getMessage("accessDenied.msg"));
5454
}
@@ -65,10 +65,23 @@ public CommonResult communicationException(HttpServletRequest request, CUserExis
6565
return responseService.getFailResult(Integer.valueOf(getMessage("existingUser.code")), getMessage("existingUser.msg"));
6666
}
6767

68+
@ExceptionHandler(CNotOwnerException.class)
69+
@ResponseStatus(HttpStatus.NON_AUTHORITATIVE_INFORMATION)
70+
public CommonResult notOwnerException(HttpServletRequest request, CNotOwnerException e) {
71+
return responseService.getFailResult(Integer.valueOf(getMessage("notOwner.code")), getMessage("notOwner.msg"));
72+
}
73+
74+
@ExceptionHandler(CResourceNotExistException.class)
75+
@ResponseStatus(HttpStatus.NOT_FOUND)
76+
public CommonResult resourceNotExistException(HttpServletRequest request, CResourceNotExistException e) {
77+
return responseService.getFailResult(Integer.valueOf(getMessage("resourceNotExist.code")), getMessage("resourceNotExist.msg"));
78+
}
79+
6880
// code정보에 해당하는 메시지를 조회합니다.
6981
private String getMessage(String code) {
7082
return getMessage(code, null);
7183
}
84+
7285
// code정보, 추가 argument로 현재 locale에 맞는 메시지를 조회합니다.
7386
private String getMessage(String code, Object[] args) {
7487
return messageSource.getMessage(code, args, LocaleContextHolder.getLocale());
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.rest.api.advice.exception;
2+
3+
public class CNotOwnerException extends RuntimeException {
4+
5+
private static final long serialVersionUID = 2241549550934267615L;
6+
7+
public CNotOwnerException(String msg, Throwable t) {
8+
super(msg, t);
9+
}
10+
11+
public CNotOwnerException(String msg) {
12+
super(msg);
13+
}
14+
15+
public CNotOwnerException() {
16+
super();
17+
}
18+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.rest.api.advice.exception;
2+
3+
public class CResourceNotExistException extends RuntimeException {
4+
public CResourceNotExistException(String msg, Throwable t) {
5+
super(msg, t);
6+
}
7+
8+
public CResourceNotExistException(String msg) {
9+
super(msg);
10+
}
11+
12+
public CResourceNotExistException() {
13+
super();
14+
}
15+
}

‎src/main/java/com/rest/api/config/security/CustomAccessDeniedHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,4 @@ public class CustomAccessDeniedHandler implements AccessDeniedHandler {
1717
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException exception) throws IOException {
1818
response.sendRedirect("/exception/accessdenied");
1919
}
20-
}
20+
}

‎src/main/java/com/rest/api/config/security/CustomAuthenticationEntryPoint.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,15 @@
55
import org.springframework.security.web.AuthenticationEntryPoint;
66
import org.springframework.stereotype.Component;
77

8-
import javax.servlet.RequestDispatcher;
9-
import javax.servlet.ServletException;
108
import javax.servlet.http.HttpServletRequest;
119
import javax.servlet.http.HttpServletResponse;
1210
import java.io.IOException;
1311

1412
@Slf4j
1513
@Component
1614
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
17-
1815
@Override
19-
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException ex) throws IOException,
20-
ServletException {
16+
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException ex) throws IOException {
2117
response.sendRedirect("/exception/entrypoint");
2218
}
23-
}
19+
}

‎src/main/java/com/rest/api/config/security/SecurityConfiguration.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,7 @@ protected void configure(HttpSecurity http) throws Exception {
3232
.and()
3333
.authorizeRequests() // 다음 리퀘스트에 대한 사용권한 체크
3434
.antMatchers("/*/signin", "/*/signin/**", "/*/signup", "/*/signup/**", "/social/**").permitAll() // 가입 및 인증 주소는 누구나 접근가능
35-
.antMatchers(HttpMethod.GET, "/exception/**","/helloworld/**").permitAll() // hellowworld로 시작하는 GET요청 리소스는 누구나 접근가능
36-
.antMatchers(HttpMethod.GET, "/helloworld/**","/actuator/health").permitAll() // hellowworld로 시작하는 GET요청 리소스는 누구나 접근가능
35+
.antMatchers(HttpMethod.GET, "/exception/**", "/helloworld/**","/actuator/health", "/v1/board/**").permitAll() // hellowworld로 시작하는 GET요청 리소스는 누구나 접근가능
3736
.anyRequest().hasRole("USER") // 그외 나머지 요청은 모두 인증�� 회원만 접근 가능
3837
.and()
3938
.exceptionHandling().accessDeniedHandler(new CustomAccessDeniedHandler())

‎src/main/java/com/rest/api/controller/HelloController.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import lombok.extern.slf4j.Slf4j;
66
import org.springframework.stereotype.Controller;
77
import org.springframework.web.bind.annotation.GetMapping;
8-
import org.springframework.web.bind.annotation.RequestMapping;
98
import org.springframework.web.bind.annotation.ResponseBody;
109

1110
@Slf4j

‎src/main/java/com/rest/api/controller/v1/UserController.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,12 @@ public SingleResult<User> findUser() {
5151
@ApiOperation(value = "회원 수정", notes = "회원정보를 수정한다")
5252
@PutMapping(value = "/user")
5353
public SingleResult<User> modify(
54-
@ApiParam(value = "회원번호", required = true) @RequestParam long msrl,
5554
@ApiParam(value = "회원이름", required = true) @RequestParam String name) {
56-
User user = User.builder()
57-
.msrl(msrl)
58-
.name(name)
59-
.build();
55+
56+
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
57+
String id = authentication.getName();
58+
User user = userJpaRepo.findByUid(id).orElseThrow(CUserNotFoundException::new);
59+
user.setName(name);
6060
return responseService.getSingleResult(userJpaRepo.save(user));
6161
}
6262

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package com.rest.api.controller.v1.board;
2+
3+
import com.rest.api.entity.board.Board;
4+
import com.rest.api.entity.board.Post;
5+
import com.rest.api.model.board.ParamsPost;
6+
import com.rest.api.model.response.CommonResult;
7+
import com.rest.api.model.response.ListResult;
8+
import com.rest.api.model.response.SingleResult;
9+
import com.rest.api.service.ResponseService;
10+
import com.rest.api.service.board.BoardService;
11+
import io.swagger.annotations.Api;
12+
import io.swagger.annotations.ApiImplicitParam;
13+
import io.swagger.annotations.ApiImplicitParams;
14+
import io.swagger.annotations.ApiOperation;
15+
import lombok.RequiredArgsConstructor;
16+
import org.springframework.security.core.Authentication;
17+
import org.springframework.security.core.context.SecurityContextHolder;
18+
import org.springframework.web.bind.annotation.*;
19+
20+
import javax.validation.Valid;
21+
22+
@Api(tags = {"3. Board"})
23+
@RequiredArgsConstructor
24+
@RestController
25+
@RequestMapping(value = "/v1/board")
26+
public class BoardController {
27+
28+
private final BoardService boardService;
29+
private final ResponseService responseService;
30+
31+
@ApiOperation(value = "게시판 정보 조회", notes = "게시판 정보를 조회한다.")
32+
@GetMapping(value = "/{boardName}")
33+
public SingleResult<Board> boardInfo(@PathVariable String boardName) {
34+
return responseService.getSingleResult(boardService.findBoard(boardName));
35+
}
36+
37+
@ApiOperation(value = "게시글 리스트", notes = "게시글 리스트를 조회한다.")
38+
@GetMapping(value = "/{boardName}/posts")
39+
public ListResult<Post> posts(@PathVariable String boardName) {
40+
return responseService.getListResult(boardService.findPosts(boardName));
41+
}
42+
43+
@ApiImplicitParams({
44+
@ApiImplicitParam(name = "X-AUTH-TOKEN", value = "로그인 성공 후 access_token", required = true, dataType = "String", paramType = "header")
45+
})
46+
@ApiOperation(value = "게시글 작성", notes = "게시글을 작성한다.")
47+
@PostMapping(value = "/{boardName}")
48+
public SingleResult<Post> post(@PathVariable String boardName, @Valid @ModelAttribute ParamsPost post) {
49+
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
50+
String uid = authentication.getName();
51+
return responseService.getSingleResult(boardService.writePost(uid, boardName, post));
52+
}
53+
54+
@ApiOperation(value = "게시글 상세", notes = "게시글 상세정보를 조회한다.")
55+
@GetMapping(value = "/post/{postId}")
56+
public SingleResult<Post> post(@PathVariable long postId) {
57+
return responseService.getSingleResult(boardService.getPost(postId));
58+
}
59+
60+
@ApiImplicitParams({
61+
@ApiImplicitParam(name = "X-AUTH-TOKEN", value = "로그인 성공 후 access_token", required = true, dataType = "String", paramType = "header")
62+
})
63+
@ApiOperation(value = "게시글 수정", notes = "게시판의 글을 수정한다.")
64+
@PutMapping(value = "/post/{postId}")
65+
public SingleResult<Post> post(@PathVariable long postId, @Valid @ModelAttribute ParamsPost post) {
66+
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
67+
String uid = authentication.getName();
68+
return responseService.getSingleResult(boardService.updatePost(postId, uid, post));
69+
}
70+
71+
@ApiImplicitParams({
72+
@ApiImplicitParam(name = "X-AUTH-TOKEN", value = "로그인 성공 후 access_token", required = true, dataType = "String", paramType = "header")
73+
})
74+
@ApiOperation(value = "게시글 삭제", notes = "게시글을 삭제한다.")
75+
@DeleteMapping(value = "/post/{postId}")
76+
public CommonResult deletePost(@PathVariable long postId) {
77+
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
78+
String uid = authentication.getName();
79+
boardService.deletePost(postId, uid);
80+
return responseService.getSuccessResult();
81+
}
82+
}

‎src/main/java/com/rest/api/entity/User.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.rest.api.entity;
22

3+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
34
import com.fasterxml.jackson.annotation.JsonProperty;
5+
import com.rest.api.entity.common.CommonDateEntity;
46
import lombok.*;
57
import org.springframework.security.core.GrantedAuthority;
68
import org.springframework.security.core.authority.SimpleGrantedAuthority;
@@ -15,13 +17,15 @@
1517
@Builder // builder를 사용할수 있게 합니다.
1618
@Entity // jpa entity임을 알립니다.
1719
@Getter // user 필드값의 getter를 자동으로 생성합니다.
20+
@Setter
1821
@NoArgsConstructor // 인자없는 생성자를 자동으로 생성합니다.
1922
@AllArgsConstructor // 인자를 모두 갖춘 생성자를 자동으로 생성합니다.
2023
@Table(name = "user") // 'user' 테이블과 매핑됨을 명시
21-
public class User implements UserDetails {
24+
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) // Post Entity에서 User와의 관계를 Json으로 변환시 오류 방지를 위한 코드
25+
public class User extends CommonDateEntity implements UserDetails {
2226
@Id // pk
2327
@GeneratedValue(strategy = GenerationType.IDENTITY)
24-
private long msrl;
28+
private Long msrl;
2529
@Column(nullable = false, unique = true, length = 50)
2630
private String uid;
2731
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.rest.api.entity.board;
2+
3+
import com.rest.api.entity.common.CommonDateEntity;
4+
import lombok.Getter;
5+
import lombok.NoArgsConstructor;
6+
7+
import javax.persistence.*;
8+
9+
@Entity
10+
@Getter
11+
@NoArgsConstructor
12+
public class Board extends CommonDateEntity {
13+
@Id
14+
@GeneratedValue(strategy = GenerationType.IDENTITY)
15+
private Long boardId;
16+
@Column(nullable = false, length = 100)
17+
private String name;
18+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package com.rest.api.entity.board;
2+
3+
import com.rest.api.entity.User;
4+
import com.rest.api.entity.common.CommonDateEntity;
5+
import lombok.Getter;
6+
import lombok.NoArgsConstructor;
7+
8+
import javax.persistence.*;
9+
10+
@Entity
11+
@Getter
12+
@NoArgsConstructor
13+
public class Post extends CommonDateEntity {
14+
@Id
15+
@GeneratedValue(strategy = GenerationType.IDENTITY)
16+
private Long postId;
17+
@Column(nullable = false, length = 50)
18+
private String author;
19+
@Column(nullable = false, length = 100)
20+
private String title;
21+
@Column(length = 500)
22+
private String content;
23+
24+
@ManyToOne(fetch = FetchType.LAZY)
25+
@JoinColumn(name = "board_id")
26+
private Board board; // 게시글 - 게시판의 관계 - N:1
27+
28+
29+
@ManyToOne(fetch = FetchType.LAZY)
30+
@JoinColumn(name = "msrl")
31+
private User user; // 게시글 - 회원의 관계 - N:1
32+
33+
// Join 테이블이 Json결과에 표시되지 않도록 처리.
34+
protected Board getBoard() {
35+
return board;
36+
}
37+
38+
// 생성자
39+
public Post(User user, Board board, String author, String title, String content) {
40+
this.user = user;
41+
this.board = board;
42+
this.author = author;
43+
this.title = title;
44+
this.content = content;
45+
}
46+
47+
// 수정시 데이터 처리
48+
public Post setUpdate(String author, String title, String content) {
49+
this.author = author;
50+
this.title = title;
51+
this.content = content;
52+
return this;
53+
}
54+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.rest.api.entity.common;
2+
3+
import lombok.Getter;
4+
import org.springframework.data.annotation.CreatedDate;
5+
import org.springframework.data.annotation.LastModifiedDate;
6+
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
7+
8+
import javax.persistence.EntityListeners;
9+
import javax.persistence.MappedSuperclass;
10+
import java.time.LocalDateTime;
11+
12+
@Getter
13+
@MappedSuperclass
14+
@EntityListeners(AuditingEntityListener.class)
15+
public abstract class CommonDateEntity {
16+
@CreatedDate
17+
private LocalDateTime createdAt;
18+
@LastModifiedDate
19+
private LocalDateTime modifiedAt;
20+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.rest.api.model.board;
2+
3+
import io.swagger.annotations.ApiModelProperty;
4+
import lombok.Getter;
5+
import lombok.NoArgsConstructor;
6+
import lombok.Setter;
7+
8+
import javax.validation.constraints.Max;
9+
import javax.validation.constraints.NotEmpty;
10+
11+
@Getter
12+
@Setter
13+
@NoArgsConstructor
14+
public class ParamsPost {
15+
@NotEmpty
16+
@Max(50)
17+
@ApiModelProperty(value = "작성자명", required = true)
18+
private String author;
19+
@NotEmpty
20+
@Max(100)
21+
@ApiModelProperty(value = "제목", required = true)
22+
private String title;
23+
@Max(500)
24+
@ApiModelProperty(value = "내용", required = true)
25+
private String content;
26+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.rest.api.repo.board;
2+
3+
import com.rest.api.entity.board.Board;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
6+
public interface BoardJpaRepo extends JpaRepository<Board, Long> {
7+
Board findByName(String name);
8+
}

0 commit comments

Comments
 (0)
X