반응형

신규 플젝에 투입되면서 공통 웹 개발파트를 맡게 되었다. 그놈의 웹개발은 그만하고 싶긴 한데, 하라면 해야지 뭐. 아무튼, 공통부라길래 그냥 공통 컴포넌트 정도 만지작거릴 줄 알았는데 그게 아니었고, 이번에 많이 배우는 듯 싶다.

 

서론 . tiles 추가하기에 앞서

현재 전자정부 프레임워크 4.2 버전을 사용중이다.

SI를 하건 뭘 하건 대부분의 웹 페이지는 다음과 같은 레이아웃 구조를 가지고 있다. 

 

저기서 상단의 Header , 좌측의 Nav, 하단의 Footer는 고정형 이미지이며 Body는 개발자들이 만들어내는 업무페이지라고 보면 된다. 처음에는 Header / Nav / Footer에 해당하는 JSP를 각각 만들고 Include하는 방식으로 생각했었는데 이거 아무리봐도 나이스하지가 않단말이다. 무슨 말이냐 하면, 

1
2
3
4
5
6
7
8
9
10
11
<div class="root-container">
    <%@ include file="/WEB-INF/jsp/commons/commLeft.jsp"%> <!-- 좌측 메뉴 -->
    <div class="container-wrap">
        <%@ include file="/WEB-INF/jsp/commons/commNav.jsp"%> <!--슬라이드 메뉴 -->
    </div>
    
    <!-- 요약을 많이 했지만 jsp 화면 컴포넌트가 여기들어감. -->
 
    <div class="footer-container">
    <%@ include file="/WEB-INF/jsp/commons/commFooter.jsp"%> <!-- 하단 푸터 -->
</div>
cs

 

 

이렇게 모든 공통 레이아웃들을 저렇게 주저리주저리 include해야 한다. 우리는 상단의 이미지와 같이 심플한 구조가 아니라 공통 헤더, 공통 타이틀, 공통 네비게이터, 공통 슬라이드 네비게이터, 공통 인피니트탭, 공통 푸터 까지 있으니 위와 같은 방식으로 include file하려면 여섯개는 더 있어야 한다.

 

가장 큰 문제는 무어냐, 저 포맷을 고대로 갖다 써서 수많은 div태그를 뚫고 업무 화면을 그려내면 좋으련만, 저건 아주 극도로 축약한 div 태그들일 뿐이고 실제로는 약 100여줄에 가까운 태그들이 난무를 하고 있다는거다.

그럼 당연히 개발자의 실수 하나로 레이아웃이 모조리 깨지기도 하고 가독성도 너무 구려서 개발 난이도가 올라간다. 이럴때 무엇을 쓴다? apache tiles다.

tiles를 적용함으로 인해 공통으로 사용하는 레이아웃은 그대로 공통부에서 처리하고 업무 화면을 지정한 div태그의 어딘가에 끼워넣는 개념이라고 보면 된다. 즉, tiles로 사전에 레이아웃을 설정하고 특정 영역만 호출하는 개념이다. 이마리야.

 

1. tiles 적용 - pom.xml

tiles를 적용하기에 앞서 기본적인 레이아웃에 대한 작업은 퍼블리셔분께서 작업해주셨다고 가정한다. 이것까지 하다간 난 죽을지도 모른다. 아무튼, pom.xml에 다음과 같이 추가했다. GPT는 몇개 안넣어줬는데 돌려보니 계속 오류가 나서, 보태보태 병에 걸려 저렇게까지 추가하고 성공함.

<dependency>
  <groupId>org.apache.tiles</groupId>
  <artifactId>tiles-core</artifactId>
  <version>3.0.8</version>
</dependency>
<dependency>
  <groupId>org.apache.tiles</groupId>
  <artifactId>tiles-jsp</artifactId>
  <version>3.0.8</version>
</dependency>
<dependency>
  <groupId>org.apache.tiles</groupId>
  <artifactId>tiles-servlet</artifactId>
  <version>3.0.8</version>
</dependency>
<dependency>
  <groupId>org.apache.tiles</groupId>
  <artifactId>tiles-api</artifactId>
  <version>3.0.8</version>
</dependency>
<dependency>
  <groupId>org.apache.tiles</groupId>
  <artifactId>tiles-el</artifactId>
  <version>3.0.8</version>
