본문 바로가기

프로젝트/멋사 개인 프로젝트 (mutsa-SNS)

[11] mutsa-SNS 5일차 - (2) Post 삭제, 수정 기능 추가

Post의 삭제와 수정 기능을 추가하였다.

해당 기능은 아래의 조건을 충족했을 때만 가능하다.

  • JWT token을 갖고 있는 자 (로그인 한 유저)
  • UserRole = ADMIN인 경우 모든 글에 대하여 삭제와 수정 가능
  • UserRole = USER인 경우 자신의 글에 대하여 삭제와 수정 가능

 

1. Configuration

SecurityConfig

@EnableWebSecurity
@Configuration
@RequiredArgsConstructor
//WebSecurityConfigurerAdapter 는 이후 SpringBoot에서 잘 안쓰게 됨
public class SecurityConfig {

    ...

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
        return httpSecurity
                .httpBasic().disable()
                .csrf().disable()
                .cors().and()
                .exceptionHandling()
                .authenticationEntryPoint(new CustomAuthenticationEntryPoint())
                .and()
                .authorizeRequests()
                .antMatchers(PERMIT_URL_ARRAY).permitAll()
                .antMatchers(HttpMethod.POST,"/api/**").authenticated() // post는 인가자만 허용
                .antMatchers(HttpMethod.DELETE,"/api/**").authenticated() // delete는 인가자만 허용
                .antMatchers(HttpMethod.PUT,"/api/**").authenticated() // put는 인가자만 허용 (글 수정)
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS) // jwt사용하는 경우 씀
                .and()
                .addFilterBefore(new JwtTokenFilter(userService, secretKey), UsernamePasswordAuthenticationFilter.class) //UserNamePasswordAuthenticationFilter적용하기 전에 JWTTokenFilter를 적용
                .build();
    }

}

해당 SecurrityConfiguration에서 Delete와 Put method에도 접근 제한을 추가하였다.

 

2. Domain

PostModifyRequest(domain - dto directory)

@AllArgsConstructor
@NoArgsConstructor
@Getter
@Builder
public class PostModifyRequest {
    private String title;
    private String body;
}

글 수정시 클라이언트가 입력해야하는 글 제목과 글 내용을 담기 위한 dto를 추가하였다.

 

3. Service

PostService

@Service
@RequiredArgsConstructor
@Slf4j
public class PostService {

    private final PostRepository postRepository;
    private final UserRepository userRepository;

	...
    
    public void deletePost(String userName, Integer postId) {
        Post post = postRepository.findById(postId)
                .orElseThrow(() -> new AppException(ErrorCode.POST_NOT_FOUND, ""));

        User user = userRepository.findByUserName(userName)
                .orElseThrow(() -> new AppException(ErrorCode.NOT_FOUNDED_USER_NAME, ""));


        //userRole이 USER이고, 작성자와 삭제자 불일치시.
        //ADMIN은 모두 제거 가능
        if (user.getRole() == UserRole.USER && !Objects.equals(post.getUser().getUserName(), userName)) {
            throw new AppException(ErrorCode.INVALID_PERMISSION, "");
        }

        postRepository.delete(post);

    }

    public PostDto modifyPost(Integer postId, String title, String body, String userName) {
        Post post = postRepository.findById(postId)
                .orElseThrow(() -> new AppException(ErrorCode.POST_NOT_FOUND, ""));

        User user = userRepository.findByUserName(userName)
                .orElseThrow(() -> new AppException(ErrorCode.NOT_FOUNDED_USER_NAME, ""));


        //userRole이 USER이고, 작성자와 삭제자 불일치시.
        //ADMIN은 모두 수정 가능.
        if (user.getRole() == UserRole.USER && !Objects.equals(post.getUser().getUserName(), userName)) {
            throw new AppException(ErrorCode.INVALID_PERMISSION, "");
        }

        post.setTitle(title);
        post.setBody(body);

        Post savedPost = postRepository.saveAndFlush(post);

        return savedPost.toResponse();

    }

}

글 수정과 삭제에 대한 비지니스 로직을 추가하였다.

  • view에서 받은 postId를 통해 db에서 post를 검색하였을 시 나오지 않은 경우 exception 발생
  • view에서 받은 userName을 통해 db에서 user를 검색하였을 시 나오지 않은 경우 exception 발생
  • role = UserRole.USER일 경우, 작성자와 수정자, 삭제자가 일치하지 않은 경우 exception 발생

즉시 db에 수정사항이 반영되어야 하기 때문에, 글 수정의 경우 기존의 jpaRepository의 save()가 아닌 saveAndFlush()를 사용하였다.

 

<Reference>

https://velog.io/@codren/JPA-save-%EC%99%80-saveAndFlush-%EC%9D%98-%EC%B0%A8%EC%9D%B4

 

JPA - save() 와 saveAndFlush() 의 차이

영속성 컨텍스트(Persistence Context) 와 DB 사이, Baeldung 문서

velog.io

 

4. Controller

PostController

@RestController
@RequestMapping("/api/v1/posts")
@RequiredArgsConstructor
public class PostController {

    private final PostService postService;

	...

    @DeleteMapping("/{postId}")
    public Response<PostResponse> deletePost(@PathVariable Integer postId, Authentication authentication) {

        postService.deletePost(authentication.getName(), postId);
        return Response.success(new PostResponse("포스트 삭제 완료", postId));

    }

    @PutMapping("/{postId}")
    public Response<PostResponse> modifyPost(@PathVariable Integer postId, @RequestBody PostModifyRequest req, Authentication authentication) {

        PostDto postDto = postService.modifyPost(postId, req.getTitle(), req.getBody(), authentication.getName());
        return Response.success(new PostResponse("포스트 수정 완료", postDto.getId()));
    }


}

글 수정과 삭제에 대한 매핑을 추가하였다.

 

<전체 Reference>

https://velog.io/@codren/JPA-save-%EC%99%80-saveAndFlush-%EC%9D%98-%EC%B0%A8%EC%9D%B4