[Info]Tags categorized posts and contents patterns..

[AJAX] Ajax Code E xamples.. [Book] About the book.. [CSS] CSS Code E xamples.. [DB] Sql Code E xamples.. [DEV] All development stor...

레이블이 템플릿인 게시물을 표시합니다. 모든 게시물 표시
레이블이 템플릿인 게시물을 표시합니다. 모든 게시물 표시

2016년 2월 24일 수요일

[JS]Template사용시 페이지 별로 Javascript 초기화 코드 다르게 하기..

출처 : Outsider's Dev Story https://blog.outsider.ne.kr/

보통 웹사이트를 구축하면 헤더나 푸터등 공통된 부분이 있기 때문에 이런 부분은 별도로 만들어서 공통으로 사용하게 한다. 각페이지에 헤더,푸터파일을 인클루드해서 사용할 수도 있지만 그렇게 되도 반복코드가 많이 발생하니까 일반적으로는(그냥 내 생각에.. ㅡ..ㅡ) 템플릿 파일을 만들고 contents부분만 바꿔가면서 사용하지 않을까 싶다.(일단 난 그렇게 한다 ㅡ..ㅡ 전에 올렸던 포스팅처럼...)

이렇게 할때 가장 큰 문제가 자바스크립트 초기화 코드이다. 항상 바꿔치기할 contents부분은 <body>의 정중앙에 들어있는데 보통 스크립트는 <head>안에 있거나 <body>맨아래 있단 말이지. contents부분에 들어갈 페이지에 스크립트코드를 같이 써줘도 되기는 하지만 완성된 html에서 중간에 스크립트 코드가 들어가기 때문에 별로 좋은 방법은 아니라고 본다.

여기서 초기화코드라는 것은 머 여러가지가 될수 있는데 쉽게 페이지 로딩후(onload)에 자동으로 수행할 함수를 말한다. 가장 많이 쓰는데 이벤트 핸들러 등록이라던가 하는거고 onload후에 focus를 어디에 둔다던지 하는등의 코드를 말한다. 페이지가 다 다르게 생겼으므로 이런 코드도 다 다를 수 밖에 없는데 contents에 들어갈 페이지에서는 이걸 다룰수가 없다는게 고민거리였다. 물론 if-else문으로 해당 엘리먼트가 있는지 라든가 페이지 주소를 이용해서 억지로 할수야 있겠지만 쓸데없이 검사해야 하기 때문에 성능도 떨어지고 별로 아름답지 못한 방법같았다. 이벤트 핸들러의 경우 html 엘리먼트에 직접 써넣는게 일반적이지만(<input type="button" onclick="test();"> 이렇게...) 요즘 추세는 자바스크립트도 완전히 분리하는 것이기 때문에 이걸 분리하자면 초기화코드가 꽤 많아진다. (이게 Unobtrusive Javascript.... 이렇게 하면 디자인 바뀌어도 많이 손 안대도 된다. 물론 Unobtrusive Javascript가 말하고자 하는건 저게 중점은 아니지만 개인적으로는 큰범주에서 보면 같은 흐름이라고 생각한다.)


어쨌든 이번에 플젝하면서는 이걸 좀 해결해 보고 싶었기 때문에 OKJSP에 질문글을 올렸더니 임은천님이 답변을 해 주셨다.(거의 익명사이트긴 하지만 도움얻은걸 혼자한척 하진 않는다.. ㅡ..ㅡ) 딱 내가 기다리던 명쾌한 답변.... 너무 자세하게 답변을 주셔서 구현하는데 별로 어렵지 않았다.


1
2
3
4
5
6
7
document.observe('dom:loaded', function() {
    <% if (request.getAttribute("jsDispatcher") != null && !request.getAttribute("jsDispatcher").equals("")) { %>
    var dispatcher = new Dispatcher();
    var jdName = "<%= request.getAttribute("jsDispatcher") %>";
    eval(dispatcher.get(jdName));
    <% } %>
}); }

위의 코드를 Template의 부모(?)가 되는 페이지의 스크립트 부분에 넣어준다. 물론 저 코드는 Prototype Framework의 코드이다. 쉽게 가자면 window.onload에다가 이벤트를 건거다. 여기선 JSP코드니까 JSP로 jsDispatcher이 파라미터로 넘어왔는지를 검사하고 jsDispatcher값이 있으면 디스패쳐를 실행한다. 물론 템플릿에 어떤 페이지를 contents부분에 띄워줄지 파라미터로 넘겨줄때 jsDispatcher의 값도 같이 넘겨주어야 한다. 어차피 템플릿으로 구성되는게 구현되어 있을테니까 파라미터 하나 더 넘겨주는건 그리 어렵지 않은 일이다.

