CodeIgniter 4로 블로그 만들기 #02 — 정적 페이지와 기본 라우팅
지난 회차에서는 프로젝트를 만들고 개발 환경으로 전환해 디버그 툴바까지 확인했습니다. 하지만 우리가 직접 만든 페이지는 아직 하나도 없습니다. 브라우저에 보이는 건 CI4가 기본으로 넣어 준 환영 페이지뿐이죠.
이번 회차의 목표는 아주 단순합니다. "소개(about)" 정적 페이지 하나를 우리 손으로 그리는 것입니다. 다만 그 과정에서 CI4의 가장 기본이자 가장 중요한 흐름을 짚고 갑니다. 바로 주소(라우트) → 컨트롤러 → 뷰로 이어지는 요청 처리의 뼈대입니다. 앞으로 만들 모든 기능(글 목록, 상세, 작성, 댓글…)이 예외 없이 이 흐름 위에 올라갑니다.
이번 회차 목표
- CI4에서 URL 하나가 어떻게 화면까지 도달하는지 흐름 이해하기
Routes.php에 주소 등록하기- 그 주소를 받아 줄 컨트롤러 메서드 만들기
- 컨트롤러가 그려 줄 뷰(HTML) 만들기
레이아웃(공통 골격)이나 디자인은 일부러 여기서 다루지 않습니다. 이번엔 흐름 자체에 집중하기 위해 뷰 하나에 HTML을 통째로 넣습니다. 공통 레이아웃으로 걷어내는 작업은 바로 다음 회차(ep03)에서 합니다.
1. CI4의 요청 흐름 이해하기
브라우저가 http://localhost:8080/about을 요청하면 CI4 안에서는 이런 일이 순서대로 일어납니다.
브라우저 요청 (/about)
↓
Routes.php ← "about 주소는 누가 처리하지?" 를 찾는 곳
↓
Pages 컨트롤러의 about() 메서드 ← 실제 처리 담당
↓
pages/about 뷰 ← 사용자에게 보여줄 HTML
↓
브라우저에 응답
핵심은 세 조각이 각자 역할을 나눠 갖는다는 점입니다. 라우트는 "어떤 주소를 누구에게 넘길지"만 정하고, 컨트롤러는 "무엇을 할지"를 담고, 뷰는 "어떻게 보일지"를 담습니다. 이 분리가 MVC의 출발점입니다.
2. 라우트 등록하기
먼저 about이라는 주소가 들어오면 Pages 컨트롤러의 about()을 부르도록 등록합니다. app/Config/Routes.php를 열면 ep01에서 이미 홈 라우트 한 줄이 있습니다. 그 아래에 한 줄을 더합니다.
/** @var RouteCollection $routes */
$routes->get('/', 'Home::index');
$routes->get('about', 'Pages::about'); // ← 이 줄을 추가
읽는 그대로입니다. "about 주소로 들어오는 GET 요청은 Pages 컨트롤러의 about() 메서드가 처리하라" 는 뜻입니다.
get— HTTP GET 요청에만 반응합니다. 나중에 폼 저장 같은 곳에서는post를 씁니다.- 첫 번째 인자
'about'— URL 경로. 앞에 슬래시를 붙이지 않아도 됩니다. - 두 번째 인자
'Pages::about'—컨트롤러::메서드형식.
CI4는 이렇게 라우트를 명시적으로 등록하는 방식을 권장합니다. "URL과 컨트롤러 이름이 우연히 같으면 알아서 연결"되는 자동 라우팅에 기대지 않고, 어떤 주소가 살아 있는지 이 파일 한 곳에서 눈으로 확인할 수 있게 하는 편이 안전하기 때문입니다.
3. 컨트롤러 만들기
이제 그 요청을 받아 줄 컨트롤러가 필요합니다. app/Controllers/Pages.php 파일을 새로 만듭니다.
<?php
namespace App\Controllers;
class Pages extends BaseController
{
public function about(): string
{
return view('pages/about');
}
}
몇 가지만 짚어 봅니다.
namespace App\Controllers;— CI4는app/Controllers/폴더의 클래스를 이 네임스페이스로 인식합니다. 파일 위치와 네임스페이스가 맞아야 클래스를 찾아 줍니다.extends BaseController— 모든 컨트롤러는 프로젝트 공통 부모인BaseController를 상속합니다. 공통 헬퍼 로딩 같은 설정이 이 부모에 모입니다(뒤 회차에서 활용).about()메서드가return view('pages/about')—view()헬퍼는 지정한 뷰 파일을 렌더링한 문자열(HTML) 을 돌려줍니다. 컨트롤러 메서드가 문자열을 반환하면 CI4는 그걸 그대로 응답 본문으로 내보냅니다. 그래서 반환 타입을: string으로 명시했습니다.
여기서 'pages/about'은 app/Views/pages/about.php를 가리킵니다. 확장자 .php와 Views/는 생략합니다.
4. 뷰 만들기
마지막으로 실제로 보일 HTML입니다. app/Views/pages/about.php를 만듭니다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>소개 · CI4 Blog</title>
</head>
<body>
<h1>소개</h1>
<p>CodeIgniter 4로 한 회차씩 만들어 가는 학습용 블로그입니다.</p>
<p>이 페이지는 라우트 → 컨트롤러 → 뷰 흐름을 확인하기 위한 정적 페이지입니다.</p>
</body>
</html>
보다시피 <!DOCTYPE html>부터 </html>까지 문서 전체가 이 한 파일에 들어 있습니다. 지금은 이대로 두는 게 맞습니다. 이번 회차의 주인공은 "흐름"이지 "구조"가 아니니까요.
다만 눈치채셨겠지만, 이런 식이면 페이지를 하나 더 만들 때마다 <head>, <body> 같은 뼈대를 통째로 복사해야 합니다. 이 중복을 걷어내는 것이 정확히 다음 회차(ep03)에서 할 일입니다. 지금은 일부러 "나쁜 상태"를 만들어 두고, 다음에 개선하는 과정을 눈으로 보여 주려는 것입니다.
5. 브라우저에서 확인
개발 서버가 떠 있다면(php spark serve) 브라우저에서 열어 봅니다.
http://localhost:8080/about
"소개" 제목과 두 문단이 보이면 성공입니다. 방금 우리가 만든 라우트 → 컨트롤러 → 뷰가 처음으로 끝까지 이어진 순간입니다.
혹시 404가 뜬다면 대개 다음 중 하나입니다.
Routes.php에 줄을 추가하고 저장하지 않았다.- 컨트롤러 파일명/클래스명이
Pages가 아니다(대소문자 포함해서 정확히 맞아야 합니다). - 뷰 파일 경로가
app/Views/pages/about.php가 아니다.
핵심 개념 — 왜 이렇게 나눌까
한 페이지를 세 파일로 쪼갠 게 번거로워 보일 수 있습니다. 하지만 이 분리는 프로젝트가 커질수록 위력을 발휘합니다.
- 주소 관리가 한 곳에 — 어떤 URL이 살아 있는지
Routes.php만 보면 됩니다. - 처리 로직과 표현의 분리 — 나중에 about 페이지에 "방문 수를 세는" 같은 로직이 붙어도, 그건 컨트롤러에만 들어갑니다. HTML(뷰)은 건드릴 필요가 없습니다. 반대로 디자인을 바꿀 땐 뷰만 손댑니다.
- 재사용 — 하나의 컨트롤러 메서드가 여러 뷰를 조합하거나, 여러 라우트가 한 컨트롤러를 공유할 수 있습니다.
지금은 뷰가 정적이라 컨트롤러가 하는 일이 "뷰를 그려서 반환"뿐이지만, 이 골격은 바뀌지 않습니다. 앞으로 컨트롤러가 데이터베이스에서 글을 꺼내 뷰에 넘기는 식으로 살을 붙여 갈 겁니다.
덧붙임 — 정적 페이지에도 자기 설명이 필요하다
Pages::about()은 뷰 이름만 넘기면 끝나는 가장 단순한 컨트롤러입니다. 그런데 이 단순함이 나중에 한 가지 문제를 만듭니다.
메타 설명(<meta name="description">)을 페이지가 따로 주지 않으면 사이트 기본 문구가 그대로 나갑니다. 정적 페이지가 하나일 때는 눈에 띄지 않지만, 목록·카테고리·소개 페이지가 나란히 생기고 나면 서로 다른 페이지들이 전부 같은 설명을 달고 있게 됩니다.
검색엔진에게 이것은 "이 페이지들은 서로 구별할 필요가 없다"는 신호에 가깝습니다. 실제로 이 블로그도 그 상태였고, 그 페이지들이 크롤은 됐지만 색인되지 않았습니다.
고치는 방법은 컨트롤러가 자기 설명을 함께 넘기는 것뿐입니다.
public function about(): string
{
return view('pages/about', [
'meta' => [
'title' => '소개',
'description' => '이 블로그가 무엇을 기록하는 곳인지 정리한 소개 페이지입니다.',
],
]);
}
한 줄 더 쓰는 일이지만, 페이지를 새로 만들 때마다 "이 페이지를 한 문장으로 설명하면 무엇인가"를 스스로 묻게 됩니다. 그 문장이 안 떠오른다면 그 페이지가 정말 따로 있어야 하는지부터 다시 볼 일이고요.
마무리 — 커밋과 태그
이번 회차에서 한 일을 정리하면:
Routes.php에about라우트 등록Pages컨트롤러와about()메서드 작성pages/about정적 뷰 작성- 브라우저에서 라우트 → 컨트롤러 → 뷰 흐름 확인
한 회차의 작업을 한 번에 커밋하고 태그를 답니다.
git add .
git commit -m "feat: 정적 페이지와 기본 라우팅"
git tag ep02
다음 회차
다음 글(#03)에서는 공통 레이아웃과 블로그 골격을 만듭니다. 이번에 뷰마다 통째로 들어간 <head>·<body> 같은 뼈대를 extend() / section() / renderSection()으로 걷어내고, 헤더·푸터 같은 공통 조각을 분리합니다. 여기에 순수 CSS 한 장으로 블로그의 첫 디자인까지 입힙니다.
이번 회차 요약
- 다루는 파일:
app/Config/Routes.php(수정) /app/Controllers/Pages.php(추가) /app/Views/pages/about.php(추가)- 핵심: CI4의 기본 요청 흐름은 라우트 → 컨트롤러 → 뷰. 라우트는
$routes->get('about', 'Pages::about')처럼 명시적으로 등록하고, 컨트롤러가 문자열(view 결과)을 반환하면 그대로 응답이 된다.- 다음: 공통 레이아웃과 첫 디자인(ep03)
댓글 0
아직 댓글이 없습니다.