3 분 소요

뉴스 API 호출 과정

뉴스 내용을 사용자들에게 뿌려주기 위해 크롤링 해온 뉴스 데이터들을 관리자 페이지에서 다루는 내용부터, 각 페이지에 수정된 뉴스 객체들이 출력되는 과정까지 기술하고자 한다.

⚠️ Trouble Shooting

문제 상황 : 관리자 페이지에서 갓 크롤링 해온 뉴스 객체 수정 메뉴, 배너 뉴스 선택 메뉴, 사용자 이용 통계 메뉴를 다루고자 했고, 각 페이지를 nested routing을 통해 접근하고자 했다. Link 컴포넌트를 통해서는 잘 이동했지만, 경로를 입력하면 로그아웃되는 현상이 발생했다. 시작부터 난관에 부딪혀 문제를 찾아나서게 되었다.

해결

Link 컴포넌트를 거치지 않고 주소 창에 직접 경로를 입력하면 새로고침이 일어나게 되는데, 이때 페이지의 상태가 다 업데이트 되기 전에 렌더링이 먼저 되어버리는 문제가 발생했다. 관리자 페이지의 경우 먼저 로그인 상태인지, 관리자인지 확인하는 과정을 거친 후 isLoggedIn, isAdmin을 true로 바꿔주는데 이 상태를 체크하기 전 렌더링이 되면서 로그인이 되어 있지 않다고 판단되는 문제가 발생했다. 그래서 로그인 페이지로 이동을 하는데, 뒤늦게 업데이트 되어 로그인 페이지에서는 로그인이 되어 있다고 판단을 하니 기본 페이지로 리디렉트 되는 것이었다. 하필 기본 페이지로 새로고침이 되니 문제를 찾는 데 더 오래 걸린 것 같다.

📖 뉴스 데이터 및 이미지 크롤링하기

크롤링하기까지의 과정은 블로그에 따로 정리해두었다.

  1. 웹크롤링을 위한 기본 개념 정리

    https://giwon512.github.io/python/WebCrawling/

  2. 자바스크립트 환경에서 크롤링 파이썬 코드 실행하기

    https://giwon512.github.io/python/NodePython/

  3. 크롤링한 이미지 파일 base64형식으로 db에 저장하기

    https://giwon512.github.io/python/ImageCrawling/

구현해야 할 과정

1. [node connectPython.js] 명령어를 통해 scraping.py 실행
- test_news에 뉴스 insert
- 직전에 새로 삽입된 뉴스 ID 값 select
- test_image에 base64로 인코딩된 jpg 파일 내용 + 해당하는 뉴스 ID 값 삽입
2. api 실행을 통해 db에서 뉴스 객체와 객체의 newsID에 해당하는 이미지 객체 가져오기
3. edit 버튼을 누르면 quill 에디터 img text box 안에 이미지 값 삽입
4. 카테코리 지정 후 저장 시 뉴스 페이지에 대표이미지 보이기

📖 뉴스 데이터 수정 및 게시하기

여기서 필요한 기능은 다음과 같다.

  1. 크롤링해온 뉴스 목록 출력
  2. 수정 버튼을 누르면 웹에디터에 내용 출력
  3. 웹에디터에 수정하고 카테고리 지정해주기
  4. 완료 시 카테고리에 맞게 수정된 내용 그대로 게시

단순한 Read, Update, Delete를 하기 때문에 백엔드 로직은 굳이 설명하지 않는다.

📚 GET /raw-news?pageNum={}&pageSize={}

/raw-news?pageNum=3&pageSize=10을 하게 되면 한 페이지에 출력되는 뉴스의 개수가 10개인데, 3페이지의 뉴스 데이터들을 가져오겠다는 의미이다.

📄 allNewsList

fetchAllNews() 함수로 값이 정해지는 상태 값으로, 최신 1000개의 뉴스 데이터를 가지고 있다.

📄 searchTerm

검색 창에 적힌 내용이 기록되는 상태 값이다.

📄 filteredNewsList

handleSearch() 함수를 통해 allNewsList에 있는 뉴스 데이터들 중 타이틀이나 카테고리의 내용에 searchTerm 상태 값이 포함되는 뉴스 객체들을 저장하고 있는 상태 값이다. 페이징 처리가 되어있어 한 번에 10개까지의 뉴스 데이터들이 들어가있다.

