프로젝트 진행 중 발생한 어려움 및 고민거리

2024. 1. 12. 16:11
728x90

1. 초기 데이터 설정하기 (Board의 Category)

Board 테이블의 카테고리들은 변하지 않는 파트로 한 번 입력된 후 변경 가능성이 거의 없다. 

처음에는 전체 게시판 카테고리 불러오기 메서드 안에서 네가지 카테고리를 입력하고, 그것들을 불러오는 로직을 짰다. 

 

ex. 

// BoardService class

    // 전체 게시판 카테고리 불러오기
    // 게시판의 카테고리가 정해져있기 때문에 불러오면서 바로 카테고리를 저장하도록 했다.
    // todo: 고민점은 카테고리를 저장하는게 맞는지가 ? 고민... 확장성도 고려하고 싶은데..
	public List<Board> readBoardCategories() {
        Board board1 = Board.builder().category(BoardCategory.자유).build();
        Board board2 = Board.builder().category(BoardCategory.개발).build();
        Board board3 = Board.builder().category(BoardCategory.일상).build();
        Board board4 = Board.builder().category(BoardCategory.사건사고).build();
        boardRepository.save(board1);
        boardRepository.save(board2);
        boardRepository.save(board3);
        boardRepository.save(board4);
        return boardRepository.findAll();
    }
    
// BoardController class
    // 게시판 목록 전체 보기
    @GetMapping
    public String showBoardList(Model model) {
        model.addAttribute("boards", boardService.readBoardCategories());
        return "boardList";
    }

이렇게 짜면서도 이게 맞나 싶긴 했다. 

 

역시나 문제가 있었다. 

 

이후 테스트 도중 일단 /boards endpoint로 여러 번 새로고침하여 들어갈 때마다 계속해서 이 카테고리들이 insert되었다. 

ddl-auto를 update로 고쳐도 마찬가지였다. 왜냐? 당연... INSERT문은 ddl이 아니니까용 ~ 

 

일단 핵심은 

** 단 한 번!! 카테고리가 입력되도록 해야 한다.

** 이 입력 시점은 언제가 좋을까? 

 

나의 결론은 일단,

** 카테고리 입력 메서드를 따로 만들기. + 카테고리가 비어있을 때만 추가하는 조건 주기.

** 입력 시점은... BoardController가 생성되는 시점.. 그러므로 BoardController의 생성자에 메서드를 불러왔다.  

// BoardService class
    // 게시판의 카테고리가 정해져있기 때문에 카테고리를 저장하는 메서드가 필요.
    public void createCategories() {
        // board 카테고리가 비어있을 때에만 추가!
        if (boardRepository.findAll().isEmpty()) {
            Board board1 = Board.builder().category(BoardCategory.자유).build();
            Board board2 = Board.builder().category(BoardCategory.개발).build();
            Board board3 = Board.builder().category(BoardCategory.일상).build();
            Board board4 = Board.builder().category(BoardCategory.사건사고).build();
            boardRepository.save(board1);
            boardRepository.save(board2);
            boardRepository.save(board3);
            boardRepository.save(board4);
        }
    }
    
// BoardController class
    // BoardController가 생성될 때 카테고리가 저장되도록 한다.
    public BoardController(BoardService boardService) {
        this.boardService = boardService;
        boardService.createCategories();
    }

 

이렇게 짜서, 카테고리가 추가되지 않은 상태라면 board 카테고리가 비어있을 테니 isEmtpy() 메서드를 써서 비어있지 않을 때에만 추가할 수 있도록 조건을 주었다.

그리고, BoardController의 생성자에 createCategories() 메서드를 추가해주었다.

 

 

** 여기서 생각해볼 점은...........

만약 게시판에 카테고리가 새로 추가된다면..? 그땐 어떻게 하나요!!?

"확장성"을 생각한다면 굉장히 비효율적인 코드가 된다. 게시판 특성상 여러가지 카테고리가 새로 추가될 수도 있다는 점에서 이 로직을 바꿔야겠다는 생각이 들었다. 

 

ㅎㅎ 그래서 나는 다시 냅다.. 조건문을 다르게 달아서 주었는데

// BoardService class
	public void createCategories() {
        // board 카테고리가 비어있을 때에만 추가!
        if (!boardRepository.findAll().contains(BoardCategory.자유)) {
            Board board1 = new Board(BoardCategory.자유);
            boardRepository.save(board1);
        }
        if (!boardRepository.findAll().contains(BoardCategory.개발)) {
            Board board2 = new Board(BoardCategory.개발);
            boardRepository.save(board2);
        }
        if (!boardRepository.findAll().contains(BoardCategory.일상)) {
            Board board3 = new Board(BoardCategory.일상);
            boardRepository.save(board3);
        }
        if (!boardRepository.findAll().contains(BoardCategory.사건사고)) {
            Board board4 = new Board(BoardCategory.사건사고);
            boardRepository.save(board4);
        }
    }

 

서버 실행하면 1회 생성, 그리고 새로고침을 하면 생성되지 않음.

그러나, 서버 재실행하면 다시 1회 생성되어 또다시 카테고리가 늘어나는 상황이 되었다..... ㅠㅠ

 

이게 Controller 생성 시점에 boardService >> boardRepository.findAll()로 가져오고 카테고리가 있는지 확인한 후 카테고리를 추가하고 있는 과정인데, 애플리케이션 재실행마다 새로운 세션에서 보드를 가져오기 때문에, 이전에 저장된 보드들이 무시되고 항상 새로운 보드가 추가된다는 문제점이 있었다. 

 

