본문 바로가기
WEB/✿JSP

[JSP] 🔗/EL & JSTL

by W_W_Woody 2022. 1. 20.

EL (Express Language; 표현 언어)

(1) EL 특징

  • JSP의 네가지 기본 객체가 제공하는 영역의 속성 사용
  • 집합 객체에 대한 접근 방법 제공
  • 수치 연산, 관계 연산, 논리 연산자 제공
  • 자바 클래스 메서드 호출 기능 제공
  • 표현 언어만의 기본 객체 제공
  • 일반적으로 MVC패턴일 때만 쓴다
  • 데이터를 읽어오는 역할

(2) EL 표기법

${expr}

식별자와 연결된 값을 출력한다. (표현식과 유사함.)

(3) EL의 연산자

- 수치 연산자 : +, - , *, / 또는 div, % 또는 mod

- 비교 연산자 : == 또는 eq, != 또는 ne, < 또는 lt, > 또는 gt, <= 또는 le, >= 또는 ge

- 논리 연산자 : && 또는 and, || 또는 or, ! 또는 not

- empty 연산자 

1) 값이 null이면 true 반환

2) 값이 빈 문자열(“”)이면 true 반환

3) 값이 길이가 0인 배열이면 true 반환

3) 값이 빈 Map이면 true를 반환

4) 값이 빈 Collection이면 true를 반환

 

5) 이외의 경우에는 false를 반환

 

EL은  값을 출력하는 용도 말고, 연산하는 용도로 쓰지 않는다 이유는 아래와 같다.

<tr>
    <td>\${"10"+2}</td> 
    <td> ${"10"+2}</td>
</tr>
 <tr>
    <td>\${"10"+"2"}</td>
    <td> ${"10"+"2"}</td> 
 </tr>

Java 문법에서는  문자열과 +연산자가 있으면 문자열을 연결시켰지만.

EL 문법에서는 문자열"" 안에 숫자가 있으면 자동으로 파싱(String->int)하여 연산을 한다.

 <tr>
    <td>\${"십"+5}</td>
    <td> ${"십"+5}</td>
 </tr>

내부적으로 파싱을 못해서 NumberFormatException 에러발생

 <tr>
    <td>\${4/5}</td> 
    <td> ${4/5}</td> 
 </tr>

자바스크립트처럼 정수 정수 연산 →실수데이터 출력 

 

(4) EL의 기본객체(내장객체)

기본객체 설명
pageContext JSP의 page 기본 객체와 동일
pageScope pageContext 기본 객체에 저장된 속성의 <속성,값>매핑을 저장한 Map 객체
requestScope request 기본 객체에 저장된 속성의 <속성,값> 매핑을 저장한 Map 객체
sessionScope session 기본 객체에 저장된 속성의 <속성,값> 매핑을 저장한 Map객체
applicationScope application 기본 객체에 저장된 속성의 <속성,값>매핑을 저장한 Map객체
param 요청 파라미터의 <파라미터이름, 값> 매핑을 저장한 Map객체
paramValues 요청 정보의 <파라미터이름,값 배열> 매핑을 저장한 Map 객체
header 요청 정보의 <헤더이름,값> 매핑을 저장한 Map 객체
headerValues 요청 정보의 <헤더이름,값 배열> 매핑을 저장한 Map 객체
cookie <쿠키 이름, Cookie> 매핑을 저장한  Map 객체
initParam 초기화 파라미터의 <이름,값> 매핑을 저장한 Map 객체

EL의 기본객체(내장객체)는 명시하거나, 생략해서 사용할 수 있다.

◎ Scope

<%
	//변수에 값 저장
	String str = "여름 여행";

	//jsp 4개 영역에 데이터 저장 (속성명, 속성값)
	pageContext.setAttribute("msg", "봄"); //page영역
	request.setAttribute("msg2", "여름"); //request영역
	session.setAttribute("msg3", "가을"); //session영역
	application.setAttribute("msg4", "겨울"); //application영역
%>

 ${내장객체. 속성명}  또는  ${(내장객체생략)속성명}

${pageScope.msg} 또는 ${msg}   page영역

${requestScope.msg} 또는 ${msg2}   request영역

${sessionScope.msg} 또는 ${msg3}   session영역