디스패쳐가 각 jdName별로 실행할 함수목록을 가지고 있고 파라미터로 넘겨받은 jsDispatcher의 이름으로 디스패쳐에다가 조회해서(get) 해당 실행할 함수들을 가져오고 그자리에서 eval()해서 실행해 버리는거다. 이것 자체가 window.onload때 실행되니까(Prototype.js의 dom:loaded는 약간은 다른의미지만 여기선 별로 중요하지 않다.) 디스패쳐로 가져온 값도 페이지 초기화코드로 실행된다. 물론 여기서 Dispatcher은 이어서 만들 클래스이다. 원래 제공되는게 아니라...

그럼 Dispatcher클래스를 보자.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var Dispatcher = Class.create();
Dispatcher.prototype = {
    initialize : function() {},
    get : function(name) {
        return this.map[name];
    },
    map : { listform: 'ListenerCollection.registEventListFrom()',
                  writeform: 'ListenerCollection.registEventWriteFrom()',
                  modifyform: 'ListenerCollection.registEventModifyForm()'
    }
}

var ListenerCollection = {
    registEventListFrom: function() {
        // 리스트 페이지의 초기화 코드들
    },
    registEventWriteFrom: function() {
        // 작성 페이지의 초기화 코드들
    },
    registEventModifyForm: function() {
        // 수정 페이지의 초기화 코드들
    }
}

여기에는 Dispatcher와 ListenerCollection 2가지 클래스가 있다.(Prototype.js의 관점에서는 Dispatcher만 클래스이지만 그냥 넘어가자.)

Dispatcher클래스는 3가지 매서드가 있다.  initialize는 보는바와같이 아무것도 없는데 prototype.js의 클래스에선 필수로 만들어주어야 하는거라서 신경안써두 되고 get하고 map이사용할 메서드이다. map은 넘겨받은 이름과 함수가 쌍으로 맵핑되어 있고 get에서 넘겨받은 name으로 map에서 찾아서 해당 함수를 돌려준다.

ListenerCollection은 등록할 이벤트리스너(꼭 이벤트리스너일 필욘 없지만)의 코드목록을 담는 곳이다. map내애서 funcion(){}으로 바로 적어줄 수도 있지만 코드량이 많아서 분리했다. 약간 꼬아놔서 그렇지 구조는 별로 어렵지 않다.

이렇게 하면 템플릿을 유지하면서도 페이지별로 초기화 자바스크립트 코드를 따로 둘 수 있다. 모든 페이지에서 이코드가 들어가긴 하지만 위쪽에서 onload로 이벤트를 건 곳을 제외하고는 외부 js파일로 빼면 어차피 캐시가 되기 때문에 성능면에서는 별로 신경안써도 될듯하다. prototype.js를 기반으로 작성되서 prototype.js를 안써본 사람은 약간 코드이해에 어려움이 있을까 좀 걱정되긴 한다...

2016년 2월 23일 화요일

[JS]prototype.js에서 HTML엘리먼트 생성에 Template 객체 사용하기..

출처 : Outsider's Dev Story https://blog.outsider.ne.kr/

prototype.js에서는 Template이라는 정해진 형식의 문자열을 생성해 주는 객체를 제공하고 있다. Template는 어떤 정해진 문자열(또는 HTML)을 반복해서 찍어낼 때 아주 유용하다.(한번만 사용할꺼라면 당연히 Template를 쓸 일이 없기 때문에...)

사용법은 아주 단순하다.
JavaScript

var tpl = new Template('<div><ul><li>test</li></ul></div>');
tpl.evaluate("");

해주면 된다. 물론 저코드는 아무동작도 안한다.  템플릿 결과로 나온 걸로 어떤 액션을 주지 않았기 때문에 tpl.evaluate("")의 결과값으로 Template로 만든 String이 리턴되기 때문에 저런식으로 만든 HTML을 원하는 위치에 삽입해 주면 된다. 위 코드에서는 사용법을 예시로 들기 위해서 evaluate()의 파라미터로 빈문자열("")을 파라미터로 주었는데(없으면 에러가 나기 때문에...) 머 다른 변수를 주어도 상관이 없다.

저 정도만으로는 그다지 유용하지 않은데 당연히 그럴리가 없다. 템플릿안에 #{fieldName}라는 식별자를 통해서 객체의 값을 받을 수 있다.
JavaScript

var tpl = new Template('<div><ul><li>#{id}</li><li>#{nickname}</li><li>#{job}</li></ul></div>');
var obj = { id:'rockdoli', nickname:'Outsider', job:'Web Developer'};