다시 어떻게 해결할까 고민하다 초기데이터 설정 방법을 찾아보았다..

 

애플리케이션 실행 시 DDL, DML 스크립트를 실행할 수 있는 방법이 있었다.

스프링 애플리케이션 실행시

resources 경로에 있는 schema.sql(DDL), data.sql(DML) 스크립트를 실행하므로 이를 활용하였다. 

DDL은 필요없었고, DML만 조정해주었다.

// data.sql

INSERT OR IGNORE INTO board (category) VALUES ('자유');
INSERT OR IGNORE INTO board (category) VALUES ('개발');
INSERT OR IGNORE INTO board (category) VALUES ('일상');
INSERT OR IGNORE INTO board (category) VALUES ('사건사고');

 

요렇게 설정하여 애플리케이션 실행 시 자동으로 insert가 되고, 이미 있다면? ignore 하라는 DML을 실행하게 되었다.

그랬더니 아무리 새로고침을 해도, 서버 재실행을 해도 ~ 그대로 남아있는 카테고리를 볼 수 있었다.

또한, 새로운 카테고리를 추가한다면? 그땐 data.sql만 바꾸면 된다~

 

 

2. redirect 시 url에 파라미터값 넘겨주기

 

endpoint를 위해서는 redirect:/를 하고, 그 url에 파라미터를 넘겨주어야 했다.

그런데 어떻게 해야 넘겨줄 수 있을지 몰라 헤맸다. 

검색 결과

RedirectAttributes로 redirect에서도 파라미터 값을 넘길 수 있다고 한다. 

 

.addAttribute(Object attributeValue)

.addAttribute(String attributeName, Object attributeValue)

 

>> 이렇게 하여 articleId를 잘 넘겨주었다! 

 

++ 추가로 addAttribute는 String/Integer와 같은 값을 넘길 때 사용이 되고, 

복잡한 객체를 노출 없이 넘겨주거나, 일회성 성공 알림 등을 만들고 싶을 때에는 FlashAttribute를 쓸 수 있다.

.addFlashAttribute(Object attributeValue)

.addFlashAttribute(String attributeName, Object attributeValue)

이름처럼 일회성으로 사용 가능하다. 새로고침을 하면 휘발된다. 

 

++ 추가로 

- Model 객체를 Redirect 방식으로 넘겨주려고 하면 원래 요청은 끊어지고 새로운 HTTP 요청이 시작되어.. 리다이렉트로 모델을 전달하는 것은 불가능하다. 

- RedirectAttributes의 FlashAttribute는 리다이렉트가 발생하기 전에 모든 플래시 속성을 세션에 복사한다. 그래서 리다이렉션 이후에 저장된 플래시 속성을 모델로 이동시킬 수 있다. 

 

 

3. 비밀번호 확인 절차는 언제 어디에서??? 

게시글 수정시 비밀번호 확인 절차가 서비스단에서, 컨트롤러 단에서 이루어져야 할지?와

비밀번호 불일치시에는 어떤 처리를 해야할지 고민...

현재는 그냥 프론트 html에서 확인하여 form 제출하는 절차를 자바스크립트로 구현했다..

 

 

4. 게시글 삭제시 댓글의 행방은!?

게시글 삭제시 댓글은 어떻게 해야하는지에 대한 고민...

게시글만 삭제하니 다시 새로운 id의 글이 올라왔을 때에 다른 글이지만 boardId가 같으므로 새로운 게시물의 댓글로 표시가 된다.

 

일단 댓글이 모두 삭제되는 것이 맞는지? 

근데 일단은 삭제하게 만들어두었다.

엔티티 맵핑시에 Cascade옵션을 주었다.

@Entity
@Getter
@NoArgsConstructor
public class Article {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Setter
    private String title;
    @Lob
    @Setter
    private String content;

    @CreationTimestamp
//    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm")
//    @JsonFormat(shape= JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm", timezone="Asia/Seoul") //날짜 포멧 바꾸기
    private Timestamp createDate;

    private String password;

    @ManyToOne
    @Setter
    private Board board;

    @OneToMany(mappedBy = "article", cascade = CascadeType.ALL)
    private final List<Comment> commentList = new ArrayList<>();

    public Article(String title, String content, String password, Board board) {
        this.title = title;
        this.content = content;
        this.password = password;
        this.board = board;
    }

}

 

5. DTO는 과연 어떻게 써야하는지요!?

DTO를 쓸 때 하나의 DTO를 만들고, 계속 재사용하는지, 아니면 일회용으로 담는 그릇으로 쓰고 다시 새로운 DTO를 만들어야할지에 대한 의문이 들었다...

 

 

지금은 아주 간단한 프로젝트이지만 진행 중 많은 의문과 고민이 들었다.

아무리 해도 배울거 투성이... 점점 깊어지는 고민들....ㅎㅎ

뭔가 하나씩 찾아보면서 배워가고 있지만 지금 배우는 것들이 빙산의 일각이라는 느낌을 강하게 받아서

마음이 불안하고 어렵지만 그래도 하나씩 조금씩만 익히다보면 끝..은 아니고 ㅎㅎ 발전 하겠지!!!! 

 

 

728x90

'Project > anonymous board project' 카테고리의 다른 글

Entity와 Dto  (1) 2024.01.09
모델 설정 여부에 따른 th:if 조건문 설정  (0) 2024.01.08
익명 게시판 프로젝트  (0) 2024.01.08

BELATED ARTICLES

more