[SECTION 03. JSP에서 Java 코드를 사용하자 — 스크립틀릿]
<%
String title = "스프링 입문";
int price = 50000;
boolean isSale = true;
%>
<h2><%= title %></h2>
<p>가격: <%= price %>원</p>
<p>할인 중: <%= isSale %></p>
<% %> 블록은 여러 개로 쪼개도 됩니다. HTML을 사이에 끼워 넣을 수 있어요.
<%
int score = 78;
%>
<% if (score >= 90) { %>
<p style="color: blue;">A등급 — 우수합니다!</p>
<% } else if (score >= 70) { %>
<p style="color: green;">B등급 — 양호합니다.</p>
<% } else { %>
<p style="color: red;">C등급 — 분발하세요.</p>
<% } %>
핵심 원리:
<% if (score >= 90) { %>와<% } %>사이의 HTML은 조건이 참일 때만 출력됩니다.{와}는 짝을 맞춰야 합니다!
<%
String[] fruits = {"사과", "바나나", "포도", "오렌지"};
%>
<ul>
<% for (String fruit : fruits) { %>
<li><%= fruit %></li>
<% } %>
</ul>
출력 결과:
<ul>
<li>사과</li>
<li>바나나</li>
<li>포도</li>
<li>오렌지</li>
</ul>
인덱스를 활용하거나 조건에 따라 다른 스타일 적용하기:
<%
String[] names = {"홍길동", "김철수", "이영희", "박민준", "최수진"};
%>
<table border="1">
<tr><th>번호</th><th>이름</th><th>비고</th></tr>
<% for (int i = 0; i < names.length; i++) { %>
<tr style="background-color: <%= (i % 2 == 0) ? "#ffffff" : "#f2f2f2" %>">
<td><%= i + 1 %></td>
<td><%= names[i] %></td>
<td>
<% if (i == 0) { %>
1등
<% } else { %>
-
<% } %>
</td>
</tr>
<% } %>
</table>
서블릿이 request.setAttribute()로 저장한 데이터를 JSP에서 꺼낼 때:
<%
// Object로 반환되므로 반드시 형변환(캐스팅) 필요
String username = (String) request.getAttribute("username");
Integer age = (Integer) request.getAttribute("age"); // int가 아닌 Integer!
List<String> hobbies = (List<String>) request.getAttribute("hobbies");
%>
<p>이름: <%= username %></p>
<p>나이: <%= age %>세</p>
<ul>
<% for (String hobby : hobbies) { %>
<li><%= hobby %></li>
<% } %>
</ul>
자주 하는 실수
<% int age = (int) request.getAttribute("age"); // ❌ Cannot cast Object to int Integer age = (Integer) request.getAttribute("age"); // ✅ 올바른 방법 %>
getAttribute()는 값이 없으면 null을 반환합니다. null 처리를 잊으면 화면이 깨집니다.
<%
String errorMsg = (String) request.getAttribute("error");
%>
<%-- null 체크 후 출력 --%>
<% if (errorMsg != null) { %>
<p style="color: red;">❌ <%= errorMsg %></p>
<% } %>
<%-- 삼항 연산자로 간결하게 --%>
<p><%= (username != null) ? username : "비회원" %></p>
[SECTION 04. 모든 요청을 한 곳으로 — 프론트 컨트롤러 패턴]
src/main/
├── java/com/example/
│ ├── front/
│ │ └── FrontController.java ← 핵심! 모든 요청의 입구
│ └── model/
│ └── Member.java
└── webapp/
└── WEB-INF/
└── views/
└── member/
├── list.jsp
└── form.jsp
package com.example.front;
import com.example.model.Member;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@WebServlet("/member/*")
public class FrontController extends HttpServlet {
private List<Member> memberStore = new ArrayList<>();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
process(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
process(req, resp);
}
private void process(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html");
resp.setCharacterEncoding("UTF-8");
String requestURI = req.getRequestURI();
System.out.println("[FrontController] 요청 URI: " + requestURI);
if (requestURI.equals("/member/list")) {
memberList(req, resp);
} else if (requestURI.equals("/member/new") && req.getMethod().equals("GET")) {
memberForm(req, resp);
} else if (requestURI.equals("/member/new") && req.getMethod().equals("POST")) {
memberSave(req, resp);
} else {
resp.sendError(HttpServletResponse.SC_NOT_FOUND);
}
}
private void memberList(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
req.setAttribute("members", memberStore);
forward(req, resp, "/WEB-INF/views/member/list.jsp");
}
private void memberForm(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
forward(req, resp, "/WEB-INF/views/member/form.jsp");
}
private void memberSave(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String name = req.getParameter("name");
String email = req.getParameter("email");
if (name == null || name.trim().isEmpty()) {
req.setAttribute("error", "이름을 입력해주세요.");
forward(req, resp, "/WEB-INF/views/member/form.jsp");
return;
}
memberStore.add(new Member(name, email, ""));
resp.sendRedirect("/member/list");
}
private void forward(HttpServletRequest req, HttpServletResponse resp, String path)
throws ServletException, IOException {
RequestDispatcher dispatcher = req.getRequestDispatcher(path);
dispatcher.forward(req, resp);
}
}
package com.example.model;
public class Member {
private String name;
private String email;
private String password;
public Member(String name, String email, String password) {
this.name = name;
this.email = email;
this.password = password;
}
public String getName() { return name; }
public String getEmail() { return email; }
public String getPassword() { return password; }
}
src/main/webapp/WEB-INF/views/member/list.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ page import="java.util.List" %>
<%@ page import="com.example.model.Member" %>
<%
List<Member> members = (List<Member>) request.getAttribute("members");
%>
<%= members %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ page import="java.util.List" %>
<%@ page import="com.example.model.Member" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원 목록</title>
<style>
body { font-family: Arial, sans-serif; max-width: 500px; margin: 40px auto; }
.member { padding: 12px; margin: 8px 0; background: #f5f5f5; border-radius: 6px; }
a { display: inline-block; margin-bottom: 16px; padding: 8px 16px; background: #4CAF50; color: white; text-decoration: none; border-radius: 4px; }
</style>
</head>
<body>
<h2>회원 목록</h2>
<a href="/member/new">+ 회원 추가</a>
<%
List<Member> members = (List<Member>) request.getAttribute("members");
%>
<% if (members == null || members.isEmpty()) { %>
<p>등록된 회원이 없습니다.</p>
<% } else { %>
<p>총 <strong><%= members.size() %></strong>명</p>
<% for (Member m : members) { %>
<div class="member">
<strong><%= m.getName() %></strong> — <%= m.getEmail() %>
</div>
<% } %>
<% } %>
</body>
</html>
src/main/webapp/WEB-INF/views/member/form.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원 가입</title>
<style>
body { font-family: Arial, sans-serif; max-width: 400px; margin: 40px auto; }
input { width: 100%; padding: 8px; margin-top: 4px; box-sizing: border-box; }
button { margin-top: 12px; padding: 10px 20px; background: #4CAF50; color: white; border: none; cursor: pointer; width: 100%; }
.error { color: red; margin-bottom: 12px; }
</style>
</head>
<body>
<h2>회원 가입</h2>
<% if (request.getAttribute("error") != null) { %>
<p class="error">❌ <%= request.getAttribute("error") %></p>
<% } %>
<form action="/member/new" method="post">
<label>이름 *<br>
<input type="text" name="name">
</label><br><br>
<label>이메일<br>
<input type="email" name="email">
</label><br>
<button type="submit">가입하기</button>
</form>
<br><a href="/member/list">← 목록으로</a>
</body>
</html>
| 개념 | 핵심 내용 |
|---|---|
| 프론트 컨트롤러 | 모든 요청을 서블릿 하나가 받아서 URL에 따라 처리를 분기하는 패턴 |
@WebServlet("/*") | 모든 URL 요청을 이 서블릿이 받겠다는 선언 |
getRequestURI() | 현재 요청의 URL 경로를 가져오는 메서드 |
| 공통 처리 집중 | 인코딩 설정 등 반복 코드를 한 곳에서 처리 |
| DispatcherServlet | 스프링이 제공하는 프론트 컨트롤러. 우리가 만든 것의 완성형 |