tpl.evaluate(obj);
// output : <div><ul><li>rockdoli</li><li>Outsider</li><li>Web Developer</li></ul></div>

위 처럼 탬플릿에 #{fieldName}를 사용할 경우 넘겨받은 객체에서 해당 이름으로 값을 찾아서 해당 값으로 교체한다 원하는 이름과 매치되는 값이 없을 경우에는 아무값도 넣지 않는다. 이걸 사용하면 원하는 엘리먼트를 자유롭게 생성해 낼 수 있다.  prototype.js의 Enumerable을 이용해서 다음과 같이 사용할수가 있다.(이렇게 하는게 제일 편한듯...)
JavaScript

var tpl = new
Template('<div><ul><li>#{id}</li><li>#{name}</li><li>#{age}</li></ul></div>');
var obj = [{id:'1', name:'Steve', age:'24'},
           {id:'2', name:'Mike', age:'30'},
           {id:'3', name:'Julie', age:'19'}]
obj.each(function(w) {
    tpl.evaluate(obj);
});

위처럼 사용하면 원하는 위치에 값을 바꿔가면서 쉽게 반복해서 찍어낼 수 있다.

var tpl = new Template('<div><ul><li>#{id}</li><li>\\#{nickname}</li><li>#{job}</li></ul></div>');

escape도 있는데 위처럼 역슬래시 2개(\\)르 사용하면 #{nickname}부분은 해당값으로 치환하지 않고 #{nickname}가 그대로 찍힌다.

2016년 2월 19일 금요일

[JSP]JSP 템플릿 사용하기..

출처 : Outsider's Dev Story https://blog.outsider.ne.kr/