${applicationScope.msg} 또는 ${msg4}   application영역

 

속성명은 유니크하게 명시하는 편이 좋음

속성명을 동일한 명칭을 사용하는데, 내장객체를 생략해서(${msg}) 호출 시 문제가 발생함
그러므로 동일한 명칭일 땐 내장객체를 명시하여(${pageScope.msg) 호출해야한다.

el로 읽을 때는 속성명을 유일(unique)하게 명시했을 때, 내장 객체를 생략해서 사용할 수 있음

변수의 값  :  ${str}  →   EL 은 데이터를 못 읽어옴

EL은 이런식으로 스크립틀릿<%%>에 만든 변수를 사용하는 것이 아니라,

jsp 4개 영역(page, request, session, application)에 저장한 뒤 읽어오는 형태를 취해야한다.

* application은 일반데이터를 저장하지않고,  설정정보를 사용하는 영역

 

EL을 단독으로만 사용하면 작업이 제한 적. 그래서 단독으로 사용하지않고 JSTL와 함께 사용한다.

 

◎ param 

request.getParameter()의 역할을 한다.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%
	//method="post" 방법이므로 전송된 데이터 인코딩처리한다.
	request.setCharacterEncoding("utf-8");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>EL-param</title>
</head>
<body>
<h3>표현언어(EL;Express Language) - 파라미터 값 처리</h3>
<%-- action을 생략해도 기본값이라 자기자신을 호출  --%>
<form action="s02_el.jsp" method="post">
	이름  : <input type="text" name="name">
	<input type="submit" value="확인"> 
</form>
<br>
이름은 <%= request.getParameter("name") %> <br>
이름은 ${param.name}
</body>
</html>

* <form>에서  action을 생략해도 기본값이라서 자기자신을 호출한다

[s02_el.jsp]

<form action="s02_el.jsp" method="post">

 

이름은  <%= request.getParameter("name") %>
이름은  ${param.name }

차이점을 본다면
submit 하기 전 null 상태인 경우

request.getParameter  →  null로 출력
param  →  빈문자로 표시

 


 

 

MVC에서는 선언부, 스크립틀릿, 표현식을 쓸 수 없어서 jstl.jar의 도움을 받는다

WEB-INF/lib 경로에 Jstl.jar 파일을 넣는다.

JSTL

 = 커스텀 태그 = 만들어진 태그

java코드로 나열해야 하는 것을 쉽게 사용하기 위해 태그화시킨 것

태그형태로 되어있는데 servlet으로 변환 할 때 java코드가 된다 (전에 사용한 액션태그와 비슷함)

 

 

 

- core 라이브러리 (기본)

jsp 페이지에 core 라이브러리를 사용할 수 있도록 taglib 디렉티브 명시 

(액션태그는 톰캣에 내장되어있지만 커스텀태그를 사용하기 위해서는 명시해야 태그 사용이 가능하다)

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

prefix : 접두사 (태그앞에  코어라이브러리를 사용하려고 c라고 명시했음)

uri : core 라이브러리가 존재하는 위치 (jar파일의 설정정보를 읽어오는 식별자역할)

jar 파일로 부터 설정정보를 읽어오기 위해서 유니크하게 식별자를 만들었다.

 

자바빈(vo) 역할을 하기위해 

(직접 접근을 못하니까) public한 getter, setter 메서드 생성

 

<%@ page import="kr.web.member.UserVO" %>

 

(1) <c:set var="변수명" value="설정값" target="객체" property="값" scope="저장영역" />

- 지정된 변수에 값을 저장하는 태그 (≒setAttribute)

 

target은 값을 설정하고자 하는 객체를 명시한다. target에 객체를 명시하면 명시된 객체에 값을 셋팅할 수 있다.

property는 taregt에 명시된 객체의 프로퍼티를 의미하며 명시된 프로퍼티에 value에 명시한 설정값을 셋팅합니다.

scope은 값을 셋팅한 범위를 의미(page,request,session,application), 생략하면 기본값인 scope="page"

 

//테스트로 스크립트릿으로 객체 생성

<% UserVO user = new UserVO(); %>

<c:set target="${user}" property="name" value="홍길동"/>

 

${user.property명} / ${user.메서드 명시}

회원이름 : ${user.name}  (표준)

회원 이름 : ${user.getName()}

명시만 프로퍼티명인 것이고 EL이  자바빈(VO)에 접근하고 "name" 이 private으로 막혀있어서

setName을 찾아서 홍길동을 넣어준다
property="name"  : setName(set메서드/get메서드)을 호출하고 거기에 데이터를 넣어준다.


(2) <c:remove var="변수명" scope="범위" />

- 설정된 속성을 제거하는 태그 

빈도수는 그닥 높지않음

 

scope은 값이 셋팅된 범위를 의미(page,request,session,application), 생략하면 scope="page"


 

(3) <c:out value="출력값" default="기본값" escapeXml="true/false"  />

- 지정된 값을 출력하는 태그

 

value 에 명시한 값을 출력하며 value 가 null 일경우 default에 기술한 값을 출력

escapeXml는 기본값이 true이며 true라고 지정하면 <과 같은 특수문자를 &lt; 엔티티 레퍼런스 형태로 변환한다.즉, escapeXml를 true라고 하면 HTML 태그를 인정하지 않는다는 의미.

false라고 지정하면 태그를 인정함.( HTML태그 인정할 때는 그냥 EL을 쓴다.)

 

escapeXml="true"이면 html태그 불인정(기본값)

<c:out value="<h1>escapeXml=true 오늘은 목요일</h1>" escapeXml="true"/>

escapeXml="false"이면 html태그 인정

<c:out value="<h1>escapeXml=false 내일은 금요일</h1>" escapeXml="false"/>

 static만 되있으면 다 읽어와서 출력한다. 특별한 경우에만 out태그로 사용한다


(4) <c:if test="조건" var="변수명" scope="범위" > </c:if>

- 조건이 true이면 수행문을 수행하는 태그  단독태그 아님! 

 

test에서 조건을 체크해서 true 또는 false가 되면 var에 지정된 변수의 그 값이 담김

scope은 var에 지정한 변수가 셋팅되는 범위를 의미(page,request,session,application), 생략하면 scope="page"

 

<c:if test="boolean공간">

<c:if test="true">

true 무조건 수행 <br>

</c:if>

 

test>

문자열 명시할 때 큰 따옴표지만 밖에 큰따옴표가 있으므로 작은따옴표 써도 인정이 된다.

<c:if test="${param.name.equals('dragon') }">

name 파라미터 값이 ${param.name }입니다 <br>

</c:if>

테스트라서

전송이 안됐고 값이 없어서 false → 빈 문자 출력
get방식으로 값을 넘겨서 테스트하려면
http://localhost:8081/jspMain/ch18-jstl/s03_if.jsp뒤에 ?name=dragon 붙여서 테스트 해볼 수 있다(결과 true)


문자열을 비교할 떄 equals메서드나, 비교연산자(==)쓴다 

(원래 EL안에서 메서드 호출이 안됐는데 상위버전으로 올라가면서 equals메서드 사용도 인정이 된다. 표준은 비교연산자)   

<c:if test="${param.name == 'dragon' }">

name 파라미터 값이 ${param.name }입니다 <br>  

</c:if>

 

단일 if문만 된다. if else, 다중if 가 안된다.

그래서 다중if문을 구현한 choose/when/otherwise를 만들었다


(5) <c:choose>

   <c:when test="조건"></c:when>

   <c:when test="조건"></c:when>

   <c:otherwise></c:otherwise>

   </c:choose>

- 여러개의 when 태그에 명시한 조건을 체크하고 조건에 만족하는 수행문을 수행, 만족하는 조건이 없으면 otherwise에 명시한 수행문을 수행. 단독태그 아님! 

<c:choose>

    <c:when test="${param.name=='dragon'&& param.age >= 20 }"> <%--첫번째 조건 if --%>

          당신의 이름은 ${param.name }이고 20 이상 입니다.

    </c:when>

    <c:when test="${param.name=='dragon'}"> <%--두번째 조건 else if--%>

          당신의 이름은 ${param.name }입니다

    </c:when>

    <c:when test="${param.age >= 20 }"> <%--세번째 조건 else if --%>

          당신은 20 이상입니다.

    </c:when>

    <c:otherwise> <%--네번째 조건  else--%>

          당신은 dragon 아니고 20 이상이 아닙니다.

    </c:otherwise>

</c:choose>


(6) <c:forEach items="객체명" begin="시작 인덱스" end="끝 인덱스" step="증감식" var="변수명" varStatus="상태변수" />

- 수행문을 반복해서 수행 (단순반복문과 확장for문을 합쳐놓은 형태), 목록작업 시 많이 쓰임

 

items : 속성에 인덱스가 존재하는 객체를 지정하여 반복수행할 때 사용

begin : 수행문을 반복시킬 시작 인덱스 지정

end : 수행문의 반복이 끝날 인덱스 지정

step : 증감식 지정 기본값은 step="1"

var : 현재 반복하고 있는 값이 저장되는 변수지정

varStatus : 반복 상태를 지정하는 변수 지정

 

예) varStatus ()의 사용예

 

