[클론 코딩] 네이버 카페 - 통합게시판 수정

2024. 5. 29. 21:53Project/Naver Cafe

  저번에는 일반 게시판을 카페에 추가하는 기능을 구현했으니 이번에는 수정하는 기능을 구현하고자 한다. 사용자가 요청을 하면 서버에서는 기존 게시판의 정보를 담아 응답하며 사용자는 현재 게시판의 정보를 확인하면서 수정하고자하는 데이터를 입력해 수정 요청을 서버에 전달할 것이다. 서버는 요청 정보를 확인해 기존 게시판 정보를 수정후 DB에 반영하면 게시판 수정이 완료될 것이다.

 

  참고로 이번 기능을 구현하면 클래스명이나 메서드명때문에 고민을하였다. 문제는 너무 길어서...게시판이라 생각하고 BulletinBoard라는 이름을 사용했는데 이후 메서들 만들거나 할 때 길이가 너무 길어져 내심 불편한 점이 있었고 다음의 방법으로 이를 해결해 보았다.

 

  네이버는 게시판 목록을 '메뉴'라고 묶고 기본, 일반등으로 나누고 있다. 그리고 또 그 아래로 여러 타입의 게시판을 갖는다. 현재 프로젝트는 DDD 설계를 토대로 작성하고 있는데 도메인으로 menu를 만들고 그 아래에 하위 도메인으로 normal, 또 그 아래에 integrate를 두었다. 파악한 내용과 상충되기도 하고 무엇보다 엔티티 클래스명(=Integrate)이 짧아 가지는 의미가 많지 않지만 패키지 루트를 통해 '메뉴-일반-통합'이라는 부가적인 의미를 가질 수 있어 이러한 방법을 사용하게 되었다.


Integrate

package CloneCoding.NaverCafe.domain.menu.normal.integrate;

import static CloneCoding.NaverCafe.domain.menu.MenuType.*;
import static CloneCoding.NaverCafe.domain.menu.normal.integrate.enums.BasicData.*;
import static CloneCoding.NaverCafe.domain.cafeMember.enums.CafeMemberPosition.CAFE_MEMBER;

@Entity
@Table(name = "INTEGRATE")
@Getter
@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
public class Integrate {

    public void updateIntegrate(RequestUpdateIntegrate request) {
        this.sequence = request.getSequence();
        this.name = request.getName();
        this.description = request.getDescription();
        this.writeAuth = changeToPosition(request.getWriteAuth());
        this.readAuth = changeToPosition(request.getReadAuth());
        this.commentAuth = changeToPosition(request.getCommentAuth());
        this.useFavorite = request.isUseFavorite();
    }

    private static String changeToPosition(String value) {
        CafeMemberPosition position = CafeMemberPosition.findByPosition(value);
        return position.name();
    }

    private static String changeToType(String value) {
        MenuType type = MenuType.findByType(value);
        return type.name();
    }

}

 

  • updateIntegrate() : Integrate 객체를 요청 정보를 토대로 수정하는 메서드
  • MenuType.changeToType() : 전달 받은 문자열과 같은 type 데이터를 가진 상수를 찾아 상수명을 반환

ResponseUpdateForm

package CloneCoding.NaverCafe.domain.menu.normal.integrate.dto;

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ResponseUpdateForm {

    private int sequence;

    private String name;

    private String description;

    private String writeAuth;

    private String readAuth;

    private String commentAuth;

    private boolean useFavorite;

}

 

  기존 Integrate 엔티티의 정보를 사용자에게 전달하는 용도의 DTO이다.


RequestUpdateIntegrate

package CloneCoding.NaverCafe.domain.menu.normal.integrate.dto;

@Getter
@NoArgsConstructor
@AllArgsConstructor
public class RequestUpdateIntegrate {

    @NotNull
    private int sequence;

    @NotNull
    private String name;

    @NotNull
    private String description;

    @NotNull
    private String writeAuth;

    @NotNull
    private String readAuth;

    @NotNull
    private String commentAuth;

    @NotNull
    private boolean useFavorite;

}

 

  일반 게시판 수정 요청시 전달되는 요청정보를 전달하는 목적으로 사용되는 DTO이다.


IntegrateController

package CloneCoding.NaverCafe.domain.menu.normal.integrate.controller;

@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/manageMenu")
public class IntegrateController {

    private final IntegrateService integrateService;

    @GetMapping("/update/{integrate_id}")
    public ResponseUpdateForm getUpdateForm(@PathVariable("integrate_id") Long id,
                                            @RequestHeader("Authorization") String token) {
        log.info("일반 게시판(통합게시판) 수정 양식 요청");
        return integrateService.createIntegrateUpdateForm(id, token);
    }