</dependency>

 

라이브러리들 이름이 참 쉬우니 대충 알아들을건데 뭐 tiles라이브러리 코어모듈, jsp 모듈, 서블릿 제어모듈, api 호출모듈, el 명령어 모듈 정도로 네이밍이 된 듯 싶다. 확실한것인지는 잘 몰루. 아무튼. 여기까지 하고 maven update~ 한다.

 

2. tiles.xml 설정

pom.xml에 라이브러리를 추가했다면 다음은 tiles.xml을 설정해준다. 공통 레이아웃을 무엇을 쓸지 선언하는 부분이라 보면 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<tiles-definitions>
    <!--공통 레이아웃 정의 -->
    <definition name="tilesbase" template="/WEB-INF/jsp/commons/commLayout.jsp">
        <!--상단 헤더 -->
        <put-attributename="header" value="/WEB-INF/jsp/commons/commHeader.jsp"/>
        <!--좌측 메뉴 -->
        <put-attributename="left" value="/WEB-INF/jsp/commons/commLeft.jsp"/>
        <!--동적 바디 -->
        <put-attributename="body" value=""/>
        <!-- 하단 푸터 -->
        <put-attributename="footer" value="/WEB-INF/jsp/commons/commFooter.jsp"/>
    </definitions>
 
    <!--URL호출에 따른 동적호출부 1depth, 2depth,3depth -->
    <definition name="site/*" extends="tilesbase">
        <put-attribute name="body" value="/WEB-INF/jsp/{1}.jsp" />
    </definition>
    <definition name="site/*/*" extends="tilesbase">
        <put-attribute name="body" value="/WEB-INF/jsp/{1}/{2}.jsp" />
    </definition>
    <definition name="site/*/*/*" extends="tilesbase">
        <put-attribute name="body" value="/WEB-INF/jsp/{1}/{2}/{3}.jsp" />
    </definition>
</tiles-definitions>
cs

 

간단히 설명하자면 공통 레이아웃을 commLayout.jsp로, tilesbase라는 이름으로 정의하고

commHeader.jsp를 header , commLeft.jsp는 left , commFooter.jsp는 footer로 태그로 정의하고

하단에는 3depth url 규격에 맞춰서 호출한다는 의미이다. 

 

현재 우리 시스템은 3depth url규격으로 되어있다. localhost:8080/test/test/test.jsp 라는 형태.

그래서 site/*/*/* 로만 정의해도 문제 없으나, 일단은 혹시몰라 3depth를 모두 개별로 정의했다.