<c:forEach var="list" items="itemList" varStatus="status">

  ${status.index} <-  0부터 시작하는 인덱스 표시

  ${status.count} <- 1부터 시작하여 1씩 증가 반복회차

  ${status.first}  <- forEach 반복의 처음 일 경우 true

  ${status.last}  <- forEach 반복의 마지막 일 경우 true

</c:forEach>

 

int형 배열 예시>  배열형태보다 List가 빈도 수 높음

<c:set var="intArray" value="<%= new int[]{10,20,30,40,50} %>"/>

EL이 배열에 접근해서 c:forEach가 roop를 돈다 

<c:forEach var="i" items="${intArray}" >

그 배열로부터 var="i"가 값을 얻어온다 

${i } <br>

<c:set var="intArray" value="<%= new int[]{10,20,30,40,50} %>"/>

EL이 배열에 접근해서 c:forEachroop를 돈다 

<c:forEach var="i" items="${intArray}" begin="2" end="4" varStatus="status">

그 배열로부터 var="i"가 값을 얻어온다 

${status.index }-${status.count }-${i } <br>

Map data 예시>

<%  HashMap<String,String> mapData= new HashMap<String,String>();

      mapData.put("name","홍길동");

      mapData.put("job","경찰");  %>

페이지 영역에 해시맵 저장(저장해야 되니까 set태그 이용)

