Servlet
--[HTML코드 출력 문제]--> JSP
--스파게티 코드 문제--> JSP MVC
-> Spring MVC
-> SpringBoot
[Servlet / JSP ) 9. 동적 페이지의 필요성] 을 보면 동적 페이지 구현을 위해 java파일을 통해 html코드를 출력했다.
따라서
문제점인 [HTML코드 출력 문제] 를 해결하기 위해 JSP, Japser를 활용하도록 한다.
Jasper는 JSP를 Servlet으로 컴파일해주는 Tomcat의 JSP엔진이다.
Jasper는
1. html 확장자가 아닌 jsp 확장자로 변환해주면 calculator.html > calculator.jsp
2. Japser는 jsp파일 내에 있는 코드를 모든 라인마다 out.println("~~~~~") 로 바꾸어서
calculator_jsp.java 파일 , 즉 calculator_jsp라는 Servlet을 만들어주게 되고 이 Servlet을 실행하게 된다.
2번에 집중해보자.
calculator.jsp
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Calc</title>
<style>
input{
width: 50px;
height: 50px;
}
.output{
height: 50px;
font-size: 24px;
font-weight: bold;
background: gray;
text-align: right;
padding-right: 5px;
}
</style>
</head>
<body>
<form action="calc" method="post">
<table>
<tr>
<td class="output" colspan="4">${4+5}</td>
</tr>
<tr>
<td><input type="submit" name="operator" value="CE"/></td>
<td><input type="submit" name="operator" value="C"/></td>
<td><input type="submit" name="operator" value="≪"/></td>
<td><input type="submit" name="operator" value="÷"/></td>
</tr>
<tr>
<td><input type="submit" name="value" value="7"/></td>
<td><input type="submit" name="value" value="8"/></td>
<td><input type="submit" name="value" value="9"/></td>
<td><input type="submit" name="operator" value="×"/></td>
</tr>
<tr>
<td><input type="submit" name="value" value="4"/></td>
<td><input type="submit" name="value" value="5"/></td>
<td><input type="submit" name="value" value="6"/></td>
<td><input type="submit" name="operator" value="-"/></td>
</tr>
<tr>
<td><input type="submit" name="value" value="1"/></td>
<td><input type="submit" name="value" value="2"/></td>
<td><input type="submit" name="value" value="3"/></td>
<td><input type="submit" name="operator" value="+"/></td>
</tr>
<tr>
<td><input type="submit" name="operator" value="±"/></td>
<td><input type="submit" name="value" value="0"/></td>
<td><input type="submit" name="dot" value="."/></td>
<td><input type="submit" name="operator" value="="/></td>
</tr>
</table>
</form>
</body>
</html>
html과의 차이점은 중간에 ${4+5} 가 있는데 이것은 EL(Expression Languade)라고 한다. (뒤에서 설명)
이렇게 jsp 파일을 생성해주면
- Jasper는 jsp파일을 한 줄씩 출력하는 Servlet을 만들어줌
- 그렇게 생성된 Servlet은 한 줄씩 출력하며 html 파일을 생성해 클라이언트에게 응답한다.
실제로 C:\Users\s_rudwhd515\AppData\Local\JetBrains\IntelliJIdea2021.3\tomcat\01bd17f8-cf04-4e22-bb7d-ef88cfb18497\work\Catalina\localhost\ROOT\org\apache\jsp
해당 위치에
calculator_jsp.java
가 생성된 것을 확인할 수 있다.
또한 해당 자바 파일 내에는
calculator_jsp.java
/*
* Generated by the Jasper component of Apache Tomcat
* Version: Apache Tomcat/9.0.63
* Generated at: 2022-06-28 12:33:19 UTC
* Note: The last modified time of this file was set to
* the last modified time of the source file after
* generation to assist with modification tracking.
*/
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
public final class calculator_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {
private static final javax.servlet.jsp.JspFactory _jspxFactory =
javax.servlet.jsp.JspFactory.getDefaultFactory();
private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;
private static final java.util.Set<java.lang.String> _jspx_imports_packages;
private static final java.util.Set<java.lang.String> _jspx_imports_classes;
static {
_jspx_imports_packages = new java.util.HashSet<>();
_jspx_imports_packages.add("javax.servlet");
_jspx_imports_packages.add("javax.servlet.http");
_jspx_imports_packages.add("javax.servlet.jsp");
_jspx_imports_classes = null;
}
private volatile javax.el.ExpressionFactory _el_expressionfactory;
private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;
public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
return _jspx_dependants;
}
public java.util.Set<java.lang.String> getPackageImports() {
return _jspx_imports_packages;
}
public java.util.Set<java.lang.String> getClassImports() {
return _jspx_imports_classes;
}
public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
if (_el_expressionfactory == null) {
synchronized (this) {
if (_el_expressionfactory == null) {
_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
}
}
}
return _el_expressionfactory;
}
public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
if (_jsp_instancemanager == null) {
synchronized (this) {
if (_jsp_instancemanager == null) {
_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
}
}
}
return _jsp_instancemanager;
}
public void _jspInit() {
}
public void _jspDestroy() {
}
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
if (!javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
final java.lang.String _jspx_method = request.getMethod();
if ("OPTIONS".equals(_jspx_method)) {
response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
return;
}
if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method)) {
response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSP들은 오직 GET, POST 또는 HEAD 메소드만을 허용합니다. Jasper는 OPTIONS 메소드 또한 허용합니다.");
return;
}
}
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
try {
response.setContentType("text/html");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write("<!DOCTYPE html>\r\n");
out.write("<html lang=\"en\">\r\n");
out.write("<head>\r\n");
out.write(" <meta charset=\"UTF-8\">\r\n");
out.write(" <title>Calc</title>\r\n");
out.write(" <style>\r\n");
out.write(" input{\r\n");
out.write(" width: 50px;\r\n");
out.write(" height: 50px;\r\n");
out.write(" }\r\n");
out.write(" .output{\r\n");
out.write(" height: 50px;\r\n");
out.write(" font-size: 24px;\r\n");
out.write(" font-weight: bold;\r\n");
out.write(" background: gray;\r\n");
out.write(" text-align: right;\r\n");
out.write(" padding-right: 5px;\r\n");
out.write(" }\r\n");
out.write(" </style>\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n");
out.write("<form action=\"calc\" method=\"post\">\r\n");
out.write(" <table>\r\n");
out.write(" <tr>\r\n");
out.write(" <td class=\"output\" colspan=\"4\">");
out.write((java.lang.String) org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate("${4+5}", java.lang.String.class, (javax.servlet.jsp.PageContext)_jspx_page_context, null));
out.write("</td>\r\n");
out.write(" </tr>\r\n");
out.write(" <tr>\r\n");
out.write(" <td><input type=\"submit\" name=\"operator\" value=\"CE\"/></td>\r\n");
out.write(" <td><input type=\"submit\" name=\"operator\" value=\"C\"/></td>\r\n");
out.write(" <td><input type=\"submit\" name=\"operator\" value=\"âª\"/></td>\r\n");
out.write(" <td><input type=\"submit\" name=\"operator\" value=\"÷\"/></td>\r\n");
out.write(" </tr>\r\n");
out.write(" <tr>\r\n");
out.write(" <td><input type=\"submit\" name=\"value\" value=\"7\"/></td>\r\n");
out.write(" <td><input type=\"submit\" name=\"value\" value=\"8\"/></td>\r\n");
out.write(" <td><input type=\"submit\" name=\"value\" value=\"9\"/></td>\r\n");
out.write(" <td><input type=\"submit\" name=\"operator\" value=\"Ã\"/></td>\r\n");
out.write(" </tr>\r\n");
out.write(" <tr>\r\n");
out.write(" <td><input type=\"submit\" name=\"value\" value=\"4\"/></td>\r\n");
out.write(" <td><input type=\"submit\" name=\"value\" value=\"5\"/></td>\r\n");
out.write(" <td><input type=\"submit\" name=\"value\" value=\"6\"/></td>\r\n");
out.write(" <td><input type=\"submit\" name=\"operator\" value=\"ï¼\"/></td>\r\n");
out.write(" </tr>\r\n");
out.write(" <tr>\r\n");
out.write(" <td><input type=\"submit\" name=\"value\" value=\"1\"/></td>\r\n");
out.write(" <td><input type=\"submit\" name=\"value\" value=\"2\"/></td>\r\n");
out.write(" <td><input type=\"submit\" name=\"value\" value=\"3\"/></td>\r\n");
out.write(" <td><input type=\"submit\" name=\"operator\" value=\"ï¼\"/></td>\r\n");
out.write(" </tr>\r\n");
out.write(" <tr>\r\n");
out.write(" <td><input type=\"submit\" name=\"operator\" value=\"±\"/></td>\r\n");
out.write(" <td><input type=\"submit\" name=\"value\" value=\"0\"/></td>\r\n");
out.write(" <td><input type=\"submit\" name=\"dot\" value=\".\"/></td>\r\n");
out.write(" <td><input type=\"submit\" name=\"operator\" value=\"=\"/></td>\r\n");
out.write(" </tr>\r\n");
out.write("\r\n");
out.write(" </table>\r\n");
out.write("\r\n");
out.write("</form>\r\n");
out.write("</body>\r\n");
out.write("</html>");
} catch (java.lang.Throwable t) {
if (!(t instanceof javax.servlet.jsp.SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try {
if (response.isCommitted()) {
out.flush();
} else {
out.clearBuffer();
}
} catch (java.io.IOException e) {}
if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
else throw new ServletException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
}
calculator.jsp
를 한 줄씩 출력해주고 있음을 확인할 수 있다.
JSP 코드 블록
<% %>
태그를 활용해 java파일로 출력을 전달할 수 있다.
<%
out.write("Hello JSP~");
%>
JSP 코드 블록
<% %>
태그를 활용해 JSP 파일 내에 변수를 선언할 수 있다.
<%
int x = 1;
int y = 2;
%>
JSP 코드 블록
<%= %>
태그를 활용해 JSP 파일 내에 변수를 선언할 수 있다.
y 값은 <% = y %>
JSP 코드 블록
<%! %>
태그를 활용해 JSP 파일 내에 함수를 선언할 수 있다.
<%!
public int sum(int a, int b) {
return a+b;
}
%>
JSP 코드 블록
<%@ %>
태그를 활용해 JSP 파일의 페이지 설정을 할 수 있다.
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"
%>
jsp 파일 상단에 추가해주면,
calculator_jsp.java
~~~
out = pageContext.getOut();
_jspx_out = out;
int x = 1;
int y = 2;
out.write("\r\n");
out.write("\r\n");
out.write("<!DOCTYPE html>\r\n");
~~~
자바 코드로 추가가 됨을 확인할 수 있다.
JSP 컨테이너가 EL 표현식을 해석할 수 있게 도어 표준 액션 태그, 커스텀 태그, 템플릿 데이터와 같이 자바코드를 사용해야 했던 모든 곳에 EL을 사용하게 된다.
${...} 형식으로 적게 되고
EL 표현식
${true}
${false}
${123+123}
${3.14}
${"JAVA"}
${'java'}
EL 연산자
산술연산자: +, -, *, /, %, mode
논리연산자: &&, ||, !, and, or, not
비교연산자: ==, !=, <, >, <=, >=, eq, ne, lt, get, le, ge
empty연산자: 값이 null이거나 공백문자인지를 판단하는 연산자
${empty ""} → true
${empty null} → true
Request 객체 내
- 변수 -
<%= request.getAttribute("model"); %> --> ${model}
- 리스트 -
<%= ((List)request.getAttribute("list")).get(0); %> --> ${list[0]}
- 맵 -
<%= ((Map)request.getAttribute("map")).get("title"); %> --> %{map.title}
map.title은 사실 map.getTitle()이다.
EL에서는 getter만 호출이 가능하기 때문에 get과 괄호를 때고 첫 글자는 소문자로 바꿔줌으로써 구현한다.
!! EL 표현식 안에서 연산이 가능함이 특징이다.
JSP또한 일반 Servlet처럼 상태 유지를 위한 저장소가 있는데
- PageContext : JSP 페이지의 저장소
- Request : 요청, request에 데이터들 담아 전달할 수 있다.
- Session : Servlet처럼 사용자에 따라 Session으로 상태 유지를 할 수 있다.
- Page : page 전체에 대한 정보를 담고 있는 page객체
- Cookie : Servlet처럼 데이터가 브라우저에 저장되도록 할 수 있다.