[TIL/크래프톤 정글9기] 3일차(feat. Offset)

blueprint·2025년 5월 16일

크래프톤정글9기

목록 보기
4/55

어제 데이터와 학습페이지 문제 데이터를 넣고, 오늘은 하루종일 프로젝트할 시간이 있어 추가할 기능들을 생각해 봤다.

  • 내 답변 수정
  • 좋아요 누르기
  • 다른 사람 답변 보기
  • 타이머 기능을 JS로 조작해 제출 방지
  • 내 학습 시 문제 목록 페이징 처리
  • 문제 검색 기능을 넣기
  • 답변 삭제
  • 시간 괜찮으면 OpenSSL 인증서 적용으로 HTTPS 통신

페이지네이션을 사용하는 이유

많은 양의 데이터를 사용자와 서버 모두에게 효율적으로 보여주기 위함
1. 성능 향상

  • 한 번에 모든 데이터를 불러오면 데이터가 적으면 서버 부하가 적지만 버여줄 데이터가 많아지만 서버 부하가 커짐
  1. 사용자 경험 향상
    • 정보를 나눠 보여주면 사용자가 보기 편함
    • 스크롤, 페이지 버튼 등으로 사용자에게 탐색 제어권 제공
  2. 네트워크 최적화
    • 필요한 만큼의 데이를 주고받으므로 트랙픽 절감
    • 모바일 환경에서 데이터 사용량을 절감 가능
  3. DB 처리 최적화
    • LIMIT, OFFSET 등을 통해 부분 데이터만 쿼리

페이지네이션에도 여러 종류가 있었지만 적은 인원과 시간을 고려하여 Offset 방식으로 페이지 처리를 하기로 했다.

페이지네이션

  • Offset

Offset 장점

  1. 페이지에서 4페이지 등으로 한번에 이동 가능
  2. 데이터 순서와 무관
  3. 기능 구현 간단

Offset 단점

  1. 데이터 양이 많아지면 느려지고, 중간 데이터가 삽입/삭제시 정확하지 않을 수 있음
# 페이지 번호 (기본값 1)
page = int(request.args.get('page', 1))
per_page = 10  # 페이지당 항목 수

# 전체 페이지 수 계산
total_items = len(combined_data)
total_pages = (total_items + per_page - 1) // per_page

# 페이지 범위 확인 및 조정
if page < 1:
    page = 1
elif page > total_pages and total_pages > 0:
    page = total_pages

# 페이지네이션을 위한 페이지 범위 계산
start_page = max(1, page - 1)
end_page = min(total_pages, page + 1)

# 현재 페이지의 데이터만 슬라이싱
start_idx = (page - 1) * per_page
end_idx = start_idx + per_page

# All 카테고리일 때는 페이징하지 않음
if active_cate == 'All':
    paginated_data = combined_data
else:
    paginated_data = combined_data[start_idx:end_idx]
  • per_page = 10: 한 페이지당 10개
  • total_pages 계산: 전체 항목 수를 페이지당 항목 수로 나누어 전체 페이지 수를 계산
  • start_idx와 end_idx: 현재 페이지에 해당하는 데이터의 시작과 끝 인덱스를 계산
  • 'All' 카테고리일 때는 페이징 X
{% if show_pagination and total_pages > 1 %}
    <nav class="pagination is-centered mt-5" role="navigation" aria-label="pagination">
        <ul class="pagination-list">
            {% if current_page > 2 %}
                <li>
                    <a href="{{ url_for('myStudy', cate=active_cate, page=1, q=query) }}"
                       class="pagination-link">1</a>
                </li>
                {% if current_page > 3 %}
                    <li><span class="pagination-ellipsis">&hellip;</span></li>
                {% endif %}
            {% endif %}

            {% for p in range(start_page, end_page + 1) %}
                <li>
                    <a href="{{ url_for('myStudy', cate=active_cate, page=p, q=query) }}"
                       class="pagination-link {{ 'is-current' if p == current_page }}">
                        {{ p }}
                    </a>
                </li>
            {% endfor %}

            {% if current_page < total_pages-2 %}
                <li><span class="pagination-ellipsis">&hellip;</span></li>
            {% endif %}
            <li>
                <a href="{{ url_for('myStudy', cate=active_cate, page=total_pages, q=query) }}"
                   class="pagination-link">
                    {{ total_pages }}
                </a>
            </li>
        </ul>
    </nav>
{% endif %}
  • 백엔드에서 받은 페이지 값들을 jinja2를 이용하여 프론트로 전달

결과 화면

# 검색어 가져오기
query = request.args.get('q', '').strip()

# 검색 필터링
if query:
    combined_data = [
        data for data in combined_data
        if query.lower() in data['question']['question'].lower()
    ]
<form method="get" action="{{ url_for('myStudy') }}" class="mb-4">
    <div class="field has-addons">
        <div class="control is-expanded">
            <input class="input" type="text" name="q" placeholder="문제 검색..."
                   value="{{ request.args.get('q', '') }}">
        </div>
        <div class="control">
            <button class="button is-info" type="submit">
                검색
            </button>
        </div>
    </div>
</form>
  1. 검색어 입력:
  • 사용자가 검색 폼에 검색어를 입력
  • name="q"로 지정된 input 필드에 검색어가 입력
  1. 검색어 전송:
  • 폼이 GET 방식으로 제출
  • URL에 ?q=검색어 형태로 검색어가 전달
  1. 백엔드에서 검색 처리:
  • request.args.get('q', '')로 URL에서 검색어를 가져옴
  • strip()으로 앞뒤 공백을 제거
  • 검색어가 있는 경우에만 필터링을 수행
  1. 검색 필터링:
  • 모든 문제를 순회
  • query.lower()와 data['question']['question'].lower()를 비교
  • 대소문자 구분 없이 검색하기 위해 lower()를 사용
  • 검색어가 문제 내용에 포함되어 있는지 확인
  1. 검색 결과 유지:
  • 페이지네이션 링크에 검색어 파라미터를 포함시켜 검색 상태를 유지
   <a href="{{ url_for('myStudy', cate=active_cate, page=p, q=query) }}"

OpenSSL 인증서 발급 받기

HTTP와 HTTPS의 주요 차이점을 설명해드리겠습니다:

  1. 기본 개념:
  • HTTP (HyperText Transfer Protocol)

  • 웹에서 데이터를 주고받는 기본 프로토콜

  • 평문(plain text)으로 데이터 전송

  • 포트 80 사용

  • HTTPS (HyperText Transfer Protocol Secure)

  • HTTP에 SSL/TLS 암호화가 추가된 보안 프로토콜

  • 암호화된 데이터 전송

  • 포트 443 사용

HTTPS 통신을 위해 OpenSSL을 통해 인증서를 발급 받았다.

Openssl 인증서 발급

openssl req -x509 -newkey rsa:4096 -nodes -out cert.pem -keyout key.pem -days 365
chmod 777 cert.pem
Chmod 777 key.pem


0개의 댓글