    @PutMapping("/update/{integrate_id}")
    public String updateIntegrate(@PathVariable("integrate_id") Long id,
                                  @RequestBody @Valid RequestUpdateIntegrate request,
                                  @RequestHeader("Authorization") String token) {

        log.info("일반 게시판(통합게시판) 수정 요청");
        return integrateService.updateIntegrate(request, id, token);
    }

}

 

  • getUpdateForm() : 게시판 id 정보와 token 정보로 intergrateService의 createIntegrateUpdateForm()를 호출하고 결과 값을 반환
  • updateIntegrate() : 게시판 id 정보, 요청정보, 토큰 정보로 integrateService의 updateIntegrate()를 호출하고 결과 메시지를 반환

IntegrateServiceImpl

package CloneCoding.NaverCafe.domain.menu.normal.integrate.service;

import static CloneCoding.NaverCafe.domain.cafeMember.enums.CafeMemberPosition.changeNameToPosition;
import static CloneCoding.NaverCafe.message.SystemMessage.SUCCESSFULLY_REFLECT;

@Service
@RequiredArgsConstructor
public class IntegrateServiceImpl implements IntegrateService {

    private final IntegrateRepository integrateRepository;
    private final MemberRepository memberRepository;
    private final CafeRepository cafeRepository;
    private final CafeMemberRepository cafeMemberRepository;
    private final AesUtil aesUtil;

    @Override
    public ResponseUpdateForm createIntegrateUpdateForm(Long id, String token) {

        Integrate integrate = integrateRepository.findById(id)
                .orElseThrow(() -> new NoSuchElementException("게시판 정보를 찾을 수 없습니다."));

        Cafe cafe = cafeRepository.findById(integrate.getCafeId().getId())
                .orElseThrow(() -> new NoSuchElementException("카페 정보를 찾을 수 없습니다."));
        checkCafeMember(cafe, token);

        return ResponseUpdateForm.builder()
                .sequence(integrate.getSequence())
                .name(integrate.getName())
                .description(integrate.getDescription())
                .writeAuth(changeNameToPosition(integrate.getWriteAuth()))
                .readAuth(changeNameToPosition(integrate.getReadAuth()))
                .commentAuth(changeNameToPosition(integrate.getCommentAuth()))
                .useFavorite(integrate.isUseFavorite())
                .build();
    }

    @Override
    public String updateIntegrate(RequestUpdateIntegrate request,
                                  Long id, String token) {

        Integrate integrate = integrateRepository.findById(id)
                .orElseThrow(() -> new NoSuchElementException("게시판 정보를 찾을 수 없습니다."));

        Cafe cafe = cafeRepository.findById(integrate.getCafeId().getId())
                .orElseThrow(() -> new NoSuchElementException("카페 정보를 찾을 수 없습니다."));
        checkCafeMember(cafe, token);

        integrate.updateIntegrate(request);

        integrateRepository.save(integrate);

        return SUCCESSFULLY_REFLECT.getMessage();

    }

    private void checkCafeMember(Cafe cafe, String token) {
        String accountId = aesUtil.aesDecode(token);
        cafeMemberRepository.findByAccountId(cafe, accountId);
    }

}

 

  • createIntegrateUpdateForm() : 일반 게시판의 현재 정보로 ResponseUpdateForm 객체를 생성후 반환
  • updateIntegrate() : 일반 게시판의 정보를 요청정보로 수정 후 엔티티를 저장, 결과 메시지를 반환
  • changeNameToPosition() : 문자열과 같은 이름을 가진 상수를 찾고 상수가 갖는 position 값을 반환

API TEST

DB - 일반 게시판 수정 전

 

  게시판 수정 전, 카페에 기본 게시판과 일반 게시판 하나가 추가된 상태이다. '첫 게시판'이라는 게시판을 수정할 것이다.

 

API TEST - 일반 게시판 수정양식 요청

 

  게시판 수정을 위해 기존 정보를 요청하였다. 성공적으로 기존 게시판 정보를 반환한 것을 확인할 수 있다.

 

API TEST - 일반 게시판 수정 요청

 

DB - 일반 게시판 수정 후

 

  게시판 수정 요청에 따른 결과이다. 일단 요청에 정상적으로 수정 정보가 반영되었다는 결과 메시지가 반환되었다. DB를 확인하면 기존에 name 필드에 '첫 게시판'이란 값을 가진 레코드가 요청정보로 수정된 것을 확인할 수 있다.