개발을 할 때 어찌됐든 가장 신경써야 하는 것중 하나는 DRY(Don't Repeat Yourself)이다. 실용주의 프로그래밍같은 쪽에서 항상 강조하는거고... 유지보수 해보면 코드를 모듈화해서 재사용성이 얼마나 중요한지 피부로 느낄수 있다.(메뉴 글자 하나 바꾸는거 똑같은거 열몇개씩 계속 해보면... ㅋ 꼭 한번에 말안하고 다 바꾸면 변경사항 또 얘기해주고.. ㅋ )

JSP에서도 forword기능을 사용해서 페이지의 공통부분을 템플릿으로 뽑아내서 공통으로 사용할 수 있다. 예를 들어 모든페이지에 똑같은 로고, 상단메뉴, 사이드메뉴, 푸터 등등 어느 페이지나 공통으로 들어가는 틀을 가지고 있는 템플릿을 사용해서 코드작성을 줄일수 있다. 참고로 말하자면 이건 MVC Model 1정도에서 쓰일 방법이라고 생각한다. 고급으로 갈수록 이런 걸 대체할 수 있는 용도의 것들이 많이 존재하고 있으니까...(나두 Model 2에 JSTL하고 싶다규 ㅠ..ㅠ)

Java Jsp
[햄한테서 가져올 때는 Java 였지만, 아무래도 Jsp 가 맞는듯 해서 바꿨다..
물론, 전체적으로 봤을 때 Java 가 될 수도 있지만, 현재 저 소스만 봐선.. Jsp 내에서..
다른 Jsp 로 forward 하는 듯하기 때문에..]

<jsp:forward page="template.jsp">
    <jsp:param name="CONTENT" value="introView.jsp" />
</jsp:forward>


예를 들어 사이트 소개페이지인 intro.jsp를 위처럼 만든다. 아무것도 하는 일이 없다. 페이지를 받자마자 template.jsp로 요청을 포워딩해준다. forward는 요청을 그대로 포워딩하는 것이기 때문에 포워딩된 후에도 주소창에는 그냥 intro.jsp가 있다. 페이지를 템플릿으로 포워딩하면서 introView.jsp라는 파일명을 파라미터로 넘겨준다.

그럼 template.jsp를 보자.

Html

<%
    String content = request.getParameter("CONTENT");
%>
<html>
    <head></head>
    <body>
        <jsp:include page="/template/header.jsp" flush="false" />

        <jsp:include page="/template/mainMenu.jsp" flush="false" />

        <jsp:include page="<%= content %>" flush="false" />

        <jsp:include page="/template/footer.jsp" flush="false" />
    </body>
</html>



html코드는 별로 중요하지 않으니 간략화 했다. 탬플릿페이지를 가지고 있고 템플릿이 각 부분(위에서는 헤더, 메인메뉴, 푸터)의 공통파일을 불러들이고 바뀌어야 하는 부분만 content변수를 이용해서 다른 파일을 불러온다. 이렇게 하면 공통적인 곳의 코드는 한파일에서 관리하고 상황에 따라 어느정도 유연하게 템플릿파일을 구성해서 사용할 수 있다. 그리고 위의 예제에서는 3번째 include에서 파라미터로 받은 introView.jsp를 인클루드 한다. 바뀌는 부분의 파일명만 변수로 설정하여 원하는대로 바꾸어서 출력할 수 있다.

flush는 true일 경우 인클루드 전에 현재 있는 버퍼를 출력한다. 보통 false를 사용하는 듯한대 상황에 따라 선택할 나름이다. 인클루드에도 파라미터를 forwoard사용시와 동일하게 넘겨줄 수 있지만 이런식에 구성에서는 intro.jsp가 받은 파라미터를 템플릿이나 include되는 파일내에서 모두 getParameter로 받을수 있기 때문에 아주 특이한 경우 아니면 템플릿에서 파라미터를 넘겨줄 필요는 없을 듯 하다.(너무 믿지는 마시길.. ㅎㅎ) 이제 introView.jsp에 원하는 내용부분을 작성하면 된다.





여기서 인클루드를 사용할 때 동적으로 할지 정적으로 할지는 약간 생각해 보아야 할 문제이다. 파일 인클루드는 <jsp:include>액션태그(동적)와 include 디렉티브(정적) 2가지 방식이 있다.

<jsp:include page="introView.jsp" flush="false" />
<%@ include file="introView.jsp" %>

위 두 코드는 보이는 면 동일하게 동작을 한다. 하지만 동작방식 자체는 완전히 다른데 동적과 정적이라는 말에서도 느낄 수 있듯이 액션태그로 사용하면 페이지가 요청할 때마다 인클루드 페이지를 실행하고 결과를 가져와서 인클루드 하는 방식이고 디렉티브 방식으로 하면 jsp를 처음 컴파일 할 때부터 인클루드 할 페이지의 소스를 가져와서 해당위치에 넣은 후에 컴파일을 한다. 컴파일된 입장에서 본다면 디렉티브를 사용하면 하나의 파일이나 마찬가지란 얘기다.

이 방식을 이해하면 몇가지 더 생각해야 할 부분이 있다. 액션태그로 하면 모든 jsp가 다른 파일이나 마찬가지기 때문에 모든 변수를 새로 정의해 주어야 한다. 파라미터도 파일마다 따로 받고.... 보여주고자 하는 intro.jsp의 입장에서는 같은 변수나 파라미터를 여러번 정의하고 받아오는 것이다. 반면 디렉티브 방식은 결국은 하나의 파일이 된다고 했다. 그래서 template이나 다른 인클루드 파일에서 정의한 변수를 또다른 인클루드에서 정의할 경우는 변수가 중복되기 때문에 에러가 난다.

또한 디렉티브 방식은 소스가 바뀔때 반드시 재컴파일 되는것을 보장해주지 않는다고 한다. 그리고 완전히까지는 분석되지 않았는데 액션태그 방식을 사용하던 중 특정 인클루드된 파일이 갱신되지 않고 계속해서 임시인터넷 파일에서 나와서 캐시사용을 막아주어야 했었다.. ㅜ..ㅜ  물론 속도면에서는 디렉티브 방식이 당연히 빠르다. 그리고 또한유지보수 할 때 자신이 만든 소스가 아니면 변수추적을 해야 되는데 이렇게 파일이 쪼개져 있을 경우 상당히 쉽지 않다. 액션태그 방식은 그나마 괜찮지만 디렉티브 방식을 사용하면 변수선언이나 할당등이 다른 파일에 있을 경우가 많기 때문에 추적하기가 만만치 않다. 어느쪽이 좋을지는 자신이 상황에 맞게 선택할 일이다.

2016년 2월 16일 화요일

[HTML]HTML 4.01 Transitional 문서 템플릿..

출처 : Outsider's Dev Story https://blog.outsider.ne.kr/


<!-- HTML 4.01 Transitional Template -->
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
<html lang="ko">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <title>Untitled Document</title>

        <link rel="stylesheet" href="" type="text/css" />
        <style type="text/css">
        </style>

        <script type="text/javascript" src=""></script>
        <script type="text/javascript">
        //<![CDATA[
        //]]>
        </script>
    </head>

    <body>
    </body>
</html>

계속 XHTML만 쓰다보니까 HTML 4.01 갑자기 만나니까 영~ 헤매게 되어버려서.... 적어놔야지... ㅎ