<c:set var="map" value="<%= mapData %>"/>

<c:forEach var="i" items="${map }">

${i.key }=${i.value } <br>


- functions 라이브러리

(7) <c:forTokens items="객체명" delims="구분자" begin="시작 인덱스" end="끝 인덱스" step="증감식" var="변수명" varStatus="상태변수" />

- 문자열을 구분자로 잘라내어 출력

 

items : 잘라내고자 하는 문자열이 담겨있는 객체

delims : 구분자 지정 구분자를 여러개 사용가능 (반면에 split 은 하나만 가능)

begin : 시작 인덱스

end : 끝 인덱스

step : 증감식

var : 잘라진 문자열이 담기는 변수

varStatus : 반복 상태지정 변수


(8) <c:catch var="변수명" />

- 예외 발생시 예외 처리 태그

 

예외가 발생할 수 있는 수행문 앞 뒤에 catch 태그를 배치하고 예외가 발생하면

var에 지정한 변수명에 예외 문구를 저장한다. out 태그 또는 el 를 통해 예외 문구를 호출해 출력할 수 있다.

 

(9) <c:import url="URL" var="변수명" scope="범위" varReader="변수명" context="context" charEncoding="인코딩" />

- 지정한 url 페이지의 내용을 읽어와 출력

 

(10) <c:redirect url="URL" context="context" />

- 지정한 url로 redirect

 

(11) <c:url var="변수명" scope="범위" value="값" context="context" />

- url 생성

 

(12) <c:param name="파라미터명" value="값" />

- 파라미터로 전달하고 싶은 값을 name에 기술된 파라미터명과 value에 명시한 값의 쌍으로 전송

 

 

예) forEach를 사용할 때 List의 크기 구하기

<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>

<- 페이지 상단에 명시

${fn:length(itemList)}

 

 

접두사를 붙이고 함수 호출

- formatting 라이브러리

-JSTL i18n capable formatting 라이브러리의 국제화 태그를 이용해 국제화 지원

 

 

