ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 학원 day77. JSP의 속성과 스코프, EL, JSTL
    기록 2022. 12. 22. 18:05

    톰캣 내부 

    자바웹에서는 속성을 저장할 수 있는 곳이 4군데가 있다. 

    HttpServletRequest는요청이 오면 만들어지고 응답가면 사라지는 일회성 객체이다. 

    PageContext는 home.jsp에서만 쓸 수 있다. 메소드 안에서만 사용할 수 있다.

    HttpSession은 특정 클라이언트와 특정 브라우저와 연결된 객체

    ServletContext는 웹어플리케이션 당 하나씩 만들어지는 객체

     

    forward는 전달받은 request객체를 다른 jsp나 서블릿으로 이동시켜준다.

    jsp 안에서는 자신이 사용할 수 있는 객체를 미리 획득하고 있다. 

     

    서블릿(FrontController)요청접수, 컨트롤러 실행, 내부이동 3가지를 한다. 

    Controller요청처리, 업무로직 메소드 호출, JSP에서 표현할 데이터 저장, 뷰페이지 반환

    JSP데이터 표현을 한다.

     

    데이터는 request.setAttribute("message", "안녕");으로 메소드 실행할 때 request객체 속성에 담긴다.

     

    데이터표현 

    <p>${message} </p>

    message라는 속성명으로 저장된 속성값을 표현한다. 

     

    * 왜 하필 request객체에 데이터를 저장하는가?

    - 요청객체를 다른 jsp로 전달가능하다.

    - 요청객체는 응답이 완료되면 폐기된다.

    - 메모리 부담이 적다. 

    - 모델 2방식에서는 컨트롤러가 요청객체를 이용해서 뷰에게 데이터를 전달한다.

     

    스코프가 다르다는 건 저장된 속성을 공유할 수 있는 유효범위가 각각 다른 것을 의미한다.

    PageContext 스코프 < Request 스코프 < Session 스코프 < ServletContext인 어플리케이션 스코프 순으로 유효범위가 넓어진다.

    객체 범위 속성
    PageContext 페이지 객체
    HttpServletRequest 요청 객체
    HttpSession 세션 객체
    ServletContext 애플리케이션 객체

    속성은 HttpServletRequest와 PageContext는 금방 사라지는 곳이니까 속성을 막 담아도 된다.

    다른 곳에는 협의를 통해서 결정해야 한다. 

     

    +)

    질문 : 세션객체에서 로그아웃하면 세션객체가 사라지니까 사용자정보도 사라지고, 로그인하기 전까지는 세션객체도 존재하지 않고 사용자정보도 없는게 맞나요?

    답변 : 세션객체는 생성시점을 컨트롤하는게 가능하다. 디폴트는 JSP에 접속만해도 세션객체가 만들어진다. 

    session = "false"라고 하면 jsp에서 자동으로 세션을 생성하지 않는다. 

    지금 우리 개발 환경에서는 로그인하기 전이어도 세션객체 자체는 존재하고, 사용자정보는 들어있지 않다.


    요청파라미터는 2가지 방식(쿼리스트링, 폼 입력값)으로만 저장가능하다. 

     

    * 속성 관련 주요 API (객체에 상관없이 속성관련 API는 똑같다. )

    void setAttribute(String name, Object value) : 지정된 이름으로 속성을 저장한다.

    Object getAttribute(String name) : 지정된 이름의 속성을 조회한다.

    void removeAttribute(String name) : 지정된 이름의 속성을 제거한다. 

     

    * 요청파라미터 관련 주요 API

    String getParameter(String name) : 지정된 이름으로 요청파라미터값을 조회한다.

    String[] getParameterValues(String name) : 지정된 이름으로 여러개의 요청파라미터값을 조회한다.

     

    * 초기화파라미터 관련 주요 API

    String getInitParameter(String name) : 지정된 이름으로 초기화파라미터값을 조회한다. 


    EL (Expression Language)

    내장객체
    사용예
    설명
    param
    ${param.파라미터명}
    요청파라미터값을 조회할 수 있다.
    request.getParameter("파라미터명")와 동일하다.
    paramValues
    ${paramValues.파라미터명}
    요청파라미터값을 조회할 수 있다.
    동일한 매개변수 이름에 대한 여러 값을 가져오기 위해 사용된다.
    request.getParameterValues("파라미터명")와 동일한다.
    pageScope
    ${pageScope.속성명}
    PageContext에 저장된 속성(값, 객체)을 조회한다.
    requestScope
    ${requestScope.속성명}
    HttpServletRequest에 저장된 속성을 조회한다.
    sessionScope
    ${sessionScope.속성명}
    HttpSession에 저장된 속성을 조회한다.
    applicationScope
    ${applicationScope.속성명}
    ServletContext에 저장된 속성을 조회한다.
    initParam
    ${initParam.초기화파라미터명}
    초기화파라미터값을 조회한다.
    header
    ${header.요청헤더명}
    요청헤더정보에서 헤더명에 해당하는 값을 조회한다.
    cookie
    ${cookie.쿠키명}
    쿠키명에 해당하는 쿠키값을 조회한다.
    pageContext
    ${pageContext.getter메소드이름}
    PageContext의 getXXX()메소드의 실행결과를 조회한다.
    JSP의 기본객체를 제공받을 수 있다.

    JSP에서는 JSP의 요청파라미터, 속성, 스코프, 요청헤더정보, 초기화파라미터 정보에 접근할 수 있도록 해당 값을 제공하는 EL내장객체를 제공한다.

    EL의 내장객체는 내부적으로 Map객체이다. 

     

    요청파라미터는 param을 적으면 가져올 수 있다. 

    속성 이외에는 param 등 EL내장객체 이름을 적어야 한다.

    안적으면 무조건 속성을 찾는 거다.  (page->request->session->servletContext순으로 같은 name으로 저장되어 있는 것을 찾는다.) 찾았는데도 값이 없으면 null이 출력되는게 아니라 공백(빈문자열)이 출력된다.

    * ServletContext의 EL 내장객체 이름은 contextParam이 아닌 InitParam이다.

    ( InitParam인 이유는 꺼내는 메소드이름이 InitParam이라서 그렇다! )

     

    +)

    질문 : 톰캣에 ServletConfig객체는 없나요?

    답변 : 존재한다. 하지만  잘 쓰이지 않고 사용하는 EL이 없기 때문에 생략했다.

     

    연산자

    empty 연산자가 true를 반환하는 경우

    • 값이 null인 경우
    • "" 빈문자열인 경우
    • 배열이나 콜렉션의 길이가 0인 경우
    • 비어있는 맵인 경우
    web.xml
    
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:web="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd http://xmlns.jcp.org/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="5.0">
    
    	<!-- 
    		FrontController 서블릿을 웹서버(톰캣)에 배포하기
    			- FrontController 서블릿은 *.hta 형식의 HTTP 요청이 접수되면 실행되도록 배포한다.  
    	 --> 
       <servlet>
        	 <servlet-name>fc</servlet-name>
        	 <servlet-class>com.sample.model2.FrontController</servlet-class>
       </servlet>
       <servlet-mapping>
         	 <servlet-name>fc</servlet-name>
         	 <url-pattern>*.hta</url-pattern>
       </servlet-mapping>
    </web-app>
    FrontController.java
    
    package com.sample.model2;
    
    import java.io.IOException;  
    import java.util.HashMap;
    import java.util.Map;
    
    import com.sample.controllers.CoreController;
    import com.sample.controllers.FmtController;
    import com.sample.controllers.HomeController;
    import com.sample.controllers.ListController;
    import com.sample.controllers.LoginFormController;
    import com.sample.controllers.RegisterFormController;
    
    import jakarta.servlet.RequestDispatcher;
    import jakarta.servlet.ServletConfig;
    import jakarta.servlet.ServletException;
    import jakarta.servlet.http.HttpServlet;
    import jakarta.servlet.http.HttpServletRequest;
    import jakarta.servlet.http.HttpServletResponse;
    
    public class FrontController extends HttpServlet {
    	
    	private Map<String, Controller> controllerMap = new HashMap<>();
    	
    	/**
    	 * 서블릿의 초기화 메소드다.<br/>
    	 * 서블릿 객체가 생성되면 톰캣이 딱 한번 호출해서 서블릿을 초기화시킨다<br/>
    	 * 초기화는 필요한 객체를 미리 만들어두는것, 멤버변수에 값을 저장하는 것이 초기화에 해당한다. 
    	 * FrontController를 사용할 준비를 하는 것이다. 클라이언트가 요청이 올 때마다 맞는 Controller를 찾아서 실행시켜야 하는데 그 Controller를 미리 만들어놓는 것이다.
    	 */
    	public void init(ServletConfig config) throws ServletException {
    		controllerMap.put("/home.hta", new HomeController());
    		controllerMap.put("/register-form.hta", new RegisterFormController());
    		controllerMap.put("/login-form.hta", new LoginFormController());
    		controllerMap.put("/list.hta", new ListController());
    		controllerMap.put("/core.hta", new CoreController());
    		controllerMap.put("/fmt.hta", new FmtController());
    	}
    
    	// 서비스라는 메소드는 요청이 올 때마다 실행된다.
    	@Override
    	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		System.out.println("### FrontController의 service(request, response) 메소드 실행.");
    		
    		/////////////////////////////////////////////////////////////////////////////
    		// 요청 URI 분석하기
    		/////////////////////////////////////////////////////////////////////////////
    		
    		// ContextPath(웹애플리케이션을 구분하는 고유한 경로다. 보통은 프로젝트명과 동일하다.) 조회하기
    		String contextPath = request.getContextPath();
    		// 요청 URI 조회하기
    		String requestURI = request.getRequestURI();
    		// contextPath 지우고 조회하기 (model2는 똑같으니까)
    		requestURI = requestURI.replace(contextPath, "");
    		System.out.println("### 요청 URI: " + requestURI);          
    		
    		/////////////////////////////////////////////////////////////////////////////
    		// 컨트롤러 실행하기 (요청URI에 맞는 특정한 자바클래스가 실행되게 함)
    		/////////////////////////////////////////////////////////////////////////////
    		try {
    			// HashMap객체에 저장된 Controller 인터페이스 구현객체 꺼내기
    			Controller controller = controllerMap.get(requestURI);
    			// 조회된 컨트롤러 객체의 execute(request, response);
    			String viewName = controller.execute(request, response);
    			
    			
    			viewName = "/WEB-INF/views/" + viewName;
    			// 지정된 뷰페이지(viewName)으로 클라이언트의 요청을 이동시킨다.
    			// 즉, JSP를 실행시키는 것이다.
    			// 내부로 이동, 클라이언트의 요청을 파견, 실제 표현은 다른애가 할 거라는걸 알려줌
    			RequestDispatcher requestDispatcher = request.getRequestDispatcher(viewName);
    			
    			// 내가 추가한 주석
    			// include는 다른 jsp를 실행시켰다가 되돌아오게 하는 것임.
    			// forward는 다른 jsp로 영원히 보내버리는 것임. 내부이동은 자신이 전달받은 request와 response객체를 반드시 전달해줘야 한다.
    			// 요청객체와 응답객체 없이 jsp를 실행할 수 없다. jsp를 직접 호출한게 아니라 서블릿을 호출한건데 jsp가 데이터를 표현해주는 역할을 하니까 jsp를 실행시켜야 하는데 요청객체와 응답객체를 전달해줘야 한다. 
    			// 컨트롤러 실행한 다음에 jsp가 실행된다. 
    			requestDispatcher.forward(request, response);
    		} catch (Exception e) {
    			throw new ServletException(e);
    		}
    		
    	}
    }
    HomeController.java
    
    package com.sample.controllers;
    
    import java.util.HashMap;
    import java.util.Map;
    
    import com.sample.model2.Controller;
    import com.sample.vo.Product;
    
    import jakarta.servlet.http.HttpServletRequest;
    import jakarta.servlet.http.HttpServletResponse;
    
    public class HomeController implements Controller {
    
    	@Override
    	public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
    		System.out.println("### HomeController의 execute(request, response) 실행.");
    		
    		// 요청객체의 속성에 값 혹은 객체 저장하기
    		request.setAttribute("message", "안녕하세요");
    		
    		Product product = new Product(100, "갤럭시폴더 4", "삼성전자", 2000000, 1750000, 3);
    		// 요청객체의 속성에 값 혹은 객체 저장하기
    		request.setAttribute("bestGoods", product);
    		
    		String[] keywords = {"크리스마스", "연말", "선물", "산타"};
    		// 요청객체의 속성에 값 혹은 객체 저장하기
    		request.setAttribute("keywords", keywords);
    		
    		Map<String, Object> map = new HashMap<>();
    		map.put("name", "홍길동");
    		map.put("kor", 100);
    		map.put("eng", 80);
    		map.put("math", 90);
    		// 요청객체의 속성에 값 혹은 객체 저장하기
    		request.setAttribute("student", map);
    		
    		// 요청처리를 마치고 home.jsp로 이동시킨다.
    		// 요청처리가 완료되면, 데이터를 표현할 뷰페이지이름을 반환한다.
    		//return "/WEB-INF/views/home.jsp"; 이렇게 적어도 되지만 /WEB-INF/views/까지는 공통이기 때문에 이동시켜주는 FrontController에 적어줘도 된다.
    		return "home.jsp";
    	}
    }
    home.jsp
    
    <%@ page language="java" contentType="text/html; charset=UTF-8" 
    	pageEncoding="UTF-8"%>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <!DOCTYPE html>
    <html lang="ko">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet" >
    <title>웹 애플리케이션</title>
    </head>
    <body>
    <!-- pageContext 객체의 속성을 추가한다.
    	 속성명 : "menu"
    	 속성값 : "home"	
    -->
    <c:set var="menu" value="home" />
    <div class="container">
    	<div class="row">
    		<div class="col-12">
    			<%@ include file="common/header.jsp" %>
    		</div>
    	</div>
    	<div class="row mb-3">
       		<div class="col-12">
       			<h1>홈</h1>
       		</div>
       	</div>
       	
       	<div class="row mb-3">
       		<div class="row col-12">
       			<a href="list.hta?page=1">1</a>
       			<a href="list.hta?page=2">2</a>
       			<a href="list.hta?page=3">3</a>
       			<a href="list.hta?page=4">4</a>
       		</div>
       	</div>
       	
     	<div class="row mb-3"> 
    	 	<div class="col-12">
    	 		<p>${requestScope.message }</p>
    	 		<p>${message }</p>
    	 	</div>
     	</div>
     	<div class="row mb-3">
     		<div class="col-12">
     			<p>
     				<span class="badge bg-secondary">${keywords[0] }</span>
     				<span class="badge bg-secondary">${keywords[1] }</span>
     				<span class="badge bg-secondary">${keywords[2] }</span>
     				<span class="badge bg-secondary">${keywords[3] }</span>
     			</p>
     		</div>
     	</div>
     	<div class="row mb-3">
     		<div class="col-12">
    			<table class="table">
    				<thead>
    					<tr>
    						<th>이름</th>
    						<th>국어점수</th>
    						<th>영어점수</th>
    						<th>수학점수</th>
    						<th>총점</th>
    						<th>평균점수</th>
    						<th>합격여부</th>
    					</tr>
    				</thead>
    				<tbody>
    					<tr>
    						<td>${student.name }</td>
    						<td>${student.kor }</td>
    						<td>${student.eng }</td>
    						<td>${student.math }</td>
    						<td>${student.kor + student.eng + student.math }</td>
    						<td>${(student.kor + student.eng + student.math)/3 }</td>
    						<td>${(student.kor + student.eng + student.math)/3 >=60 ? "합격" : "불합격" }</td>
    					</tr>
    				</tbody>
    			</table> 		
     		</div>
     			<table class="table">
     				<colgroup>
     					<col width="15%">
     					<col width="35%">
     					<col width="15%">
     					<col width="35%">
     				</colgroup>
     				<tbody>
     					<tr>
     						<th>상품번호</th><td>${bestGoods.no }</td>
     						<th>재고수량</th><td>${bestGoods.stock } 개</td>
     					</tr>
     					<tr>
     						<th>상품명</th><td>${bestGoods.name }</td>
     						<th>제조회사</th><td>${bestGoods.maker }</td>
     					</tr>
     					<tr>
     						<th>가격</th><td>${bestGoods.price } 원</td>
     						<th>할인가격</th><td>${bestGoods.discountPrice } 원</td>
     					</tr>
     				</tbody>
     			</table>
     			<div>
     				<a href="cart.hta?no=${bestGoods.no }" class="btn btn-primary btx-sm">장바구니 추가</a>
     				<a href="order.hta?no=${bestGoods.no }" class="btn btn-success btx-sm">바로구매</a>
     			</div>
     		</div>
     	</div>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
    </body>
    </html>

    EL표현식 안에서는 쌍따옴표 안에서 홑따옴표로 적어도 쌍따옴표로 적어도 된다.

     

    조건문처리, 반복처리 등 EL로 못했던 것을 JSTL로 표현할 수 있다.

     

    JSTL(JSP Standard Tag Library)

    • JSP 표준태그 라이브러리
    • 스크립틀릿을 사용해서 작성했던 자바코드를 대체할 수 있다.
      • 변수 선언/삭제, 값 출력, 제어문 처리, 반복문 처리, 숫자나 날짜에 대한 포맷팅, 국제화처리, URL처리
    • 사용법
      • JSTL 파일을 다운받아서 WEB-INF/lib에 복사한다.
      • JSP 파일에 사용할 태그라이브러리를 지시어를 사용해서 정의한다.
        <%@ taglib prefix="별칭" uri="태그라이브러리식별자" %>
        <별칭:태그명 value="${EL표현식}" />

    page 지시어(디렉티브)

    <%@ page %>

                   contentType="text/html; charset=UTF-8"   

                   

    include 지시어

    <%@ include file="abc.jsp" %>

          다른 JSP파일을 포함시킨다. 

     

    taglib지시어

    <%@ taglib prefix="별칭" uri="태그라이브러리 식별자" %>

                jsp 페이지에서 사용할 태그라이브러리를 정의한다. 

     

    JSTL 태그라이브러리의 태그 종류

    Core 태그 

    • 가장 많이 사용되는 태그 라이브러리다.
    • 변수/출력/제어문/반복문/URL 처리를 지원한다.
    • JSP에 아래의 지시어를 정의한다.
      <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    • <c:out> 태그
      • 값을 출력한다.
      • <%=값 %>, ${표현식} 과 동일한 작업을 수행한다.
      • XSS(Cross Site Scripting) 취약점 공격에 대한 가장 기본적인 방어을 지원한다.
        • XSS는 악의적인 사용자가 공격하려는 사이트에 스크립트를 넣어서 쿠키나 세션아이디와 같은 정보를 취득하는 것을 말한다.
        • 주로 공개된 게시판의 게시글에 html과 script 코드를 입력해서 해당 스크립트를 실행시키는 것이다.
        • 사이트 이용자가 작성하는 컨텐츠는 반드시 <c:out />태그를 사용해서 출력하자.
      • 사용법
        <c:out value="${표현식}" />
      • 주요 속성
        • value
          • 출력할 값을 지정한다.
          • 생략할 수 없음
            <c:out value="${book.title}" />
        • escapeXml
          • 특수문자(< > " ' &)를 변환할지 여부를 지정한다.
          • 기본값은 true다.
          • 생략가능
        • default
          • value에서 지정한 값이 null인 경우 표현할 값을 지정한다.
          • 생략가능

     

    • <c:if> 태그
      • if문과 동일한 역할을 수행한다.
      • else에 해당하는 태그는 없다.
      • 사용법
        <c:if test="${표현식}">
          HTML 컨텐츠
        </c:if>
        <!-- test에서 제시한 조건이 true면 HTML 컨텐츠가 화면에 출력된다. --->
      • 주요 속성
        • test
          • 검사조건을 정의한다.
          • 결과값이 boolean 타입이어야 한다.
          • 생략할 수 없다.

    model1방식과 model2방식

    • <c:choose> <c:when> <c:otherwise> 태그
      • if ~ else if ~ else if ~ else 와 동일한 역할을 수행한다.
      • 사용법
        <c:choose>
          <c:when test="${조건식1}">
            HTML 컨텐츠
            <!-- test에서 제시한 조건식1이 true면 HTML 컨텐츠가 화면에 출력된다. --->
          </c:when>
          <c:when test="${조건식2}">
            HTML 컨텐츠
            <!-- test에서 제시한 조건식2이 true면 HTML 컨텐츠가 화면에 출력된다. --->
          </c:when>
          <c:when test="${조건식3}">
            HTML 컨텐츠
            <!-- test에서 제시한 조건식3이 true면 HTML 컨텐츠가 화면에 출력된다. --->
          </c:when>
          <c:otherwise>
            HTML 컨텐츠
            <!-- test에서 제시한 조건식1, 조건식2, 조건식3이 전부 false면 HTML 컨텐츠가 화면에 출력된다. --->
          </c:otherwise>
        </c:choose>
      • <c:when>과 <c:otherwise>는 반드시 <c:choose>안에 위치해야 한다.
      • <c:when>은 조건식을 다르게 해서 여러 번 정의할 수 있다. test라는 필수 속성이 있다.
      • <c:otherwise>는 생략할 수 있고, 맨 마지막 <c:when> 다음에 정의해야 한다.
      • <c:when>으로 제시한 조건식이 true가 되면 남아있는 <c:when>은 검사하지 않는다.
      • <c:otherwise>는 <c:when>으로 제시한 조건이 모두 false로 판정될 때만 실행된다.

     

    fmt 태그 (formating의 약자)

    • 숫자나 날짜에 대한 포맷팅을 지원한다. (지역에 맞게 숫자나 날짜를 바꿔주는 걸 포맷팅이라고 함)
    • 국제화처리를 지원한다. (트위터 등 전세계적으로 사용하는 웹사이트 메뉴가 내가 원하는 언어로 나오도록 처음부터 내가 언어를 설정해 주는 것을 국제화처리라고 한다.)
    • JSP에 아래의 지시어를 정의한다.
      <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

     

     

     

    '기록' 카테고리의 다른 글

    학원 day79. Redirect, 세션  (0) 2022.12.26
    학원 day78. JSTL(2)  (0) 2022.12.23
    학원 day76. MVC 패턴  (0) 2022.12.21
    학원. 세미프로젝트  (0) 2022.12.21
    학원 day71.  (0) 2022.12.14

    댓글

Designed by Tistory.