-
JSP 커스텀 태그/웹 프로그램의 전반적인 흐름TIL(Today I Learned) 2022. 9. 20. 22:55
커스텀 태그란?
커스텀 태그란 사용자가 직접 태그를 설정하고 사용하는 태그를 의미하는데요~ 커스텀 태그 방식이 주는 장점은 꽤 많답니다 ㅎㅎ
커스텀태그가 주는 장점은?
- HTML에 스크립트 코드를 비교적 적게 사용할 수 있게 해줍니다.(프론트 개발자가 편리해집니다. 가독성과 유지보수성이 증가하거든요)(커스텀 태그는 HTML에 사용되는 자바코드 수를 줄여줄 수 있어요 왜냐하면 태그핸들러에 중복되는 자바코드를 정리하는 방식이기 때문에 여기에 포함된 자바코드를 수정할 땐 태그핸들러만 수정하면 되는거에요)
- 커스텀 태그 제작 후 다른 사용자에게 배포하여 공용으로 사용가능해요.(제작하고 함께 사용할 수 있어서 재사용성이 좋아요)
커스텀태그의 생성 흐름은?
1. 직접 사용자 태그를 처리하는 클래스를 만듭니다. (이러한 클래스를 Tag Handler라고 칭해요) 태그 핸들러 클래스에는 SimpleTagSupport 클래스를 반드시 상속해야 합니다!
(여기서 잠깐!)
SimpleTagSupport 클래스는 무엇일까요?
커스텀태그를 만든다는 것은 태그 핸들러를 만든다라고 표현할 수 있을 정도로 태그핸들러는 중요해요! 그런데 태그핸들러를 만드는건 쉽지 않아요 자바프로그래밍을 잘해야 하거든요ㅠㅠ 그래서 고수분들이 편의성을 제공하고자 SimpleTageSupport 클래스를 만들어주셨어요! 우리는 이 클래스를 상속해서 @Override하고 주어진 틀대로 구현하기만 하면 돼서 커스텀태그를 만드는게 훨씬 쉬워졌어요.
2. 사용자 태그에 대한 정보를 기술하고 있는 Tag Library Descripter(TLD) 파일을 작성해요. 이 파일은 xml 형식으로 구성되어 있어요.
3. 마지막으로 jsp 파일 지시자에 tld 파일의 경로와 prefix를 기재하면 사용 가능해져요 ㅎㅎ
번외) namespace에 대해서
namespace의 의미는 이러해요 우리가 대화를 할 때 아무 맥락 없이 그냥 '배'라고 하면 그 배가 과일의 배인지 바다의 배인지 알 수 없잖아요? 그래서 과일:배 또는 바다:배와 같이 구분해줄 수 있도록 하는게 namespace입니다. 커스텀 태그나, JSTL에서의 namespace는 prefix라고 봐도 될 것 같네요(예시) prefix="c" 또는 prefix="tag"..등)
tld 파일에 대해서
tld 파일은 xml 형식의 파일이에요. 이 파일은 Jsp에서 사용자 태그를 어떻게 사용할지 정의해주는 파일이죠 사용예시는 아래와 같아요
<tag> <name>welcom</name> <tag-class>ch19.WelcomeTag</tag-class> <body-content>empty</body-content> </tag>
(원래는 위 코드 말고도 taglib라는 루트 태그와, tlib-version, jsp-version, short-name이라는 기본 태그들이 존재하지만 생략했어요.)
위 코드에서 name은 사용자 태그의 이름을 지정한거에요. 여기서 지정한 사용자 태그의 이름을 Jsp 파일에서 아래 코드와 같이 사용할 수 있습니다.
<tag:welcome/> //tld 파일에서 name으로 설정된 태그핸들러 클래스를 가져옵니다. // 만약 태그 핸들러 클래스에서 "기분 좋은 하루"라는 출력을 하라는 로직이 있다면 화면에는 // "기분 좋은 하루"라고 출력이 될 것 입니다.
이번에는 tag-class에 대해서 설명해볼게요 tag-class는 핸드 클래스가 위치한 경로를 의미합니다.
다음으로 body-content를 설명해볼게요 이 태그는 사용자 태그의 몸체가 있는지 없는지의 여부를 지정하는데요 여기에서 몸체는 아래와 같은 코드에서 설명하겠습니다.
<tag:welcome/> 또는 <tag:welcome></tag:welcome> // 몸체가 없는 경우입니다. 이럴 때는 body-content에 empty를 선언해줘요 <tag:welcome>Hi everyone<tag:welcome/> // 몸체가 있는 경우입니다. 이럴 때는 scriptless라고 선언해줘요
만약 body-content 태그에 scriptless가 선언된다면 태그 몸체에 스크립트릿 코드, 스크립팅 표현식, 선언문 등이 들어갈 수 없고, 템플릿 텍스트, EL, 커스텀태그, 표준액션 등만이 선언 가능해집니다. 기본 값으로는 scriptless 설정되어 있어요
태그 핸들러의 예시를 한번 작성해볼게요
public class WelcomBodyTag extends SimpleTagSupoort{ @Override public void doTag() throws JspException, IOException{ //doTag() 메서드는 SimpleTagSupport 클래스에 정의된 메서드로 jsp 페이지에서 태그가 호출되면 자동적으로 이 메소드가 호출되고 실행합니다. JspContext context = getJspContext(); JspWriter out = context.getOut(); JspFragment body = getJspBody(); out.println("환영합니다."); StringWriter strw = new StringWriter(); //문자열을 담아주는 객체입니다. body.invoke(strw); // jsp에 body 부분에 쓰인 즉, body-content 부분에 선언된 값이 strw에 담깁니다. String str = strw.toString(); // strw는 현재 jsp의 body 값입니다. 그 값의 문자열을 str에 저장합니다. for(int i = 0; i<5; i++){ out.println(i+1+"."+str+); } } }
커스텀 태그는 속성 값을 사용할 수 있습니다.
여기서 말하는 속성 값이란 html에서 <input type="" name="" value=""> type, name, value와 같은 것을 의미합니다.
커스텀 태그에서의 속성 값은 아래 코드와 같이 jsp 파일에서 선언됩니다.
<tag:page from='<%=start%>' to='<%=end%>'/>
위 코드와 같이 속성 값을 사용하기 위해선 tld 파일에 Attribute 태그를 따로 설정해주어야 합니다.
<tag> <attribute> <name>from</name> <type>java.lang.Integer</type> <rtexprvlaue>true</rtexprvlaue> </tag>
와 같이 선언됩니다.
name은 jsp에서 사용 될 속성명 입니다. 이 속성명은 좀 이따 설명할 내용에 중요한 부분이니 기억해두시길 바랍니다.
type은 사용자 태그에서 사용된 속성의 data 타입을 지정해줍니다. java.lang.String과 같은 값도 올 수 있습니다.
여기서부터 중요한데 태그 핸들러 부분입니다.
public class PageTag extends SimpleTagSupport { private int from; private int to; public void setFrom(int i){ this.from = i; } public void setTo(int i){ this.to = i; }
커스텀 태그에서 속성을 사용하기 위해 setXxx 형식으로 선언해줘야 합니다. 그런데 특이한 점은 jsp에서는 setFrom(8)과 같은 형식으로 선언해주지 않는다는 것입니다.(<tag:page from='<%=start%>' to='<%=end%>'/>)와 같이 선언됩니다.
보시면 메서드 호출 방식이 아니죠? 그 이유는 아까 중요하다고 말씀 드렸던 name 부분에 있습니다. name 부분이 필드명과 일치한다면 set필드명 메서드가 존재할 때 알아서 인자 값을 셋해주고 반환해준다는 것입니다. 이렇게 함으로써 setXxx와 같은 자바코드를 몰라도 프론트 개발자 분들은 쉽게 값을 출력할 수 있게 되겠죠?
(제 생각인데 이 방식은 <jsp:setProperty> 액션 태그와 유사한 성질이 있는 것 같습니다. 이 액션태그도 필드명과 파라미터명만 같다면 알아서 beans에 set 해주니까요)
커스텀태그로 스크립트 변수 생성하기
스크립트 변수란 무엇일까요? 아래 코드에 정답이 있습니다 ㅎㅎ
<jsp:useBean id="db" class="ch20.DBConnection"> //id 값인 db가 스크립트 변수입니다
우리는 이러한 스크립트 변수를 직접 만드는 방법을 알아볼건데요.
스트립트 변수 선언 과정은 대략 아래와 같습니다.
1. TLD 파일 작성
1-1. <tei-class>태그가 필요합니다 아래 코드는 예시입니다.
<tag-class>ch19.ConnectionTag</tag-class>
1-2. 스크립트 변수에 id 속성이 들어가는 만큼 attribute 태그도 필요하겠죠, 다만 여기에는 type이 선언되지 않습니다.
2. Helper 클래스 작성
2-1. 스크립트 변수를 만들기 위해 필수적으로 선언해줘야 하는 클래스입니다
2-2. 태그핸들러에서 SimpleTagSupport를 상속 받았듯이 Helper 클래스는 TagExtraInfo라는 클래스를 상속 받습니다.
2-3. getVariableInfo(TageData data) 메소드를 작성합니다. 이 메소드는 스크립트 변수에 대한 정보를 제공해주는 메소드입니다.
3. 스크립트 변수와 관련된 클래스 작성
3-1. 만약 DB 연결을 위한 스크립트릿 변수를 생성한다면 DBConnection 클래스를 생성합니다.
3-2. DBConnection에는 DB 연결을 위한 DB 정보 즉, url, user, password, Driver 값 들과 디폴트 생성자가 있습니다. 여기서 설명하는 디폴트 생성자는 필수적으로 선언되어야 합니다.
4. 태그 핸들러 작성
4-1. 직접 처리를 담당하는 태그핸들러를 작성합니다.
4-2. jsp 페이지에서 사용자 태그를 사용하여 Connection을 가져오려고 할 때, getJspContext() 메소드를 이용하여 jsp 페이지에서 사용하는 스크립트 변수와 관련 클래스(DBConnection)의 객체를 연결 시켜줘야 합니다.
getJspContext().setAttribute(id, new DBConnection());
위 코드와 같이 id 속성에 DBConnection() 객체를 담아줍니다.
5. 마지막으로 jsp에서 스크립트 변수를 사용합니다.
<tag:db id="db"/> //스크립트 변수 명 = "db" Connection conn = db.getConnection(); // id에 담긴 DBConnection 객체안에 있는 getConnection() 메서드를 사용할 수 있게 되어 이와 같이 선언했습니다.
스크립트 변수에서 DB를 연결한 것을 보면 자바 코드가 거의 없어 가독성이 정말 좋고 객체가 분리되어 있어서 유지보수성도 증가했다는걸 쉽게 느낄 수 있어요.
웹 프로그램의 전반적인 흐름
클라이언트에서 즉, 브라우저에서 사용자가 어떤 요청을 했을 때의 웹 프로그램의 전반적인 흐름을 간략하게 알아볼거에요.
일반적으로 사용되는 흐름은 client -> WebServer -> WAS -> DB 에요 이 방식을 전체적으로 정리하고 마무리하도록 할게
JSP의 내부 동작
클라이언트에서 요청 받음(HttpRequest 전달 받습니다.) WebServer는 정적 파일만 반환할 수 있기 때문에 동적 처리를 하기 위해 WebContainer로 요청을 전달합니다.
-> JSP 파일을 Servlet으로 변환(.java)합니다.(서블릿을 메모리에 적재했다고 표현할 수 있을 것 같습니다.)
-> Servlet 파일(.java) 컴파일 하여 .class 파일로 변환합니다.(이 파트부터는 웹컨테이너 파트라고 보시면 될 것 같습니다.)
Servlet 내부에선 전달 받은 요청(request)마다 thread를 생성합니다.(스레드의 갯수는 스레드풀에 스레드 수를 미리 저장해놓고 꺼내서 쓰는 방식입니다.)
(여기서 유의할 점은 request 마다 스레드를 새로 생성하거나 미리 저장해놓은 스레드를 가져와 사용하는 것이지 서블릿 인스턴스를 새로 생성하는 것은 아니라는 것입니다.)
(여기서 설명하는 서블릿 인스턴스는 HttpServeltRequest와 HttpServeltResponse를 의미합니다. 이 인스턴스는 바로 아래의 설명에 등장합니다. 그리고 서블릿 인스턴스는 init()메서드가 아닙니다.)
-> 각각의 thread에서 필요한 메서드(doPost 또는 doGet)를 호출합니다.
-> 서블릿 객체(인스턴스) 생성 HttpServeltRequest, HttpServeltResponse
-> 서블릿 분석(web.xml)(url mapping)(서블릿이 알맞은 url을 찾기 위해 개발자가 mapping을 설정해줘야합니다.)
-> 찾은 서블릿에서 init()메서드 생성(서블릿 생명 주기중 한번만 호출, 서블릿 클래스를 초기화하는 것입니다.(읽어들인다라고 해석하면 편할 것 같습니다))
(init() 메서드가 쓰이는 이유는 한번 초기화가 된 서블릿 클래스는 다시 초기화를 하지 않고 재사용하기 위함입니다. 이렇게 함으로써 부하를 줄일 수 있습니다.)
-> service() 호출
-> 적절한 doPost(), doGet()을 실행하고 결괏값을 HttpServletResponse 객체에 응답을 보냅니다. 이는 HttpResponse 형식으로 클라이언트에 전달합니다.
-> 응답이 모두 끝난후 HttpServeltRequest, HttpServeltResponse를 제거합니다.
-> 서블릿 컨테이너가 종료되면 destroy() 메서드 호출(즉, 톰캣이 종료되기 전까지는 destroy()메서드를 호출하지 않습니다.)서블릿 인스턴스는 WAS의 인스턴스라고 생각하시면 편할 것 같습니다. 그래서 서블릿에서 생성하는 스레드와 구분해야 하는 것이지요. WAS의 인스턴스는 톰캣을 기준으로 본다고 생각하시면 될 것 같습니다. 톰캣이 실행됐을 때부터 init() 메서드가 호출되고 톰캣이 종료되면 destroy() 메서드가 호출되는 것입니다.
Servlet life cycle HTTP란 무엇일까요?
HTTP란 www에서 웹서버와 사용자 사이의 약속된 통신 규약이에요 이 규약으로 인해 사용자가 요청한 값을 우리가 받을 수 있게 되는 것이지요. (HTTPS는 암호화된 HTTP에요)
WebServer란?
WebServer는 사용자가 요청한 값에서 정적페이지(html)을 보여주는 역할을 해요. 동적페이지는 반환해주지 못한답니다. 그래서 webContainer라는게 존재해요.
WebContainer란?
WebServer에서 처리하지 못하는 동적페이지 처리를 웹컨테이너에 보내줘요 그러면 웹컨테이너가 대신 처리를 해주고 정적페이지로 만든 후에 웹서버에 보내면 웹서버에서 다시 사용자에게 출력해주는 방식이에요
WAS란?
웹 애플리케이션이(jsp나 servlet이) 실행될 수 있도록 환경을 제공하는 소프트웨어(또는 미들웨어)에요. 예로 tomcat이 있겠네요. WAS는 WebServer와 WebContainer 둘다 가지고 있어요 그리고 둘을 구분하고 분리해요
분리하는 이유는?
성능 때문이에요 컨테이너에서 정적페이지와 동적페이지를 모두 처리한다면 부하가 심할 거에요. 그래서 분리 시켜준거죠 부하를 덜기위해. 다른 장점도 다양한데 찾아보시길 권장드려요 ㅎㅎ
Thread란?
Thread를 이해하는건 프로세스와의 차이점을 알아두는게 편해요. 일단 프로세스부터 설명드려볼게요
프로세스란?
프로세스란 하나의 요청 자원이라고 생각하시면 편해요. 그리고 이러한 요청 자원에는 그것을 실행하기 위한 하나의 스레드가 존재해요. 그리고 그 스레드가 여러개일 때는 멀티스레드라고 표현하는거죠.
프로세스를 많이 만드는건 비효율적이에요 왜냐하면 자원의 요청을 많이 만들게 되면 시스템 콜이 쌓이게 되는데 이게 과부하를 부르거든요(스레드를 다량으로 만드는 것보다) 그래서 하나의 프로세스에 여러개의 스레드를 만드는 방식이 더 유리하게 된거에요 그리고 덧붙여서 프로세스는 통신간의 비용이 스레드보다 더 커요 그래서 스레드를 사용하는게 부담을 더 덜어주는 것이 되는거죠. 하지만 스레드를 다량으로 만드는 작업은 동기화가 정말 중요해요 왜냐하면 스레드는 서로간의 자원을 공유하는 전역변수 방식을 사용하기 때문이죠. 그래서 프로그래머의 역량이 중요하게 됩니다. ㅎㅎ
마지막으로 Servlet에서의 프로세스와 스레드는?
Servlet에서의 프로세스는 저의 추측인데 사용자가 요청한 자원을 의미해요(클라이언트에서 어떠한 요청을 했을 때 발생하는 자원) 그리고 스레드는 그 요청한 자원을 처리하는 과정 즉, WAS(WebContainer 파트)라고 볼 수 있겠네요 ㅎㅎ
'TIL(Today I Learned)' 카테고리의 다른 글
동시성 문제란?/ JSP 지시어, 내장 객체의 간략한 설명 (2) 2022.09.24 JSP와 Spring framwork의 차이/ 네트워크 통신 간략한 정리 (2) 2022.09.22 TIL 55th day (0) 2021.12.17 TIL 54th day (0) 2021.12.16 TIL 53th day (0) 2021.12.14