tilesbase, tiles.xml 및 site/* 등등 모든것들은 개발에 맞춰 설정하면 된다.

 

3. commLayout.jsp생성

예시로 맨 위의 이미지와 같이 첨부하는 방법을 들어줄 것이다. 기본 공통 레이아웃은 div태그별로 잘게 잘 쪼개서 commHeader.jsp, commLeft.jsp, commFooter.jsp와 같은 형태로 만들어준다. 

저 comm시리즈와 함께 우리가 업무에서 만들 것들을 조립하는 큰 판을 commLayout.jsp라고 칭한다. 이 commLayout.jsp에서 블록을 조립하듯 퍼블리셔분께서 작업해주신 div태그 class별로 조립을 하는거다.

 

노파심에 덧붙여(미래의 이 작업을 할 내게) jsp의 div class 별로 큰 구획들이 잡혀있으니 이것들을 잘게 쪼개면 된다.

큰 class 별로 쪼개서 commHeader, commLeft, commFooter 등등을 만들어 jsp로 만들어두고, commLayout 에서 tiles 에서 설정한 각각의 jsp들을 조립하는 형태다. 다음의 소스코드를 보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
(중략)
 
<div class="wrapper">
    <!--공통 Header -->
    <tiles:insertAttribute name="header" />
 
    <div class="root-container">
        <div class="left-wrap">
            <tiles:insertAttribute name="left" />
        </div>
        <div class="contents-wrap">
            <tiles:insertAttribute name="body" />
            <tiles:insertAttribute name="footer" />
        </div>    
    </div>
</div>
cs

commLayout.jsp 에서 tiles태그를 사용하여 tiles.xml에서 정의한 jsp들을 include하는 형태이다.

예제 소스코드라서 간략하게 되어있지만, 실제로는 div class의 구조가 복잡하느라 퍼블리셔 작업물을 몇 번이나 확인했는지 모르겠다.

일단 여기까지 설정을 온전하게 잘 했다면 큰 고비는 넘긴것이다.

 

4. dispatcher-servlet.xml 설정

dispatcher-servlet에서는 spring mvc 구조에서 모든 클라이언트의 요청을 받아 처리하는 부분으로, 일반적으로 jsp view resolver로 설정이 되어있다.

그런데 이렇게 설정했다가는 호출하는 jsp가 먼저 먹어버리니까, 우선순위를 tiles 로 먹도록 설정해야한다. 다음의 설정을 보자. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
(중략)
 
<!-- Tiles 설정 -->
<bean id="tilesConfigurer"
    class="org.springframework.web.servlet.view.tiles3.TilesConfigurer"
    p:checkRefresh ="true">
    <property name="definitions">
        <list>
            <value>/WEB-INF/tiles/tiles.xml</value>
        </list>
    </property>
</bean>
 
<!-- Tiles 설정 -->
<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver"
    p:viewClass="org.springframework.web.servlet.view.tiles3.TilesView"
    p:order="0" />
 
<!--기존의 ViewResolver 설정 - order를 후순위(3)로 설정 -->
<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver"
    p:viewClass="org.springframework.web.servlet.view.JstlView"
    p:prefix="/WEB-INF/jsp/"
    p:suffix=".jsp"
    p:order="3" />
cs

 

dispatcher-servlet에 tiles관련 설정을 넣어준다. 동시에, 모든 view호출은 tiles 우선으로 처리하도록 (그래야 레이아웃이 먹으니) p:order를 0으로 주고, 기존의 view Resolver설정을 유지함과 동시에 후순위(나는 3순위로)로 설정한다.

이게 끝이 아니다. 우리는 Controller 에서 url을 호출하는 부분도 수정해야 한다.

 

 

5. 공통 컨트롤러 수정 

나는 위에서 site/*/*/* 형태로 설정했다. 이 말은, ModelAndView 에서 return 하는 uri에 대해 tiles definition이 가로채서 WEB-INF/jsp/{1}/{2}/{3}.jsp 에 있는 jsp를 리턴해준다는 의미이다.

기존에 설정된 viewResolver도 동일하다. 하지만 내가 설정한 것은 site/를 반환하도록 되어있으니, 공통부 ModelAndView에서도 site/ 형태로 반환해야 한다.

 

그냥 별거 없이, ModelAndView return시 "site/"를 StringBuilder 에서 append해주면 된다. 이건 개발자 구현 나름이니까.

그래서 최종 형태는 다음과 같아야 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public ModelAndView commonVie(HttpServletRequestreq, HttpServletResponse resp
        , @PathVariable String oneDepth
        , @PathVariable String twoDepth
        , @PathVariable String threeDepth) throws Exception{
    
    // 중략
 
    StringBuilder pagePath = new StringBuilder();
    pagePath.append("site/")
        .append(oneDepth)
        .append("/")
        .append(twoDepth)
        .append("/")
        .append(threeDepth);
    
    // site/oneDepth/twoDepth/threeDepth 형태로 반환
    ModelAndView mav = new ModelAndView(pagePath.toString());
    
    return mav;
}
cs

 

이렇게 해줘야 site/ 형태로 url을 리턴하고, tilesResolver가 캐치해서 tiles.xml의 구조로 리턴하게 될 것이다.

 

그런데 왜 site/형태를 쓸까?

site/ 형태의 url을 쓰지 않으면 모든 경로는 /one/two/three형태로 리턴이 될 것이고, 모든 페이지에 대해 tiles 가 적용이 될 것이다. 이 말인 즉, /login , /error와 같은 수많은 퍼블릭 페이지들도 tiles영향을 받게 된다는 점이다.

 

그래서 퍼블릭 페이지와의 구분을 위해 내부 페이지들의 구분자 역할을 하는 개념이라 보면 된다.

 

일단 여기까지, 이 설정을 내부망에서 한다고 얼마나 삽질했던지. 아휴 힘들었다. 

반응형
블로그 이미지

김생선

세상의 모든것을 어장관리

,