📚 DELETE /raw-news/{newsId}

단순히 newsId에 해당하는 뉴스 데이터를 db에서 제거하는 요청을 수행한다.

📚 PUT /raw-news/{selectedNews.newsId}

  1. edit 버튼을 누르면 selectedNews state의 값이 변경되고, content state에 해당 뉴스의 본문 내용이 저장된다. 그 후, ReactQuill 에디터 컴포넌트가 밑에 렌더링이 되고, content 값이 에디터에 출력이 된다.
  2. handleCategoryChange() 함수를 통해 카테고리를 지정해줄 수 있고, 이를 통해 추후에 카테고리 뉴스를 출력할 수 있게 된다.
  3. 그 후 save 버튼을 누르면 handleSaveNews() 함수가 호출이 되는데, 여기서 ql-editor 클래스는 정확히 본문 내용이 담긴 에디터에 해당하는 div 태그를 가리키고 있다.
  4. put 방식으로 api를 호출해서 바뀐 컨텐츠의 내용을 가지고 업데이트 쿼리를 실행한 후에, allNewsList를 초기화해서 최신 반영된 내용을 다시 저장해두게 된다.

📖 메인 페이지에 카테고리 별로 뉴스 3개씩 게시하기

📚 GET /top3?category=${category}

말 그대로 특정 카테고리에서 가장 최신 뉴스 3개를 가져오는 역할을 수행한다.

📚 GET /top3/${newsId}

해당 뉴스의 대표 이미지 값을 가져온다. 이때 가져오는 값은, base64로 인코딩된 값이다.

useEffect(() => {
    const getImages = async () => {
        let imgContent = []
        for (const news of newsList) {
            await api.get(`/top3/${news.newsId}`)
            .then(response => imgContent.push(response.data))
            .catch(error => console.error('Error fetching news images', error));
        }
        setImgList(imgContent);
        setIsLoading(false);
    }

    getImages();
}, [newsList]);

if(isLoading) {
    return <h2>Loading...</h2>
}

useEffect() 함수를 통해 메인 페이지를 실행하면 newsListimgList에 값을 저장하고, 렌더링해주는 작업을 수행한다.

📄 newsList

props로 넘어온 category값에 해당하는 카테고리의 최신 뉴스 3개가 저장되어 있다.

📄 imgList

newsList를 순회하며, 순서대로 이미지 데이터를 가져와 저장한다.

📖 최근 게시글 표시하기

홈페이지 하단에는 최신 순으로 9개의 뉴스가 표시된다.

📚 GET /processed-news?pageNum=1&pageSize=9

가공된 뉴스를 최신 순으로 가져오는 api인데 첫 9개만 가져오도록 파라미터 값을 설정해주었다. GET /top3?category=${category} api와는 다르게 백엔드에서 이미지까지 한 번에 가져오도록 처리를 하였다.

public Map<String, Object> getAllProcessedNews(int pageNum, int pageSize) {
    int offset = (pageNum - 1) * pageSize;
    List<ProcessedNews> processedNewsList = newsMapper.findProcessedNewsByPagination(offset, pageSize);
    long total = newsMapper.countProcessedNewsAll();
    Map<Long, String> imgContent = new HashMap<>(); 
    for(ProcessedNews news : processedNewsList) {
    	String img = newsMapper.getImageByNewsId(news.getNewsId());
    	imgContent.put(news.getNewsId(), img);
    }

    Map<String, Object> response = new HashMap<>();
    response.put("content", processedNewsList);
    response.put("currentPage", pageNum);
    response.put("totalItems", total);
    response.put("totalPages", (int) Math.ceil((double) total / pageSize));
    response.put("imgContent", imgContent);
    return response;
}

hashMap에 뉴스 아이디를 키로 갖는 base64Url 이미지를 넣어 값을 리턴한다. 저 형식으로 넣게 되면 프론트엔드에서 이미지 값은 다음과 같이 넣을 수 있다.

<img src={"data:image/jpg;base64,"+ imgList[article.newsId]} alt={article.title} className="article-image" />

나머지 뉴스 출력을 위한 api들도 다 비슷하게 동작하기 때문에, 다른 api는 더 이상 다루지 않는다.

댓글남기기