빼버리고 싶은 정보가 출력되거ㅏㄴ 짧게 출력하고싶을 때 반영이안되서 이때  패턴을 사용하여 조절한다.,

 

jsp 페이지에 i18n capable formatting 라이브러리를 사용할 수 있도록 taglib 디렉티브 명시

<%@ taglib prefix="fmt" uri=http://java.sun.com/jsp/jstl/fmt %>

prefix : 접두사

uri : i18n capable formatting 라이브러리가 존재하는 위치

 

(1) <fmt:bundle basename="properties파일경로및 파일명" prefix="prefix">....</fmt:bundle>

- 국제화를 적용을 위해 properties 파일경로 및 파일을 읽어와서 언어 적용

 

basename :  사용할 언어별 데이터가 key와 value의 쌍으로 작성된 properties 파일의 경로및 파일명 지정

prefix :  bundle 태그 내에서 message 태그를 통해 value를 읽어올 때 key속성 앞에 접두사 지정

 

(2) <fmt:message key="메시지의 key값" bundle="setBundle 태그를 통해 로딩한 번들을 얽어올 때 사용함" var="변수명" scope="범위" />

- 국제화를 적용한 메시지의 key에 대한 value를 호출

 

key : 메시지의 key값을 통해 value 호출

var :  변수명을 지정하면 message태그를 출력기능을 상실하고 변수를 out 태그 또는 el를 통해 호출 하여 value를 출력해야 함

 

(3) <fmt:setBundle basename="properties파일경로및 파일명" var="메시지를 저장할 변수명" scope="범위" />

- 페이지 전체에서 사용할 번들을 지정

 

--------------------------------------------------

국제화 처리 예)

1. 각 페이지에서 읽어갈 key와 value가 저장될 properties 파일 작성

 

message.properties <-  default 언어가 사용될 파일

message_ko.properties <- 한글이 사용될 파일

message_en.properties <- 영어가 사용될 파일

 

2. properties 파일이 들어갈 폴더 생성

WEB-INF/classes/폴더 생성(bundle) <- 배포시 (Dynamic Web Project를 만들어 이클립스에서 작업중이라면 Java Resources:src 에 폴더를 만듬, 자동적으로 classes 이하에 폴더가 복사됨)

 

3. 생성한 폴더에 message.properties, message_ko.properties 파일 등을 만들고 내용 입력

message_ko.properties 예

 

member_admin_title=회원관리

member_admin_name=관리자

member_admin_email=admin@test.com

member_admin_phone= 관리자 연락처는 {0}입니다. <- {0}은 message 태그 호출시 param 태그로 전달되는 데이터를 받음

 

4-1. properties 파일의 내용을 읽어갈 jsp 파일 작성(bundle 태그 이용시)

bundle 태그를 사용하면 지정된 영역내에 단일한 언어를 적용함

---------------------------------------------------------------

<%@ page contentType = "text/html; charset=euc-kr" %>

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

<fmt:bundle basename="bundle.message">

<html>

<head>

   <title><fmt:message key="member_admin_title"/></title>

</head>

<body>

  <fmt:message key="member_admin_name"/>

  <br>

   <fmt:message key="member_admin_phone">

      <fmt:param value="${phone}" />

   </fmt:message>

</body>

</html>

</fmt:bundle>

------------------------------------------------------------------

4-2. properties 파일의 내용을 읽어갈 jsp 파일 작성(setBundle 태그 이용시)

setBunde 태그를 사용할 경우 setBundle 태그에 변수를 지정해서 페이지내에서

적용할 bundle를 선택적으로 사용할 수 있음

------------------------------------------------------------------

<%@ page contentType = "text/html; charset=euc-kr" %>

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

<fmt:setBundle var="msg" basename="bundle.message"/>

<html>

<head>

  <title><fmt:message bundle="${msg}" key="member_admin_title"/></title>

</head>

<body>

<fmt:message bundle="${msg}" key="member_admin_name"/>

<br>

 <fmt:message bundle="${msg}" key="member_admin_phone">

    <fmt:param value="${phone}" />

 </fmt:message>

</body>

</html>

------------------------------------------------------------------

 

(4) <fmt:requestEncoding value="인코딩값" />

- request.setCharacterEncoding()과 같이 전송된 데이터의 인코딩 처리

 

 

(fmt:formatNumber5) <fmt:setLocale value="로케일값" variant="브라우저 스펙" scope="범위" />

- 로케일 지정

value : 로케일 값 지정 ex) ko, en

 

(6) <fmt:bundle basename="properties파일경로및 파일명" prefix="prefix">....</fmt:bundle>

- 국제화를 적용을 위해 properties 파일경로 및 파일을 읽어와서 언어 적용

 

basename :  사용할 언어별 데이터가 key와 value의 쌍으로 작성된 properties 파일의 경로및 파일명 지정

prefix :  bundle 태그 내에서 message 태그를 통해 value를 읽어올 때 key속성 앞에 접두사 지정

 

(7) <fmt:message key="메시지의 key값" bundle="setBundle 태그를 통해 로딩한 번들을 얽어올 때 사용함" var="변수명" scope="범위" />

- 국제화를 적용한 메시지의 key에 대한 value를 호출

 

key : 메시지의 key값을 통해 value 호출

var :  변수명을 지정하면 message태그를 출력기능을 상실하고 변수를 out 태그 또는 el를 통해 호출 하여 value를 출력해야 함

 

(8) <fmt:setBundle basename="properties파일경로및 파일명" var="메시지를 저장할 변수명" scope="범위" />

- 페이지 전체에서 사용할 번들을 지정

 

(9) <fmt:formatNumber value="Number로 형식화할 수치 데이터"

                           type="숫자, 통화, 퍼센트 중 하나{number|currency|percent}"

                           pattern="사용자 지정 패턴"

                           currencyCode="통화코드지정"

                           currencySymbol="통화기호"

                           groupingUsed="{true|false}출력시 그룹 분리 기호(,) 

                                포함여부"

                           maxIntegerDigits="출력시 integer 최대 자릿수 지정"

                           minIntegerDigits="출력시 integer 최소 자릿수 지정"

                           maxFractionDigits="출력시 소수점 이하 최대 자릿수 지정"

                           minFractionDigits="출력시 소수점 이하 최소 자릿수 지정"

                           var="변수"

                           scope="범위" />

- 수치 데이터를 숫자, 통화, 퍼센트로 변환


 

(10) <fmt:parseNumber value="Number로 파싱할 수 있는 수치 데이터"

                            type="숫자, 통화, 퍼센트 중 하나{number|currency|percent}"

                            pattern="사용자 지정 패턴"

                            parseLocale="로케일지정"

                            integerOnly="integer로만 파싱할지 지정"

                            var="변수"

                            scope="범위" />

- 문자열에서 숫자로 파싱

 

(11) <fmt:formatDate value="형식화할 날짜와 시간 데이터"

                          type="{time|date|both}"

                       deteStyle="{short|full}"

                       timeStyle="{short|full}"

                       pattern="사용자 지정 패턴"

                       timeZone="타임존 지정"

                       var="변수"

                       scope="범위" />

- 날짜에 형식 지정

 

(12) <fmt:parseDate value="파싱할 날짜 데이터"

                       type="{time|date|both}"

                       dateStyle="{short|full}"

                       timeStyle="{short|full}"

                       pattern="사용자 지정 패턴"

                       timeZone="타임존 지정"

                       parseLocale="로케일 지정"

                       var="변수"

                       scope="범위" />

- 문자열에서 날짜로 파싱

 

(13) <fmt:setTimeZone value="타임존 지정"

                               var="변수"

                            scope="범위" />

- 타임존 지정

 

value : ex) Australia/Brisbane, America/New_York 등등

 

(14) <fmt:timeZone value="">....</fmt:timeZone>

- 타임존 지정

 

value : ex)GMT, KST, UTC

 

 

 

'WEB > ✿JSP' 카테고리의 다른 글

[JSP] 🔗/MVC (2) 실습  (0) 2022.01.25
[JSP] 🔗MVC  (0) 2022.01.20
[JSP] 🔗모델1 구조(3) 실습  (0) 2022.01.18
[JSP] 🔗모델1 구조(2) 실습  (0) 2022.01.15
[JSP] 🔗JDBC와 커넥션 풀  (0) 2022.01.15

댓글